/* -*- 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.                                                 */
/*                                                                       */

/* 2-23-89  BJ  Added a pascal callable version of SwapMMUMode.          */
/* 2-23-89  BJ  Changed hiFox in nubus read calls to use make_pointer. */
/* 2-23-89  BJ  Added virtual <> physical address translations for AUX. */

#include <micronet-device.h>
#include <micronet-accessors.h>
#include <utility.h>
#include <strings.h>
#include <packages.h>
#include <dialogs.h>
#include <resources.h>
#include <memory.h>    /* needed for BlockMove()  clm 08/30/89   */

#pragma segment Dummy
/* This dummy routine is required because it is referenced by r_ioctl() but is only called in the driver where it is overridden. */
drvr_control()
{
	debugstr("drvr_control can only be called inside the driver.");
}
#pragma segment Main

extern BE_Data BE_INFO = {0};				/* Where NuBus Error Information goes	*/

short
r_ioctl(refnum, cmd, args)
	 int refnum;
	 unsigned int cmd;
	 short *args;
{
  ParamBlockRec parms;
  short error;

  parms.cntrlParam.ioCompletion = NULL;
  parms.cntrlParam.ioVRefNum = NULL;
  parms.cntrlParam.ioCRefNum = (short) refnum;
  parms.cntrlParam.csCode = (unsigned short) cmd;
  
  BlockMove((Ptr)args, (Ptr)parms.cntrlParam.csParam, 20);		

  if(in_driver_p)
	error = drvr_control(&parms, 0);
  else
	error = PBControl(&parms, false);
	
  BlockMove((Ptr)parms.cntrlParam.csParam,(Ptr)args, 20);
  
  return (error < 0) ? error : parms.cntrlParam.ioResult;
}

/************************************************************/
/*                                                          */
/* DCE Functions                                            */
/*                                                          */
/************************************************************/

/* Returns the handle for a dce from the unit table. */
DCtlEntry **
get_dce(refnum)
	 short refnum;
{
  DCtlEntry **base = *uTableBase;
  unsigned int offset = -1 * (refnum + 1);
  return (DCtlHandle) *(base + offset);
}

/* Sets the handle for a dce from the unit table. */
void
set_dce(refnum, handle)
	 short refnum;
	 DCtlEntry **handle;
{
  DCtlEntry **base = *uTableBase;
  unsigned int offset = -1 * (refnum + 1);
  (DCtlHandle) *(base + offset) = handle;
}

/************************************************************/
/*                                                          */
/* Ram cache control                                        */
/*                                                          */
/************************************************************/

#define CacheCom (*((unsigned char *) 0x39c))
#define ram_cache_mask 0x80

/* Mode = true means that ram caching is inhibited.     */
/* Returns the mode that was in effect before swapping. */

pascal Boolean
set_ram_cache_mode(mode)
	 Boolean mode;
{
  Boolean old_mode = (CacheCom & ram_cache_mask);
  if(mode)
	CacheCom |= ram_cache_mask;
  else
	CacheCom &= ~ram_cache_mask;
  return old_mode;
}


/************************************************************/
/*                                                          */
/* Queueing                                                 */
/*                                                          */
/************************************************************/

static void
get_q_lock(queue)
  	queue_struct *queue ;
{
  unsigned long collision_count = 0;
  
  while(!test_and_set(&queue->lock))
	{
	  collision_count++;
	  if(collision_count > 5000)
	    {
			SystemTask();
		    if(collision_count > 6000)
			  debugstr("Queue lock stuck");
			  break;
		}
	}
  set_q_lock_collisions(queue, collision_count + q_lock_collisions(queue));
}

void 
q_element(queue, el)
     queue_struct *queue;
     q_elem *el;
{
  q_elem *tail_q_el;
  extern Boolean use24bitmode;

  if(!el) debugstr("Tried to queue a null element.");
  if(!(use24bitmode ? ((unsigned long) queue & 0xfffff) : ((unsigned long) queue & 0xffffff))) debugstr("queue_element received a null queue.");
  
  set_q_link(el, NULL);
  get_q_lock(queue);
  
  /* clm 8/24/89 - cast result of ptr32to24 to be of type (q_elem *) */
  if(tail_q_el = (q_elem *)ptr32to24(q_tail(queue)))
	  set_q_link(tail_q_el, ptr24to32(el));
  else
	/* Implies queue empty. */
	set_q_head(queue, ptr24to32(el));
	 
  set_q_tail(queue, ptr24to32(el));

  queue->length = swap_32b(swap_32b(queue->length) + 1);
  q_unlock(queue);
}

q_elem
*deq_element(queue)
	 queue_struct *queue;
{
  q_elem *head_q_el;
  Ptr next_lispm_el;
  extern Boolean use24bitmode;

  if(!(use24bitmode ? ((unsigned long) queue & 0xfffff) : ((unsigned long) queue & 0xffffff))) debugstr("queue_element received a null queue.");
  
  get_q_lock(queue);

  /* clm 8/24/89 - cast result of ptr32to24 to be of type (q_elem *) */
  if (head_q_el = (q_elem *)ptr32to24(q_head(queue)))
	{	  
	  next_lispm_el = q_link(head_q_el);
	  set_q_head(queue, next_lispm_el);
	  
	  if(!next_lispm_el)  	/* Implies Q just became empty */
		 set_q_tail(queue, NULL);
		 
  	  queue->length = swap_32b(swap_32b(queue->length) - 1);
	  set_q_link(head_q_el, NULL);  
	}
  q_unlock(queue);
  return(head_q_el);
}

launch(pname)
	 char *pname;
{
  struct
	{
	  char *pfname;
	  unsigned short param;
	  char lc[2];
	  unsigned long ExtBlockLen;
	  unsigned short fFlags;
	  unsigned long LaunchFlags;
	}  launch_info;

  launch_info.pfname = pname;
  launch_info.param = 0;
  launch_info.lc[0] = 'L';
  launch_info.lc[1] = 'C';
  launch_info.ExtBlockLen = 6;
  launch_info.fFlags = 0;
  launch_info.LaunchFlags = 0xc0000000;
  launch_internal(&launch_info);
}

/************************************************************/
/*                                                          */
/* NuBus Read/Write                                         */
/*                                                          */
/************************************************************/

unsigned int mmu_mode = MMU24;

void	
nubus_write(slot, offset, value)
  short 	slot;        
  unsigned long  	offset;	
  unsigned long 	value;
{	
  unsigned long *address;
  
  address = (unsigned long *)make_pointer(slot, offset);
  /* clm 9/25/89 - the new 3.0 compiler doesn't seem to like the following macro */
  /* with_32_bit_mode(*address = swap_32b(value));  */
  mmu_mode = MMU32; 
  swap_mmu_mode(mmu_mode);
 
  *address = swap_32b(value);
  
  mmu_mode = MMU24;	
  swap_mmu_mode(mmu_mode);
}

unsigned long
nubus_read(slot, offset)
  short 	slot;
  unsigned long  	offset;	
{	
  unsigned long  	value;	
  unsigned long *address;
  
  address = (unsigned long *)make_pointer(slot, offset);
  mmu_mode = MMU32;
  swap_mmu_mode(mmu_mode);
  value = *address;       /* clm 9/25/89 - removed use of with_32_bit_mode  */
  mmu_mode = MMU24;	
  swap_mmu_mode(mmu_mode);    
  return(swap_32b(value));
}

void
  nubus_write_byte(slot, offset, value)
short 	slot;
unsigned long  	offset;	
unsigned short 	value;
{	
  char *address;
  
  address = (char *)make_pointer(slot, offset);
  mmu_mode = MMU32;
  swap_mmu_mode(mmu_mode);
  *address = value;      /* clm 9/25/89 - removed use of with_32_bit_mode  */
  mmu_mode = MMU24;	
  swap_mmu_mode(mmu_mode);
}	

unsigned short
  nubus_read_byte(slot, offset)
short 	slot;
unsigned long  	offset;	
{	
  unsigned short value;	
  char *address;
  	
  address = (char *) make_pointer(slot, offset);
  mmu_mode = MMU32;
  swap_mmu_mode(mmu_mode);
  value =  *address;      /* clm 9/25/89 - removed use of with_32_bit_mode  */
  mmu_mode = MMU24;	
  swap_mmu_mode(mmu_mode);    
  return(value);
}
#define BadCmdAlert 128

PrtWarnMsg(CmdType, BadCmd)
	 char *CmdType;
	 short BadCmd;
{
/* Send an alert message that an illegal command was received */

  char cmdString[255];
  
  with_24_bit_mode
	(
	 if (BadCmd != 0) {
		numtostring((long) BadCmd, cmdString);
	 	paramtext(CmdType, cmdString, "", "");
	 } else
		paramtext(CmdType, "", "", "") ;
	 NoteAlert(BadCmdAlert, NULL);
	 )
}

#define ErrorAlert		100

PrtErrorMsg(errno,arg)
int errno;
short arg;
{
    Handle string ;
	char cmdString[255];

	with_24_bit_mode(
	  string = GetResource('STR ', errno) ;	/* MicronetDriver init failed */
	  if (arg != 0) {
		  numtostring((long) arg, cmdString);
		  paramtext(*string, cmdString, "", "") ;
		  }
	  else
	  	  paramtext(*string, "", "", "") ;
	  StopAlert(ErrorAlert, NULL) ;
	) ;
}


pascal unsigned int
swapMMUMode(mode)
	 unsigned char *mode;
{
	return *mode = (unsigned char) swap_mmu_mode(*mode);
}


/************************************************************************/
/*                                                                      */
/* AUX virtual to physical support.                                     */
/*                                                                      */
/************************************************************************/

pascal Ptr
physical_to_virtual(address)
	Ptr address;
{
	unsigned long ptr = (unsigned long) address;
	return ((Ptr) (AUX_p ? (0x0fffffff & ptr) : ptr));
}

pascal Ptr
virtual_to_physical(address)
	Ptr address;
{
	unsigned long ptr = (unsigned long) address;
	/* If address is 0 then leave it 0 so that queueing functions that use 0 as the empty flag will work. */
    return ((Ptr) (ptr ? (AUX_p ? (0xf0000000 | ptr) : ptr) : 0));
}

/* Return a "virtual" memory pointer that points to the physical memory described by slot and offset. */
/* 9/26/89 clm - cast slot to unsigned long so that proper instructions generated. */
pascal Ptr
make_pointer(slot, offset)
	 unsigned char slot;
	 unsigned long offset;
{
	return ((Ptr) (((unsigned long)slot << 24) | offset | (AUX_p ? 0x00000000 : 0xf0000000)));
}

/************************************************************************/
/*                                                                      */
/* Misc AUX support                                                     */
/*                                                                      */
/************************************************************************/

pascal Boolean
aux_p()
{
	extern Boolean AUX_p;
	return AUX_p;
}
