The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/userconfig.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /**
    2  ** Copyright (c) 1995
    3  **      Michael Smith, msmith@freebsd.org.  All rights reserved.
    4  **
    5  ** This code contains a module marked :
    6 
    7  * Copyright (c) 1991 Regents of the University of California.
    8  * All rights reserved.
    9  * Copyright (c) 1994 Jordan K. Hubbard
   10  * All rights reserved.
   11  * Copyright (c) 1994 David Greenman
   12  * All rights reserved.
   13  *
   14  * Many additional changes by Bruce Evans
   15  *
   16  * This code is derived from software contributed by the
   17  * University of California Berkeley, Jordan K. Hubbard,
   18  * David Greenman and Bruce Evans.
   19 
   20  ** As such, it contains code subject to the above copyrights.
   21  ** The module and its copyright can be found below.
   22  ** 
   23  ** Redistribution and use in source and binary forms, with or without
   24  ** modification, are permitted provided that the following conditions
   25  ** are met:
   26  ** 1. Redistributions of source code must retain the above copyright
   27  **    notice, this list of conditions and the following disclaimer as
   28  **    the first lines of this file unmodified.
   29  ** 2. Redistributions in binary form must reproduce the above copyright
   30  **    notice, this list of conditions and the following disclaimer in the
   31  **    documentation and/or other materials provided with the distribution.
   32  ** 3. All advertising materials mentioning features or use of this software
   33  **    must display the following acknowledgment:
   34  **      This product includes software developed by Michael Smith.
   35  ** 4. The name of the author may not be used to endorse or promote products
   36  **    derived from this software without specific prior written permission.
   37  **
   38  ** THIS SOFTWARE IS PROVIDED BY MICHAEL SMITH ``AS IS'' AND ANY EXPRESS OR
   39  ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   40  ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   41  ** IN NO EVENT SHALL MICHAEL SMITH BE LIABLE FOR ANY DIRECT, INDIRECT,
   42  ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   43  ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   44  ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   45  ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   46  ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   47  ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   48  **
   49  ** $FreeBSD$
   50  **/
   51 
   52 /**
   53  ** USERCONFIG
   54  **
   55  ** Kernel boot-time configuration manipulation tool for FreeBSD.
   56  **
   57  ** Two modes of operation are supported : the default is the line-editor mode,
   58  ** the command "visual" invokes the fullscreen mode.
   59  **
   60  ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the 
   61  ** fullscreen mode requires syscons or a minimal-ansi serial console.
   62  **/
   63 
   64 /**
   65  ** USERCONFIG, visual mode.
   66  **
   67  **   msmith@freebsd.org
   68  **
   69  ** Look for "EDIT THIS LIST" to add to the list of known devices
   70  ** 
   71  **
   72  ** There are a number of assumptions made in this code.
   73  ** 
   74  ** - That the console supports a minimal set of ANSI escape sequences
   75  **   (See the screen manipulation section for a summary)
   76  **   and has at least 24 rows.
   77  ** - That values less than or equal to zero for any of the device
   78  **   parameters indicate that the driver does not use the parameter.
   79  ** - That flags are _always_ editable.
   80  **
   81  ** Devices marked as disabled are imported as such.
   82  **
   83  ** For this tool to be useful, the list of devices below _MUST_ be updated 
   84  ** when a new driver is brought into the kernel.  It is not possible to 
   85  ** extract this information from the drivers in the kernel.
   86  **
   87  ** XXX - TODO:
   88  ** 
   89  ** - Display _what_ a device conflicts with.
   90  ** - Implement page up/down (as what?)
   91  ** - Wizard mode (no restrictions)
   92  ** - Find out how to put syscons back into low-intensity mode so that the
   93  **   !b escape is useful on the console.  (It seems to be that it actually
   94  **   gets low/high intensity backwards. That looks OK.)
   95  **
   96  ** - Only display headings with devices under them. (difficult)
   97  **/
   98 
   99 #include "opt_userconfig.h"
  100 #define COMPAT_OLDISA   /* get the definitions */
  101 
  102 #include <sys/param.h>
  103 #include <sys/systm.h>
  104 #include <sys/kernel.h>
  105 #include <sys/malloc.h>
  106 #include <sys/reboot.h>
  107 #include <sys/linker.h>
  108 #include <sys/sysctl.h>
  109 #include <sys/bus.h>
  110 #include <sys/cons.h>
  111 
  112 #include <machine/md_var.h>
  113 #include <machine/limits.h>
  114 
  115 #define _I386_ISA_ISA_DEVICE_H_
  116 
  117 #undef NPNP
  118 #define NPNP 0
  119 
  120 #if NPNP > 0
  121 #include <i386/isa/pnp.h>
  122 #endif
  123 
  124 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
  125 
  126 #include <machine/uc_device.h>
  127 static struct uc_device *uc_devlist;    /* list read by kget to extract changes */
  128 static struct uc_device *uc_devtab;     /* fake uc_device table */
  129 
  130 static int userconfig_boot_parsing;     /* set if we are reading from the boot instructions */
  131 
  132 #define putchar(x)      cnputc(x)
  133 
  134 static void load_devtab(void);
  135 static void free_devtab(void);
  136 static void save_resource(struct uc_device *);
  137 
  138 static int
  139 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
  140 {
  141         struct uc_device *id;
  142         int error=0;
  143         char name[8];
  144 
  145         if(!req->oldptr) {
  146                 /* Only sizing */
  147                 id=uc_devlist;
  148                 while(id) {
  149                         error+=sizeof(struct uc_device)+8;
  150                         id=id->id_next;
  151                 }
  152                 return(SYSCTL_OUT(req,0,error));
  153         } else {
  154                 /* Output the data. The buffer is filled with consecutive
  155                  * struct uc_device and char buf[8], containing the name
  156                  * (not guaranteed to end with '\0').
  157                  */
  158                 id=uc_devlist;
  159                 while(id) {
  160                         error=sysctl_handle_opaque(oidp,id,
  161                                 sizeof(struct uc_device),req);
  162                         if(error) return(error);
  163                         strncpy(name,id->id_name,8);
  164                         error=sysctl_handle_opaque(oidp,name,
  165                                 8,req);
  166                         if(error) return(error);
  167                         id=id->id_next;
  168                 }
  169                 return(0);
  170         }
  171 }
  172 
  173 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
  174         0, 0, sysctl_machdep_uc_devlist, "A",
  175         "List of ISA devices changed in UserConfig");
  176 
  177 /*
  178 ** Obtain command input.
  179 **
  180 ** Initially, input is read from a possibly-loaded script.
  181 ** At the end of the script, or if no script is supplied, 
  182 ** behaviour is determined by the RB_CONFIG (-c) flag.  If 
  183 ** the flag is set, user input is read from the console; if
  184 ** unset, the 'quit' command is invoked and userconfig
  185 ** will exit.
  186 **
  187 ** Note that quit commands encountered in the script will be
  188 ** ignored if the RB_CONFIG flag is supplied.
  189 */
  190 static const char       *config_script;
  191 static int              config_script_size; /* use of int for -ve magic value */
  192 
  193 #define has_config_script()     (config_script_size > 0)
  194 
  195 static int
  196 init_config_script(void)
  197 {
  198     caddr_t             autoentry, autoattr;
  199 
  200     /* Look for loaded userconfig script */
  201     autoentry = preload_search_by_type("userconfig_script");
  202     if (autoentry != NULL) {
  203         /* We have one, get size and data */
  204         config_script_size = 0;
  205         if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
  206             config_script_size = (size_t)*(u_int32_t *)autoattr;
  207         config_script = NULL;
  208         if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
  209             config_script = *(const char **)autoattr;
  210         /* sanity check */
  211         if ((config_script_size == 0) || (config_script == NULL)) {
  212             config_script_size = 0;
  213             config_script = NULL;
  214         }
  215     }
  216     return has_config_script();
  217 }
  218 
  219 static int
  220 getchar(void)
  221 {
  222     int                 c = -1;
  223 #ifdef INTRO_USERCONFIG
  224     static int          intro = 0;
  225 #endif
  226     
  227     if (has_config_script()) 
  228     {
  229         /* Consume character from loaded userconfig script, display */
  230         userconfig_boot_parsing = 1;
  231         c = *config_script;
  232         config_script++;
  233         config_script_size--;
  234 
  235     } else {
  236         
  237 #ifdef INTRO_USERCONFIG
  238         if (userconfig_boot_parsing) {
  239             if (!(boothowto & RB_CONFIG)) {
  240                 /* userconfig_script, !RB_CONFIG -> quit */
  241                 if (intro == 0) {
  242                     c = 'q';
  243                     config_script = "uit\n";
  244                     config_script_size = strlen(config_script);
  245                     /* userconfig_script will be 1 on the next pass */
  246                 }
  247             } else {
  248                 /* userconfig_script, RB_CONFIG -> cngetc() */
  249             }
  250         } else {
  251             if (!(boothowto & RB_CONFIG)) {
  252                 /* no userconfig_script, !RB_CONFIG -> show intro */
  253                 if (intro == 0) {
  254                     intro = 1;
  255                     c = 'i';
  256                     config_script = "ntro\n";
  257                     config_script_size = strlen(config_script);
  258                     /* userconfig_script will be 1 on the next pass */
  259                 }
  260             } else {
  261                 /* no userconfig_script, RB_CONFIG -> cngetc() */
  262             }
  263         }
  264 #else /* !INTRO_USERCONFIG */
  265         /* assert(boothowto & RB_CONFIG) */
  266 #endif /* INTRO_USERCONFIG */
  267         userconfig_boot_parsing = 0;
  268         if (c <= 0)
  269             c = cngetc();
  270     }
  271     return(c);
  272 }
  273 
  274 #ifndef FALSE
  275 #define FALSE   (0)
  276 #define TRUE    (!FALSE)
  277 #endif
  278 
  279 #ifdef VISUAL_USERCONFIG
  280 
  281 typedef struct
  282 {
  283     char        dev[16];                /* device basename */
  284     char        name[60];               /* long name */
  285     int         attrib;                 /* things to do with the device */
  286     int         class;                  /* device classification */
  287 } DEV_INFO;
  288 
  289 #define FLG_INVISIBLE   (1<<0)          /* device should not be shown */
  290 #define FLG_MANDATORY   (1<<1)          /* device can be edited but not disabled */
  291 #define FLG_FIXIRQ      (1<<2)          /* device IRQ cannot be changed */
  292 #define FLG_FIXIOBASE   (1<<3)          /* device iobase cannot be changed */
  293 #define FLG_FIXMADDR    (1<<4)          /* device maddr cannot be changed */
  294 #define FLG_FIXMSIZE    (1<<5)          /* device msize cannot be changed */
  295 #define FLG_FIXDRQ      (1<<6)          /* device DRQ cannot be changed */
  296 #define FLG_FIXED       (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
  297 #define FLG_IMMUTABLE   (FLG_FIXED|FLG_MANDATORY)
  298 
  299 #define CLS_STORAGE     1               /* storage devices */
  300 #define CLS_NETWORK     2               /* network interfaces */
  301 #define CLS_COMMS       3               /* serial, parallel ports */
  302 #define CLS_INPUT       4               /* user input : mice, keyboards, joysticks etc */
  303 #define CLS_MMEDIA      5               /* "multimedia" devices (sound, video, etc) */
  304 #define CLS_MISC        255             /* none of the above */
  305 
  306 
  307 typedef struct 
  308 {
  309     char        name[60];
  310     int         number;
  311 } DEVCLASS_INFO;
  312 
  313 static DEVCLASS_INFO devclass_names[] = {
  314 {       "Storage :        ",    CLS_STORAGE},
  315 {       "Network :        ",    CLS_NETWORK},
  316 {       "Communications : ",    CLS_COMMS},
  317 {       "Input :          ",    CLS_INPUT},
  318 {       "Multimedia :     ",    CLS_MMEDIA},
  319 {       "Miscellaneous :  ",    CLS_MISC},
  320 {       "",0}};
  321 
  322 
  323 /********************* EDIT THIS LIST **********************/
  324 
  325 /** Notes :
  326  ** 
  327  ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
  328  ** - XXX The list below should be reviewed by the driver authors to verify
  329  **   that the correct flags have been set for each driver, and that the
  330  **   descriptions are accurate.
  331  **/
  332 
  333 static DEV_INFO device_info[] = {
  334 /*---Name-----   ---Description---------------------------------------------- */
  335 {"adv",         "AdvanSys SCSI narrow controller",      0,              CLS_STORAGE},
  336 {"bt",          "Buslogic SCSI controller",             0,              CLS_STORAGE},
  337 {"aha",         "Adaptec 154x SCSI controller",         0,              CLS_STORAGE},
  338 {"aic",         "Adaptec 152x SCSI and compatible sound cards", 0,      CLS_STORAGE},
  339 {"nca",         "ProAudio Spectrum SCSI and compatibles",       0,      CLS_STORAGE},
  340 {"sea",         "Seagate ST01/ST02 SCSI and compatibles",       0,      CLS_STORAGE},
  341 {"stg",         "TMC 18C30/18C50 based SCSI cards",     0,              CLS_STORAGE},
  342 {"wdc",         "IDE/ESDI/MFM disk controller",         0,              CLS_STORAGE},
  343 {"ata",         "ATA/ATAPI compatible disk controller", 0,              CLS_STORAGE},
  344 {"fdc",         "Floppy disk controller",               FLG_FIXED,      CLS_STORAGE},
  345 {"mcd",         "Mitsumi CD-ROM",                       0,              CLS_STORAGE},
  346 {"scd",         "Sony CD-ROM",                          0,              CLS_STORAGE},
  347 {"wt",          "Wangtek/Archive QIC-02 Tape drive",    0,              CLS_STORAGE},
  348 {"wd",          "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
  349 {"ad",          "ATA/ATAPI compatible storage device",  FLG_INVISIBLE,  CLS_STORAGE},   
  350 {"fd",          "Floppy disk device",                   FLG_INVISIBLE,  CLS_STORAGE},
  351 
  352 {"cm",          "SMC COM90Cx6-based Arcnet adapters",   0,              CLS_NETWORK},
  353 {"cs",          "IBM EtherJet, CS89x0-based Ethernet adapters",0,       CLS_NETWORK},
  354 {"ctau",        "Cronyx/Tau multiport synchronous adapter",     0,      CLS_NETWORK},
  355 {"ed",          "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0,   CLS_NETWORK},
  356 {"el",          "3C501 Ethernet adapter",               0,              CLS_NETWORK},
  357 {"ep",          "3C509 Ethernet adapter",               0,              CLS_NETWORK},
  358 {"ex",          "Intel EtherExpress Pro/10 Ethernet adapter",   0,      CLS_NETWORK},
  359 {"fe",          "Fujitsu MB86960A/MB86965A Ethernet adapters",  0,      CLS_NETWORK},
  360 {"ie",          "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
  361 {"le",          "DEC Etherworks 2 and 3 Ethernet adapters",     0,      CLS_NETWORK},
  362 {"lnc",         "Isolan, Novell NE2100/NE32-VL Ethernet adapters",      0,CLS_NETWORK},
  363 {"sn",          "SMC/Megahertz Ethernet adapters",                      0,CLS_NETWORK},
  364 {"xe",          "Xircom PC Card Ethernet adapter",              0,      CLS_NETWORK},
  365 {"rdp",         "RealTek RTL8002 Pocket Ethernet",      0,              CLS_NETWORK},
  366 {"sbni",        "Granch SBNI12-xx adapters",            0,              CLS_NETWORK},
  367 
  368 {"sio",         "8250/16450/16550 Serial port",         0,              CLS_COMMS},
  369 {"cx",          "Cronyx/Sigma multiport sync/async adapter",0,          CLS_COMMS},
  370 {"rc",          "RISCom/8 multiport async adapter",     0,              CLS_COMMS},
  371 {"cy",          "Cyclades multiport async adapter",     0,              CLS_COMMS},
  372 {"dgb",         "Digiboard PC/Xe, PC/Xi async adapter", 0,              CLS_COMMS},
  373 {"si",          "Specialix SI/XIO/SX async adapter",    0,              CLS_COMMS},
  374 {"stl",         "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
  375 {"stli",        "Stallion intelligent async adapter"    ,0,             CLS_COMMS},
  376 {"ppc",         "Parallel Port chipset",                0,              CLS_COMMS},
  377 {"gp",          "National Instruments AT-GPIB/TNT driver",      0,      CLS_COMMS},
  378 
  379 {"atkbdc",      "Keyboard controller",                  FLG_INVISIBLE,  CLS_INPUT},
  380 {"atkbd",       "Keyboard",                             FLG_FIXED,      CLS_INPUT},
  381 {"mse",         "Microsoft Bus Mouse",                  0,              CLS_INPUT},
  382 {"psm",         "PS/2 Mouse",                           FLG_FIXED,      CLS_INPUT},
  383 {"joy",         "Joystick",                             FLG_FIXED,      CLS_INPUT},
  384 {"vt",          "PCVT console driver",                  FLG_IMMUTABLE,  CLS_INPUT},
  385 {"sc",          "Syscons console driver",               FLG_IMMUTABLE,  CLS_INPUT},
  386 
  387 {"sbc",         "PCM Creative SoundBlaster/ESS/Avance sounce cards",    0,CLS_MMEDIA},
  388 {"gusc",        "PCM Gravis UltraSound sound cards",    0,              CLS_MMEDIA},
  389 {"pcm",         "PCM Generic soundcard support",                0,              CLS_MMEDIA},
  390 {"sb",          "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
  391 {"sbxvi",       "VOXWARE Soundblaster 16",              0,              CLS_MMEDIA},
  392 {"sbmidi",      "VOXWARE Soundblaster MIDI interface",  0,              CLS_MMEDIA},
  393 {"awe",         "VOXWARE AWE32 MIDI",                   0,              CLS_MMEDIA},
  394 {"pas",         "VOXWARE ProAudio Spectrum PCM and MIDI",       0,      CLS_MMEDIA},
  395 {"gus",         "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
  396 {"gusxvi",      "VOXWARE Gravis Ultrasound 16-bit PCM", 0,              CLS_MMEDIA},
  397 {"gusmax",      "VOXWARE Gravis Ultrasound MAX",        0,              CLS_MMEDIA},
  398 {"mss",         "VOXWARE Microsoft Sound System",       0,              CLS_MMEDIA},
  399 {"opl",         "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
  400 {"mpu",         "VOXWARE Roland MPU401 MIDI",           0,              CLS_MMEDIA},
  401 {"sscape",      "VOXWARE Ensoniq Soundscape MIDI interface",    0,      CLS_MMEDIA},
  402 {"sscape_mss",  "VOXWARE Ensoniq Soundscape PCM",       0,              CLS_MMEDIA},
  403 {"uart",        "VOXWARE 6850 MIDI UART",               0,              CLS_MMEDIA},
  404 {"pca",         "PC speaker PCM audio driver",          FLG_FIXED,      CLS_MMEDIA},
  405 {"ctx",         "Coretex-I frame grabber",              0,              CLS_MMEDIA},
  406 {"spigot",      "Creative Labs Video Spigot video capture",     0,      CLS_MMEDIA},
  407 {"scc",         "IBM Smart Capture Card",               0,              CLS_MMEDIA},
  408 {"gsc",         "Genius GS-4500 hand scanner",          0,              CLS_MMEDIA},
  409 {"asc",         "AmiScan scanner",                      0,              CLS_MMEDIA},
  410 
  411 {"apm",         "Advanced Power Management",            FLG_FIXED,      CLS_MISC},
  412 {"labpc",       "National Instruments Lab-PC/Lab-PC+",  0,              CLS_MISC},
  413 {"pcic",        "PC-card controller",                   0,              CLS_MISC},
  414 {"npx",         "Math coprocessor",                     FLG_IMMUTABLE,  CLS_MISC},
  415 {"vga",         "Catchall PCI VGA driver",              FLG_INVISIBLE,  CLS_MISC},
  416 {"","",0,0}};
  417 
  418 
  419 typedef struct _devlist_struct
  420 {
  421     char        name[80];
  422     int         attrib;                 /* flag values as per the FLG_* defines above */
  423     int         class;                  /* disk, etc as per the CLS_* defines above */
  424     char        dev[16];
  425     int         iobase,irq,drq,maddr,msize,unit,flags,id;
  426     int         comment;                /* 0 = device, 1 = comment, 2 = collapsed comment */
  427     int         conflicts;              /* set/reset by findconflict, count of conflicts */
  428     int         changed;                /* nonzero if the device has been edited */
  429     struct uc_device    *device;
  430     struct _devlist_struct *prev,*next;
  431 } DEV_LIST;
  432 
  433 
  434 #define DEV_DEVICE      0
  435 #define DEV_COMMENT     1
  436 #define DEV_ZOOMED      2
  437 
  438 #define LIST_CURRENT    (1<<0)
  439 #define LIST_SELECTED   (1<<1)
  440 
  441 #define KEY_EXIT        0       /* return codes from dolist() and friends */
  442 #define KEY_DO          1
  443 #define KEY_DEL         2
  444 #define KEY_TAB         3
  445 #define KEY_REDRAW      4
  446 
  447 #define KEY_UP          5       /* these only returned from editval() */
  448 #define KEY_DOWN        6
  449 #define KEY_LEFT        7
  450 #define KEY_RIGHT       8
  451 #define KEY_NULL        9       /* this allows us to spin & redraw */
  452 
  453 #define KEY_ZOOM        10      /* these for zoom all/collapse all */
  454 #define KEY_UNZOOM      11
  455 
  456 #define KEY_HELP        12      /* duh? */
  457 
  458 static void redraw(void);
  459 static void insdev(DEV_LIST *dev, DEV_LIST *list);
  460 static int  devinfo(DEV_LIST *dev);
  461 static int  visuserconfig(void);
  462 
  463 static DEV_LIST *active = NULL,*inactive = NULL;        /* driver lists */
  464 static DEV_LIST *alist,*ilist;                          /* visible heads of the driver lists */
  465 static DEV_LIST scratch;                                /* scratch record */
  466 static int      conflicts;                              /* total conflict count */
  467 
  468 
  469 static char lines[] = "--------------------------------------------------------------------------------";
  470 static char spaces[] = "                                                                                     ";
  471 
  472 
  473 /**
  474  ** Device manipulation stuff : find, describe, configure.
  475  **/
  476 
  477 /**
  478  ** setdev
  479  **
  480  ** Sets the device referenced by (*dev) to the parameters in the struct,
  481  ** and the enable flag according to (enabled)
  482  **/
  483 static void 
  484 setdev(DEV_LIST *dev, int enabled)
  485 {
  486     dev->device->id_iobase = dev->iobase;                               /* copy happy */
  487     dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0);   /* IRQ is bitfield */
  488     dev->device->id_drq = (short)dev->drq;
  489     dev->device->id_maddr = (caddr_t)dev->maddr;
  490     dev->device->id_msize = dev->msize;
  491     dev->device->id_flags = dev->flags;
  492     dev->device->id_enabled = enabled;
  493 }
  494 
  495 
  496 /**
  497  ** getdevs
  498  **
  499  ** Walk the kernel device tables and build the active and inactive lists
  500  **/
  501 static void 
  502 getdevs(void)
  503 {
  504     int                 i;
  505     struct uc_device    *ap;
  506 
  507         ap = uc_devtab;                         /* pointer to array of devices */
  508         for (i = 0; ap[i].id_id; i++)                   /* for each device in this table */
  509         {
  510             scratch.unit = ap[i].id_unit;               /* device parameters */
  511             strcpy(scratch.dev,ap[i].id_name);
  512             scratch.iobase = ap[i].id_iobase;
  513             scratch.irq = ffs(ap[i].id_irq)-1;
  514             scratch.drq = ap[i].id_drq;
  515             scratch.maddr = (int)ap[i].id_maddr;
  516             scratch.msize = ap[i].id_msize;
  517             scratch.flags = ap[i].id_flags;
  518 
  519             scratch.comment = DEV_DEVICE;               /* admin stuff */
  520             scratch.conflicts = 0;
  521             scratch.device = &ap[i];                    /* save pointer for later reference */
  522             scratch.changed = 0;
  523             if (!devinfo(&scratch))                     /* get more info on the device */
  524                 insdev(&scratch,ap[i].id_enabled?active:inactive);
  525         }
  526 }
  527 
  528 
  529 /**
  530  ** Devinfo
  531  **
  532  ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
  533  ** If the device is unknown, put it in the CLS_MISC class, with no flags.
  534  **
  535  ** If the device is marked "invisible", return nonzero; the caller should
  536  ** not insert any such device into either list.
  537  **
  538  **/
  539 static int
  540 devinfo(DEV_LIST *dev)
  541 {
  542     int         i;
  543 
  544     for (i = 0; device_info[i].class; i++)
  545     {
  546         if (!strcmp(dev->dev,device_info[i].dev))
  547         {
  548             if (device_info[i].attrib & FLG_INVISIBLE)  /* forget we ever saw this one */
  549                 return(1);
  550             strcpy(dev->name,device_info[i].name);      /* get the name */
  551             dev->attrib = device_info[i].attrib;
  552             dev->class = device_info[i].class;
  553             return(0);
  554         }
  555     }
  556     strcpy(dev->name,"Unknown device");
  557     dev->attrib = 0;
  558     dev->class = CLS_MISC;
  559     return(0);
  560 }
  561     
  562 
  563 /**
  564  ** List manipulation stuff : add, move, initialise, free, traverse
  565  **
  566  ** Note that there are assumptions throughout this code that
  567  ** the first entry in a list will never move. (assumed to be
  568  ** a comment).
  569  **/
  570 
  571 
  572 /**
  573  ** Adddev
  574  ** 
  575  ** appends a copy of (dev) to the end of (*list)
  576  **/
  577 static void 
  578 addev(DEV_LIST *dev, DEV_LIST **list)
  579 {
  580 
  581     DEV_LIST    *lp,*ap;
  582 
  583     lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
  584     bcopy(dev,lp,sizeof(DEV_LIST));                     /* create copied record */
  585 
  586     if (*list)                                          /* list exists */
  587     {
  588         ap = *list;
  589         while(ap->next)
  590             ap = ap->next;                              /* scoot to end of list */
  591         lp->prev = ap;
  592         lp->next = NULL;
  593         ap->next = lp;
  594     }else{                                              /* list does not yet exist */
  595         *list = lp;
  596         lp->prev = lp->next = NULL;                     /* list now exists */
  597     }
  598 }
  599 
  600 
  601 /**
  602  ** Findspot
  603  **
  604  ** Finds the 'appropriate' place for (dev) in (list)
  605  **
  606  ** 'Appropriate' means in numeric order with other devices of the same type,
  607  ** or in alphabetic order following a comment of the appropriate type.
  608  ** or at the end of the list if an appropriate comment is not found. (this should
  609  ** never happen)
  610  ** (Note that the appropriate point is never the top, but may be the bottom)
  611  **/
  612 static DEV_LIST *
  613 findspot(DEV_LIST *dev, DEV_LIST *list)
  614 {
  615     DEV_LIST    *ap = NULL;
  616 
  617     /* search for a previous instance of the same device */
  618     for (ap = list; ap; ap = ap->next)
  619     {
  620         if (ap->comment != DEV_DEVICE)                  /* ignore comments */
  621             continue;
  622         if (!strcmp(dev->dev,ap->dev))                  /* same base device */
  623         {
  624             if ((dev->unit <= ap->unit)                 /* belongs before (equal is bad) */
  625                 || !ap->next)                           /* or end of list */
  626             {
  627                 ap = ap->prev;                          /* back up one */
  628                 break;                                  /* done here */
  629             }
  630             if (ap->next)                                       /* if the next item exists */
  631             {
  632                 if (ap->next->comment != DEV_DEVICE)    /* next is a comment */
  633                     break;
  634                 if (strcmp(dev->dev,ap->next->dev))             /* next is a different device */
  635                     break;
  636             }
  637         }
  638     }
  639 
  640     if (!ap)                                            /* not sure yet */
  641     {
  642         /* search for a class that the device might belong to */
  643         for (ap = list; ap; ap = ap->next)
  644         {
  645             if (ap->comment != DEV_DEVICE)              /* look for simlar devices */
  646                 continue;
  647             if (dev->class != ap->class)                /* of same class too 8) */
  648                 continue;
  649             if (strcmp(dev->dev,ap->dev) < 0)           /* belongs before the current entry */
  650             {
  651                 ap = ap->prev;                          /* back up one */
  652                 break;                                  /* done here */
  653             }
  654             if (ap->next)                               /* if the next item exists */
  655                 if (ap->next->comment != DEV_DEVICE)    /* next is a comment, go here */
  656                     break;
  657         }
  658     }
  659 
  660     if (!ap)                                            /* didn't find a match */
  661     {
  662         for (ap = list; ap->next; ap = ap->next)        /* try for a matching comment */
  663             if ((ap->comment != DEV_DEVICE) 
  664                 && (ap->class == dev->class))           /* appropriate place? */
  665                 break;
  666     }                                                   /* or just put up with last */
  667 
  668     return(ap);
  669 }
  670 
  671 
  672 /**
  673  ** Insdev
  674  **
  675  ** Inserts a copy of (dev) at the appropriate point in (list)
  676  **/
  677 static void 
  678 insdev(DEV_LIST *dev, DEV_LIST *list)
  679 {
  680     DEV_LIST    *lp,*ap;
  681 
  682     lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
  683     bcopy(dev,lp,sizeof(DEV_LIST));                     /* create copied record */
  684 
  685     ap = findspot(lp,list);                             /* find appropriate spot */
  686     lp->next = ap->next;                                /* point to next */
  687     if (ap->next)
  688         ap->next->prev = lp;                            /* point next to new */
  689     lp->prev = ap;                                      /* point new to current */
  690     ap->next = lp;                                      /* and current to new */
  691 }
  692 
  693 
  694 /**
  695  ** Movedev
  696  **
  697  ** Moves (dev) from its current list to an appropriate place in (list)
  698  ** (dev) may not come from the top of a list, but it may from the bottom.
  699  **/
  700 static void 
  701 movedev(DEV_LIST *dev, DEV_LIST *list)
  702 {
  703     DEV_LIST    *ap;
  704 
  705     ap = findspot(dev,list);
  706     dev->prev->next = dev->next;                        /* remove from old list */
  707     if (dev->next)
  708         dev->next->prev = dev->prev;
  709     
  710     dev->next = ap->next;                               /* insert in new list */
  711     if (ap->next)
  712         ap->next->prev = dev;                           /* point next to new */
  713     dev->prev = ap;                                     /* point new to current */
  714     ap->next = dev;                                     /* and current to new */
  715 }
  716 
  717 
  718 /**
  719  ** Initlist
  720  **
  721  ** Initialises (*list) with the basic headings
  722  **/
  723 static void 
  724 initlist(DEV_LIST **list)
  725 {
  726     int         i;
  727 
  728     for(i = 0; devclass_names[i].name[0]; i++)          /* for each devtype name */
  729     {
  730         strcpy(scratch.name,devclass_names[i].name);
  731         scratch.comment = DEV_ZOOMED;
  732         scratch.class = devclass_names[i].number;
  733         scratch.attrib = FLG_MANDATORY;                 /* can't be moved */
  734         addev(&scratch,list);                           /* add to the list */
  735     }
  736 }
  737 
  738 
  739 /**
  740  ** savelist
  741  **
  742  ** Walks (list) and saves the settings of any entry marked as changed.
  743  **
  744  ** The device's active field is set according to (active).
  745  **
  746  ** Builds the uc_devlist used by kget to extract the changed device information.
  747  ** The code for this was taken almost verbatim from the original module.
  748  **/
  749 static void
  750 savelist(DEV_LIST *list, int active)
  751 {
  752     struct uc_device    *id_p,*id_pn;
  753     char *name;
  754 
  755     while (list)
  756     {
  757         if ((list->comment == DEV_DEVICE) &&            /* is a device */
  758             (list->changed) &&                          /* has been changed */
  759             (list->device != NULL)) {                   /* has an uc_device structure */
  760 
  761             setdev(list,active);                        /* set the device itself */
  762 
  763             id_pn = NULL;
  764             for (id_p=uc_devlist; id_p; id_p=id_p->id_next) 
  765             {                                           /* look on the list for it */
  766                 if (id_p->id_id == list->device->id_id) 
  767                 {
  768                     name = list->device->id_name;
  769                     id_pn = id_p->id_next;
  770                     if (id_p->id_name)
  771                             free(id_p->id_name, M_DEVL);
  772                     bcopy(list->device,id_p,sizeof(struct uc_device));
  773                     save_resource(list->device);
  774                     id_p->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
  775                     strcpy(id_p->id_name, name);
  776                     id_pn->id_next = uc_devlist;
  777                     id_p->id_next = id_pn;
  778                     break;
  779                 }
  780             }
  781             if (!id_pn)                                 /* not already on the list */
  782             {
  783                 name = list->device->id_name;
  784                 id_pn = malloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
  785                 bcopy(list->device,id_pn,sizeof(struct uc_device));
  786                 save_resource(list->device);
  787                 id_pn->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
  788                 strcpy(id_pn->id_name, name);
  789                 id_pn->id_next = uc_devlist;
  790                 uc_devlist = id_pn;                     /* park at top of list */
  791             }
  792         }
  793         list = list->next;
  794     }
  795 }
  796 
  797 
  798 /**
  799  ** nukelist
  800  **
  801  ** Frees all storage in use by a (list).
  802  **/
  803 static void 
  804 nukelist(DEV_LIST *list)
  805 {
  806     DEV_LIST    *dp;
  807 
  808     if (!list)
  809         return;
  810     while(list->prev)                                   /* walk to head of list */
  811         list = list->prev;
  812 
  813     while(list)
  814     {
  815         dp = list;
  816         list = list->next;
  817         free(dp,M_DEVL);
  818     }
  819 }
  820 
  821 
  822 /**
  823  ** prevent
  824  **
  825  ** Returns the previous entry in (list), skipping zoomed regions.  Returns NULL
  826  ** if there is no previous entry. (Only possible if list->prev == NULL given the
  827  ** premise that there is always a comment at the head of the list)
  828  **/
  829 static DEV_LIST *
  830 prevent(DEV_LIST *list)
  831 {
  832     DEV_LIST    *dp;
  833 
  834     if (!list)
  835         return(NULL);
  836     dp = list->prev;                    /* start back one */
  837     while(dp)
  838     {
  839         if (dp->comment == DEV_ZOOMED)  /* previous section is zoomed */
  840             return(dp);                 /* so skip to comment */
  841         if (dp->comment == DEV_COMMENT) /* not zoomed */
  842             return(list->prev);         /* one back as normal */
  843         dp = dp->prev;                  /* backpedal */
  844     }
  845     return(dp);                         /* NULL, we can assume */
  846 }
  847 
  848 
  849 /**
  850  ** nextent
  851  **
  852  ** Returns the next entry in (list), skipping zoomed regions.  Returns NULL
  853  ** if there is no next entry. (Possible if the current entry is last, or
  854  ** if the current entry is the last heading and it's collapsed)
  855  **/
  856 static DEV_LIST *
  857 nextent(DEV_LIST *list)
  858 {
  859     DEV_LIST    *dp;
  860 
  861     if (!list)
  862         return(NULL);
  863     if (list->comment != DEV_ZOOMED)    /* no reason to skip */
  864         return(list->next);
  865     dp = list->next;
  866     while(dp)
  867     {
  868         if (dp->comment != DEV_DEVICE)  /* found another heading */
  869             break;
  870         dp = dp->next;
  871     }
  872     return(dp);                         /* back we go */
  873 }
  874     
  875 
  876 /**
  877  ** ofsent
  878  **
  879  ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist 
  880  **/
  881 static DEV_LIST *
  882 ofsent(int ofs, DEV_LIST *list)
  883 {
  884     while (ofs-- && list)
  885         list = nextent(list);
  886     return(list);
  887 }
  888 
  889 
  890 /**
  891  ** findconflict
  892  **
  893  ** Scans every element of (list) and sets the conflict tags appropriately
  894  ** Returns the number of conflicts found.
  895  **/
  896 static int
  897 findconflict(DEV_LIST *list)
  898 {
  899     int         count = 0;                      /* number of conflicts found */
  900     DEV_LIST    *dp,*sp;
  901 
  902     for (dp = list; dp; dp = dp->next)          /* over the whole list */
  903     {
  904         if (dp->comment != DEV_DEVICE)          /* comments don't usually conflict */
  905             continue;
  906 
  907         dp->conflicts = 0;                      /* assume the best */
  908         for (sp = list; sp; sp = sp->next)      /* scan the entire list for conflicts */
  909         {
  910             if (sp->comment != DEV_DEVICE)      /* likewise */
  911                 continue;
  912 
  913             if (sp == dp)                       /* always conflict with itself */
  914                 continue;
  915 
  916             if ((dp->iobase > 0) &&             /* iobase conflict? */
  917                 (dp->iobase == sp->iobase))
  918                 dp->conflicts = 1;
  919             if ((dp->irq > 0) &&                /* irq conflict? */
  920                 (dp->irq == sp->irq))
  921                 dp->conflicts = 1;
  922             if ((dp->drq > 0) &&                /* drq conflict? */
  923                 (dp->drq == sp->drq))
  924                 dp->conflicts = 1;
  925             if ((sp->maddr > 0) &&              /* maddr/msize conflict? */
  926                 (dp->maddr > 0) &&
  927                 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
  928                 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
  929                 dp->conflicts = 1;
  930         }
  931         count += dp->conflicts;                 /* count conflicts */
  932     }
  933     return(count);
  934 }
  935 
  936 
  937 /**
  938  ** expandlist
  939  **
  940  ** Unzooms all headings in (list)
  941  **/
  942 static void
  943 expandlist(DEV_LIST *list)
  944 {
  945     while(list)
  946     {
  947         if (list->comment == DEV_COMMENT)
  948             list->comment = DEV_ZOOMED;
  949         list = list->next;
  950     }
  951 }
  952 
  953 
  954 /**
  955  ** collapselist
  956  **
  957  ** Zooms all headings in (list)
  958  **/
  959 static void
  960 collapselist(DEV_LIST *list)
  961 {
  962     while(list)
  963     {
  964         if (list->comment == DEV_ZOOMED)
  965             list->comment = DEV_COMMENT;
  966         list = list->next;
  967     }
  968 }
  969 
  970 
  971 /**
  972  ** Screen-manipulation stuff
  973  **
  974  ** This is the basic screen layout :
  975  **
  976  **     0    5   10   15   20   25   30   35   40   45   50   55   60   67   70   75
  977  **     |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
  978  **    +--------------------------------------------------------------------------------+
  979  ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
  980  ** 1 -| ........................                                    .......  ..  0x....|
  981  ** 2 -| ........................                                    .......  ..  0x....|
  982  ** 3 -| ........................                                    .......  ..  0x....|
  983  ** 4 -| ........................                                    .......  ..  0x....|
  984  ** 5 -| ........................                                    .......  ..  0x....|
  985  ** 6 -| ........................                                    .......  ..  0x....|
  986  ** 7 -| ........................                                    .......  ..  0x....|
  987  ** 8 -| ........................                                    .......  ..  0x....|
  988  ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
  989  ** 10-| ........................                                    .......            |
  990  ** 11-| ........................                                    .......            |
  991  ** 12-| ........................                                    .......            |
  992  ** 13-| ........................                                    .......            |
  993  ** 14-| ........................                                    .......            |
  994  ** 15-| ........................                                    .......            |
  995  ** 16-| ........................                                    .......            |
  996  ** 17-|------------------------------------------------------UP-DOWN-------------------|
  997  ** 18-| Relevant parameters for the current device                                     |
  998  ** 19-|                                                                                |
  999  ** 20-|                                                                                |
 1000  ** 21-|--------------------------------------------------------------------------------|
 1001  ** 22-| Help texts go here                                                             |
 1002  ** 23-|                                                                                |
 1003  **    +--------------------------------------------------------------------------------+
 1004  **
 1005  ** Help texts
 1006  **
 1007  ** On a collapsed comment :
 1008  **
 1009  ** [Enter] Expand device list      [z]   Expand all lists
 1010  ** [TAB]   Change fields           [Q]   Save and Exit
 1011  **
 1012  ** On an expanded comment :
 1013  ** 
 1014  ** [Enter] Collapse device list    [Z]   Collapse all lists
 1015  ** [TAB]   Change fields           [Q]   Save and Exit
 1016  **
 1017  ** On a comment with no followers
 1018  **
 1019  ** 
 1020  ** [TAB]   Change fields           [Q]   Save and Exit
 1021  **
 1022  ** On a device in the active list
 1023  **
 1024  ** [Enter] Edit device parameters  [DEL] Disable device
 1025  ** [TAB]   Change fields           [Q]   Save and Exit             [?] Help
 1026  **
 1027  ** On a device in the inactive list
 1028  **
 1029  ** [Enter] Enable device
 1030  ** [TAB]   Change fields           [Q]   Save and Exit             [?] Help
 1031  **
 1032  ** While editing parameters
 1033  **
 1034  ** <parameter-specific help here>
 1035  ** [TAB]   Change fields           [Q]   Save device parameters
 1036  **/
 1037 
 1038 
 1039 
 1040 /**
 1041  **
 1042  ** The base-level screen primitives :
 1043  **
 1044  ** bold()      - enter bold mode               \E[1m     (md)
 1045  ** inverse()   - enter inverse mode            \E[7m     (so)
 1046  ** normal()    - clear bold/inverse mode       \E[m      (se)
 1047  ** clear()     - clear the screen              \E[H\E[J  (ce)
 1048  ** move(x,y)   - move the cursor to x,y        \E[y;xH:  (cm)
 1049  **/
 1050 
 1051 static void 
 1052 bold(void)
 1053 {
 1054     printf("\033[1m");
 1055 }
 1056 
 1057 static void 
 1058 inverse(void)
 1059 {
 1060     printf("\033[7m");
 1061 }
 1062 
 1063 static void 
 1064 normal(void)
 1065 {
 1066     printf("\033[m");
 1067 }
 1068 
 1069 static void 
 1070 clear(void)
 1071 {
 1072     normal();
 1073     printf("\033[H\033[J");
 1074 }
 1075 
 1076 static void 
 1077 move(int x, int y)
 1078 {
 1079     printf("\033[%d;%dH",y+1,x+1);
 1080 }
 1081 
 1082 
 1083 /**
 1084  **
 1085  ** High-level screen primitives :
 1086  ** 
 1087  ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
 1088  ** putxy(x,y,str)      - put (str) at (x,y), supports embedded formatting
 1089  ** erase(x,y,w,h)      - clear the box (x,y,w,h)
 1090  ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
 1091  ** putmsg(str)         - put (str) in the message area
 1092  ** puthelp(str)        - put (str) in the upper helpline
 1093  ** pad(str,len)        - pad (str) to (len) with spaces
 1094  ** drawline(row,detail,list,inverse,*dhelp)
 1095  **                     - draws a line for (*list) at (row) onscreen.  If (detail) is 
 1096  **                       nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
 1097  **                       draw the line in inverse video, and display (*dhelp) on the
 1098  **                       helpline.
 1099  ** drawlist(row,num,detail,list)
 1100  **                     - draw (num) entries from (list) at (row) onscreen, passile (detail)
 1101  **                       through to drawline().
 1102  ** showparams(dev)     - displays the relevant parameters for (dev) below the lists onscreen.
 1103  ** yesno(str)          - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
 1104  ** redraw();           - Redraws the entire screen layout, including the 
 1105  **                     - two list panels.
 1106  **/
 1107 
 1108 /** 
 1109  ** putxy
 1110  **   writes (str) at x,y onscreen
 1111  ** putxyl
 1112  **   writes up to (len) of (str) at x,y onscreen.
 1113  **
 1114  ** Supports embedded formatting :
 1115  ** !i - inverse mode.
 1116  ** !b - bold mode.
 1117  ** !n - normal mode.
 1118  **/
 1119 static void 
 1120 putxyl(int x, int y, char *str, int len)
 1121 {
 1122     move(x,y);
 1123     normal();
 1124 
 1125     while((*str) && (len--))
 1126     {
 1127         if (*str == '!')                /* format escape? */
 1128         {
 1129             switch(*(str+1))            /* depending on the next character */
 1130             {
 1131             case 'i':
 1132                 inverse();
 1133                 str +=2;                /* skip formatting */
 1134                 len++;                  /* doesn't count for length */
 1135                 break;
 1136                 
 1137             case 'b':
 1138                 bold();
 1139                 str  +=2;               /* skip formatting */
 1140                 len++;                  /* doesn't count for length */
 1141                 break;
 1142 
 1143             case 'n':
 1144                 normal();
 1145                 str +=2;                /* skip formatting */
 1146                 len++;                  /* doesn't count for length */
 1147                 break;
 1148                 
 1149             default:
 1150                 putchar(*str++);        /* not an escape */
 1151             }
 1152         }else{
 1153             putchar(*str++);            /* emit the character */
 1154         }
 1155     }
 1156 }
 1157 
 1158 #define putxy(x,y,str)  putxyl(x,y,str,-1)
 1159 
 1160 
 1161 /**
 1162  ** erase
 1163  **
 1164  ** Erases the region (x,y,w,h)
 1165  **/
 1166 static void 
 1167 erase(int x, int y, int w, int h)
 1168 {
 1169     int         i;
 1170 
 1171     normal();
 1172     for (i = 0; i < h; i++)
 1173         putxyl(x,y++,spaces,w);
 1174 }
 1175 
 1176 
 1177 /** 
 1178  ** txtbox
 1179  **
 1180  ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
 1181  ** putxy.  Lines are not wrapped, newlines must be forced with \n.
 1182  **/
 1183 static void 
 1184 txtbox(int x, int y, int w, int h, char *str)
 1185 {
 1186     int         i = 0;
 1187 
 1188     h--;
 1189     while((str[i]) && h)
 1190     {
 1191         if (str[i] == '\n')                     /* newline */
 1192         {
 1193             putxyl(x,y,str,(i<w)?i:w);          /* write lesser of i or w */
 1194             y++;                                /* move down */
 1195             h--;                                /* room for one less */
 1196             str += (i+1);                       /* skip first newline */
 1197             i = 0;                              /* zero offset */
 1198         }else{
 1199             i++;                                /* next character */
 1200         }
 1201     }
 1202     if (h)                                      /* end of string, not region */
 1203         putxyl(x,y,str,w);
 1204 }
 1205 
 1206 
 1207 /**
 1208  ** putmsg
 1209  **
 1210  ** writes (msg) in the helptext area
 1211  **/
 1212 static void 
 1213 putmsg(char *msg)
 1214 {
 1215     erase(0,18,80,3);                           /* clear area */
 1216     txtbox(0,18,80,3,msg);
 1217 }
 1218 
 1219 
 1220 /**
 1221  ** puthelp
 1222  **
 1223  ** Writes (msg) in the helpline area
 1224  **/
 1225 static void 
 1226 puthelp(char *msg)
 1227 {
 1228     erase(0,22,80,1);
 1229     putxy(0,22,msg);
 1230 }
 1231 
 1232 
 1233 /**
 1234  ** masterhelp
 1235  **
 1236  ** Draws the help message at the bottom of the screen
 1237  **/
 1238 static void
 1239 masterhelp(char *msg)
 1240 {
 1241     erase(0,23,80,1);
 1242     putxy(0,23,msg);
 1243 }
 1244 
 1245 
 1246 /**
 1247  ** pad 
 1248  **
 1249  ** space-pads a (str) to (len) characters
 1250  **/
 1251 static void 
 1252 pad(char *str, int len)
 1253 {
 1254     int         i;
 1255 
 1256     for (i = 0; str[i]; i++)                    /* find the end of the string */
 1257         ;
 1258     if (i >= len)                               /* no padding needed */
 1259         return;
 1260     while(i < len)                              /* pad */
 1261         str[i++] = ' ';
 1262     str[i] = '\0';
 1263 }
 1264                                                    
 1265 
 1266 /**
 1267  ** drawline
 1268  **
 1269  ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
 1270  ** the port and IRQ fields if (detail) is nonzero.  If (inverse), in inverse video.
 1271  **
 1272  ** The text (dhelp) is displayed if the item is a normal device, otherwise
 1273  ** help is shown for normal or zoomed comments
 1274  **/
 1275 static void 
 1276 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
 1277 {
 1278     char        lbuf[90],nb[70],db[20],ib[16],pb[16];
 1279     
 1280     if (list->comment == DEV_DEVICE)
 1281     {
 1282         nb[0] = ' ';
 1283         strncpy(nb+1,list->name,57);
 1284     }else{
 1285         strncpy(nb,list->name,58);
 1286         if ((list->comment == DEV_ZOOMED) && (list->next))
 1287             if (list->next->comment == DEV_DEVICE)      /* only mention if there's something hidden */
 1288                 strcat(nb,"  (Collapsed)");
 1289     }
 1290     nb[58] = '\0';
 1291     pad(nb,60);
 1292     if (list->conflicts)                        /* device in conflict? */
 1293     {
 1294         if (inverse)
 1295         {
 1296             strcpy(nb+54," !nCONF!i ");         /* tag conflict, careful of length */
 1297         }else{
 1298             strcpy(nb+54," !iCONF!n ");         /* tag conflict, careful of length */
 1299         }
 1300     }
 1301     if (list->comment == DEV_DEVICE)
 1302     {
 1303         sprintf(db,"%s%d",list->dev,list->unit);
 1304         pad(db,8);
 1305     }else{
 1306         strcpy(db,"        ");
 1307     }
 1308     if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
 1309     {
 1310         sprintf(ib," %d",list->irq);
 1311         pad(ib,4);
 1312     }else{
 1313         strcpy(ib,"    ");
 1314     }
 1315     if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
 1316     {
 1317         sprintf(pb,"0x%x",list->iobase);
 1318         pad(pb,7);
 1319     }else{
 1320         strcpy(pb,"       ");
 1321     }
 1322 
 1323     sprintf(lbuf,"  %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
 1324 
 1325     putxyl(0,row,lbuf,80);
 1326     if (dhelp)
 1327     {
 1328         switch(list->comment)
 1329         {
 1330         case DEV_DEVICE:        /* ordinary device */
 1331             puthelp(dhelp);
 1332             break;
 1333         case DEV_COMMENT:
 1334             puthelp("");
 1335             if (list->next)
 1336                 if (list->next->comment == DEV_DEVICE)
 1337                     puthelp("  [!bEnter!n] Collapse device list    [!bC!n]    Collapse all lists");
 1338             break;
 1339         case DEV_ZOOMED:        
 1340             puthelp("");
 1341             if (list->next)
 1342                 if (list->next->comment == DEV_DEVICE)
 1343                     puthelp("  [!bEnter!n] Expand device list      [!bX!n]    Expand all lists");
 1344             break;
 1345         default:
 1346             puthelp("  WARNING: This list entry corrupted!");
 1347             break;
 1348         }
 1349     }
 1350     move(0,row);                                /* put the cursor somewhere relevant */
 1351 }
 1352 
 1353 
 1354 /**
 1355  ** drawlist
 1356  **
 1357  ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
 1358  ** port and IRQ fields as well if (detail) is nonzero
 1359  **
 1360  ** printf in the kernel is essentially useless, so we do most of the hard work ourselves here.
 1361  **/
 1362 static void 
 1363 drawlist(int row, int num, int detail, DEV_LIST *list)
 1364 {
 1365     int         ofs;
 1366 
 1367     for(ofs = 0; ofs < num; ofs++)
 1368     {
 1369         if (list)
 1370         {
 1371             drawline(row+ofs,detail,list,0,NULL);       /* NULL -> don't draw empty help string */
 1372             list = nextent(list);                       /* move down visible list */
 1373         }else{
 1374             erase(0,row+ofs,80,1);
 1375         }
 1376     }
 1377 }
 1378 
 1379 
 1380 /**
 1381  ** redrawactive
 1382  **
 1383  ** Redraws the active list 
 1384  **/
 1385 static void
 1386 redrawactive(void)
 1387 {
 1388     char        cbuf[16];
 1389 
 1390     if (conflicts)
 1391     {
 1392         sprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
 1393         putxy(45,0,cbuf);
 1394     }else{
 1395         putxyl(45,0,lines,16);
 1396     }
 1397     drawlist(1,8,1,alist);                      /* draw device lists */
 1398 }
 1399 
 1400 /**
 1401  ** redrawinactive
 1402  **
 1403  ** Redraws the inactive list 
 1404  **/
 1405 static void
 1406 redrawinactive(void)
 1407 {
 1408     drawlist(10,7,0,ilist);                     /* draw device lists */
 1409 }
 1410 
 1411 
 1412 /**
 1413  ** redraw
 1414  **
 1415  ** Clear the screen and redraw the entire layout
 1416  **/
 1417 static void 
 1418 redraw(void)
 1419 {
 1420     clear();
 1421     putxy(0,0,lines);
 1422     putxy(3,0,"!bActive!n-!bDrivers");
 1423     putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
 1424     putxy(0,9,lines);
 1425     putxy(3,9,"!bInactive!n-!bDrivers");
 1426     putxy(63,9,"!bDev");
 1427     putxy(0,17,lines);
 1428     putxy(0,21,lines);
 1429     masterhelp("  [!bTAB!n]   Change fields           [!bQ!n]   Save and Exit             [!b?!n] Help");
 1430 
 1431     redrawactive();
 1432     redrawinactive();
 1433 }
 1434 
 1435 
 1436 /**
 1437  ** yesnocancel
 1438  **
 1439  ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
 1440  ** 2 if they hit 'c' or 'C',  or 0 for 'n' or 'N'.
 1441  **/
 1442 static int
 1443 yesnocancel(char *str)
 1444 {
 1445 
 1446     putmsg(str);
 1447     for(;;)
 1448         switch(getchar())
 1449         {
 1450         case -1:
 1451         case 'n':
 1452         case 'N':
 1453             return(0);
 1454             
 1455         case 'y':
 1456         case 'Y':
 1457             return(1);
 1458             
 1459         case 'c':
 1460         case 'C':
 1461             return(2);
 1462         }
 1463 }
 1464 
 1465 
 1466 /**
 1467  ** showparams
 1468  **
 1469  ** Show device parameters in the region below the lists
 1470  **
 1471  **     0    5   10   15   20   25   30   35   40   45   50   55   60   67   70   75
 1472  **     |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
 1473  **    +--------------------------------------------------------------------------------+
 1474  ** 17-|--------------------------------------------------------------------------------|
 1475  ** 18-| Port address : 0x0000     Memory address : 0x00000   Conflict allowed          |
 1476  ** 19-| IRQ number   : 00         Memory size    : 0x0000                              |
 1477  ** 20-| Flags        : 0x0000     DRQ number     : 00                                  |
 1478  ** 21-|--------------------------------------------------------------------------------|
 1479  **/
 1480 static void 
 1481 showparams(DEV_LIST *dev)
 1482 {
 1483     char        buf[80];
 1484 
 1485     erase(0,18,80,3);                           /* clear area */
 1486     if (!dev)
 1487         return;
 1488     if (dev->comment != DEV_DEVICE)
 1489         return;
 1490 
 1491 
 1492     if (dev->iobase > 0)
 1493     {
 1494         sprintf(buf,"Port address : 0x%x",dev->iobase);
 1495         putxy(1,18,buf);
 1496     }
 1497             
 1498     if (dev->irq > 0)
 1499     {
 1500         sprintf(buf,"IRQ number   : %d",dev->irq);
 1501         putxy(1,19,buf);
 1502     }
 1503     sprintf(buf,"Flags        : 0x%x",dev->flags);
 1504     putxy(1,20,buf);
 1505     if (dev->maddr > 0)
 1506     {
 1507         sprintf(buf,"Memory address : 0x%x",dev->maddr);
 1508         putxy(26,18,buf);
 1509     }
 1510     if (dev->msize > 0)
 1511     {
 1512         sprintf(buf,"Memory size    : 0x%x",dev->msize);
 1513         putxy(26,19,buf);
 1514     }
 1515 
 1516     if (dev->drq > 0)
 1517     {
 1518         sprintf(buf,"DRQ number     : %d",dev->drq);
 1519         putxy(26,20,buf);
 1520     }
 1521 }
 1522 
 1523 
 1524 /**
 1525  ** Editing functions for device parameters
 1526  **
 1527  ** editval(x,y,width,hex,min,max,val)  - Edit (*val) in a field (width) wide at (x,y)
 1528  **                                       onscreen.  Refuse values outsise (min) and (max).
 1529  ** editparams(dev)                     - Edit the parameters for (dev)
 1530  **/
 1531 
 1532 
 1533 #define VetRet(code)                                                    \
 1534 {                                                                       \
 1535     if ((i >= min) && (i <= max))       /* legit? */                    \
 1536     {                                                                   \
 1537         *val = i;                                                       \
 1538         sprintf(buf,hex?"0x%x":"%d",i);                                 \
 1539         putxy(hex?x-2:x,y,buf);                                         \
 1540         return(code);                   /* all done and exit */         \
 1541     }                                                                   \
 1542     i = *val;                           /* restore original value */    \
 1543     delta = 1;                          /* restore other stuff */       \
 1544 }
 1545 
 1546 
 1547 /**
 1548  ** editval
 1549  **
 1550  ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
 1551  ** in a field (width) wide. (Allow one space)
 1552  ** If (ro) is set, we're in "readonly" mode, so disallow edits.
 1553  **
 1554  ** Return KEY_TAB on \t, KEY_EXIT on 'q'
 1555  **/
 1556 static int 
 1557 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
 1558 {
 1559     int         i = *val;                       /* work with copy of the value */
 1560     char        buf[2+11+1],tc[11+1];           /* display buffer, text copy */
 1561     int         xp = 0;                         /* cursor offset into text copy */
 1562     int         delta = 1;                      /* force redraw first time in */
 1563     int         c;
 1564     int         extended = 0;                   /* stage counter for extended key sequences */
 1565 
 1566     if (hex)                                    /* we presume there's a leading 0x onscreen */
 1567         putxy(x-2,y,"!i0x");                    /* coz there sure is now */
 1568         
 1569     for (;;)
 1570     {
 1571         if (delta)                              /* only update if necessary */
 1572         {
 1573             sprintf(tc,hex?"%x":"%d",i);        /* make a text copy of the value */
 1574             sprintf(buf,"!i%s",tc);             /* format for printing */
 1575             erase(x,y,width,1);                 /* clear the area */
 1576             putxy(x,y,buf);                     /* write */
 1577             xp = strlen(tc);                    /* cursor always at end */
 1578             move(x+xp,y);                       /* position the cursor */
 1579         }
 1580 
 1581         c = getchar();
 1582 
 1583         switch(extended)                        /* escape handling */
 1584         {
 1585         case 0:
 1586             if (c == 0x1b)                      /* esc? */
 1587             {
 1588                 extended = 1;                   /* flag and spin */
 1589                 continue;
 1590             }
 1591             extended = 0;
 1592             break;                              /* nope, drop through */
 1593         
 1594         case 1:                                 /* there was an escape prefix */
 1595             if (c == '[' || c == 'O')           /* second character in sequence */
 1596             {
 1597                 extended = 2;
 1598                 continue;
 1599             }
 1600             if (c == 0x1b)
 1601                 return(KEY_EXIT);               /* double esc exits */
 1602             extended = 0;
 1603             break;                              /* nup, not a sequence. */
 1604 
 1605         case 2:
 1606             extended = 0;
 1607             switch(c)                           /* looks like the real McCoy */
 1608             {
 1609             case 'A':
 1610                 VetRet(KEY_UP);                 /* leave if OK */
 1611                 continue;
 1612             case 'B':
 1613                 VetRet(KEY_DOWN);               /* leave if OK */
 1614                 continue;
 1615             case 'C':
 1616                 VetRet(KEY_RIGHT);              /* leave if OK */
 1617                 continue;
 1618             case 'D':
 1619                 VetRet(KEY_LEFT);               /* leave if OK */
 1620                 continue;
 1621                 
 1622             default:
 1623                 continue;
 1624             }
 1625         }
 1626     
 1627         switch(c)
 1628         {
 1629         case '\t':                              /* trying to tab off */
 1630             VetRet(KEY_TAB);                    /* verify and maybe return */
 1631             break;
 1632 
 1633         case -1:
 1634         case 'q':
 1635         case 'Q':
 1636             VetRet(KEY_EXIT);
 1637             break;
 1638             
 1639         case '\b':
 1640         case '\177':                            /* BS or DEL */
 1641             if (ro)                             /* readonly? */
 1642             {
 1643                 puthelp(" !iThis value cannot be edited (Press ESC)");
 1644                 while(getchar() != 0x1b);       /* wait for key */
 1645                 return(KEY_NULL);               /* spin */
 1646             }
 1647             if (xp)                             /* still something left to delete */
 1648             {
 1649                 i = (hex ? i/0x10u : i/10);     /* strip last digit */
 1650                 delta = 1;                      /* force update */
 1651             }
 1652             break;
 1653 
 1654         case 588:
 1655             VetRet(KEY_UP);
 1656             break;
 1657 
 1658         case '\r':
 1659         case '\n':
 1660         case 596:
 1661             VetRet(KEY_DOWN);
 1662             break;
 1663 
 1664         case 591:
 1665             VetRet(KEY_LEFT);
 1666             break;
 1667 
 1668         case 593:
 1669             VetRet(KEY_RIGHT);
 1670             break;
 1671                 
 1672         default:
 1673             if (ro)                             /* readonly? */
 1674             {
 1675                 puthelp(" !iThis value cannot be edited (Press ESC)");
 1676                 while(getchar() != 0x1b);       /* wait for key */
 1677                 return(KEY_NULL);               /* spin */
 1678             }
 1679             if (xp >= width)                    /* no room for more characters anyway */
 1680                 break;
 1681             if (hex)
 1682             {
 1683                 if ((c >= '') && (c <= '9'))
 1684                 {
 1685                     i = i*0x10 + (c-'');       /* update value */
 1686                     delta = 1;
 1687                     break;
 1688                 }
 1689                 if ((c >= 'a') && (c <= 'f'))
 1690                 {
 1691                     i = i*0x10 + (c-'a'+0xa);
 1692                     delta = 1;
 1693                     break;
 1694                 }
 1695                 if ((c >= 'A') && (c <= 'F'))
 1696                 {
 1697                     i = i*0x10 + (c-'A'+0xa);
 1698                     delta = 1;
 1699                     break;
 1700                 }
 1701             }else{
 1702                 if ((c >= '') && (c <= '9'))
 1703                 {
 1704                     i = i*10 + (c-'');         /* update value */
 1705                     delta = 1;                  /* force redraw */
 1706                     break;
 1707                 }
 1708             }
 1709             break;
 1710         }
 1711     }
 1712 }
 1713 
 1714 
 1715 /**
 1716  ** editparams
 1717  **
 1718  ** Edit the parameters for (dev)
 1719  **
 1720  ** Note that it's _always_ possible to edit the flags, otherwise it might be
 1721  ** possible for this to spin in an endless loop...
 1722  **     0    5   10   15   20   25   30   35   40   45   50   55   60   67   70   75
 1723  **     |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
 1724  **    +--------------------------------------------------------------------------------+
 1725  ** 17-|--------------------------------------------------------------------------------|
 1726  ** 18-| Port address : 0x0000     Memory address : 0x00000   Conflict allowed          |
 1727  ** 19-| IRQ number   : 00         Memory size    : 0x0000                              |
 1728  ** 20-| Flags        : 0x0000     DRQ number     : 00                                  |
 1729  ** 21-|--------------------------------------------------------------------------------|
 1730  **
 1731  ** The "intelligence" in this function that hops around based on the directional
 1732  ** returns from editval isn't very smart, and depends on the layout above.
 1733  **/
 1734 static void 
 1735 editparams(DEV_LIST *dev)
 1736 {
 1737     int         ret;
 1738     char        buf[16];                /* needs to fit the device name */
 1739 
 1740     putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
 1741     sprintf(buf,"!b%s",dev->dev);
 1742     putxy(24,17,buf);
 1743 
 1744     erase(1,22,80,1);
 1745     for (;;)
 1746     {
 1747     ep_iobase:
 1748         if (dev->iobase > 0)
 1749         {
 1750             puthelp("  IO Port address (Hexadecimal, 0x1-0xffff)");
 1751             ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
 1752             switch(ret)
 1753             {
 1754             case KEY_EXIT:
 1755                 goto ep_exit;
 1756 
 1757             case KEY_RIGHT:
 1758                 if (dev->maddr > 0)
 1759                     goto ep_maddr;
 1760                 break;
 1761 
 1762             case KEY_TAB:
 1763             case KEY_DOWN:
 1764                 goto ep_irq;
 1765             }
 1766             goto ep_iobase;
 1767         }
 1768     ep_irq:
 1769         if (dev->irq > 0)
 1770         {
 1771             puthelp("  Interrupt number (Decimal, 1-15)");
 1772             ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
 1773             switch(ret)
 1774             {
 1775             case KEY_EXIT:
 1776                 goto ep_exit;
 1777 
 1778             case KEY_RIGHT:
 1779                 if (dev->msize > 0)
 1780                     goto ep_msize;
 1781                 break;
 1782 
 1783             case KEY_UP:
 1784                 if (dev->iobase > 0)
 1785                     goto ep_iobase;
 1786                 break;
 1787 
 1788             case KEY_TAB:
 1789             case KEY_DOWN:
 1790                 goto ep_flags;
 1791             }
 1792             goto ep_irq;
 1793         }
 1794     ep_flags:
 1795         puthelp("  Device-specific flag values.");
 1796         ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
 1797         switch(ret)
 1798         {
 1799         case KEY_EXIT:
 1800             goto ep_exit;
 1801 
 1802         case KEY_RIGHT:
 1803             if (dev->drq > 0) 
 1804                 goto ep_drq;
 1805             break;
 1806 
 1807         case KEY_UP:
 1808             if (dev->irq > 0)
 1809                 goto ep_irq;
 1810             if (dev->iobase > 0)
 1811                 goto ep_iobase;
 1812             break;
 1813 
 1814         case KEY_DOWN:
 1815             if (dev->maddr > 0)
 1816                 goto ep_maddr;
 1817             if (dev->msize > 0)
 1818                 goto ep_msize;
 1819             if (dev->drq > 0)
 1820                 goto ep_drq;
 1821             break;
 1822 
 1823         case KEY_TAB:
 1824             goto ep_maddr;
 1825         }
 1826         goto ep_flags;
 1827     ep_maddr:
 1828         if (dev->maddr > 0)
 1829         {
 1830             puthelp("  Device memory start address (Hexadecimal, 0x1-0xfffff)");
 1831             ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
 1832             switch(ret)
 1833             {
 1834             case KEY_EXIT:
 1835                 goto ep_exit;
 1836 
 1837             case KEY_LEFT:
 1838                 if (dev->iobase > 0)
 1839                     goto ep_iobase;
 1840                 break;
 1841 
 1842             case KEY_UP:
 1843                 goto ep_flags;
 1844 
 1845             case KEY_DOWN:
 1846                 if (dev->msize > 0)
 1847                     goto ep_msize;
 1848                 if (dev->drq > 0)
 1849                     goto ep_drq;
 1850                 break;
 1851 
 1852             case KEY_TAB:
 1853                 goto ep_msize;
 1854             }
 1855             goto ep_maddr;
 1856         }
 1857     ep_msize:
 1858         if (dev->msize > 0)
 1859         {
 1860             puthelp("  Device memory size (Hexadecimal, 0x1-0x10000)");
 1861             ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
 1862             switch(ret)
 1863             {
 1864             case KEY_EXIT:
 1865                 goto ep_exit;
 1866 
 1867             case KEY_LEFT:
 1868                 if (dev->irq > 0)
 1869                     goto ep_irq;
 1870                 break;
 1871 
 1872             case KEY_UP:
 1873                 if (dev->maddr > 0)
 1874                     goto ep_maddr;
 1875                 goto ep_flags;
 1876 
 1877             case KEY_DOWN:
 1878                 if (dev->drq > 0)
 1879                     goto ep_drq;
 1880                 break;
 1881 
 1882             case KEY_TAB:
 1883                 goto ep_drq;
 1884             }
 1885             goto ep_msize;
 1886         }
 1887     ep_drq:
 1888         if (dev->drq > 0)
 1889         {
 1890             puthelp("  Device DMA request number (Decimal, 1-7)");
 1891             ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
 1892             switch(ret)
 1893             {
 1894             case KEY_EXIT:
 1895                 goto ep_exit;
 1896 
 1897             case KEY_LEFT:
 1898                 goto ep_flags;
 1899 
 1900             case KEY_UP:
 1901                 if (dev->msize > 0)
 1902                     goto ep_msize;
 1903                 if (dev->maddr > 0)
 1904                     goto ep_maddr;
 1905                 goto ep_flags;
 1906 
 1907             case KEY_TAB:
 1908                 goto ep_iobase;
 1909             }
 1910             goto ep_drq;
 1911         }
 1912     }
 1913     ep_exit:
 1914     dev->changed = 1;                                   /* mark as changed */
 1915 }
 1916 
 1917 static char *helptext[] =
 1918 {
 1919     "                Using the UserConfig kernel settings editor",
 1920     "                -------------------------------------------",
 1921     "",
 1922     "VISUAL MODE:",
 1923     "",
 1924     "- - Layout -",
 1925     "",
 1926     "The screen displays a list of available drivers, divided into two",
 1927     "scrolling lists: Active Drivers, and Inactive Drivers.  Each list is",
 1928     "by default collapsed and can be expanded to show all the drivers",
 1929     "available in each category.  The parameters for the currently selected",
 1930     "driver are shown at the bottom of the screen.",
 1931     "",
 1932     "- - Moving around -",
 1933     "",
 1934     "To move in the current list, use the UP and DOWN cursor keys to select",
 1935     "an item (the selected item will be highlighted).  If the item is a",
 1936     "category name, you may alternatively expand or collapse the list of",
 1937     "drivers for that category by pressing [!bENTER!n].  Once the category is",
 1938     "expanded, you can select each driver in the same manner and either:",
 1939     "",
 1940     "  - change its parameters using [!bENTER!n]",
 1941     "  - move it to the Inactive list using [!bDEL!n]",
 1942     "",
 1943     "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
 1944     "you need to move a driver from the Inactive list back to the Active",
 1945     "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
 1946     "necessary, and press [!bENTER!n] -- the device will be moved back to",
 1947     "its place in the Active list.",
 1948     "",
 1949     "- - Altering the list/parameters -",
 1950     "",
 1951     "Any drivers for devices not installed in your system should be moved",
 1952     "to the Inactive list, until there are no remaining parameter conflicts",
 1953     "between the drivers, as indicated at the top.",
 1954     "",
 1955     "Once the list of Active drivers only contains entries for the devices",
 1956     "present in your system, you can set their parameters (Interrupt, DMA",
 1957     "channel, I/O addresses).  To do this, select the driver and press",
 1958     "[!bENTER!n]: it is now possible to edit the settings at the",
 1959     "bottom of the screen.  Use [!bTAB!n] to change fields, and when you are",
 1960     "finished, use [!bQ!n] to return to the list.",
 1961     "",
 1962     "- - Saving changes -",
 1963     "",
 1964     "When all settings seem correct, and you wish to proceed with the",
 1965     "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
 1966     "confirm your choice.",
 1967     "",
 1968     NULL
 1969 };
 1970 
 1971 
 1972 /**
 1973  ** helpscreen
 1974  **
 1975  ** Displays help text onscreen for people that are confused, using a simple
 1976  ** pager.
 1977  **/
 1978 static void
 1979 helpscreen(void) 
 1980 {
 1981     int         topline = 0;                    /* where we are in the text */
 1982     int         line = 0;                       /* last line we displayed */
 1983     int         c, delta = 1;
 1984     char        prompt[80];
 1985 
 1986     for (;;)                                    /* loop until user quits */
 1987     {
 1988         /* display help text */
 1989         if (delta) 
 1990         {
 1991             clear();                            /* remove everything else */
 1992             for (line = topline; 
 1993                  (line < (topline + 24)) && (helptext[line]); 
 1994                  line++)
 1995                 putxy(0,line-topline,helptext[line]);
 1996             delta = 0;
 1997         }
 1998         
 1999         /* prompt */
 2000         sprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
 2001         putxy(0,24,prompt);
 2002         
 2003         c = getchar();                          /* so what do they say? */
 2004         
 2005         switch (c)
 2006         {
 2007         case 'u':
 2008         case 'U':
 2009         case 'b':
 2010         case 'B':                               /* wired into 'more' users' fingers */
 2011             if (topline > 0)                    /* room to go up? */
 2012             {
 2013                 topline -= 24;
 2014                 if (topline < 0)                /* don't go too far */
 2015                     topline = 0;
 2016                 delta = 1;
 2017             }
 2018             break;
 2019 
 2020         case 'd':
 2021         case 'D':
 2022         case ' ':                               /* expected by most people */
 2023             if (helptext[line])                 /* maybe more below? */
 2024             {
 2025                 topline += 24;
 2026                 delta = 1;
 2027             }
 2028             break;
 2029             
 2030         case 'q':
 2031         case 'Q':
 2032             redraw();                           /* restore the screen */
 2033             return;
 2034         }
 2035     }
 2036 }
 2037 
 2038 
 2039 /** 
 2040  ** High-level control functions
 2041  **/
 2042 
 2043 
 2044 /**
 2045  ** dolist
 2046  **
 2047  ** Handle user movement within (*list) in the region starting at (row) onscreen with
 2048  ** (num) lines, starting at (*ofs) offset from row onscreen.
 2049  ** Pass (detail) on to drawing routines.
 2050  **
 2051  ** If the user hits a key other than a cursor key, maybe return a code.
 2052  **
 2053  ** (*list) points to the device at the top line in the region, (*ofs) is the 
 2054  ** position of the highlight within the region.  All routines below
 2055  ** this take only a device and an absolute row : use ofsent() to find the 
 2056  ** device, and add (*ofs) to (row) to find the absolute row.
 2057  **/
 2058 static int 
 2059 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
 2060 {
 2061     int         extended = 0;
 2062     int         c;
 2063     DEV_LIST    *lp;
 2064     int         delta = 1;
 2065     
 2066     for(;;)
 2067     {
 2068         if (delta)
 2069         {
 2070             showparams(ofsent(*ofs,*list));                             /* show device parameters */
 2071             drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp);       /* highlight current line */
 2072             delta = 0;
 2073         }
 2074 
 2075         c = getchar();                          /* get a character */
 2076         if ((extended == 2) || (c==588) || (c==596))    /* console gives "alternative" codes */
 2077         {
 2078             extended = 0;                       /* no longer */
 2079             switch(c)
 2080             {
 2081             case 588:                           /* syscons' idea of 'up' */
 2082             case 'A':                           /* up */
 2083                 if (*ofs)                       /* just a move onscreen */
 2084                 {
 2085                     drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
 2086                     (*ofs)--;                   /* move up */
 2087                 }else{
 2088                     lp = prevent(*list);        /* can we go up? */
 2089                     if (!lp)                    /* no */
 2090                         break;
 2091                     *list = lp;                 /* yes, move up list */
 2092                     drawlist(row,num,detail,*list);
 2093                 }
 2094                 delta = 1;
 2095                 break;
 2096 
 2097             case 596:                           /* dooby-do */
 2098             case 'B':                           /* down */
 2099                 lp = ofsent(*ofs,*list);        /* get current item */
 2100                 if (!nextent(lp))
 2101                     break;                      /* nothing more to move to */
 2102                 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);   /* unhighlight current line */
 2103                 if (*ofs < (num-1))             /* room to move onscreen? */
 2104                 {
 2105                     (*ofs)++;               
 2106                 }else{
 2107                     *list = nextent(*list);     /* scroll region down */
 2108                     drawlist(row,num,detail,*list);
 2109                 }               
 2110                 delta = 1;
 2111                 break;
 2112             }
 2113         }else{
 2114             switch(c)
 2115             {
 2116             case '\033':
 2117                 extended=1;
 2118                 break;
 2119                     
 2120             case '[':                           /* cheat : always preceeds cursor move */
 2121             case 'O':                           /* ANSI application key mode */
 2122                 if (extended==1)
 2123                     extended=2;
 2124                 else
 2125                     extended=0;
 2126                 break;
 2127                 
 2128             case 'Q':
 2129             case 'q':
 2130                 return(KEY_EXIT);               /* user requests exit */
 2131 
 2132             case '\r':                          
 2133             case '\n':
 2134                 return(KEY_DO);                 /* "do" something */
 2135 
 2136             case '\b':
 2137             case '\177':
 2138             case 599:
 2139                 return(KEY_DEL);                /* "delete" response */
 2140 
 2141             case 'X':
 2142             case 'x':
 2143                 return(KEY_UNZOOM);             /* expand everything */
 2144                 
 2145             case 'C':
 2146             case 'c':
 2147                 return(KEY_ZOOM);               /* collapse everything */
 2148 
 2149             case '\t':
 2150                 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);   /* unhighlight current line */
 2151                 return(KEY_TAB);                                /* "move" response */
 2152                 
 2153             case '\014':                        /* ^L, redraw */
 2154                 return(KEY_REDRAW);
 2155                 
 2156             case '?':                           /* helptext */
 2157                 return(KEY_HELP);
 2158                 
 2159             }
 2160         }
 2161     }           
 2162 }
 2163 
 2164 
 2165 /**
 2166  ** visuserconfig
 2167  ** 
 2168  ** Do the fullscreen config thang
 2169  **/
 2170 static int
 2171 visuserconfig(void)
 2172 {
 2173     int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
 2174     DEV_LIST    *dp;
 2175     
 2176     initlist(&active);
 2177     initlist(&inactive);
 2178     alist = active;
 2179     ilist = inactive;
 2180 
 2181     getdevs();
 2182 
 2183     conflicts = findconflict(active);           /* find conflicts in the active list only */
 2184 
 2185     redraw();
 2186 
 2187     for(;;)
 2188     {
 2189         switch(mode)
 2190         {
 2191         case 0:                                 /* active devices */
 2192             ret = dolist(1,8,1,&actofs,&alist,
 2193                          "  [!bEnter!n] Edit device parameters  [!bDEL!n] Disable device");
 2194             switch(ret)
 2195             {
 2196             case KEY_TAB:
 2197                 mode = 1;                       /* swap lists */
 2198                 break;
 2199 
 2200             case KEY_REDRAW:
 2201                 redraw();
 2202                 break;
 2203 
 2204             case KEY_ZOOM:
 2205                 alist = active;
 2206                 actofs = 0;
 2207                 expandlist(active);
 2208                 redrawactive();
 2209                 break;
 2210 
 2211             case KEY_UNZOOM:
 2212                 alist = active;
 2213                 actofs = 0;
 2214                 collapselist(active);
 2215                 redrawactive();
 2216                 break;
 2217 
 2218             case KEY_DEL:
 2219                 dp = ofsent(actofs,alist);      /* get current device */
 2220                 if (dp)                         /* paranoia... */
 2221                 {
 2222                     if (dp->attrib & FLG_MANDATORY)     /* can't be deleted */
 2223                         break;
 2224                     if (dp == alist)            /* moving top item on list? */
 2225                     {
 2226                         if (dp->next)
 2227                         {
 2228                             alist = dp->next;   /* point list to non-moving item */
 2229                         }else{
 2230                             alist = dp->prev;   /* end of list, go back instead */
 2231                         }
 2232                     }else{
 2233                         if (!dp->next)          /* moving last item on list? */
 2234                             actofs--;
 2235                     }
 2236                     dp->conflicts = 0;          /* no conflicts on the inactive list */
 2237                     movedev(dp,inactive);       /* shift to inactive list */
 2238                     conflicts = findconflict(active);   /* update conflict tags */
 2239                     dp->changed = 1;
 2240                     redrawactive();                     /* redraw */
 2241                     redrawinactive();
 2242                 }
 2243                 break;
 2244                 
 2245             case KEY_DO:                        /* edit device parameters */
 2246                 dp = ofsent(actofs,alist);      /* get current device */
 2247                 if (dp)                         /* paranoia... */
 2248                 {
 2249                     if (dp->comment == DEV_DEVICE)      /* can't edit comments, zoom? */
 2250                     {
 2251                         masterhelp("  [!bTAB!n]   Change fields           [!bQ!n]   Save device parameters");
 2252                         editparams(dp);
 2253                         masterhelp("  [!bTAB!n]   Change fields           [!bQ!n]   Save and Exit             [!b?!n] Help");
 2254                         putxy(0,17,lines);
 2255                         conflicts = findconflict(active);       /* update conflict tags */
 2256                     }else{                              /* DO on comment = zoom */
 2257                         switch(dp->comment)             /* Depends on current state */
 2258                         {
 2259                         case DEV_COMMENT:               /* not currently zoomed */
 2260                             dp->comment = DEV_ZOOMED;
 2261                             break;
 2262 
 2263                         case DEV_ZOOMED:
 2264                             dp->comment = DEV_COMMENT;
 2265                             break;
 2266                         }
 2267                     }
 2268                     redrawactive();
 2269                 }
 2270                 break;
 2271             }
 2272             break;
 2273 
 2274         case 1:                                 /* inactive devices */
 2275             ret = dolist(10,7,0,&inactofs,&ilist,
 2276                          "  [!bEnter!n] Enable device                                   ");
 2277             switch(ret)
 2278             {
 2279             case KEY_TAB:
 2280                 mode = 0;
 2281                 break;
 2282 
 2283             case KEY_REDRAW:
 2284                 redraw();
 2285                 break;
 2286 
 2287             case KEY_ZOOM:
 2288                 ilist = inactive;
 2289                 inactofs = 0;
 2290                 expandlist(inactive);
 2291                 redrawinactive();
 2292                 break;
 2293 
 2294             case KEY_UNZOOM:
 2295                 ilist = inactive;
 2296                 inactofs = 0;
 2297                 collapselist(inactive);
 2298                 redrawinactive();
 2299                 break;
 2300 
 2301             case KEY_DO:
 2302                 dp = ofsent(inactofs,ilist);    /* get current device */
 2303                 if (dp)                         /* paranoia... */
 2304                 {
 2305                     if (dp->comment == DEV_DEVICE)      /* can't move comments, zoom? */
 2306                     {
 2307                         if (dp == ilist)                /* moving top of list? */
 2308                         {
 2309                             if (dp->next)
 2310                             {
 2311                                 ilist = dp->next;       /* point list to non-moving item */
 2312                             }else{
 2313                                 ilist = dp->prev;       /* can't go down, go up instead */
 2314                             }
 2315                         }else{
 2316                             if (!dp->next)              /* last entry on list? */
 2317                                 inactofs--;             /* shift cursor up one */
 2318                         }
 2319 
 2320                         movedev(dp,active);             /* shift to active list */
 2321                         conflicts = findconflict(active);       /* update conflict tags */
 2322                         dp->changed = 1;
 2323                         alist = dp;                     /* put at top and current */
 2324                         actofs = 0;
 2325                         while(dp->comment == DEV_DEVICE)
 2326                             dp = dp->prev;              /* forcibly unzoom section */
 2327                         dp ->comment = DEV_COMMENT;
 2328                         mode = 0;                       /* and swap modes to follow it */
 2329 
 2330                     }else{                              /* DO on comment = zoom */
 2331                         switch(dp->comment)             /* Depends on current state */
 2332                         {
 2333                         case DEV_COMMENT:               /* not currently zoomed */
 2334                             dp->comment = DEV_ZOOMED;
 2335                             break;
 2336 
 2337                         case DEV_ZOOMED:
 2338                             dp->comment = DEV_COMMENT;
 2339                             break;
 2340                         }
 2341                     }
 2342                     redrawactive();                     /* redraw */
 2343                     redrawinactive();
 2344                 }
 2345                 break;
 2346 
 2347             default:                            /* nothing else relevant here */
 2348                 break;
 2349             }
 2350             break;
 2351         default:
 2352             mode = 0;                           /* shouldn't happen... */
 2353         }
 2354 
 2355         /* handle returns that are the same for both modes */
 2356         switch (ret) {
 2357         case KEY_HELP:
 2358             helpscreen();
 2359             break;
 2360             
 2361         case KEY_EXIT:
 2362             i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
 2363             switch(i)
 2364             {
 2365             case 2:                             /* cancel */
 2366                 redraw();
 2367                 break;
 2368                 
 2369             case 1:                             /* save and exit */
 2370                 savelist(active,1);
 2371                 savelist(inactive,0);
 2372 
 2373             case 0:                             /* exit */
 2374                 nukelist(active);               /* clean up after ourselves */
 2375                 nukelist(inactive);
 2376                 normal();
 2377                 clear();
 2378                 return(1);
 2379             }
 2380             break;
 2381         }
 2382     }
 2383 }
 2384 #endif /* VISUAL_USERCONFIG */
 2385 
 2386 /*
 2387  * Copyright (c) 1991 Regents of the University of California.
 2388  * All rights reserved.
 2389  * Copyright (c) 1994 Jordan K. Hubbard
 2390  * All rights reserved.
 2391  * Copyright (c) 1994 David Greenman
 2392  * All rights reserved.
 2393  *
 2394  * Many additional changes by Bruce Evans
 2395  *
 2396  * This code is derived from software contributed by the
 2397  * University of California Berkeley, Jordan K. Hubbard,
 2398  * David Greenman and Bruce Evans.
 2399  *
 2400  * Redistribution and use in source and binary forms, with or without
 2401  * modification, are permitted provided that the following conditions
 2402  * are met:
 2403  * 1. Redistributions of source code must retain the above copyright
 2404  *    notice, this list of conditions and the following disclaimer.
 2405  * 2. Redistributions in binary form must reproduce the above copyright
 2406  *    notice, this list of conditions and the following disclaimer in the
 2407  *    documentation and/or other materials provided with the distribution.
 2408  * 3. All advertising materials mentioning features or use of this software
 2409  *    must display the following acknowledgement:
 2410  *      This product includes software developed by the University of
 2411  *      California, Berkeley and its contributors.
 2412  * 4. Neither the name of the University nor the names of its contributors
 2413  *    may be used to endorse or promote products derived from this software
 2414  *    without specific prior written permission.
 2415  *
 2416  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 2417  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 2418  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 2419  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 2420  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 2421  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 2422  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 2423  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 2424  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 2425  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 2426  * SUCH DAMAGE.
 2427  *
 2428  * $FreeBSD$
 2429  */
 2430 
 2431 #include "scbus.h"
 2432 
 2433 #define PARM_DEVSPEC    0x1
 2434 #define PARM_INT        0x2
 2435 #define PARM_ADDR       0x3
 2436 #define PARM_STRING     0x4
 2437 
 2438 typedef struct _cmdparm {
 2439     int type;
 2440     union {
 2441         struct uc_device *dparm;
 2442         int iparm;
 2443         union {
 2444                 void *aparm;
 2445                 const char *sparm;
 2446         } u;
 2447     } parm;
 2448 } CmdParm;
 2449 
 2450 typedef int (*CmdFunc)(CmdParm *);
 2451 
 2452 typedef struct _cmd {
 2453     char *name;
 2454     CmdFunc handler;
 2455     CmdParm *parms;
 2456 } Cmd;
 2457 
 2458 
 2459 #if 0
 2460 static void lsscsi(void);
 2461 static int list_scsi(CmdParm *);
 2462 #endif
 2463 
 2464 static int lsdevtab(struct uc_device *);
 2465 static struct uc_device *find_device(char *, int);
 2466 static struct uc_device *search_devtable(struct uc_device *, char *, int);
 2467 static void cngets(char *, int);
 2468 static Cmd *parse_cmd(char *);
 2469 static int parse_args(const char *, CmdParm *);
 2470 static int save_dev(struct uc_device *);
 2471 
 2472 static int list_devices(CmdParm *);
 2473 static int set_device_ioaddr(CmdParm *);
 2474 static int set_device_irq(CmdParm *);
 2475 static int set_device_drq(CmdParm *);
 2476 static int set_device_iosize(CmdParm *);
 2477 static int set_device_mem(CmdParm *);
 2478 static int set_device_flags(CmdParm *);
 2479 static int set_device_enable(CmdParm *);
 2480 static int set_device_disable(CmdParm *);
 2481 static int quitfunc(CmdParm *);
 2482 static int helpfunc(CmdParm *);
 2483 static int introfunc(CmdParm *);
 2484 
 2485 #if NPNP > 0
 2486 static int lspnp(void);
 2487 static int set_pnp_parms(CmdParm *);
 2488 #endif
 2489 
 2490 static int lineno;
 2491 
 2492 #include "eisa.h"
 2493 
 2494 #if NEISA > 0
 2495 
 2496 #include <dev/eisa/eisaconf.h>
 2497 
 2498 static int set_num_eisa_slots(CmdParm *);
 2499 
 2500 #endif /* NEISA > 0 */
 2501 
 2502 static CmdParm addr_parms[] = {
 2503     { PARM_DEVSPEC, {} },
 2504     { PARM_ADDR, {} },
 2505     { -1, {} },
 2506 };
 2507 
 2508 static CmdParm int_parms[] = {
 2509     { PARM_DEVSPEC, {} },
 2510     { PARM_INT, {} },
 2511     { -1, {} },
 2512 };
 2513 
 2514 static CmdParm dev_parms[] = {
 2515     { PARM_DEVSPEC, {} },
 2516     { -1, {} },
 2517 };
 2518 
 2519 #if NPNP > 0
 2520 static CmdParm string_arg[] = {
 2521     { PARM_STRING, {} },
 2522     { -1, {} },
 2523 };
 2524 #endif
 2525 
 2526 #if NEISA > 0
 2527 static CmdParm int_arg[] = {
 2528     { PARM_INT, {} },
 2529     { -1, {} },
 2530 };
 2531 #endif /* NEISA > 0 */
 2532 
 2533 static Cmd CmdList[] = {
 2534     { "?",      helpfunc,               NULL },         /* ? (help)     */
 2535     { "di",     set_device_disable,     dev_parms },    /* disable dev  */
 2536     { "dr",     set_device_drq,         int_parms },    /* drq dev #    */
 2537 #if NEISA > 0
 2538     { "ei",     set_num_eisa_slots,     int_arg },      /* # EISA slots */
 2539 #endif /* NEISA > 0 */
 2540     { "en",     set_device_enable,      dev_parms },    /* enable dev   */
 2541     { "ex",     quitfunc,               NULL },         /* exit (quit)  */
 2542     { "f",      set_device_flags,       int_parms },    /* flags dev mask */
 2543     { "h",      helpfunc,               NULL },         /* help         */
 2544     { "intro",  introfunc,              NULL },         /* intro screen */
 2545     { "iom",    set_device_mem,         addr_parms },   /* iomem dev addr */
 2546     { "ios",    set_device_iosize,      int_parms },    /* iosize dev size */
 2547     { "ir",     set_device_irq,         int_parms },    /* irq dev #    */
 2548     { "l",      list_devices,           NULL },         /* ls, list     */
 2549 #if NPNP > 0
 2550     { "pn",     set_pnp_parms,          string_arg },   /* pnp ... */
 2551 #endif
 2552     { "po",     set_device_ioaddr,      int_parms },    /* port dev addr */
 2553     { "res",    (CmdFunc)cpu_reset,     NULL },         /* reset CPU    */
 2554     { "q",      quitfunc,               NULL },         /* quit         */
 2555 #if 0
 2556     { "s",      list_scsi,              NULL },         /* scsi */
 2557 #endif
 2558 #ifdef VISUAL_USERCONFIG
 2559     { "v",      (CmdFunc)visuserconfig, NULL },         /* visual mode */
 2560 #endif
 2561     { NULL,     NULL,                   NULL },
 2562 };
 2563 
 2564 void
 2565 userconfig(void)
 2566 {
 2567     static char banner = 1;
 2568     char input[80];
 2569     int rval;
 2570     Cmd *cmd;
 2571 
 2572     load_devtab();
 2573     init_config_script();
 2574     while (1) {
 2575 
 2576         /* Only display signon banner if we are about to go interactive */
 2577         if (!has_config_script()) {
 2578             if (!(boothowto & RB_CONFIG))
 2579 #ifdef INTRO_USERCONFIG
 2580                 banner = 0;
 2581 #else
 2582                 return;
 2583 #endif
 2584             if (banner) {
 2585                 banner = 0;
 2586                 printf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
 2587                        " Type \"help\" for help" 
 2588 #ifdef VISUAL_USERCONFIG
 2589                        " or \"visual\" to go to the visual\n"
 2590                        " configuration interface (requires MGA/VGA display or\n"
 2591                        " serial terminal capable of displaying ANSI graphics)"
 2592 #endif
 2593                        ".\n");
 2594             }
 2595         }
 2596 
 2597         printf("config> ");
 2598         cngets(input, 80);
 2599         if (input[0] == '\0')
 2600             continue;
 2601         cmd = parse_cmd(input);
 2602         if (!cmd) {
 2603             printf("Invalid command or syntax.  Type `?' for help.\n");
 2604             continue;
 2605         }
 2606         rval = (*cmd->handler)(cmd->parms);
 2607         if (rval) {
 2608             free_devtab();
 2609             return;
 2610         }
 2611     }
 2612 }
 2613 
 2614 static Cmd *
 2615 parse_cmd(char *cmd)
 2616 {
 2617     Cmd *cp;
 2618 
 2619     for (cp = CmdList; cp->name; cp++) {
 2620         int len = strlen(cp->name);
 2621 
 2622         if (!strncmp(cp->name, cmd, len)) {
 2623             while (*cmd && *cmd != ' ' && *cmd != '\t')
 2624                 ++cmd;
 2625             if (parse_args(cmd, cp->parms))
 2626                 return NULL;
 2627             else
 2628                 return cp;
 2629         }
 2630     }
 2631     return NULL;
 2632 }
 2633 
 2634 static int
 2635 parse_args(const char *cmd, CmdParm *parms)
 2636 {
 2637     while (1) {
 2638         char *ptr;
 2639 
 2640         if (*cmd == ' ' || *cmd == '\t') {
 2641             ++cmd;
 2642             continue;
 2643         }
 2644         if (parms == NULL || parms->type == -1) {
 2645                 if (*cmd == '\0')
 2646                         return 0;
 2647                 printf("Extra arg(s): %s\n", cmd);
 2648                 return 1;
 2649         }
 2650         if (parms->type == PARM_DEVSPEC) {
 2651             int i = 0;
 2652             char devname[64];
 2653             int unit = 0;
 2654 
 2655             while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
 2656               (*cmd >= '' && *cmd <= '9')))
 2657                 devname[i++] = *(cmd++);
 2658             devname[i] = '\0';
 2659             if (*cmd >= '' && *cmd <= '9') {
 2660                 unit = strtoul(cmd, &ptr, 10);
 2661                 if (cmd == ptr) {
 2662                     printf("Invalid device number\n");
 2663                     /* XXX should print invalid token here and elsewhere. */
 2664                     return 1;
 2665                 }
 2666                 /* XXX else should require end of token. */
 2667                 cmd = ptr;
 2668             }
 2669             if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
 2670                 printf("No such device: %s%d\n", devname, unit);
 2671                 return 1;
 2672             }
 2673             ++parms;
 2674             continue;
 2675         }
 2676         if (parms->type == PARM_INT) {
 2677             parms->parm.iparm = strtoul(cmd, &ptr, 0);
 2678             if (cmd == ptr) {
 2679                 printf("Invalid numeric argument\n");
 2680                 return 1;
 2681             }
 2682             cmd = ptr;
 2683             ++parms;
 2684             continue;
 2685         }
 2686         if (parms->type == PARM_ADDR) {
 2687             parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
 2688             if (cmd == ptr) {
 2689                 printf("Invalid address argument\n");
 2690                 return 1;
 2691             }
 2692             cmd = ptr;
 2693             ++parms;
 2694             continue;
 2695         }
 2696         if (parms->type == PARM_STRING) {
 2697             parms->parm.u.sparm = cmd;
 2698             return 0;
 2699         }
 2700     }
 2701     return 0;
 2702 }
 2703 
 2704 static int
 2705 list_devices(CmdParm *parms)
 2706 {
 2707     lineno = 0;
 2708     if (lsdevtab(uc_devtab)) return 0;
 2709 #if NPNP > 0
 2710     if (lspnp()) return 0;
 2711 #endif
 2712 #if NEISA > 0
 2713     printf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
 2714 #endif /* NEISA > 0 */
 2715     return 0;
 2716 }
 2717 
 2718 static int
 2719 set_device_ioaddr(CmdParm *parms)
 2720 {
 2721     parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
 2722     save_dev(parms[0].parm.dparm);
 2723     return 0;
 2724 }
 2725 
 2726 static int
 2727 set_device_irq(CmdParm *parms)
 2728 {
 2729     unsigned irq;
 2730 
 2731     irq = parms[1].parm.iparm;
 2732     if (irq == 2) {
 2733         printf("Warning: Remapping IRQ 2 to IRQ 9\n");
 2734         irq = 9;
 2735     }
 2736     else if (irq != -1 && irq > 15) {
 2737         printf("An IRQ > 15 would be invalid.\n");
 2738         return 0;
 2739     }
 2740     parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
 2741     save_dev(parms[0].parm.dparm);
 2742     return 0;
 2743 }
 2744 
 2745 static int
 2746 set_device_drq(CmdParm *parms)
 2747 {
 2748     unsigned drq;
 2749 
 2750     /*
 2751      * The bounds checking is just to ensure that the value can be printed
 2752      * in 5 characters.  32768 gets converted to -32768 and doesn't fit.
 2753      */
 2754     drq = parms[1].parm.iparm;
 2755     parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
 2756     save_dev(parms[0].parm.dparm);
 2757     return 0;
 2758 }
 2759 
 2760 static int
 2761 set_device_iosize(CmdParm *parms)
 2762 {
 2763     parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
 2764     save_dev(parms[0].parm.dparm);
 2765     return 0;
 2766 }
 2767 
 2768 static int
 2769 set_device_mem(CmdParm *parms)
 2770 {
 2771     parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
 2772     save_dev(parms[0].parm.dparm);
 2773     return 0;
 2774 }
 2775 
 2776 static int
 2777 set_device_flags(CmdParm *parms)
 2778 {
 2779     parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
 2780     save_dev(parms[0].parm.dparm);
 2781     return 0;
 2782 }
 2783 
 2784 static int
 2785 set_device_enable(CmdParm *parms)
 2786 {
 2787     parms[0].parm.dparm->id_enabled = TRUE;
 2788     save_dev(parms[0].parm.dparm);
 2789     return 0;
 2790 }
 2791 
 2792 static int
 2793 set_device_disable(CmdParm *parms)
 2794 {
 2795     parms[0].parm.dparm->id_enabled = FALSE;
 2796     save_dev(parms[0].parm.dparm);
 2797     return 0;
 2798 }
 2799 
 2800 #if NPNP > 0
 2801 
 2802 static int
 2803 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
 2804 {
 2805         int error=0;
 2806 
 2807         if(!req->oldptr) {
 2808                 /* Only sizing */
 2809                 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
 2810         } else {
 2811                 /*
 2812                  * Output the pnp_ldn_overrides[] table.
 2813                  */
 2814                 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
 2815                         sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
 2816                 if(error) return(error);
 2817                 return(0);
 2818         }
 2819 }
 2820 
 2821 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
 2822         0, 0, sysctl_machdep_uc_pnplist, "A",
 2823         "List of PnP overrides changed in UserConfig");
 2824 
 2825 /*
 2826  * this function sets the kernel table to override bios PnP
 2827  * configuration.
 2828  */
 2829 static int      
 2830 set_pnp_parms(CmdParm *parms)      
 2831 {   
 2832     u_long idx, val, ldn, csn;
 2833     int i;
 2834     char *q;
 2835     const char *p = parms[0].parm.u.sparm;
 2836     struct pnp_cinfo d;
 2837 
 2838     csn=strtoul(p,&q, 0);
 2839     ldn=strtoul(q,&q, 0);
 2840     for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
 2841     if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
 2842         printf("bad csn/ldn %ld:%ld\n", csn, ldn);
 2843         return 0;
 2844     }
 2845     for (i=0; i < MAX_PNP_LDN; i++) {
 2846         if (pnp_ldn_overrides[i].csn == csn &&
 2847             pnp_ldn_overrides[i].ldn == ldn)
 2848                 break;
 2849     }
 2850     if (i==MAX_PNP_LDN) {
 2851         for (i=0; i < MAX_PNP_LDN; i++) {
 2852             if (pnp_ldn_overrides[i].csn <1 ||
 2853                  pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
 2854                  break;
 2855         }
 2856     }
 2857     if (i==MAX_PNP_LDN) {
 2858         printf("sorry, no PnP entries available, try delete one\n");
 2859         return 0 ;
 2860     }
 2861     d = pnp_ldn_overrides[i] ;
 2862     d.csn = csn;
 2863     d.ldn = ldn ;
 2864     while (*p) {
 2865         idx = 0;
 2866         val = 0;
 2867         if (!strncmp(p,"irq",3)) {
 2868             idx=strtoul(p+3,&q, 0);
 2869             val=strtoul(q,&q, 0);
 2870             if (idx >=0 && idx < 2) d.irq[idx] = val;
 2871         } else if (!strncmp(p,"flags",5)) {
 2872             idx=strtoul(p+5,&q, 0);
 2873             d.flags = idx;
 2874         } else if (!strncmp(p,"drq",3)) {
 2875             idx=strtoul(p+3,&q, 0);
 2876             val=strtoul(q,&q, 0);
 2877             if (idx >=0 && idx < 2) d.drq[idx] = val;
 2878         } else if (!strncmp(p,"port",4)) {
 2879             idx=strtoul(p+4,&q, 0);
 2880             val=strtoul(q,&q, 0);
 2881             if (idx >=0 && idx < 8) d.port[idx] = val;
 2882         } else if (!strncmp(p,"mem",3)) {
 2883             idx=strtoul(p+3,&q, 0);
 2884             val=strtoul(q,&q, 0);
 2885             if (idx >=0 && idx < 4) d.mem[idx].base = val;
 2886         } else if (!strncmp(p,"bios",4)) {
 2887             q = p+ 4;
 2888             d.override = 0 ;
 2889         } else if (!strncmp(p,"os",2)) {
 2890             q = p+2 ;
 2891             d.override = 1 ;
 2892         } else if (!strncmp(p,"disable",7)) {
 2893             q = p+7 ;
 2894             d.enable = 0 ;
 2895         } else if (!strncmp(p,"enable",6)) {
 2896             q = p+6;
 2897             d.enable = 1 ;
 2898         } else if (!strncmp(p,"delete",6)) {
 2899             bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
 2900             if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
 2901             return 0;
 2902         } else {
 2903             printf("unknown command <%s>\n", p);
 2904             break;
 2905         }
 2906         for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
 2907     }
 2908     pnp_ldn_overrides[i] = d ;
 2909     return 0; 
 2910 }
 2911 #endif /* NPNP */
 2912 
 2913 #if NEISA > 0
 2914 static int
 2915 set_num_eisa_slots(CmdParm *parms)
 2916 {
 2917     int num_slots;
 2918 
 2919     num_slots = parms[0].parm.iparm;
 2920     num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
 2921     return 0;
 2922 }
 2923 #endif /* NEISA > 0 */
 2924 
 2925 static int
 2926 quitfunc(CmdParm *parms)
 2927 {
 2928     /*
 2929      * If kernel config supplied, and we are parsing it, and -c also supplied,
 2930      * ignore a quit command,  This provides a safety mechanism to allow
 2931      * recovery from a damaged/buggy kernel config.
 2932      */
 2933     if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
 2934         return 0;
 2935     return 1;
 2936 }
 2937 
 2938 static int
 2939 helpfunc(CmdParm *parms)
 2940 {
 2941     printf(
 2942     "Command\t\t\tDescription\n"
 2943     "-------\t\t\t-----------\n"
 2944     "ls\t\t\tList currently configured devices\n"
 2945     "port <devname> <addr>\tSet device port (i/o address)\n"
 2946     "irq <devname> <number>\tSet device irq\n"
 2947     "drq <devname> <number>\tSet device drq\n"
 2948     "iomem <devname> <addr>\tSet device maddr (memory address)\n"
 2949     "iosize <devname> <size>\tSet device memory size\n"
 2950     "flags <devname> <mask>\tSet device flags\n"
 2951     "enable <devname>\tEnable device\n"
 2952     "disable <devname>\tDisable device (will not be probed)\n");
 2953 #if NPNP > 0
 2954     printf(
 2955     "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
 2956     "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
 2957     "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
 2958     "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
 2959     "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
 2960     "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
 2961 #endif
 2962 #if NEISA > 0
 2963     printf("eisa <number>\t\tSet the number of EISA slots to probe\n");
 2964 #endif /* NEISA > 0 */
 2965     printf(
 2966     "quit\t\t\tExit this configuration utility\n"
 2967     "reset\t\t\tReset CPU\n");
 2968 #ifdef VISUAL_USERCONFIG
 2969     printf("visual\t\t\tGo to fullscreen mode.\n");
 2970 #endif
 2971     printf(
 2972     "help\t\t\tThis message\n\n"
 2973     "Commands may be abbreviated to a unique prefix\n");
 2974     return 0;
 2975 }
 2976 
 2977 #if defined (VISUAL_USERCONFIG)
 2978 static void
 2979 center(int y, char *str)
 2980 {
 2981     putxy((80 - strlen(str)) / 2, y, str);
 2982 }
 2983 #endif
 2984 
 2985 static int
 2986 introfunc(CmdParm *parms)
 2987 {
 2988 #if defined (VISUAL_USERCONFIG)
 2989     int curr_item, first_time, extended = 0;
 2990     static char *choices[] = {
 2991         " Skip kernel configuration and continue with installation ",
 2992         " Start kernel configuration in full-screen visual mode    ",
 2993         " Start kernel configuration in CLI mode                   ",
 2994     };
 2995 
 2996     clear();
 2997     center(2, "!bKernel Configuration Menu!n");
 2998 
 2999     curr_item = 0;
 3000     first_time = 1;
 3001     while (1) {
 3002         char tmp[80];
 3003         int c, i;
 3004 
 3005         if (!extended) { 
 3006             for (i = 0; i < 3; i++) {
 3007                 tmp[0] = '\0';
 3008                 if (curr_item == i)
 3009                     strcpy(tmp, "!i");
 3010                 strcat(tmp, choices[i]);
 3011                 if (curr_item == i)
 3012                     strcat(tmp, "!n");
 3013                 putxy(10, 5 + i, tmp);
 3014             }
 3015 
 3016             if (first_time) {
 3017                 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
 3018                 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
 3019                 putxy(2, 12, "match your hardware configuration.");
 3020                 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
 3021                 putxy(2, 15, "(press Down-Arrow then ENTER).");
 3022                 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
 3023                 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
 3024                 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
 3025                 putxy(2, 21, "then simply press ENTER or Q now.");
 3026                 first_time = 0;
 3027             }
 3028             
 3029             move(0, 0); /* move the cursor out of the way */
 3030         }
 3031         c = getchar();
 3032         if ((extended == 2) || (c == 588) || (c == 596)) {      /* console gives "alternative" codes */
 3033             extended = 0;               /* no longer */
 3034             switch (c) {
 3035             case 588:
 3036             case 'A':                           /* up */
 3037                 if (curr_item > 0)
 3038                     --curr_item;
 3039                 break;
 3040 
 3041             case 596:
 3042             case 'B':                           /* down */
 3043                 if (curr_item < 2)
 3044                     ++curr_item;
 3045                 break;
 3046             }
 3047         }
 3048         else {
 3049             switch(c) {
 3050             case '\033':
 3051                 extended = 1;
 3052                 break;
 3053                     
 3054             case '[':                           /* cheat : always preceeds cursor move */
 3055             case 'O':                           /* ANSI application key mode */
 3056                 if (extended == 1)
 3057                     extended = 2;
 3058                 else
 3059                     extended = 0;
 3060                 break;
 3061                 
 3062             case -1:
 3063             case 'Q':
 3064             case 'q':
 3065                 clear();
 3066                 return 1;       /* user requests exit */
 3067 
 3068             case '1':                           /* select an item */
 3069             case 'S':
 3070             case 's':
 3071                 curr_item = 0;
 3072                 break;
 3073             case '2':
 3074             case 'V':
 3075             case 'v':
 3076                 curr_item = 1;
 3077                 break;
 3078             case '3':
 3079             case 'C':
 3080             case 'c':
 3081                 curr_item = 2;
 3082                 break;
 3083 
 3084             case 'U':                           /* up */
 3085             case 'u':
 3086             case 'P':
 3087             case 'p':
 3088                 if (curr_item > 0)
 3089                     --curr_item;
 3090                 break;
 3091 
 3092             case 'D':                           /* down */
 3093             case 'd':
 3094             case 'N':
 3095             case 'n':
 3096                 if (curr_item < 2)
 3097                     ++curr_item;
 3098                 break;
 3099 
 3100             case '\r':                          
 3101             case '\n':
 3102                 clear();
 3103                 if (!curr_item)
 3104                     return 1;
 3105                 else if (curr_item == 1)
 3106                     return visuserconfig();
 3107                 else {
 3108                     putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
 3109                     /* enable quitfunc */
 3110                     userconfig_boot_parsing=0;
 3111                     move (0, 3);
 3112                     boothowto |= RB_CONFIG;     /* force -c */
 3113                     return 0;
 3114                 }
 3115                 break;
 3116             }
 3117         }
 3118     }
 3119 #endif
 3120 }
 3121 
 3122 #if NPNP > 0
 3123 static int
 3124 lspnp ()
 3125 {
 3126     struct pnp_cinfo *c;
 3127     int i, first = 1;
 3128 
 3129 
 3130     for (i=0; i< MAX_PNP_LDN; i++) {
 3131         c = &pnp_ldn_overrides[i];
 3132         if (c->csn >0 && c->csn != 255) {
 3133             int pmax, mmax;
 3134             static char pfmt[] =
 3135                 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
 3136             static char mfmt[] =
 3137                 "mem 0x%x 0x%x 0x%x 0x%x";
 3138             char buf[256];
 3139             if (lineno >= 23) {
 3140                     if (!userconfig_boot_parsing) {
 3141                             printf("<More> ");
 3142                             if (getchar() == 'q') {
 3143                                     printf("quit\n");
 3144                                     return (1);
 3145                             }
 3146                             printf("\n");
 3147                     }
 3148                     lineno = 0;
 3149             }
 3150             if (lineno == 0 || first)
 3151                 printf("CSN LDN conf en irqs  drqs others (PnP devices)\n");
 3152             first = 0 ;
 3153             printf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
 3154                 c->csn, c->ldn,
 3155                 c->override ? "OS  ":"BIOS",
 3156                 c->enable ? "Y":"N",
 3157                 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
 3158             if (c->flags)
 3159                 printf("flags 0x%08lx ",c->flags);
 3160             for (pmax = 7; pmax >=0 ; pmax--)
 3161                 if (c->port[pmax]!=0) break;
 3162             for (mmax = 3; mmax >=0 ; mmax--)
 3163                 if (c->mem[mmax].base!=0) break;
 3164             if (pmax>=0) {
 3165                 strcpy(buf, pfmt);
 3166                 buf[10 + 5*pmax]='\0';
 3167                 printf(buf,
 3168                     c->port[0], c->port[1], c->port[2], c->port[3],
 3169                     c->port[4], c->port[5], c->port[6], c->port[7]);
 3170             }
 3171             if (mmax>=0) {
 3172                 strcpy(buf, mfmt);
 3173                 buf[8 + 5*mmax]='\0';
 3174                 printf(buf,
 3175                     c->mem[0].base, c->mem[1].base,
 3176                     c->mem[2].base, c->mem[3].base);
 3177             }
 3178             printf("\n");
 3179         }
 3180     }
 3181     return 0 ;
 3182 }
 3183 #endif /* NPNP */
 3184                 
 3185 static int
 3186 lsdevtab(struct uc_device *dt)
 3187 {
 3188     for (; dt->id_id != 0; dt++) {
 3189         char dname[80];
 3190 
 3191         if (lineno >= 23) {
 3192                 printf("<More> ");
 3193                 if (!userconfig_boot_parsing) {
 3194                         if (getchar() == 'q') {
 3195                                 printf("quit\n");
 3196                                 return (1);
 3197                         }
 3198                         printf("\n");
 3199                 }
 3200                 lineno = 0;
 3201         }
 3202         if (lineno == 0) {
 3203                 printf(
 3204 "Device   port       irq   drq   iomem   iosize   unit  flags      enab\n"
 3205                     );
 3206                 ++lineno;
 3207         }
 3208         sprintf(dname, "%s%d", dt->id_name, dt->id_unit);
 3209         printf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
 3210             dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
 3211             ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
 3212             /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
 3213             dt->id_enabled ? "Yes" : "No");
 3214         ++lineno;
 3215     }
 3216     return(0);
 3217 }
 3218 
 3219 static void
 3220 load_devtab(void)
 3221 {
 3222     int i, val;
 3223     int count = resource_count();
 3224     int id = 1;
 3225     int dt;
 3226     char *name;
 3227     int unit;
 3228 
 3229     uc_devtab = malloc(sizeof(struct uc_device)*(count + 1),M_DEVL,M_WAITOK);
 3230     bzero(uc_devtab, sizeof(struct uc_device) * (count + 1));
 3231     dt = 0;
 3232     for (i = 0; i < count; i++) {
 3233         name = resource_query_name(i);
 3234         unit = resource_query_unit(i);
 3235         if (unit < 0)
 3236             continue;   /* skip wildcards */
 3237         uc_devtab[dt].id_id = id++;
 3238         resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
 3239         val = 0;
 3240         resource_int_value(name, unit, "irq", &val);
 3241         uc_devtab[dt].id_irq = (1 << val);
 3242         resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
 3243         resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
 3244         resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
 3245         uc_devtab[dt].id_unit = unit;
 3246         resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
 3247         val = 0;
 3248         resource_int_value(name, unit, "disabled", &val);
 3249         uc_devtab[dt].id_enabled = !val;
 3250         uc_devtab[dt].id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
 3251         strcpy(uc_devtab[dt].id_name, name);
 3252         dt++;
 3253     }
 3254 }
 3255 
 3256 static void
 3257 free_devtab(void)
 3258 {
 3259     int i;
 3260     int count = resource_count();
 3261 
 3262     for (i = 0; i < count; i++)
 3263         if (uc_devtab[i].id_name)
 3264             free(uc_devtab[i].id_name, M_DEVL);
 3265     free(uc_devtab, M_DEVL);
 3266 }
 3267     
 3268 static struct uc_device *
 3269 find_device(char *devname, int unit)
 3270 {
 3271     struct uc_device *ret;
 3272 
 3273     if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
 3274         return ret;
 3275     return NULL;
 3276 }
 3277 
 3278 static struct uc_device *
 3279 search_devtable(struct uc_device *dt, char *devname, int unit)
 3280 {
 3281     int i;
 3282 
 3283     for (i = 0; dt->id_id != 0; dt++)
 3284         if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
 3285             return dt;
 3286     return NULL;
 3287 }
 3288 
 3289 static void
 3290 cngets(char *input, int maxin)
 3291 {
 3292     int c, nchars = 0;
 3293 
 3294     while (1) {
 3295         c = getchar();
 3296         /* Treat ^H or ^? as backspace */
 3297         if ((c == '\010' || c == '\177')) {
 3298                 if (nchars) {
 3299                         printf("\010 \010");
 3300                         *--input = '\0', --nchars;
 3301                 }
 3302                 continue;
 3303         }
 3304         /* Treat ^U or ^X as kill line */
 3305         else if ((c == '\025' || c == '\030')) {
 3306                 while (nchars) {
 3307                         printf("\010 \010");
 3308                         *--input = '\0', --nchars;
 3309                 }
 3310                 continue;
 3311         }
 3312         printf("%c", c);
 3313         if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
 3314             *input = '\0';
 3315             break;
 3316         }
 3317         *input++ = (u_char)c;
 3318     }
 3319 }
 3320 
 3321 
 3322 #if 0
 3323 /* scsi: Support for displaying configured SCSI devices.
 3324  * There is no way to edit them, and this is inconsistent
 3325  * with the ISA method.  This is here as a basis for further work.
 3326  */
 3327 static char *
 3328 type_text(char *name)   /* XXX: This is bogus */
 3329 {
 3330         if (strcmp(name, "sd") == 0)
 3331                 return "disk";
 3332 
 3333         if (strcmp(name, "st") == 0)
 3334                 return "tape";
 3335 
 3336         return "device";
 3337 }
 3338 
 3339 id_put(char *desc, int id)
 3340 {
 3341     if (id != SCCONF_UNSPEC)
 3342     {
 3343         if (desc)
 3344             printf("%s", desc);
 3345 
 3346         if (id == SCCONF_ANY)
 3347             printf("?");
 3348         else
 3349             printf("%d", id);
 3350     }
 3351 }
 3352 
 3353 static void
 3354 lsscsi(void)
 3355 {
 3356     int i;
 3357 
 3358     printf("scsi: (can't be edited):\n");
 3359 
 3360     for (i = 0; scsi_cinit[i].driver; i++)
 3361     {
 3362         id_put("controller scbus", scsi_cinit[i].scbus);
 3363 
 3364         if (scsi_cinit[i].unit != -1)
 3365         {
 3366             printf(" at ");
 3367             id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
 3368         }
 3369 
 3370         printf("\n");
 3371     }
 3372 
 3373     for (i = 0; scsi_dinit[i].name; i++)
 3374     {
 3375                 printf("%s ", type_text(scsi_dinit[i].name));
 3376 
 3377                 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
 3378                 id_put(" at scbus", scsi_dinit[i].cunit);
 3379                 id_put(" target ", scsi_dinit[i].target);
 3380                 id_put(" lun ", scsi_dinit[i].lun);
 3381 
 3382                 if (scsi_dinit[i].flags)
 3383                 printf(" flags 0x%x\n", scsi_dinit[i].flags);
 3384 
 3385                 printf("\n");
 3386     }
 3387 }
 3388 
 3389 static int
 3390 list_scsi(CmdParm *parms)
 3391 {
 3392     lineno = 0;
 3393     lsscsi();
 3394     return 0;
 3395 }
 3396 #endif
 3397 
 3398 static void
 3399 save_resource(struct uc_device *idev)
 3400 {
 3401     char *name;
 3402     int unit;
 3403 
 3404     name = idev->id_name;
 3405     unit = idev->id_unit;
 3406     resource_set_int(name, unit, "port", idev->id_iobase);
 3407     resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
 3408     resource_set_int(name, unit, "drq", idev->id_drq);
 3409     resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
 3410     resource_set_int(name, unit, "msize", idev->id_msize);
 3411     resource_set_int(name, unit, "flags", idev->id_flags);
 3412     resource_set_int(name, unit, "disabled", !idev->id_enabled);
 3413 }
 3414 
 3415 static int
 3416 save_dev(idev)
 3417 struct uc_device        *idev;
 3418 {
 3419         struct uc_device        *id_p,*id_pn;
 3420         char *name = idev->id_name;
 3421 
 3422         for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
 3423                 if (id_p->id_id == idev->id_id) {
 3424                         id_pn = id_p->id_next;
 3425                         if (id_p->id_name)
 3426                                 free(id_p->id_name, M_DEVL);
 3427                         bcopy(idev,id_p,sizeof(struct uc_device));
 3428                         save_resource(idev);
 3429                         id_p->id_name = malloc(strlen(name)+1, M_DEVL,M_WAITOK);
 3430                         strcpy(id_p->id_name, name);
 3431                         id_p->id_next = id_pn;
 3432                         return 1;
 3433                 }
 3434         }
 3435         id_pn = malloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
 3436         bcopy(idev,id_pn,sizeof(struct uc_device));
 3437         save_resource(idev);
 3438         id_pn->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
 3439         strcpy(id_pn->id_name, name);
 3440         id_pn->id_next = uc_devlist;
 3441         uc_devlist = id_pn;
 3442         return 0;
 3443 }
 3444 
 3445 

Cache object: 5fbbd1098dba9b626ebf58f8e6beb86a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.