/* This file contains the table with device <-> driver mappings. It also
 * contains some routines to dynamically add and/ or remove device drivers
 * or change mappings.  
 */

#include "fs.h"
#include "fproc.h"
#include "dmap.h"
#include <string.h>
#include <minix/com.h>
#include <minix/utils.h>

/* Some devices may or may not be there in the next table. */
#define DT(enable, opcl, io, driver, flags) \
  { (enable?(opcl):no_dev), (enable?(io):0), \
  	(enable?(driver):0), (flags) },

/* The order of the entries here determines the mapping between major device
 * numbers and tasks.  The first entry (major device 0) is not used.  The
 * next entry is major device 1, etc.  Character and block devices can be
 * intermixed at random.  The ordering determines the device numbers in /dev/.
 * Note that FS knows the device number of /dev/ram/ to load the RAM disk.
 * Also note that the major device numbers used in /dev/ are NOT the same as 
 * the process numbers of the device drivers. 
 */
/*
  Driver enabled     Open/Cls  I/O     Driver #     Flags Device  File
  --------------     --------  ------  -----------  ----- ------  ----       
 */
struct dmap dmap[] = {
  DT(1,              no_dev,   0,      0,	     0)  /* 0 = not used   */
  DT(1,		     gen_opcl, gen_io, MEMORY, 0)  /* 1 = /dev/mem   */
  DT(ENABLE_FLOPPY,  gen_opcl, gen_io, FLOPPY, 0) /* 2 = /dev/fd0   */
  DT(NR_CTRLRS >= 1, gen_opcl, gen_io, CTRLR(0), DMAP_MUTABLE)     /* 3 = /dev/c0    */
#if ENABLE_USER_TTY
  DT(1,              tty_opcl, gen_io, TERMINAL,   0)          /* 4 = /dev/tty00 */
  DT(1,              ctty_opcl,ctty_io,TERMINAL,   0)          /* 5 = /dev/tty   */
#else
  DT(1,              tty_opcl, gen_io, TTY,   0)          /* 4 = /dev/tty00 */
  DT(1,              ctty_opcl,ctty_io,TTY,   0)          /* 5 = /dev/tty   */
#endif
  DT(ENABLE_PRINTER, gen_opcl, gen_io, PRINTER,   0)  /* 6 = /dev/lp    */

#if (MACHINE == IBM_PC)
  DT(1,              no_dev,   0,      0,   DMAP_MUTABLE)          /* 7 = /dev/ip    */
  DT(NR_CTRLRS >= 2, gen_opcl, gen_io, CTRLR(1),   DMAP_MUTABLE)     /* 8 = /dev/c1    */
  DT(0,              0,        0,      0,   DMAP_MUTABLE)            /* 9 = not used   */
  DT(NR_CTRLRS >= 3, gen_opcl, gen_io, CTRLR(2),   DMAP_MUTABLE)     /*10 = /dev/c2    */
  DT(0,              0,        0,      0,   DMAP_MUTABLE)            /*11 = not used   */
  DT(NR_CTRLRS >= 4, gen_opcl, gen_io, CTRLR(3),   DMAP_MUTABLE)     /*12 = /dev/c3    */
  DT(ENABLE_SB16,    gen_opcl, gen_io, NONE,   0)     /*13 = /dev/audio */
  DT(ENABLE_SB16,    gen_opcl, gen_io, NONE,   0)    /*14 = /dev/mixer */
#endif /* IBM_PC */
};

/* This is the maximum major number at compile time. This may change when 
 * devices are dynamically added or removed.
 */
int max_major = sizeof(dmap)/sizeof(struct dmap);


/*===========================================================================*
 *				map_driver		 		     *
 *===========================================================================*/
PUBLIC int map_driver(major, proc_nr, dev_style)
int major;			/* major number of the device */
int proc_nr;			/* process number of the driver */
int dev_style;			/* style of the device */
{
/* Set a new device driver mapping in the dmap table. Given that correct 
 * arguments are given, this only works if the entry is mutable and the 
 * current driver is not busy. 
 * Normal error codes are returned so that this function can be used from
 * a system call that tries to dynamically install a new driver.
 */
  struct dmap *dp;

  /* Get pointer to device entry in the dmap table. */
  if (major >= max_major) 		/* verify bounds */
      return(ENODEV);
  dp = &dmap[major];		
	
  /* See if updating the entry is allowed. */
  if (! (dp->dmap_flags & DMAP_MUTABLE))
      return(EPERM);
  if (dp->dmap_flags & DMAP_BUSY)
      return(EBUSY);

  /* Check process number of new driver. */
  if (! isokprocnr(proc_nr))
      return(EINVAL);

  /* Try to update the entry. */
  switch (dev_style) {
  case STYLE_DEV:	dp->dmap_opcl = gen_opcl;	break;
  case STYLE_TTY:	dp->dmap_opcl = tty_opcl;	break;
  case STYLE_CLONE:	dp->dmap_opcl = clone_opcl;	break;
  default:		return(EINVAL);
  }
  dp->dmap_io = gen_io;
  dp->dmap_driver = proc_nr;
  return(OK); 
}

/*===========================================================================*
 *				map_controllers		 		     *
 *===========================================================================*/
PUBLIC void map_controllers()
{
/* Map drivers to controllers and update the dmap table to that selection. 
 * For each controller, the environment variable set by the boot monitor is
 * analyzed to see what type of Winchester disk is attached. Then, the name 
 * of the driver that handles the device is looked up in the local drivertab. 
 * Finally, the process number of the driver is looked up, and, if found, is
 * installed in the dmap table.  
 */
  static char ctrlr_nr[] = "c0";	/* controller currently analyzed */
  char ctrlr_type[8];			/* type of Winchester disk */
  int i, c, s; 
  int proc_nr=0;			/* process number of driver */
  struct drivertab *dp;
  struct drivertab {
      char wini_type[8];
      char proc_name[8];
  } drivertab[] = {
	{ "at",		"AT_WINI"	},	/* AT Winchester */
	{ "bios",	"..." },
	{ "esdi",	"..." },
	{ "xt",		"..." },
	{ "aha1540",	"..." },
	{ "dosfile",	"..." },
	{ "fatfile",	"..." },
  };

  for (c=0; c < NR_CTRLRS; c++) {
    ctrlr_nr[1] = '0' + c;
    if ((s = get_mon_param(ctrlr_nr, ctrlr_type, 8)) != OK)  {
    	 if (s != ESRCH)
             printf("FS: warning, couldn't get monitor param: %d\n", s);
         continue;
    }
    for (dp = drivertab;
        dp < drivertab + sizeof(drivertab)/sizeof(drivertab[0]); dp++)  {
      if (strcmp(ctrlr_type, dp->wini_type) == 0) {	/* found driver name */
	if ((s=sys_getprocnr(&proc_nr, 			/* lookup proc nr */
	    dp->proc_name, strlen(dp->proc_name)+1)) == OK) {
	  for (i=0; i< max_major; i++) {		/* find mapping */
	    if (dmap[i].dmap_driver == CTRLR(c)) {  
	      if (map_driver(i, proc_nr, STYLE_DEV) == OK) {
	        printf("FS: controller %s (%s) mapped to %s driver (proc. nr %d)\n",
	    	ctrlr_nr, dp->wini_type, dp->proc_name,  dmap[i].dmap_driver);
	      }
	    }
	  }
	}
      }
    }
  }
}



