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

Cache object: 29ce8318cdd23ca78ccd7d603a7b15f4


[ 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.