/* -*- Mode:C; Tab-width:4 -*- */
/*                                                                       */
/*                                                                       */
/*                      RESTRICTED RIGHTS LEGEND                         */
/*                                                                       */
/* Use, duplication, or disclosure by the Government is subject to       */ 
/* restrictions as set forth in subdivision (c)(1)(ii) of the Rights in  */
/* Technical Data and Computer Software clause at 252.227-7013.          */
/*                                                                       */
/*                    TEXAS INSTRUMENTS INCORPORATED.                    */
/*                            P.O. BOX 149149                            */
/*                         AUSTIN, TEXAS 78714-9149                      */
/*                              MS 2151                                  */
/*                                                                       */
/*  Copyright (C)   1987,1988,1989,1990 Texas Instruments Incorporated.  */
/*  All rights reserved.                                                 */
/*                                                                       */

/*  9-28-88   BJ   Add the function handle_micronet_ports to speed up RPC. */
/*  2-23-89   BJ   Added Boolean 24bitmode = true;                         */
/*                 Also conditionalized the generation of some pointers.   */

#include <micronet-device.h>
#include <micronet-accessors.h>
#include <sockets.h>
#include <strings.h>
#include <slots_TI.h>
#include <read_startup.h>
#include <addincomm.h>
#include <utility.h>

#define LOCALDEBUG 0

Boolean in_driver_p = false; /* Set to true if we are running in the main driver application. */

#define MICRONET_PORTS_TRANSMIT_CHANNEL 6
#define MICRONET_PORTS_RECEIVE_CHANNEL 6
#define register_base_offset 0xff010

Boolean use24bitmode = true;
Boolean AUX_p = false;
Ptr virtualMxBase;                    /* Base virtual address of mx board. */
int AUX_heap_zone_size =   0xf0000;

#define SEGMENT_SIZE         0x400000

map_in_board(slot)
{
	int x, error;
	printf("Mapping in physical memory.\n");
	virtualMxBase = make_pointer(slot, 0);

	for(x=0; x<4; x++)
	  {
		  if(error = phys(x, virtualMxBase + (x * SEGMENT_SIZE), SEGMENT_SIZE, virtual_to_physical(virtualMxBase + (x * SEGMENT_SIZE))))
		    {
			  printf("Error while mapping memory:%x\n", error);
		      exit(0);
			}
	  }	  
}

map_out_board(slot)
{
	int x, error;
	virtualMxBase = make_pointer(slot, 0);
	
	printf("Mapping out physical memory.\n");

	for(x=0; x<4; x++)
	  {
		  if(error = phys(x, virtualMxBase + (x * SEGMENT_SIZE), 0, virtual_to_physical(virtualMxBase + (x * SEGMENT_SIZE))))
		    {
			  printf("Error while unmapping memory:%x\n", error);
		      exit(0);
			}
	  }	  
}


void
handle_micronet_ports()
/* Give up time for the driver to do paging if necessary, then issue an ioctl to handle micronet ports channel. */
{
	unsigned long *parms[10];
	
	/* If the driver needs to do paging or there is anything in the micronet ports channel then handle it. */
	if(nubus_read(DriverData->mx_slot, nupi_register) || q_length(&(channels[MICRONET_PORTS_RECEIVE_CHANNEL]->queue_host)))
	  r_ioctl(DriverData->refnum, HANDLE_MICRONET_PORTS, parms);
	
}


extern int CPU_slot;

struct driver_data *DriverData;

#define TI_microExplorer_ID 0x012D
#define lo_slot 9
#define hi_slot 14

short mxslot ;		/* pascal referenceable(?) slot number */
	 
	 /* Return the slot number of the micro-explorer. */
#ifdef LIMPET

Boolean
find_mx(slot_var)
	 unsigned char *slot_var;
{
    OSErr	err;
    SpBlock	MySPB;
    SPRAMRecord MyPRAM ;
    unsigned char slot = 0;
    startup_tbl	**start_ptr ;
    int _status ;
	
	/* Under AUX the slot manager is not implemented so just read startup. */
    if(!AUX_p)
      {
		  
	      for (slot = lo_slot; slot <= hi_slot; slot++)
			{
				MySPB.spSlot = slot;
				MySPB.spResult = (long)&MyPRAM ;
				err = SReadPRAMRec(&MySPB);
				if (err == 0)
				  {
					  if (MyPRAM.BoardID == TI_microExplorer_ID)
						{
#if LOCALDEBUG
							printf("find_mx: slotmgr found MX in slot %d.\n",slot);
#endif
							*slot_var = slot;
							return(TRUE);
						}
				  } 
#if LOCALDEBUG
				else
				  printf("find_mx search error = %d.\n",err);
#endif
			}
		  
#if LOCALDEBUG
		  printf("find_mx: SlotMGR found no MX. Need new ROMs?\n"); /* 2.3.88 MBC */
#endif
	  }

	/* If we do not have the new roms then we have to read the startup info. Don't try this
	   outside of the driver, just default the slot number. */
		if(in_driver_p)
		  {   
			  start_ptr = read_startup();
			  slot = startup_forslot(start_ptr) ;
		  }
	else
	  slot = 0;

    if (slot == 0)
	  slot = 0x0d ;
	
	/* perform sanity check */
#ifdef TRASH
    _status = (nubus_read(slot, 0xff0010) == 0xc3000000) ;
    _status = status && (nubus_read(slot, 0xff0014) == 0) ;
    _status = status && (nubus_read(slot, 0xff0018) == 0) ;
    _status = status && (nubus_read(slot, 0xff001c) == 0) ;
    _status = status && (nubus_read(slot, 0xfffffc) == 0xe1000000) ;
#endif
    _status = TRUE ;
	
#if LOCALDEBUG
    printf("Found MX == %d\n", _status) ;
#endif
    *slot_var = slot ;
    return(_status) ;
}
#else /* !LIMPET */
/* LASHUP always defaults to slot 0x0C */
Boolean
  find_mx(slot_var)
unsigned char *slot_var;
{
    *slot_var = 0x0C ;
    return(TRUE) ;
}
#endif /* LIMPET */

/* Return the slot of the Limpet Processor from DriverData */
unsigned char
  *get_cpu_slot()
{
    return(&DriverData->mx_slot) ;
}

pascal short GetCpuSlot()		/* make this callable from nupi.p *mbc*/
{
#ifdef LIMPET
	return(mxslot);
#else
	return(0x06) ;
#endif
}


/* Return the slot of the host processor. */
Boolean
  find_host(slot_var)
unsigned char *slot_var;
{
    *slot_var = 0;
    return(TRUE) ;
}

/* Set a pointer to the driver global data. */
Boolean
find_driver_data(slot, ptr)
	 unsigned char slot;
	 struct driver_data **ptr;
{
    *ptr = ((struct driver_data *)make_pointer(slot, DriverDataOffset));
	if(use24bitmode) *ptr = (struct driver_data *)ptr32to24(*ptr);  /* clm 10/02/89 - cast */
    return(TRUE) ;
}

#define MXBoardCtlReg 0xC00004 

#define MICRONET_RUNNING 6 

#ifdef LIMPET 
#define SOFTWARE_HALTED 15
#define MXBoardCtlReg 0xC00004
#else
#define SOFTWARE_HALTED 7
#endif 

Boolean
micronet_running_p()
{
	int tempi;
	
#ifdef LIMPET
		tempi = nubus_read_byte(DriverData->mx_slot, MXBoardCtlReg) ;
#else
		tempi = nubus_read_byte(0x06, 0xC00000) ; 
#endif

	    /* Boot status is bits 4-7 in LIMPET, bits 0-2 in LASHUP */
#ifdef LIMPET
		tempi = (tempi >> 4) & 15 ;
#else
		tempi &= 7 ;
#endif
	return ((tempi >= MICRONET_RUNNING) && (tempi != SOFTWARE_HALTED));
 	
}

/* Wait until micronet is running on the lisp side. */
Boolean
  wait_micronet_running()
{
    unsigned short tempi;
	
    do {
		if (DriverData->driver_initialized == FALSE)
		  return(-1) ;
		
		event_handler(0, 1);
		
	    /* Read Board Control Register */
#ifdef LIMPET
		tempi = nubus_read_byte(DriverData->mx_slot, MXBoardCtlReg) ;
#else
		tempi = nubus_read_byte(0x06, 0xC00000) ; 
#endif
	    /* Boot status is bits 4-7 in LIMPET, bits 0-2 in LASHUP */
#ifdef LIMPET
		tempi = (tempi >> 4) & 15 ;
#else
		tempi &= 7 ;
#endif
    } while ((tempi < MICRONET_RUNNING) && (tempi != SOFTWARE_HALTED));
	
    return(0) ;
}

int
initialize_micronet()
{
    unsigned char mx_slot;
	
    if (!find_mx(&mx_slot))
	  {
#ifdef DEBUG
		DebugStr("Error while setting up Micronet driver: MicroExplorer not found:");
#endif
		return(-1) ;
    }
	
	/*  CPU_slot = mx_slot;  pass it to Nupi.p */
    find_driver_data(mx_slot, &DriverData) ;
    if (!DriverData->driver_initialized || DriverData->mx_slot != mx_slot)
	  {
#ifdef DEBUG
		  DebugStr("Error while setting up Micronet driver: Driver global data not found:");
#endif
		  return(-1) ;
	  }
	
    if (!GetDCtlEntry(DriverData->refnum))
	  {
		  return(-1) ;
	  }
	
    if (wait_micronet_running())
	  return(-1) ;
	
#ifdef DEBUG
    if (debugFlag)
	  printf("Initialize_micronet, DriverData->dce = %x, dce = %x, refnum = %d\n",
			 GetDCtlEntry(DriverData->refnum), GetDCtlEntry(DriverData->refnum), DriverData->refnum);
#endif

	initialize_comm((DriverData)->mx_slot);

    return(0) ;
}

Boolean 
add_channel_open(ch, fn)
	 int ch;
	 Ptr fn;
{
    struct accessor_info parms;
	
    parms.ch = ch;
    parms.fn = fn;
    return(r_ioctl(SOCKET_DEVICE, ADD_OPEN_FUNCTION, &parms)) ;
}

Boolean
  remove_channel_open(ch)
int ch;
{
    struct accessor_info parms;
	
    parms.ch = ch;
    return(r_ioctl(SOCKET_DEVICE, REMOVE_OPEN_FUNCTION, &parms)) ;
}

Boolean 
  add_channel_close(ch, fn)
int ch;
Ptr fn;
{
    struct accessor_info parms;
	
    parms.ch = ch;
    parms.fn = fn;
    return(r_ioctl(SOCKET_DEVICE, ADD_CLOSE_FUNCTION, &parms)) ;
}

Boolean 
  remove_channel_close(ch)
int ch;
{
    struct accessor_info parms;
	
    parms.ch = ch;
    return(r_ioctl(SOCKET_DEVICE, REMOVE_CLOSE_FUNCTION, &parms)) ;
}

Boolean 
  add_channel_handler(ch, fn)
int ch;
Ptr fn;
{
    struct accessor_info parms;
	
    parms.ch = ch;
    parms.fn = fn;
    return(r_ioctl(SOCKET_DEVICE, ADD_HANDLER_FUNCTION, &parms)) ;
}

Boolean 
  remove_channel_handler(ch)
int ch;
{
    struct accessor_info parms;
	
    parms.ch = ch;
    return(r_ioctl(SOCKET_DEVICE, REMOVE_HANDLER_FUNCTION, &parms)) ;
}

#define BOOT_TYPE 0x7fc   /* 2044. */

dowarmboot()
{
    printw("Warmboot\n") ;
#ifdef LIMPET
    nubus_write(DriverData->mx_slot, DriverDataOffset + BOOT_TYPE, 0); /* reset force-crash word */
    nubus_write(DriverData->mx_slot, 0xe00004, 1);  		/* post the event */
#else
    nubus_write(0xfc, DriverDataOffset + BOOT_TYPE, 0);
    nubus_write(0xf6, 0xe00004, 1);
#endif
}

doforcecrash()
{
    printw("Force crash\n") ;
#ifdef LIMPET
    nubus_write(DriverData->mx_slot, DriverDataOffset + BOOT_TYPE, 1); /* set force-crash word */
    nubus_write(DriverData->mx_slot, 0xe00004, 1);  					/* post the event */
#else
    nubus_write(0xfc, DriverDataOffset + BOOT_TYPE, 1);
    nubus_write(0xf6, 0xe00004, 1);
#endif
}

sendintr(value)
	 int value ;
{
#ifdef LIMPET
    nubus_write(DriverData->mx_slot, 0xE0000C, value) ;
#endif
}
