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


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

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

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

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

Cache object: 7c1a35d305b37beedb6e37e3bbad893e


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