/* -*- 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     - Conditionally create pointers in 24 or 32 bit mode. */


#include <addinComm.h>
#include <micronet-accessors.h>
#include <osutils.h> /* For sysbeep() */
#include <stdio.h>   /* For debug printf's. */
#include <strings.h> /* For DebugStr */
#include <utility.h> /* For make_pointer. */

/************************************************************/
/*                                                          */
/* Channel Communications                                   */
/*                                                          */
/************************************************************/

/* A boolean which controls whether or not boot progress messages are written on standard output.*/
Boolean verbose = true;

#define register_base_offset 0xff010

channel *channels[MAX_NUMBER_OF_CHANNELS]; /* An array of pointers to the bank of comm channels. */

initialize_comm(slot)
	 unsigned char slot;
{
  unsigned char ch;

  if(verbose)
	printf("Initializing comm.\n");

  for(ch=0; ch < MAX_NUMBER_OF_CHANNELS; ch++)
	{
	  channels[ch]  = (((channel *) make_pointer(slot,  register_base_offset)) + ch);
	  if(use24bitmode)
		channels[ch] = (channel *) ptr32to24(channels[ch]);  /* clm 9/27/89 - cast to (channel *) */
	}
  
  init_alloc_qs(slot);
}

unhandled_cmd(cmd)
	 acb *cmd;
{
#pragma unused(cmd)
	SysBeep(1);
}

acb *get_command(ch, no_hang_p)
	 int ch, no_hang_p;
{
  acb *cmd;
  if (q_length(&(channels[ch]->queue_mx)) == 0)
    if (no_hang_p) return NULL;
	else
	  wait_for_condition ((q_length(&(channels[ch]->queue_mx)) != 0));
  cmd = (acb *) deq_element(&(channels[ch]->queue_mx));  /* clm 9/27/89 - cast to (acb *) */

#ifdef DEBUG  
  if((((long) cmd) & 0x0f00000) != ((unsigned long)DriverData->mx_slot << 20))
    DebugStr("\pget_command returned a pointer from another slot");
#endif  

  return cmd;
} 

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

#define alloc_q_base_offset 0xff400

#define MAX_NUMBER_OF_QUEUES 6
	 
/* An array of allocation q element sizes. */
int alloc_queue_sizes[] = { 32 100 512 2200 10000 32768 };

/* An array of pointers to the bank ACB allocation queues. */
queue_struct *alloc_queues[MAX_NUMBER_OF_QUEUES];

queue_struct
*find_q(size)
     int size;
{
  int i;
  
  for (i=0; i < MAX_NUMBER_OF_QUEUES; i++)
	if (size <= alloc_queue_sizes[i])
	  return(alloc_queues[i]);
  return(NULL);
}

/*
;; Default ACB status:
;;   Block-Deallocatable = NIL
;;   Requestor-Complete = T
;;   Input-Complete = T
;;   Command-Complete = T
*/

#define ACB_STATUS_READY 0xc080

acb *get_acb_fast(size)
	int size;
{
  acb *ptr;
  queue_struct *queue;
  queue = find_q(size);
  
  if (queue)
	ptr = (acb *) deq_element(queue);
  else 
	return(NULL);	
  
  if (ptr)
	{
	  set_status(ptr, ACB_STATUS_READY);
	  set_deallocatable(ptr, TRUE); /* Override status for now. */
	  
#ifdef DEBUG
	  if((((long) ptr) & 0x0f00000) != ((unsigned long)DriverData->mx_slot << 20))
		DebugStr("\pget_acb returned a pointer from another slot");
#endif

	  return(ptr);
	}
  else
	{
	  printw("Can't get ACB of size %d.\n", size);
	  return(NULL);
	}
}

void
  return_acb_fast(cmd)
	 acb *cmd;
{
  int size = data_bytes(cmd);
  queue_struct *q = find_q(size);

#ifdef DEBUG
  if((((long) cmd) & 0x0f00000) != ((unsigned long)DriverData->mx_slot << 20))
    DebugStr("return_acb was passed a pointer from another slot");
#endif  

  if(servicer_complete(cmd) &&
	 requestor_complete(cmd) &&
	 deallocatable(cmd))
	if (q)
	  q_element(q, (q_elem *)cmd);
	else
	  {
		printw("Cant find queue for size %d.\n", size);
		PrtErrorMsg(214) ;	/* "return_acb_fast: Cant find acb queue" */
		exit(-1);  /* gone forever */

	  }
}

void
return_acb_server(cmd)
	acb *cmd;
{
	Boolean return_p = requestor_complete(cmd);
	set_input_complete(cmd, 1);
	set_servicer_complete(cmd, 1);
	if(return_p) return_acb_fast(cmd);
}

init_alloc_qs(slot)
	 unsigned char slot;
{
  unsigned char q;

  if(verbose)
	printf("Initializing allocation queues.\n");

  for (q=0; q < MAX_NUMBER_OF_QUEUES; q++)
	{
		alloc_queues[q]  = (((queue_struct *) make_pointer(slot, alloc_q_base_offset)) + q);
		if(use24bitmode) alloc_queues[q] = (queue_struct *) ptr32to24(alloc_queues[q]);  /* clm 9/27/89 - cast to (queue_struct *) */
	}

}

