#include "atarierr.h"
#include "kerbind.h"
#include "cookie.h"
#include "gs_descr.h"


extern struct dev_descr gsdev_descr;
extern DRV_LIST *stik_driver;
struct kerinfo *KERINFO;
char gsdev_name[] = GSDEV_NAME;

int (*init_funcs[])(void) = {
  init_stik_if,
  load_config_file,
  init_mem,
  init_debug,
  (int (*)(void ))0
};

void (*cleanup_funcs[])(void) = {
  cleanup_config,
  cleanup_mem,
  cleanup_stik_if,
  cleanup_debug,
  (void (*)(void ))0
};

int cjar_size = 0;
COOKIE *new_cjar = 0;
int ncookies = 0;
int stik_present = 0;

static void cleanup(void)
{
  int i;

  for (i = 0; cleanup_funcs[i]; i++)
    (*cleanup_funcs[i])();
}

static void check_cookies(void)
{
  register COOKIE *cjar = *CJAR, *C;

  if (!cjar)
    return;

  for (C = cjar; C->tag != 0; C++) {
    if (C->tag == COOKIE_STiK)
      stik_present = 1;
  }

  cjar_size = C->value;
  ncookies = C - cjar;
}

static void install_same_jar(void)
{
  register COOKIE *C = *CJAR + ncookies;

  C->tag = COOKIE_STiK;
  C->value = (long)&stik_driver;
  C[1].tag = 0;
  C[1].value = cjar_size;
}

static void install_new_jar(void)
{
  register COOKIE *oldC = *CJAR, *newC = new_cjar;

  *CJAR = newC;
  while (oldC->tag != 0)
    *newC++ = *oldC++;
  newC->tag = COOKIE_STiK;
  newC->value = (long)&stik_driver;
  newC[1].tag = 0;
  newC[1].value = cjar_size + 8;
}

static int install_cookie(void)
{
  if (ncookies < cjar_size - 1)
    install_same_jar();
  else {
    new_cjar = (COOKIE *)kmalloc((cjar_size+8) * sizeof(COOKIE));
    if (!new_cjar) {
      c_conws("Unable to install STiK cookie\r\n");
      return 0;
    }
    install_new_jar();
  }
  return 1;
}

static void welcome(void)
{
  c_conws("GlueSTiK\277 STiK emulator for MiNTnet\r\n"
	  "Network device driver\r\n"
	  "Version " GS_VERSION "\r\n"
	  "\275 1996-98 Scott Bigham\r\n\r\n");
}

DEVDRV *init (struct kerinfo *info)
{
  short i;
  long r;

  KERINFO = info;
  welcome();

  check_cookies();
  if (stik_present) {
    c_conws("STiK already present; not installing\r\n");
    cleanup();
    return (DEVDRV *)0;
  }
  if (!install_cookie()) {
    cleanup();
    return (DEVDRV *)0;
  }

  if (addroottimeout == 0 || cancelroottimeout == 0) {
    c_conws("MiNT-Net NOT INSTALLED: You need Mint 1.11h9 or "
	    "newer to run MiNT-Net\r\n\r\n");
    cleanup();
    return (DEVDRV *)0;
  }

  for (i = 0; init_funcs[i]; ++i) {
    if (!(*init_funcs[i])()) {
      cleanup();
      return (DEVDRV *)0;
    }
  }

  LOG(DBG_TRACE, "Device driver active");

  r = d_cntl(DEV_INSTALL, gsdev_name, &gsdev_descr);
  if (!r || r == EINVFN) {
    c_conws ("Cannot install socket device\r\n");
    cleanup();
    return (DEVDRV *)0;
  }
  c_conws("\r\n");
  return (DEVDRV *)1;
}
