/*
 * Vince version 1.0.1
 * 
 * 
 * +++++++++++
 *  V I N C E  ---  Vendor Independent Network Control Entity
 * +++++++++++
 * Copyright (c) 1994     Advanced Research Projects Agency (ARPA/CSTO)
 *                                   and the
 *                        Naval Research Laboratory (NRL/CCS)
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the software,
 * derivative works or modified versions, and any portions thereof, and
 * that both notices appear in supporting documentation.
 * 
 * ARPA AND NRL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION
 * AND DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
 * RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * ARPA and NRL request users of this software to return to:
 * 
 *                 vince-distribution@cmf.nrl.navy.mil
 * 
 *                            or
 * 
 *                 Naval Research Laboratory, Code 5590
 *                 Center for Computational Science
 *                 Washington, D.C. 20375-5000
 * 
 * any improvements or extensions that they make and grant ARPA and NRL 
 * the rights to redistribute these changes.
 * 
 */

#include <atmcore/atmcore.h>
#include <protocol/protocol.h>
#include <fcntl.h>
#include <skip/skip.h>
#include <elib/string.h>
#include <sys/types.h>

typedef struct shutdown_context {
  void (*function)();
  void *arg;
} *shutdown_context;

layer create_skip_layer();
extern layer create_kernel_layer();

static void *kernel_shutdown_function;
error host_write_path(path p)
{
}

int host_get_count()
{
  return(0);
}

void host_clear_count()
{
}

void sba_disassemble_stack(port p,layer l,int type)
{
/*  printf("sba_disassemble_stack(p=%x, l=%x, type=%x)\n",
	 p, l, type);
*/
  if (type & STACK_KERNEL) {
/*    printf("sba_disassemble_stack() KERNEL stack\n");*/
    kernel_stack_shutdown(l);
  } else {
/*    print_layer(l);*/
    (*l->receive_down)(l,0,PROTOCOL_STACK_SHUTDOWN);
    if (l->down) (*l->down->receive_up)(l->down,0,PROTOCOL_STACK_SHUTDOWN);
  }
}

static void sba100_assemble_stack(port p,int vpi,int vci,int type,layer top,
				  void (*shutdown)(),void *shutdown_arg)
{
  char up_label[8];
  char down_label[8];
  int flags=0;
  layer klayers[10];
  layer players[5];
  int number_of_klayers=0;
  int number_of_players=0;
  layer pl,z;
  int i;
  void *kernel_shutdown=0;
  shutdown_context kernel_shutdown_arg=0;

  if (shutdown){
    kernel_shutdown=kernel_shutdown_function;
    kernel_shutdown_arg=
      (shutdown_context)allocate_memory(sizeof(struct shutdown_context));
    kernel_shutdown_arg->function=shutdown;
    kernel_shutdown_arg->arg=shutdown_arg;
  }

  sprintf (up_label,"%04x:^",vci);
  sprintf (down_label,"%04x:v",vci);

  if (type & STACK_KERNEL){
    klayers[number_of_klayers++]=top;
  } else {
    if (!create_dumb_interface(klayers,&pl)) {
      printf ("couldn't assemble stack\n");
      return;
    }
    number_of_klayers++;
    players[number_of_players++]=top;
  }

  if (type&STACK_PRINT){
    if (type&STACK_KERNEL) { 
      klayers[number_of_klayers++]=
	create_kernel_layer("create_print %04x:^ %04x:v",vci,vci);
    }
    else 
      players[number_of_players++]=create_print(up_label,down_label);
  } 
  
  if (type&STACK_AAL_4){
    flags=PROTOCOL_HARDWARE_CRC10;
    klayers[number_of_klayers++]=create_kernel_layer("create_aal4 %d",flags);
  }

  if (type&STACK_AAL_5)
    klayers[number_of_klayers++]=create_kernel_layer("create_aal5 %d",flags);

  if (type&STACK_SSCOP) players[number_of_players++]=create_sscop();
  klayers[number_of_klayers++]=
    create_kernel_layer(string_format("create_sba100_atm %d %d %d %x %x",
				      flags,vpi,vci,kernel_shutdown,
				      kernel_shutdown_arg));
  
  for(i=0;i<(number_of_klayers-1);i++) kstaple(klayers[i],klayers[i+1]);
  
  ksignal(klayers[i],PROTOCOL_CONNECTED);
  if (!(type & STACK_KERNEL)) players[number_of_players++]=pl;
  if (number_of_players)
    assemble_stack(number_of_players,players[0],players[1],players[2],
		   players[3],players[4],players[5]);
}


static void sba200_assemble_stack(port p,int vpi,int vci,int type,layer top,
				  void (*shutdown)(),void *shutdown_arg)
{
  char up_label[8];
  char down_label[8];
  int flags=0,i;
  layer klayers[10];	/* kernel layers */
  layer players[5];
  layer ilayers[5];	/* i960 layers */
  int number_of_klayers=0;
  int number_of_players=0;
  int number_of_ilayers=1;
  layer kernel_bridge,pl,z;
  void *kernel_shutdown=0;
  shutdown_context kernel_shutdown_arg=0;
  if (shutdown){
    kernel_shutdown=kernel_shutdown_function;
    kernel_shutdown_arg=
      (shutdown_context)allocate_memory(sizeof(struct shutdown_context));
    kernel_shutdown_arg->function=shutdown;
    kernel_shutdown_arg->arg=shutdown_arg;
  }

  sprintf (up_label,"%04x:^",vci);
  sprintf (down_label,"%04x:v",vci);

  if (type & STACK_KERNEL){
    klayers[number_of_klayers++]=top;
  } else {
    if (!create_dumb_interface(klayers,&pl)) {
      printf ("couldn't assemble stack\n");
      return;
    }
    number_of_klayers++;
    players[number_of_players++]=top;
  }
  if (type&STACK_AAL_4){
    flags=PROTOCOL_HARDWARE_CRC10;
    ilayers[number_of_ilayers++]=
      (layer)create_960_layer("create_aal4 %d",flags);
  }
  if (type&STACK_AAL_5) {
    flags=PROTOCOL_HARDWARE_CRC32;
    ilayers[number_of_ilayers++]=
      (layer)create_960_layer("create_aal5 %d",flags);
  }
  if (type&STACK_PRINT){
    if (type&STACK_KERNEL) 
      klayers[number_of_klayers++]=
	create_kernel_layer("create_print %04x:^ %04x:v",vci,vci);
    else 
      players[number_of_players++]=create_print(up_label,down_label);
  } 
  if (type&STACK_SSCOP) players[number_of_players++]=create_sscop();

  if (type&STACK_AAL_5 && flags&PROTOCOL_HARDWARE_CRC32) {
      debug("host", 
	    "sba200_assemble_stack(): 960 layer: create_sba200_aal5_atm\n");
    ilayers[number_of_ilayers++]=
      (layer)create_960_layer
	("create_sba200_aal5_atm %d %x %x",flags,vpi,vci);
  } else {
    if (type&STACK_AAL_4 && flags&PROTOCOL_HARDWARE_CRC10) {
      debug("host", 
	    "sba200_assemble_stack(): 960 layer: create_sba200_aal4_atm\n");
      ilayers[number_of_ilayers++]=
	(layer)create_960_layer
	  ("create_sba200_aal4_atm %d %x %x",flags,vpi,vci);
    } else {
      debug("host", 
	    "sba200_assemble_stack(): 960 layer: create_sba200_atm\n");
      ilayers[number_of_ilayers++]=
	(layer)create_960_layer
	  ("create_sba200_atm %d %x %x",flags,vpi,vci);
    }
  }
  debug("crypto", "crypto_sba200_assemble_stack(): 960 bridge\n");

/* Remove this later */
#if 0
  ilayers[number_of_ilayers++]=
    (layer)create_960_layer
      ("create_sba200_atm %d %x %x",flags,vpi,vci);
#endif

  create_960_bridge(ilayers,klayers+number_of_klayers);
  number_of_klayers++;
  if (!(type & STACK_KERNEL)) players[number_of_players++]=pl;
  if (number_of_players)
    assemble_stack(number_of_players,players[0],players[1],players[2],
		   players[3],players[4],players[5]);
  for(i=0;i<(number_of_klayers-1);i++) kstaple(klayers[i],klayers[i+1]);
  for(i=0;i<(number_of_ilayers-1);i++)
    eval_960("staple %x %x\n",ilayers[i],ilayers[i+1]);
  eval_960("signal %x %x\n",ilayers[i],PROTOCOL_CONNECTED);
}

error write_host_connection(connection c)
{
  
}


static struct hardware host_sba100={
  0,0,
  write_host_connection,
  host_get_count,
  host_clear_count,
  host_write_path,
  0, /* goes away*/
  sba100_assemble_stack,
  sba_disassemble_stack};

static struct hardware host_sba200={
  0,0,
  write_host_connection,
  host_get_count,
  host_clear_count,
  host_write_path,
  0, /* goes away*/
  sba200_assemble_stack,
  sba_disassemble_stack};

static sba200_finish (char *startup)
{
  environment e=create_environment(skip_global_environment);
  port p=create_port("host:sba200",&host_sba200);
  int i;
  parser z=create_skip_parser(e,0,0);
  host_sba200.ports=insert(p,0);
  define(e,"p","host:sba200");
  for (i=0;startup[i];i++) skip_parse(z,startup[i]);
  skip_parse(z,0);
  deallocate_memory(startup);
}

void host_layer_shutdown (shutdown_context s)
{
  if (s->function) (*s->function)(s->arg);
  deallocate_memory(s);
}

/* can't get autodiscovery to work nicely no matter how hard
   we try*/
#if 0
void initialize_host(int slot,char *download_file,char *sba200_startup)
#endif
void initialize_host(void)
{
  char st[50];
  layer k,f,v;
  int j;

  open_vince_device();
  j=hardware_configuration();
  if (j&3) 
    host_sba100.ports=insert(create_port("host:sba100",&host_sba100),0);
  sprintf (st,"create_kernel_vince");
  if (create_dumb_interface(&k,&f)){
    kstaple(k,v=create_kernel_layer(st));
    ksignal(v,PROTOCOL_CONNECTED);
    assemble_stack(2,create_skip_layer(skip_global_environment),f);
    skip_function(host_layer_shutdown,"host_layer_shutdown","","x",0);
  }
  init_ip_service();
  kernel_shutdown_function=(void *)shutdown_function_pointer();
}

void boot_sba200(int slot,char *download_file,char *sba200_startup)
{
  int j=hardware_configuration();

  if (j>>2) {
    printf( "boot_sba200(): sba200 is in sbus slot %d\n", ((j>>2)&15)-1);

    /*
     * If you don't provide a download file when you call
     * boot_sba20 in the startup file, skip provides
     * one of lenth zero that isn't NULL.
     * This means that unless you test the length of the file
     * name boot_sba200() always tries to send the sba200
     * a download file.
     */
/*((j>>2)&15)-1*/
    if ((download_file) && (string_length(download_file) != 0))
      sba200_download(download_file,slot,sba200_finish,
		      duplicate_string(sba200_startup));
  }
}

void set_960_debug(char *type)
{
  eval_960("set_debug %s",type);
}

void clear_960_debug(char *type)
{
  eval_960("clear_debug %s",type);
}

void reset_960_debug(char *type)
{
  eval_960("reset_debug %s",type);
}
