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