added -y/--side-by-side option
[dfdiff.git] / sys / platform / pc32 / i386 / userconfig.c
blob64eb0ab1e3a7868ed4533dd9c585a041f577a3e7
1 /**
2 ** Copyright (c) 1995
3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
4 **
5 ** This code contains a module marked :
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.
14 * Many additional changes by Bruce Evans
16 * This code is derived from software contributed by the
17 * University of California Berkeley, Jordan K. Hubbard,
18 * David Greenman and Bruce Evans.
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.
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.
49 ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
50 ** $DragonFly: src/sys/platform/pc32/i386/userconfig.c,v 1.15 2008/01/05 14:02:41 swildner Exp $
51 **/
53 /**
54 ** USERCONFIG
56 ** Kernel boot-time configuration manipulation tool for FreeBSD.
58 ** Two modes of operation are supported : the default is the line-editor mode,
59 ** the command "visual" invokes the fullscreen mode.
61 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
62 ** fullscreen mode requires syscons or a minimal-ansi serial console.
63 **/
65 /**
66 ** USERCONFIG, visual mode.
68 ** msmith@freebsd.org
70 ** Look for "EDIT THIS LIST" to add to the list of known devices
71 **
73 ** There are a number of assumptions made in this code.
74 **
75 ** - That the console supports a minimal set of ANSI escape sequences
76 ** (See the screen manipulation section for a summary)
77 ** and has at least 24 rows.
78 ** - That values less than or equal to zero for any of the device
79 ** parameters indicate that the driver does not use the parameter.
80 ** - That flags are _always_ editable.
82 ** Devices marked as disabled are imported as such.
84 ** For this tool to be useful, the list of devices below _MUST_ be updated
85 ** when a new driver is brought into the kernel. It is not possible to
86 ** extract this information from the drivers in the kernel.
88 ** XXX - TODO:
89 **
90 ** - Display _what_ a device conflicts with.
91 ** - Implement page up/down (as what?)
92 ** - Wizard mode (no restrictions)
93 ** - Find out how to put syscons back into low-intensity mode so that the
94 ** !b escape is useful on the console. (It seems to be that it actually
95 ** gets low/high intensity backwards. That looks OK.)
97 ** - Only display headings with devices under them. (difficult)
98 **/
100 #include "opt_userconfig.h"
101 #define COMPAT_OLDISA /* get the definitions */
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/kernel.h>
106 #include <sys/malloc.h>
107 #include <sys/reboot.h>
108 #include <sys/linker.h>
109 #include <sys/sysctl.h>
110 #include <sys/bus.h>
111 #include <sys/cons.h>
113 #include <machine/md_var.h>
114 #include <machine/limits.h>
116 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
118 #undef NPNP
119 #define NPNP 0
121 #if NPNP > 0
122 #include <machine_base/isa/pnp.h>
123 #endif
125 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
127 #include <machine/uc_device.h>
128 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
129 static struct uc_device *uc_devtab; /* fake uc_device table */
131 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
133 static void load_devtab(void);
134 static void free_devtab(void);
135 static void save_resource(struct uc_device *);
137 static int
138 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
140 struct uc_device *id;
141 int error=0;
142 char name[8];
144 if(!req->oldptr) {
145 /* Only sizing */
146 id=uc_devlist;
147 while(id) {
148 error+=sizeof(struct uc_device)+8;
149 id=id->id_next;
151 return(SYSCTL_OUT(req,0,error));
152 } else {
153 /* Output the data. The buffer is filled with consecutive
154 * struct uc_device and char buf[8], containing the name
155 * (not guaranteed to end with '\0').
157 id=uc_devlist;
158 while(id) {
159 error=sysctl_handle_opaque(oidp,id,
160 sizeof(struct uc_device),req);
161 if(error) return(error);
162 strncpy(name,id->id_name,8);
163 error=sysctl_handle_opaque(oidp,name,
164 8,req);
165 if(error) return(error);
166 id=id->id_next;
168 return(0);
172 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
173 0, 0, sysctl_machdep_uc_devlist, "A",
174 "List of ISA devices changed in UserConfig");
177 ** Obtain command input.
179 ** Initially, input is read from a possibly-loaded script.
180 ** At the end of the script, or if no script is supplied,
181 ** behaviour is determined by the RB_CONFIG (-c) flag. If
182 ** the flag is set, user input is read from the console; if
183 ** unset, the 'quit' command is invoked and userconfig
184 ** will exit.
186 ** Note that quit commands encountered in the script will be
187 ** ignored if the RB_CONFIG flag is supplied.
189 static const char *config_script;
190 static int config_script_size; /* use of int for -ve magic value */
192 #define has_config_script() (config_script_size > 0)
194 static int
195 init_config_script(void)
197 caddr_t autoentry, autoattr;
199 /* Look for loaded userconfig script */
200 autoentry = preload_search_by_type("userconfig_script");
201 if (autoentry != NULL) {
202 /* We have one, get size and data */
203 config_script_size = 0;
204 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
205 config_script_size = (size_t)*(u_int32_t *)autoattr;
206 config_script = NULL;
207 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
208 config_script = *(const char **)autoattr;
209 /* sanity check */
210 if ((config_script_size == 0) || (config_script == NULL)) {
211 config_script_size = 0;
212 config_script = NULL;
215 return has_config_script();
218 static int
219 kgetchar(void)
221 int c = -1;
222 #ifdef INTRO_USERCONFIG
223 static int intro = 0;
224 #endif
226 if (has_config_script())
228 /* Consume character from loaded userconfig script, display */
229 userconfig_boot_parsing = 1;
230 c = *config_script;
231 config_script++;
232 config_script_size--;
234 } else {
236 #ifdef INTRO_USERCONFIG
237 if (userconfig_boot_parsing) {
238 if (!(boothowto & RB_CONFIG)) {
239 /* userconfig_script, !RB_CONFIG -> quit */
240 if (intro == 0) {
241 c = 'q';
242 config_script = "uit\n";
243 config_script_size = strlen(config_script);
244 /* userconfig_script will be 1 on the next pass */
246 } else {
247 /* userconfig_script, RB_CONFIG -> cngetc() */
249 } else {
250 if (!(boothowto & RB_CONFIG)) {
251 /* no userconfig_script, !RB_CONFIG -> show intro */
252 if (intro == 0) {
253 intro = 1;
254 c = 'i';
255 config_script = "ntro\n";
256 config_script_size = strlen(config_script);
257 /* userconfig_script will be 1 on the next pass */
259 } else {
260 /* no userconfig_script, RB_CONFIG -> cngetc() */
263 #else /* !INTRO_USERCONFIG */
264 /* assert(boothowto & RB_CONFIG) */
265 #endif /* INTRO_USERCONFIG */
266 userconfig_boot_parsing = 0;
267 if (c <= 0)
268 c = cngetc();
270 return(c);
273 #ifndef FALSE
274 #define FALSE (0)
275 #define TRUE (!FALSE)
276 #endif
278 #ifdef VISUAL_USERCONFIG
280 typedef struct
282 char dev[16]; /* device basename */
283 char name[60]; /* long name */
284 int attrib; /* things to do with the device */
285 int class; /* device classification */
286 } DEV_INFO;
288 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
289 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
290 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
291 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
292 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
293 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
294 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
295 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
296 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
298 #define CLS_STORAGE 1 /* storage devices */
299 #define CLS_NETWORK 2 /* network interfaces */
300 #define CLS_COMMS 3 /* serial, parallel ports */
301 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
302 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
303 #define CLS_MISC 255 /* none of the above */
306 typedef struct
308 char name[60];
309 int number;
310 } DEVCLASS_INFO;
312 static DEVCLASS_INFO devclass_names[] = {
313 { "Storage : ", CLS_STORAGE},
314 { "Network : ", CLS_NETWORK},
315 { "Communications : ", CLS_COMMS},
316 { "Input : ", CLS_INPUT},
317 { "Multimedia : ", CLS_MMEDIA},
318 { "Miscellaneous : ", CLS_MISC},
319 { "",0}};
322 /********************* EDIT THIS LIST **********************/
324 /** Notes :
326 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
327 ** - XXX The list below should be reviewed by the driver authors to verify
328 ** that the correct flags have been set for each driver, and that the
329 ** descriptions are accurate.
332 static DEV_INFO device_info[] = {
333 /*---Name----- ---Description---------------------------------------------- */
334 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
335 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE},
336 {"aha", "Adaptec 154x SCSI controller", 0, CLS_STORAGE},
337 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE},
338 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
339 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
340 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
341 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
342 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
343 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
344 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE},
345 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
346 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
347 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
349 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
350 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
351 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
352 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
353 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
354 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
355 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
356 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
357 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
358 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
359 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
360 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
361 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
363 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
364 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
365 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
366 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
367 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
368 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
369 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
370 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
371 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
372 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
374 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
375 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
376 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
377 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
378 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
379 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
381 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
382 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
383 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
384 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
385 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
386 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
387 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
388 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
389 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
390 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
391 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
392 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
393 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
394 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
395 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
396 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
397 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
398 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
399 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
400 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
401 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
402 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
404 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
405 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
406 {"pcic", "PC-card controller", 0, CLS_MISC},
407 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
408 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
409 {"","",0,0}};
412 typedef struct _devlist_struct
414 char name[80];
415 int attrib; /* flag values as per the FLG_* defines above */
416 int class; /* disk, etc as per the CLS_* defines above */
417 char dev[16];
418 int iobase,irq,drq,maddr,msize,unit,flags,id;
419 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
420 int conflicts; /* set/reset by findconflict, count of conflicts */
421 int changed; /* nonzero if the device has been edited */
422 struct uc_device *device;
423 struct _devlist_struct *prev,*next;
424 } DEV_LIST;
427 #define DEV_DEVICE 0
428 #define DEV_COMMENT 1
429 #define DEV_ZOOMED 2
431 #define LIST_CURRENT (1<<0)
432 #define LIST_SELECTED (1<<1)
434 #define KEY_EXIT 0 /* return codes from dolist() and friends */
435 #define KEY_DO 1
436 #define KEY_DEL 2
437 #define KEY_TAB 3
438 #define KEY_REDRAW 4
440 #define KEY_UP 5 /* these only returned from editval() */
441 #define KEY_DOWN 6
442 #define KEY_LEFT 7
443 #define KEY_RIGHT 8
444 #define KEY_NULL 9 /* this allows us to spin & redraw */
446 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
447 #define KEY_UNZOOM 11
449 #define KEY_HELP 12 /* duh? */
451 static void redraw(void);
452 static void insdev(DEV_LIST *dev, DEV_LIST *list);
453 static int devinfo(DEV_LIST *dev);
454 static int visuserconfig(void);
456 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
457 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
458 static DEV_LIST scratch; /* scratch record */
459 static int conflicts; /* total conflict count */
462 static char lines[] = "--------------------------------------------------------------------------------";
463 static char spaces[] = " ";
467 ** Device manipulation stuff : find, describe, configure.
471 ** setdev
473 ** Sets the device referenced by (*dev) to the parameters in the struct,
474 ** and the enable flag according to (enabled)
476 static void
477 setdev(DEV_LIST *dev, int enabled)
479 dev->device->id_iobase = dev->iobase; /* copy happy */
480 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
481 dev->device->id_drq = (short)dev->drq;
482 dev->device->id_maddr = (caddr_t)dev->maddr;
483 dev->device->id_msize = dev->msize;
484 dev->device->id_flags = dev->flags;
485 dev->device->id_enabled = enabled;
490 ** getdevs
492 ** Walk the kernel device tables and build the active and inactive lists
494 static void
495 getdevs(void)
497 int i;
498 struct uc_device *ap;
500 ap = uc_devtab; /* pointer to array of devices */
501 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
503 scratch.unit = ap[i].id_unit; /* device parameters */
504 strcpy(scratch.dev,ap[i].id_name);
505 scratch.iobase = ap[i].id_iobase;
506 scratch.irq = ffs(ap[i].id_irq)-1;
507 scratch.drq = ap[i].id_drq;
508 scratch.maddr = (int)ap[i].id_maddr;
509 scratch.msize = ap[i].id_msize;
510 scratch.flags = ap[i].id_flags;
512 scratch.comment = DEV_DEVICE; /* admin stuff */
513 scratch.conflicts = 0;
514 scratch.device = &ap[i]; /* save pointer for later reference */
515 scratch.changed = 0;
516 if (!devinfo(&scratch)) /* get more info on the device */
517 insdev(&scratch,ap[i].id_enabled?active:inactive);
523 ** Devinfo
525 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
526 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
528 ** If the device is marked "invisible", return nonzero; the caller should
529 ** not insert any such device into either list.
532 static int
533 devinfo(DEV_LIST *dev)
535 int i;
537 for (i = 0; device_info[i].class; i++)
539 if (!strcmp(dev->dev,device_info[i].dev))
541 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
542 return(1);
543 strcpy(dev->name,device_info[i].name); /* get the name */
544 dev->attrib = device_info[i].attrib;
545 dev->class = device_info[i].class;
546 return(0);
549 strcpy(dev->name,"Unknown device");
550 dev->attrib = 0;
551 dev->class = CLS_MISC;
552 return(0);
557 ** List manipulation stuff : add, move, initialise, free, traverse
559 ** Note that there are assumptions throughout this code that
560 ** the first entry in a list will never move. (assumed to be
561 ** a comment).
566 ** Adddev
568 ** appends a copy of (dev) to the end of (*list)
570 static void
571 addev(DEV_LIST *dev, DEV_LIST **list)
574 DEV_LIST *lp,*ap;
576 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
577 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
579 if (*list) /* list exists */
581 ap = *list;
582 while(ap->next)
583 ap = ap->next; /* scoot to end of list */
584 lp->prev = ap;
585 lp->next = NULL;
586 ap->next = lp;
587 }else{ /* list does not yet exist */
588 *list = lp;
589 lp->prev = lp->next = NULL; /* list now exists */
595 ** Findspot
597 ** Finds the 'appropriate' place for (dev) in (list)
599 ** 'Appropriate' means in numeric order with other devices of the same type,
600 ** or in alphabetic order following a comment of the appropriate type.
601 ** or at the end of the list if an appropriate comment is not found. (this should
602 ** never happen)
603 ** (Note that the appropriate point is never the top, but may be the bottom)
605 static DEV_LIST *
606 findspot(DEV_LIST *dev, DEV_LIST *list)
608 DEV_LIST *ap = NULL;
610 /* search for a previous instance of the same device */
611 for (ap = list; ap; ap = ap->next)
613 if (ap->comment != DEV_DEVICE) /* ignore comments */
614 continue;
615 if (!strcmp(dev->dev,ap->dev)) /* same base device */
617 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
618 || !ap->next) /* or end of list */
620 ap = ap->prev; /* back up one */
621 break; /* done here */
623 if (ap->next) /* if the next item exists */
625 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
626 break;
627 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
628 break;
633 if (!ap) /* not sure yet */
635 /* search for a class that the device might belong to */
636 for (ap = list; ap; ap = ap->next)
638 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
639 continue;
640 if (dev->class != ap->class) /* of same class too 8) */
641 continue;
642 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
644 ap = ap->prev; /* back up one */
645 break; /* done here */
647 if (ap->next) /* if the next item exists */
648 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
649 break;
653 if (!ap) /* didn't find a match */
655 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
656 if ((ap->comment != DEV_DEVICE)
657 && (ap->class == dev->class)) /* appropriate place? */
658 break;
659 } /* or just put up with last */
661 return(ap);
666 ** Insdev
668 ** Inserts a copy of (dev) at the appropriate point in (list)
670 static void
671 insdev(DEV_LIST *dev, DEV_LIST *list)
673 DEV_LIST *lp,*ap;
675 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
676 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
678 ap = findspot(lp,list); /* find appropriate spot */
679 lp->next = ap->next; /* point to next */
680 if (ap->next)
681 ap->next->prev = lp; /* point next to new */
682 lp->prev = ap; /* point new to current */
683 ap->next = lp; /* and current to new */
688 ** Movedev
690 ** Moves (dev) from its current list to an appropriate place in (list)
691 ** (dev) may not come from the top of a list, but it may from the bottom.
693 static void
694 movedev(DEV_LIST *dev, DEV_LIST *list)
696 DEV_LIST *ap;
698 ap = findspot(dev,list);
699 dev->prev->next = dev->next; /* remove from old list */
700 if (dev->next)
701 dev->next->prev = dev->prev;
703 dev->next = ap->next; /* insert in new list */
704 if (ap->next)
705 ap->next->prev = dev; /* point next to new */
706 dev->prev = ap; /* point new to current */
707 ap->next = dev; /* and current to new */
712 ** Initlist
714 ** Initialises (*list) with the basic headings
716 static void
717 initlist(DEV_LIST **list)
719 int i;
721 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
723 strcpy(scratch.name,devclass_names[i].name);
724 scratch.comment = DEV_ZOOMED;
725 scratch.class = devclass_names[i].number;
726 scratch.attrib = FLG_MANDATORY; /* can't be moved */
727 addev(&scratch,list); /* add to the list */
733 ** savelist
735 ** Walks (list) and saves the settings of any entry marked as changed.
737 ** The device's active field is set according to (active).
739 ** Builds the uc_devlist used by kget to extract the changed device information.
740 ** The code for this was taken almost verbatim from the original module.
742 static void
743 savelist(DEV_LIST *list, int active)
745 struct uc_device *id_p,*id_pn;
746 char *name;
748 while (list)
750 if ((list->comment == DEV_DEVICE) && /* is a device */
751 (list->changed) && /* has been changed */
752 (list->device != NULL)) { /* has an uc_device structure */
754 setdev(list,active); /* set the device itself */
756 id_pn = NULL;
757 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
758 { /* look on the list for it */
759 if (id_p->id_id == list->device->id_id)
761 name = list->device->id_name;
762 id_pn = id_p->id_next;
763 if (id_p->id_name)
764 kfree(id_p->id_name, M_DEVL);
765 bcopy(list->device,id_p,sizeof(struct uc_device));
766 save_resource(list->device);
767 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
768 strcpy(id_p->id_name, name);
769 id_pn->id_next = uc_devlist;
770 id_p->id_next = id_pn;
771 break;
774 if (!id_pn) /* not already on the list */
776 name = list->device->id_name;
777 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
778 bcopy(list->device,id_pn,sizeof(struct uc_device));
779 save_resource(list->device);
780 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
781 strcpy(id_pn->id_name, name);
782 id_pn->id_next = uc_devlist;
783 uc_devlist = id_pn; /* park at top of list */
786 list = list->next;
792 ** nukelist
794 ** Frees all storage in use by a (list).
796 static void
797 nukelist(DEV_LIST *list)
799 DEV_LIST *dp;
801 if (!list)
802 return;
803 while(list->prev) /* walk to head of list */
804 list = list->prev;
806 while(list)
808 dp = list;
809 list = list->next;
810 kfree(dp,M_DEVL);
816 ** prevent
818 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
819 ** if there is no previous entry. (Only possible if list->prev == NULL given the
820 ** premise that there is always a comment at the head of the list)
822 static DEV_LIST *
823 prevent(DEV_LIST *list)
825 DEV_LIST *dp;
827 if (!list)
828 return(NULL);
829 dp = list->prev; /* start back one */
830 while(dp)
832 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
833 return(dp); /* so skip to comment */
834 if (dp->comment == DEV_COMMENT) /* not zoomed */
835 return(list->prev); /* one back as normal */
836 dp = dp->prev; /* backpedal */
838 return(dp); /* NULL, we can assume */
843 ** nextent
845 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
846 ** if there is no next entry. (Possible if the current entry is last, or
847 ** if the current entry is the last heading and it's collapsed)
849 static DEV_LIST *
850 nextent(DEV_LIST *list)
852 DEV_LIST *dp;
854 if (!list)
855 return(NULL);
856 if (list->comment != DEV_ZOOMED) /* no reason to skip */
857 return(list->next);
858 dp = list->next;
859 while(dp)
861 if (dp->comment != DEV_DEVICE) /* found another heading */
862 break;
863 dp = dp->next;
865 return(dp); /* back we go */
870 ** ofsent
872 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
874 static DEV_LIST *
875 ofsent(int ofs, DEV_LIST *list)
877 while (ofs-- && list)
878 list = nextent(list);
879 return(list);
884 ** findconflict
886 ** Scans every element of (list) and sets the conflict tags appropriately
887 ** Returns the number of conflicts found.
889 static int
890 findconflict(DEV_LIST *list)
892 int count = 0; /* number of conflicts found */
893 DEV_LIST *dp,*sp;
895 for (dp = list; dp; dp = dp->next) /* over the whole list */
897 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
898 continue;
900 dp->conflicts = 0; /* assume the best */
901 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
903 if (sp->comment != DEV_DEVICE) /* likewise */
904 continue;
906 if (sp == dp) /* always conflict with itself */
907 continue;
909 if ((dp->iobase > 0) && /* iobase conflict? */
910 (dp->iobase == sp->iobase))
911 dp->conflicts = 1;
912 if ((dp->irq > 0) && /* irq conflict? */
913 (dp->irq == sp->irq))
914 dp->conflicts = 1;
915 if ((dp->drq > 0) && /* drq conflict? */
916 (dp->drq == sp->drq))
917 dp->conflicts = 1;
918 if ((sp->maddr > 0) && /* maddr/msize conflict? */
919 (dp->maddr > 0) &&
920 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
921 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
922 dp->conflicts = 1;
924 count += dp->conflicts; /* count conflicts */
926 return(count);
931 ** expandlist
933 ** Unzooms all headings in (list)
935 static void
936 expandlist(DEV_LIST *list)
938 while(list)
940 if (list->comment == DEV_COMMENT)
941 list->comment = DEV_ZOOMED;
942 list = list->next;
948 ** collapselist
950 ** Zooms all headings in (list)
952 static void
953 collapselist(DEV_LIST *list)
955 while(list)
957 if (list->comment == DEV_ZOOMED)
958 list->comment = DEV_COMMENT;
959 list = list->next;
965 ** Screen-manipulation stuff
967 ** This is the basic screen layout :
969 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
970 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
971 ** +--------------------------------------------------------------------------------+
972 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
973 ** 1 -| ........................ ....... .. 0x....|
974 ** 2 -| ........................ ....... .. 0x....|
975 ** 3 -| ........................ ....... .. 0x....|
976 ** 4 -| ........................ ....... .. 0x....|
977 ** 5 -| ........................ ....... .. 0x....|
978 ** 6 -| ........................ ....... .. 0x....|
979 ** 7 -| ........................ ....... .. 0x....|
980 ** 8 -| ........................ ....... .. 0x....|
981 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
982 ** 10-| ........................ ....... |
983 ** 11-| ........................ ....... |
984 ** 12-| ........................ ....... |
985 ** 13-| ........................ ....... |
986 ** 14-| ........................ ....... |
987 ** 15-| ........................ ....... |
988 ** 16-| ........................ ....... |
989 ** 17-|------------------------------------------------------UP-DOWN-------------------|
990 ** 18-| Relevant parameters for the current device |
991 ** 19-| |
992 ** 20-| |
993 ** 21-|--------------------------------------------------------------------------------|
994 ** 22-| Help texts go here |
995 ** 23-| |
996 ** +--------------------------------------------------------------------------------+
998 ** Help texts
1000 ** On a collapsed comment :
1002 ** [Enter] Expand device list [z] Expand all lists
1003 ** [TAB] Change fields [Q] Save and Exit
1005 ** On an expanded comment :
1007 ** [Enter] Collapse device list [Z] Collapse all lists
1008 ** [TAB] Change fields [Q] Save and Exit
1010 ** On a comment with no followers
1013 ** [TAB] Change fields [Q] Save and Exit
1015 ** On a device in the active list
1017 ** [Enter] Edit device parameters [DEL] Disable device
1018 ** [TAB] Change fields [Q] Save and Exit [?] Help
1020 ** On a device in the inactive list
1022 ** [Enter] Enable device
1023 ** [TAB] Change fields [Q] Save and Exit [?] Help
1025 ** While editing parameters
1027 ** <parameter-specific help here>
1028 ** [TAB] Change fields [Q] Save device parameters
1035 ** The base-level screen primitives :
1037 ** bold() - enter bold mode \E[1m (md)
1038 ** inverse() - enter inverse mode \E[7m (so)
1039 ** normal() - clear bold/inverse mode \E[m (se)
1040 ** clear() - clear the screen \E[H\E[J (ce)
1041 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1044 static void
1045 bold(void)
1047 kprintf("\033[1m");
1050 static void
1051 inverse(void)
1053 kprintf("\033[7m");
1056 static void
1057 normal(void)
1059 kprintf("\033[m");
1062 static void
1063 clear(void)
1065 normal();
1066 kprintf("\033[H\033[J");
1069 static void
1070 move(int x, int y)
1072 kprintf("\033[%d;%dH",y+1,x+1);
1078 ** High-level screen primitives :
1080 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1081 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1082 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1083 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1084 ** putmsg(str) - put (str) in the message area
1085 ** puthelp(str) - put (str) in the upper helpline
1086 ** pad(str,len) - pad (str) to (len) with spaces
1087 ** drawline(row,detail,list,inverse,*dhelp)
1088 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1089 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1090 ** draw the line in inverse video, and display (*dhelp) on the
1091 ** helpline.
1092 ** drawlist(row,num,detail,list)
1093 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1094 ** through to drawline().
1095 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1096 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1097 ** redraw(); - Redraws the entire screen layout, including the
1098 ** - two list panels.
1101 /**
1102 ** putxy
1103 ** writes (str) at x,y onscreen
1104 ** putxyl
1105 ** writes up to (len) of (str) at x,y onscreen.
1107 ** Supports embedded formatting :
1108 ** !i - inverse mode.
1109 ** !b - bold mode.
1110 ** !n - normal mode.
1112 static void
1113 putxyl(int x, int y, char *str, int len)
1115 move(x,y);
1116 normal();
1118 while((*str) && (len--))
1120 if (*str == '!') /* format escape? */
1122 switch(*(str+1)) /* depending on the next character */
1124 case 'i':
1125 inverse();
1126 str +=2; /* skip formatting */
1127 len++; /* doesn't count for length */
1128 break;
1130 case 'b':
1131 bold();
1132 str +=2; /* skip formatting */
1133 len++; /* doesn't count for length */
1134 break;
1136 case 'n':
1137 normal();
1138 str +=2; /* skip formatting */
1139 len++; /* doesn't count for length */
1140 break;
1142 default:
1143 cnputc(*str++); /* not an escape */
1145 }else{
1146 cnputc(*str++); /* emit the character */
1151 #define putxy(x,y,str) putxyl(x,y,str,-1)
1155 ** erase
1157 ** Erases the region (x,y,w,h)
1159 static void
1160 erase(int x, int y, int w, int h)
1162 int i;
1164 normal();
1165 for (i = 0; i < h; i++)
1166 putxyl(x,y++,spaces,w);
1170 /**
1171 ** txtbox
1173 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1174 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1176 static void
1177 txtbox(int x, int y, int w, int h, char *str)
1179 int i = 0;
1181 h--;
1182 while((str[i]) && h)
1184 if (str[i] == '\n') /* newline */
1186 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1187 y++; /* move down */
1188 h--; /* room for one less */
1189 str += (i+1); /* skip first newline */
1190 i = 0; /* zero offset */
1191 }else{
1192 i++; /* next character */
1195 if (h) /* end of string, not region */
1196 putxyl(x,y,str,w);
1201 ** putmsg
1203 ** writes (msg) in the helptext area
1205 static void
1206 putmsg(char *msg)
1208 erase(0,18,80,3); /* clear area */
1209 txtbox(0,18,80,3,msg);
1214 ** puthelp
1216 ** Writes (msg) in the helpline area
1218 static void
1219 puthelp(char *msg)
1221 erase(0,22,80,1);
1222 putxy(0,22,msg);
1227 ** masterhelp
1229 ** Draws the help message at the bottom of the screen
1231 static void
1232 masterhelp(char *msg)
1234 erase(0,23,80,1);
1235 putxy(0,23,msg);
1240 ** pad
1242 ** space-pads a (str) to (len) characters
1244 static void
1245 pad(char *str, int len)
1247 int i;
1249 for (i = 0; str[i]; i++) /* find the end of the string */
1251 if (i >= len) /* no padding needed */
1252 return;
1253 while(i < len) /* pad */
1254 str[i++] = ' ';
1255 str[i] = '\0';
1260 ** drawline
1262 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1263 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1265 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1266 ** help is shown for normal or zoomed comments
1268 static void
1269 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1271 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1273 if (list->comment == DEV_DEVICE)
1275 nb[0] = ' ';
1276 strncpy(nb+1,list->name,57);
1277 }else{
1278 strncpy(nb,list->name,58);
1279 if ((list->comment == DEV_ZOOMED) && (list->next))
1280 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1281 strcat(nb," (Collapsed)");
1283 nb[58] = '\0';
1284 pad(nb,60);
1285 if (list->conflicts) /* device in conflict? */
1287 if (inverse)
1289 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1290 }else{
1291 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1294 if (list->comment == DEV_DEVICE)
1296 ksprintf(db,"%s%d",list->dev,list->unit);
1297 pad(db,8);
1298 }else{
1299 strcpy(db," ");
1301 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1303 ksprintf(ib," %d",list->irq);
1304 pad(ib,4);
1305 }else{
1306 strcpy(ib," ");
1308 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1310 ksprintf(pb,"0x%x",list->iobase);
1311 pad(pb,7);
1312 }else{
1313 strcpy(pb," ");
1316 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1318 putxyl(0,row,lbuf,80);
1319 if (dhelp)
1321 switch(list->comment)
1323 case DEV_DEVICE: /* ordinary device */
1324 puthelp(dhelp);
1325 break;
1326 case DEV_COMMENT:
1327 puthelp("");
1328 if (list->next)
1329 if (list->next->comment == DEV_DEVICE)
1330 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1331 break;
1332 case DEV_ZOOMED:
1333 puthelp("");
1334 if (list->next)
1335 if (list->next->comment == DEV_DEVICE)
1336 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1337 break;
1338 default:
1339 puthelp(" WARNING: This list entry corrupted!");
1340 break;
1343 move(0,row); /* put the cursor somewhere relevant */
1348 ** drawlist
1350 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1351 ** port and IRQ fields as well if (detail) is nonzero
1353 ** kprintf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1355 static void
1356 drawlist(int row, int num, int detail, DEV_LIST *list)
1358 int ofs;
1360 for(ofs = 0; ofs < num; ofs++)
1362 if (list)
1364 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1365 list = nextent(list); /* move down visible list */
1366 }else{
1367 erase(0,row+ofs,80,1);
1374 ** redrawactive
1376 ** Redraws the active list
1378 static void
1379 redrawactive(void)
1381 char cbuf[16];
1383 if (conflicts)
1385 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1386 putxy(45,0,cbuf);
1387 }else{
1388 putxyl(45,0,lines,16);
1390 drawlist(1,8,1,alist); /* draw device lists */
1394 ** redrawinactive
1396 ** Redraws the inactive list
1398 static void
1399 redrawinactive(void)
1401 drawlist(10,7,0,ilist); /* draw device lists */
1406 ** redraw
1408 ** Clear the screen and redraw the entire layout
1410 static void
1411 redraw(void)
1413 clear();
1414 putxy(0,0,lines);
1415 putxy(3,0,"!bActive!n-!bDrivers");
1416 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1417 putxy(0,9,lines);
1418 putxy(3,9,"!bInactive!n-!bDrivers");
1419 putxy(63,9,"!bDev");
1420 putxy(0,17,lines);
1421 putxy(0,21,lines);
1422 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1424 redrawactive();
1425 redrawinactive();
1430 ** yesnocancel
1432 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1433 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1435 static int
1436 yesnocancel(char *str)
1439 putmsg(str);
1440 for(;;)
1441 switch(kgetchar())
1443 case -1:
1444 case 'n':
1445 case 'N':
1446 return(0);
1448 case 'y':
1449 case 'Y':
1450 return(1);
1452 case 'c':
1453 case 'C':
1454 return(2);
1460 ** showparams
1462 ** Show device parameters in the region below the lists
1464 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1465 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1466 ** +--------------------------------------------------------------------------------+
1467 ** 17-|--------------------------------------------------------------------------------|
1468 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1469 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1470 ** 20-| Flags : 0x0000 DRQ number : 00 |
1471 ** 21-|--------------------------------------------------------------------------------|
1473 static void
1474 showparams(DEV_LIST *dev)
1476 char buf[80];
1478 erase(0,18,80,3); /* clear area */
1479 if (!dev)
1480 return;
1481 if (dev->comment != DEV_DEVICE)
1482 return;
1485 if (dev->iobase > 0)
1487 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1488 putxy(1,18,buf);
1491 if (dev->irq > 0)
1493 ksprintf(buf,"IRQ number : %d",dev->irq);
1494 putxy(1,19,buf);
1496 ksprintf(buf,"Flags : 0x%x",dev->flags);
1497 putxy(1,20,buf);
1498 if (dev->maddr > 0)
1500 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1501 putxy(26,18,buf);
1503 if (dev->msize > 0)
1505 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1506 putxy(26,19,buf);
1509 if (dev->drq > 0)
1511 ksprintf(buf,"DRQ number : %d",dev->drq);
1512 putxy(26,20,buf);
1518 ** Editing functions for device parameters
1520 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1521 ** onscreen. Refuse values outsise (min) and (max).
1522 ** editparams(dev) - Edit the parameters for (dev)
1526 #define VetRet(code) \
1528 if ((i >= min) && (i <= max)) /* legit? */ \
1530 *val = i; \
1531 ksprintf(buf,hex?"0x%x":"%d",i); \
1532 putxy(hex?x-2:x,y,buf); \
1533 return(code); /* all done and exit */ \
1535 i = *val; /* restore original value */ \
1536 delta = 1; /* restore other stuff */ \
1541 ** editval
1543 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1544 ** in a field (width) wide. (Allow one space)
1545 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1547 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1549 static int
1550 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1552 int i = *val; /* work with copy of the value */
1553 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1554 int xp = 0; /* cursor offset into text copy */
1555 int delta = 1; /* force redraw first time in */
1556 int c;
1557 int extended = 0; /* stage counter for extended key sequences */
1559 if (hex) /* we presume there's a leading 0x onscreen */
1560 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1562 for (;;)
1564 if (delta) /* only update if necessary */
1566 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1567 ksprintf(buf,"!i%s",tc); /* format for printing */
1568 erase(x,y,width,1); /* clear the area */
1569 putxy(x,y,buf); /* write */
1570 xp = strlen(tc); /* cursor always at end */
1571 move(x+xp,y); /* position the cursor */
1574 c = kgetchar();
1576 switch(extended) /* escape handling */
1578 case 0:
1579 if (c == 0x1b) /* esc? */
1581 extended = 1; /* flag and spin */
1582 continue;
1584 extended = 0;
1585 break; /* nope, drop through */
1587 case 1: /* there was an escape prefix */
1588 if (c == '[' || c == 'O') /* second character in sequence */
1590 extended = 2;
1591 continue;
1593 if (c == 0x1b)
1594 return(KEY_EXIT); /* double esc exits */
1595 extended = 0;
1596 break; /* nup, not a sequence. */
1598 case 2:
1599 extended = 0;
1600 switch(c) /* looks like the real McCoy */
1602 case 'A':
1603 VetRet(KEY_UP); /* leave if OK */
1604 continue;
1605 case 'B':
1606 VetRet(KEY_DOWN); /* leave if OK */
1607 continue;
1608 case 'C':
1609 VetRet(KEY_RIGHT); /* leave if OK */
1610 continue;
1611 case 'D':
1612 VetRet(KEY_LEFT); /* leave if OK */
1613 continue;
1615 default:
1616 continue;
1620 switch(c)
1622 case '\t': /* trying to tab off */
1623 VetRet(KEY_TAB); /* verify and maybe return */
1624 break;
1626 case -1:
1627 case 'q':
1628 case 'Q':
1629 VetRet(KEY_EXIT);
1630 break;
1632 case '\b':
1633 case '\177': /* BS or DEL */
1634 if (ro) /* readonly? */
1636 puthelp(" !iThis value cannot be edited (Press ESC)");
1637 while(kgetchar() != 0x1b); /* wait for key */
1638 return(KEY_NULL); /* spin */
1640 if (xp) /* still something left to delete */
1642 i = (hex ? i/0x10u : i/10); /* strip last digit */
1643 delta = 1; /* force update */
1645 break;
1647 case 588:
1648 VetRet(KEY_UP);
1649 break;
1651 case '\r':
1652 case '\n':
1653 case 596:
1654 VetRet(KEY_DOWN);
1655 break;
1657 case 591:
1658 VetRet(KEY_LEFT);
1659 break;
1661 case 593:
1662 VetRet(KEY_RIGHT);
1663 break;
1665 default:
1666 if (ro) /* readonly? */
1668 puthelp(" !iThis value cannot be edited (Press ESC)");
1669 while(kgetchar() != 0x1b); /* wait for key */
1670 return(KEY_NULL); /* spin */
1672 if (xp >= width) /* no room for more characters anyway */
1673 break;
1674 if (hex)
1676 if ((c >= '0') && (c <= '9'))
1678 i = i*0x10 + (c-'0'); /* update value */
1679 delta = 1;
1680 break;
1682 if ((c >= 'a') && (c <= 'f'))
1684 i = i*0x10 + (c-'a'+0xa);
1685 delta = 1;
1686 break;
1688 if ((c >= 'A') && (c <= 'F'))
1690 i = i*0x10 + (c-'A'+0xa);
1691 delta = 1;
1692 break;
1694 }else{
1695 if ((c >= '0') && (c <= '9'))
1697 i = i*10 + (c-'0'); /* update value */
1698 delta = 1; /* force redraw */
1699 break;
1702 break;
1709 ** editparams
1711 ** Edit the parameters for (dev)
1713 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1714 ** possible for this to spin in an endless loop...
1715 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1716 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1717 ** +--------------------------------------------------------------------------------+
1718 ** 17-|--------------------------------------------------------------------------------|
1719 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1720 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1721 ** 20-| Flags : 0x0000 DRQ number : 00 |
1722 ** 21-|--------------------------------------------------------------------------------|
1724 ** The "intelligence" in this function that hops around based on the directional
1725 ** returns from editval isn't very smart, and depends on the layout above.
1727 static void
1728 editparams(DEV_LIST *dev)
1730 int ret;
1731 char buf[16]; /* needs to fit the device name */
1733 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1734 ksprintf(buf,"!b%s",dev->dev);
1735 putxy(24,17,buf);
1737 erase(1,22,80,1);
1738 for (;;)
1740 ep_iobase:
1741 if (dev->iobase > 0)
1743 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1744 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1745 switch(ret)
1747 case KEY_EXIT:
1748 goto ep_exit;
1750 case KEY_RIGHT:
1751 if (dev->maddr > 0)
1752 goto ep_maddr;
1753 break;
1755 case KEY_TAB:
1756 case KEY_DOWN:
1757 goto ep_irq;
1759 goto ep_iobase;
1761 ep_irq:
1762 if (dev->irq > 0)
1764 puthelp(" Interrupt number (Decimal, 1-15)");
1765 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1766 switch(ret)
1768 case KEY_EXIT:
1769 goto ep_exit;
1771 case KEY_RIGHT:
1772 if (dev->msize > 0)
1773 goto ep_msize;
1774 break;
1776 case KEY_UP:
1777 if (dev->iobase > 0)
1778 goto ep_iobase;
1779 break;
1781 case KEY_TAB:
1782 case KEY_DOWN:
1783 goto ep_flags;
1785 goto ep_irq;
1787 ep_flags:
1788 puthelp(" Device-specific flag values.");
1789 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1790 switch(ret)
1792 case KEY_EXIT:
1793 goto ep_exit;
1795 case KEY_RIGHT:
1796 if (dev->drq > 0)
1797 goto ep_drq;
1798 break;
1800 case KEY_UP:
1801 if (dev->irq > 0)
1802 goto ep_irq;
1803 if (dev->iobase > 0)
1804 goto ep_iobase;
1805 break;
1807 case KEY_DOWN:
1808 if (dev->maddr > 0)
1809 goto ep_maddr;
1810 if (dev->msize > 0)
1811 goto ep_msize;
1812 if (dev->drq > 0)
1813 goto ep_drq;
1814 break;
1816 case KEY_TAB:
1817 goto ep_maddr;
1819 goto ep_flags;
1820 ep_maddr:
1821 if (dev->maddr > 0)
1823 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1824 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1825 switch(ret)
1827 case KEY_EXIT:
1828 goto ep_exit;
1830 case KEY_LEFT:
1831 if (dev->iobase > 0)
1832 goto ep_iobase;
1833 break;
1835 case KEY_UP:
1836 goto ep_flags;
1838 case KEY_DOWN:
1839 if (dev->msize > 0)
1840 goto ep_msize;
1841 if (dev->drq > 0)
1842 goto ep_drq;
1843 break;
1845 case KEY_TAB:
1846 goto ep_msize;
1848 goto ep_maddr;
1850 ep_msize:
1851 if (dev->msize > 0)
1853 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1854 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1855 switch(ret)
1857 case KEY_EXIT:
1858 goto ep_exit;
1860 case KEY_LEFT:
1861 if (dev->irq > 0)
1862 goto ep_irq;
1863 break;
1865 case KEY_UP:
1866 if (dev->maddr > 0)
1867 goto ep_maddr;
1868 goto ep_flags;
1870 case KEY_DOWN:
1871 if (dev->drq > 0)
1872 goto ep_drq;
1873 break;
1875 case KEY_TAB:
1876 goto ep_drq;
1878 goto ep_msize;
1880 ep_drq:
1881 if (dev->drq > 0)
1883 puthelp(" Device DMA request number (Decimal, 1-7)");
1884 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1885 switch(ret)
1887 case KEY_EXIT:
1888 goto ep_exit;
1890 case KEY_LEFT:
1891 goto ep_flags;
1893 case KEY_UP:
1894 if (dev->msize > 0)
1895 goto ep_msize;
1896 if (dev->maddr > 0)
1897 goto ep_maddr;
1898 goto ep_flags;
1900 case KEY_TAB:
1901 goto ep_iobase;
1903 goto ep_drq;
1906 ep_exit:
1907 dev->changed = 1; /* mark as changed */
1910 static char *helptext[] =
1912 " Using the UserConfig kernel settings editor",
1913 " -------------------------------------------",
1915 "VISUAL MODE:",
1917 "- - Layout -",
1919 "The screen displays a list of available drivers, divided into two",
1920 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1921 "by default collapsed and can be expanded to show all the drivers",
1922 "available in each category. The parameters for the currently selected",
1923 "driver are shown at the bottom of the screen.",
1925 "- - Moving around -",
1927 "To move in the current list, use the UP and DOWN cursor keys to select",
1928 "an item (the selected item will be highlighted). If the item is a",
1929 "category name, you may alternatively expand or collapse the list of",
1930 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1931 "expanded, you can select each driver in the same manner and either:",
1933 " - change its parameters using [!bENTER!n]",
1934 " - move it to the Inactive list using [!bDEL!n]",
1936 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1937 "you need to move a driver from the Inactive list back to the Active",
1938 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1939 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1940 "its place in the Active list.",
1942 "- - Altering the list/parameters -",
1944 "Any drivers for devices not installed in your system should be moved",
1945 "to the Inactive list, until there are no remaining parameter conflicts",
1946 "between the drivers, as indicated at the top.",
1948 "Once the list of Active drivers only contains entries for the devices",
1949 "present in your system, you can set their parameters (Interrupt, DMA",
1950 "channel, I/O addresses). To do this, select the driver and press",
1951 "[!bENTER!n]: it is now possible to edit the settings at the",
1952 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1953 "finished, use [!bQ!n] to return to the list.",
1955 "- - Saving changes -",
1957 "When all settings seem correct, and you wish to proceed with the",
1958 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1959 "confirm your choice.",
1961 NULL
1966 ** helpscreen
1968 ** Displays help text onscreen for people that are confused, using a simple
1969 ** pager.
1971 static void
1972 helpscreen(void)
1974 int topline = 0; /* where we are in the text */
1975 int line = 0; /* last line we displayed */
1976 int c, delta = 1;
1977 char prompt[80];
1979 for (;;) /* loop until user quits */
1981 /* display help text */
1982 if (delta)
1984 clear(); /* remove everything else */
1985 for (line = topline;
1986 (line < (topline + 24)) && (helptext[line]);
1987 line++)
1988 putxy(0,line-topline,helptext[line]);
1989 delta = 0;
1992 /* prompt */
1993 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1994 putxy(0,24,prompt);
1996 c = kgetchar(); /* so what do they say? */
1998 switch (c)
2000 case 'u':
2001 case 'U':
2002 case 'b':
2003 case 'B': /* wired into 'more' users' fingers */
2004 if (topline > 0) /* room to go up? */
2006 topline -= 24;
2007 if (topline < 0) /* don't go too far */
2008 topline = 0;
2009 delta = 1;
2011 break;
2013 case 'd':
2014 case 'D':
2015 case ' ': /* expected by most people */
2016 if (helptext[line]) /* maybe more below? */
2018 topline += 24;
2019 delta = 1;
2021 break;
2023 case 'q':
2024 case 'Q':
2025 redraw(); /* restore the screen */
2026 return;
2032 /**
2033 ** High-level control functions
2038 ** dolist
2040 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2041 ** (num) lines, starting at (*ofs) offset from row onscreen.
2042 ** Pass (detail) on to drawing routines.
2044 ** If the user hits a key other than a cursor key, maybe return a code.
2046 ** (*list) points to the device at the top line in the region, (*ofs) is the
2047 ** position of the highlight within the region. All routines below
2048 ** this take only a device and an absolute row : use ofsent() to find the
2049 ** device, and add (*ofs) to (row) to find the absolute row.
2051 static int
2052 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2054 int extended = 0;
2055 int c;
2056 DEV_LIST *lp;
2057 int delta = 1;
2059 for(;;)
2061 if (delta)
2063 showparams(ofsent(*ofs,*list)); /* show device parameters */
2064 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2065 delta = 0;
2068 c = kgetchar(); /* get a character */
2069 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2071 extended = 0; /* no longer */
2072 switch(c)
2074 case 588: /* syscons' idea of 'up' */
2075 case 'A': /* up */
2076 if (*ofs) /* just a move onscreen */
2078 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2079 (*ofs)--; /* move up */
2080 }else{
2081 lp = prevent(*list); /* can we go up? */
2082 if (!lp) /* no */
2083 break;
2084 *list = lp; /* yes, move up list */
2085 drawlist(row,num,detail,*list);
2087 delta = 1;
2088 break;
2090 case 596: /* dooby-do */
2091 case 'B': /* down */
2092 lp = ofsent(*ofs,*list); /* get current item */
2093 if (!nextent(lp))
2094 break; /* nothing more to move to */
2095 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2096 if (*ofs < (num-1)) /* room to move onscreen? */
2098 (*ofs)++;
2099 }else{
2100 *list = nextent(*list); /* scroll region down */
2101 drawlist(row,num,detail,*list);
2103 delta = 1;
2104 break;
2106 }else{
2107 switch(c)
2109 case '\033':
2110 extended=1;
2111 break;
2113 case '[': /* cheat : always preceeds cursor move */
2114 case 'O': /* ANSI application key mode */
2115 if (extended==1)
2116 extended=2;
2117 else
2118 extended=0;
2119 break;
2121 case 'Q':
2122 case 'q':
2123 return(KEY_EXIT); /* user requests exit */
2125 case '\r':
2126 case '\n':
2127 return(KEY_DO); /* "do" something */
2129 case '\b':
2130 case '\177':
2131 case 599:
2132 return(KEY_DEL); /* "delete" response */
2134 case 'X':
2135 case 'x':
2136 return(KEY_UNZOOM); /* expand everything */
2138 case 'C':
2139 case 'c':
2140 return(KEY_ZOOM); /* collapse everything */
2142 case '\t':
2143 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2144 return(KEY_TAB); /* "move" response */
2146 case '\014': /* ^L, redraw */
2147 return(KEY_REDRAW);
2149 case '?': /* helptext */
2150 return(KEY_HELP);
2159 ** visuserconfig
2161 ** Do the fullscreen config thang
2163 static int
2164 visuserconfig(void)
2166 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2167 DEV_LIST *dp;
2169 initlist(&active);
2170 initlist(&inactive);
2171 alist = active;
2172 ilist = inactive;
2174 getdevs();
2176 conflicts = findconflict(active); /* find conflicts in the active list only */
2178 redraw();
2180 for(;;)
2182 switch(mode)
2184 case 0: /* active devices */
2185 ret = dolist(1,8,1,&actofs,&alist,
2186 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2187 switch(ret)
2189 case KEY_TAB:
2190 mode = 1; /* swap lists */
2191 break;
2193 case KEY_REDRAW:
2194 redraw();
2195 break;
2197 case KEY_ZOOM:
2198 alist = active;
2199 actofs = 0;
2200 expandlist(active);
2201 redrawactive();
2202 break;
2204 case KEY_UNZOOM:
2205 alist = active;
2206 actofs = 0;
2207 collapselist(active);
2208 redrawactive();
2209 break;
2211 case KEY_DEL:
2212 dp = ofsent(actofs,alist); /* get current device */
2213 if (dp) /* paranoia... */
2215 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2216 break;
2217 if (dp == alist) /* moving top item on list? */
2219 if (dp->next)
2221 alist = dp->next; /* point list to non-moving item */
2222 }else{
2223 alist = dp->prev; /* end of list, go back instead */
2225 }else{
2226 if (!dp->next) /* moving last item on list? */
2227 actofs--;
2229 dp->conflicts = 0; /* no conflicts on the inactive list */
2230 movedev(dp,inactive); /* shift to inactive list */
2231 conflicts = findconflict(active); /* update conflict tags */
2232 dp->changed = 1;
2233 redrawactive(); /* redraw */
2234 redrawinactive();
2236 break;
2238 case KEY_DO: /* edit device parameters */
2239 dp = ofsent(actofs,alist); /* get current device */
2240 if (dp) /* paranoia... */
2242 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2244 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2245 editparams(dp);
2246 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2247 putxy(0,17,lines);
2248 conflicts = findconflict(active); /* update conflict tags */
2249 }else{ /* DO on comment = zoom */
2250 switch(dp->comment) /* Depends on current state */
2252 case DEV_COMMENT: /* not currently zoomed */
2253 dp->comment = DEV_ZOOMED;
2254 break;
2256 case DEV_ZOOMED:
2257 dp->comment = DEV_COMMENT;
2258 break;
2261 redrawactive();
2263 break;
2265 break;
2267 case 1: /* inactive devices */
2268 ret = dolist(10,7,0,&inactofs,&ilist,
2269 " [!bEnter!n] Enable device ");
2270 switch(ret)
2272 case KEY_TAB:
2273 mode = 0;
2274 break;
2276 case KEY_REDRAW:
2277 redraw();
2278 break;
2280 case KEY_ZOOM:
2281 ilist = inactive;
2282 inactofs = 0;
2283 expandlist(inactive);
2284 redrawinactive();
2285 break;
2287 case KEY_UNZOOM:
2288 ilist = inactive;
2289 inactofs = 0;
2290 collapselist(inactive);
2291 redrawinactive();
2292 break;
2294 case KEY_DO:
2295 dp = ofsent(inactofs,ilist); /* get current device */
2296 if (dp) /* paranoia... */
2298 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2300 if (dp == ilist) /* moving top of list? */
2302 if (dp->next)
2304 ilist = dp->next; /* point list to non-moving item */
2305 }else{
2306 ilist = dp->prev; /* can't go down, go up instead */
2308 }else{
2309 if (!dp->next) /* last entry on list? */
2310 inactofs--; /* shift cursor up one */
2313 movedev(dp,active); /* shift to active list */
2314 conflicts = findconflict(active); /* update conflict tags */
2315 dp->changed = 1;
2316 alist = dp; /* put at top and current */
2317 actofs = 0;
2318 while(dp->comment == DEV_DEVICE)
2319 dp = dp->prev; /* forcibly unzoom section */
2320 dp ->comment = DEV_COMMENT;
2321 mode = 0; /* and swap modes to follow it */
2323 }else{ /* DO on comment = zoom */
2324 switch(dp->comment) /* Depends on current state */
2326 case DEV_COMMENT: /* not currently zoomed */
2327 dp->comment = DEV_ZOOMED;
2328 break;
2330 case DEV_ZOOMED:
2331 dp->comment = DEV_COMMENT;
2332 break;
2335 redrawactive(); /* redraw */
2336 redrawinactive();
2338 break;
2340 default: /* nothing else relevant here */
2341 break;
2343 break;
2344 default:
2345 mode = 0; /* shouldn't happen... */
2348 /* handle returns that are the same for both modes */
2349 switch (ret) {
2350 case KEY_HELP:
2351 helpscreen();
2352 break;
2354 case KEY_EXIT:
2355 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2356 switch(i)
2358 case 2: /* cancel */
2359 redraw();
2360 break;
2362 case 1: /* save and exit */
2363 savelist(active,1);
2364 savelist(inactive,0);
2366 case 0: /* exit */
2367 nukelist(active); /* clean up after ourselves */
2368 nukelist(inactive);
2369 normal();
2370 clear();
2371 return(1);
2373 break;
2377 #endif /* VISUAL_USERCONFIG */
2380 * Copyright (c) 1991 Regents of the University of California.
2381 * All rights reserved.
2382 * Copyright (c) 1994 Jordan K. Hubbard
2383 * All rights reserved.
2384 * Copyright (c) 1994 David Greenman
2385 * All rights reserved.
2387 * Many additional changes by Bruce Evans
2389 * This code is derived from software contributed by the
2390 * University of California Berkeley, Jordan K. Hubbard,
2391 * David Greenman and Bruce Evans.
2393 * Redistribution and use in source and binary forms, with or without
2394 * modification, are permitted provided that the following conditions
2395 * are met:
2396 * 1. Redistributions of source code must retain the above copyright
2397 * notice, this list of conditions and the following disclaimer.
2398 * 2. Redistributions in binary form must reproduce the above copyright
2399 * notice, this list of conditions and the following disclaimer in the
2400 * documentation and/or other materials provided with the distribution.
2401 * 3. All advertising materials mentioning features or use of this software
2402 * must display the following acknowledgement:
2403 * This product includes software developed by the University of
2404 * California, Berkeley and its contributors.
2405 * 4. Neither the name of the University nor the names of its contributors
2406 * may be used to endorse or promote products derived from this software
2407 * without specific prior written permission.
2409 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2410 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2412 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2413 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2414 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2415 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2416 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2417 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2418 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2419 * SUCH DAMAGE.
2421 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2424 #include "use_scbus.h"
2426 #define PARM_DEVSPEC 0x1
2427 #define PARM_INT 0x2
2428 #define PARM_ADDR 0x3
2429 #define PARM_STRING 0x4
2431 typedef struct _cmdparm {
2432 int type;
2433 union {
2434 struct uc_device *dparm;
2435 int iparm;
2436 union {
2437 void *aparm;
2438 const char *sparm;
2439 } u;
2440 } parm;
2441 } CmdParm;
2443 typedef int (*CmdFunc)(CmdParm *);
2445 typedef struct _cmd {
2446 char *name;
2447 CmdFunc handler;
2448 CmdParm *parms;
2449 } Cmd;
2452 #if 0
2453 static void lsscsi(void);
2454 static int list_scsi(CmdParm *);
2455 #endif
2457 static int lsdevtab(struct uc_device *);
2458 static struct uc_device *find_device(char *, int);
2459 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2460 static void cngets(char *, int);
2461 static Cmd *parse_cmd(char *);
2462 static int parse_args(const char *, CmdParm *);
2463 static int save_dev(struct uc_device *);
2465 static int list_devices(CmdParm *);
2466 static int set_device_ioaddr(CmdParm *);
2467 static int set_device_irq(CmdParm *);
2468 static int set_device_drq(CmdParm *);
2469 static int set_device_iosize(CmdParm *);
2470 static int set_device_mem(CmdParm *);
2471 static int set_device_flags(CmdParm *);
2472 static int set_device_enable(CmdParm *);
2473 static int set_device_disable(CmdParm *);
2474 static int quitfunc(CmdParm *);
2475 static int helpfunc(CmdParm *);
2476 static int introfunc(CmdParm *);
2478 #if NPNP > 0
2479 static int lspnp(void);
2480 static int set_pnp_parms(CmdParm *);
2481 #endif
2483 static int lineno;
2485 #include "use_eisa.h"
2487 #if NEISA > 0
2489 #include <bus/eisa/eisaconf.h>
2491 static int set_num_eisa_slots(CmdParm *);
2493 #endif /* NEISA > 0 */
2495 static CmdParm addr_parms[] = {
2496 { PARM_DEVSPEC, {} },
2497 { PARM_ADDR, {} },
2498 { -1, {} },
2501 static CmdParm int_parms[] = {
2502 { PARM_DEVSPEC, {} },
2503 { PARM_INT, {} },
2504 { -1, {} },
2507 static CmdParm dev_parms[] = {
2508 { PARM_DEVSPEC, {} },
2509 { -1, {} },
2512 #if NPNP > 0
2513 static CmdParm string_arg[] = {
2514 { PARM_STRING, {} },
2515 { -1, {} },
2517 #endif
2519 #if NEISA > 0
2520 static CmdParm int_arg[] = {
2521 { PARM_INT, {} },
2522 { -1, {} },
2524 #endif /* NEISA > 0 */
2526 static Cmd CmdList[] = {
2527 { "?", helpfunc, NULL }, /* ? (help) */
2528 { "di", set_device_disable, dev_parms }, /* disable dev */
2529 { "dr", set_device_drq, int_parms }, /* drq dev # */
2530 #if NEISA > 0
2531 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2532 #endif /* NEISA > 0 */
2533 { "en", set_device_enable, dev_parms }, /* enable dev */
2534 { "ex", quitfunc, NULL }, /* exit (quit) */
2535 { "f", set_device_flags, int_parms }, /* flags dev mask */
2536 { "h", helpfunc, NULL }, /* help */
2537 { "intro", introfunc, NULL }, /* intro screen */
2538 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2539 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2540 { "ir", set_device_irq, int_parms }, /* irq dev # */
2541 { "l", list_devices, NULL }, /* ls, list */
2542 #if NPNP > 0
2543 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2544 #endif
2545 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2546 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2547 { "q", quitfunc, NULL }, /* quit */
2548 #if 0
2549 { "s", list_scsi, NULL }, /* scsi */
2550 #endif
2551 #ifdef VISUAL_USERCONFIG
2552 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2553 #endif
2554 { NULL, NULL, NULL },
2557 void
2558 userconfig(void)
2560 static char banner = 1;
2561 char input[80];
2562 int rval;
2563 Cmd *cmd;
2565 load_devtab();
2566 init_config_script();
2567 while (1) {
2569 /* Only display signon banner if we are about to go interactive */
2570 if (!has_config_script()) {
2571 if (!(boothowto & RB_CONFIG))
2572 #ifdef INTRO_USERCONFIG
2573 banner = 0;
2574 #else
2575 return;
2576 #endif
2577 if (banner) {
2578 banner = 0;
2579 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2580 " Type \"help\" for help"
2581 #ifdef VISUAL_USERCONFIG
2582 " or \"visual\" to go to the visual\n"
2583 " configuration interface (requires MGA/VGA display or\n"
2584 " serial terminal capable of displaying ANSI graphics)"
2585 #endif
2586 ".\n");
2590 kprintf("config> ");
2591 cngets(input, 80);
2592 if (input[0] == '\0')
2593 continue;
2594 cmd = parse_cmd(input);
2595 if (!cmd) {
2596 kprintf("Invalid command or syntax. Type `?' for help.\n");
2597 continue;
2599 rval = (*cmd->handler)(cmd->parms);
2600 if (rval) {
2601 free_devtab();
2602 return;
2607 static Cmd *
2608 parse_cmd(char *cmd)
2610 Cmd *cp;
2612 for (cp = CmdList; cp->name; cp++) {
2613 int len = strlen(cp->name);
2615 if (!strncmp(cp->name, cmd, len)) {
2616 while (*cmd && *cmd != ' ' && *cmd != '\t')
2617 ++cmd;
2618 if (parse_args(cmd, cp->parms))
2619 return NULL;
2620 else
2621 return cp;
2624 return NULL;
2627 static int
2628 parse_args(const char *cmd, CmdParm *parms)
2630 while (1) {
2631 char *ptr;
2633 if (*cmd == ' ' || *cmd == '\t') {
2634 ++cmd;
2635 continue;
2637 if (parms == NULL || parms->type == -1) {
2638 if (*cmd == '\0')
2639 return 0;
2640 kprintf("Extra arg(s): %s\n", cmd);
2641 return 1;
2643 if (parms->type == PARM_DEVSPEC) {
2644 int i = 0;
2645 char devname[64];
2646 int unit = 0;
2648 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2649 (*cmd >= '0' && *cmd <= '9')))
2650 devname[i++] = *(cmd++);
2651 devname[i] = '\0';
2652 if (*cmd >= '0' && *cmd <= '9') {
2653 unit = strtoul(cmd, &ptr, 10);
2654 if (cmd == ptr) {
2655 kprintf("Invalid device number\n");
2656 /* XXX should print invalid token here and elsewhere. */
2657 return 1;
2659 /* XXX else should require end of token. */
2660 cmd = ptr;
2662 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2663 kprintf("No such device: %s%d\n", devname, unit);
2664 return 1;
2666 ++parms;
2667 continue;
2669 if (parms->type == PARM_INT) {
2670 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2671 if (cmd == ptr) {
2672 kprintf("Invalid numeric argument\n");
2673 return 1;
2675 cmd = ptr;
2676 ++parms;
2677 continue;
2679 if (parms->type == PARM_ADDR) {
2680 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2681 if (cmd == ptr) {
2682 kprintf("Invalid address argument\n");
2683 return 1;
2685 cmd = ptr;
2686 ++parms;
2687 continue;
2689 if (parms->type == PARM_STRING) {
2690 parms->parm.u.sparm = cmd;
2691 return 0;
2694 return 0;
2697 static int
2698 list_devices(CmdParm *parms)
2700 lineno = 0;
2701 if (lsdevtab(uc_devtab)) return 0;
2702 #if NPNP > 0
2703 if (lspnp()) return 0;
2704 #endif
2705 #if NEISA > 0
2706 kprintf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2707 #endif /* NEISA > 0 */
2708 return 0;
2711 static int
2712 set_device_ioaddr(CmdParm *parms)
2714 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2715 save_dev(parms[0].parm.dparm);
2716 return 0;
2719 static int
2720 set_device_irq(CmdParm *parms)
2722 unsigned irq;
2724 irq = parms[1].parm.iparm;
2725 if (irq == 2) {
2726 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2727 irq = 9;
2729 else if (irq != -1 && irq > 15) {
2730 kprintf("An IRQ > 15 would be invalid.\n");
2731 return 0;
2733 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2734 save_dev(parms[0].parm.dparm);
2735 return 0;
2738 static int
2739 set_device_drq(CmdParm *parms)
2741 unsigned drq;
2744 * The bounds checking is just to ensure that the value can be printed
2745 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2747 drq = parms[1].parm.iparm;
2748 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2749 save_dev(parms[0].parm.dparm);
2750 return 0;
2753 static int
2754 set_device_iosize(CmdParm *parms)
2756 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2757 save_dev(parms[0].parm.dparm);
2758 return 0;
2761 static int
2762 set_device_mem(CmdParm *parms)
2764 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2765 save_dev(parms[0].parm.dparm);
2766 return 0;
2769 static int
2770 set_device_flags(CmdParm *parms)
2772 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2773 save_dev(parms[0].parm.dparm);
2774 return 0;
2777 static int
2778 set_device_enable(CmdParm *parms)
2780 parms[0].parm.dparm->id_enabled = TRUE;
2781 save_dev(parms[0].parm.dparm);
2782 return 0;
2785 static int
2786 set_device_disable(CmdParm *parms)
2788 parms[0].parm.dparm->id_enabled = FALSE;
2789 save_dev(parms[0].parm.dparm);
2790 return 0;
2793 #if NPNP > 0
2795 static int
2796 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2798 int error=0;
2800 if(!req->oldptr) {
2801 /* Only sizing */
2802 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2803 } else {
2805 * Output the pnp_ldn_overrides[] table.
2807 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2808 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2809 if(error) return(error);
2810 return(0);
2814 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2815 0, 0, sysctl_machdep_uc_pnplist, "A",
2816 "List of PnP overrides changed in UserConfig");
2819 * this function sets the kernel table to override bios PnP
2820 * configuration.
2822 static int
2823 set_pnp_parms(CmdParm *parms)
2825 u_long idx, val, ldn, csn;
2826 int i;
2827 char *q;
2828 const char *p = parms[0].parm.u.sparm;
2829 struct pnp_cinfo d;
2831 csn=strtoul(p,&q, 0);
2832 ldn=strtoul(q,&q, 0);
2833 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2834 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2835 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2836 return 0;
2838 for (i=0; i < MAX_PNP_LDN; i++) {
2839 if (pnp_ldn_overrides[i].csn == csn &&
2840 pnp_ldn_overrides[i].ldn == ldn)
2841 break;
2843 if (i==MAX_PNP_LDN) {
2844 for (i=0; i < MAX_PNP_LDN; i++) {
2845 if (pnp_ldn_overrides[i].csn <1 ||
2846 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2847 break;
2850 if (i==MAX_PNP_LDN) {
2851 kprintf("sorry, no PnP entries available, try delete one\n");
2852 return 0 ;
2854 d = pnp_ldn_overrides[i] ;
2855 d.csn = csn;
2856 d.ldn = ldn ;
2857 while (*p) {
2858 idx = 0;
2859 val = 0;
2860 if (!strncmp(p,"irq",3)) {
2861 idx=strtoul(p+3,&q, 0);
2862 val=strtoul(q,&q, 0);
2863 if (idx >=0 && idx < 2) d.irq[idx] = val;
2864 } else if (!strncmp(p,"flags",5)) {
2865 idx=strtoul(p+5,&q, 0);
2866 d.flags = idx;
2867 } else if (!strncmp(p,"drq",3)) {
2868 idx=strtoul(p+3,&q, 0);
2869 val=strtoul(q,&q, 0);
2870 if (idx >=0 && idx < 2) d.drq[idx] = val;
2871 } else if (!strncmp(p,"port",4)) {
2872 idx=strtoul(p+4,&q, 0);
2873 val=strtoul(q,&q, 0);
2874 if (idx >=0 && idx < 8) d.port[idx] = val;
2875 } else if (!strncmp(p,"mem",3)) {
2876 idx=strtoul(p+3,&q, 0);
2877 val=strtoul(q,&q, 0);
2878 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2879 } else if (!strncmp(p,"bios",4)) {
2880 q = p+ 4;
2881 d.override = 0 ;
2882 } else if (!strncmp(p,"os",2)) {
2883 q = p+2 ;
2884 d.override = 1 ;
2885 } else if (!strncmp(p,"disable",7)) {
2886 q = p+7 ;
2887 d.enable = 0 ;
2888 } else if (!strncmp(p,"enable",6)) {
2889 q = p+6;
2890 d.enable = 1 ;
2891 } else if (!strncmp(p,"delete",6)) {
2892 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2893 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2894 return 0;
2895 } else {
2896 kprintf("unknown command <%s>\n", p);
2897 break;
2899 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2901 pnp_ldn_overrides[i] = d ;
2902 return 0;
2904 #endif /* NPNP */
2906 #if NEISA > 0
2907 static int
2908 set_num_eisa_slots(CmdParm *parms)
2910 int num_slots;
2912 num_slots = parms[0].parm.iparm;
2913 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2914 return 0;
2916 #endif /* NEISA > 0 */
2918 static int
2919 quitfunc(CmdParm *parms)
2922 * If kernel config supplied, and we are parsing it, and -c also supplied,
2923 * ignore a quit command, This provides a safety mechanism to allow
2924 * recovery from a damaged/buggy kernel config.
2926 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2927 return 0;
2928 return 1;
2931 static int
2932 helpfunc(CmdParm *parms)
2934 kprintf(
2935 "Command\t\t\tDescription\n"
2936 "-------\t\t\t-----------\n"
2937 "ls\t\t\tList currently configured devices\n"
2938 "port <devname> <addr>\tSet device port (i/o address)\n"
2939 "irq <devname> <number>\tSet device irq\n"
2940 "drq <devname> <number>\tSet device drq\n"
2941 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2942 "iosize <devname> <size>\tSet device memory size\n"
2943 "flags <devname> <mask>\tSet device flags\n"
2944 "enable <devname>\tEnable device\n"
2945 "disable <devname>\tDisable device (will not be probed)\n");
2946 #if NPNP > 0
2947 kprintf(
2948 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2949 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2950 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2951 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2952 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2953 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2954 #endif
2955 #if NEISA > 0
2956 kprintf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2957 #endif /* NEISA > 0 */
2958 kprintf(
2959 "quit\t\t\tExit this configuration utility\n"
2960 "reset\t\t\tReset CPU\n");
2961 #ifdef VISUAL_USERCONFIG
2962 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2963 #endif
2964 kprintf(
2965 "help\t\t\tThis message\n\n"
2966 "Commands may be abbreviated to a unique prefix\n");
2967 return 0;
2970 #if defined (VISUAL_USERCONFIG)
2971 static void
2972 center(int y, char *str)
2974 putxy((80 - strlen(str)) / 2, y, str);
2976 #endif
2978 static int
2979 introfunc(CmdParm *parms)
2981 #if defined (VISUAL_USERCONFIG)
2982 int curr_item, first_time, extended = 0;
2983 static char *choices[] = {
2984 " Skip kernel configuration and continue with installation ",
2985 " Start kernel configuration in full-screen visual mode ",
2986 " Start kernel configuration in CLI mode ",
2989 clear();
2990 center(2, "!bKernel Configuration Menu!n");
2992 curr_item = 0;
2993 first_time = 1;
2994 while (1) {
2995 char tmp[80];
2996 int c, i;
2998 if (!extended) {
2999 for (i = 0; i < 3; i++) {
3000 tmp[0] = '\0';
3001 if (curr_item == i)
3002 strcpy(tmp, "!i");
3003 strcat(tmp, choices[i]);
3004 if (curr_item == i)
3005 strcat(tmp, "!n");
3006 putxy(10, 5 + i, tmp);
3009 if (first_time) {
3010 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3011 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3012 putxy(2, 12, "match your hardware configuration.");
3013 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3014 putxy(2, 15, "(press Down-Arrow then ENTER).");
3015 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3016 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3017 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3018 putxy(2, 21, "then simply press ENTER or Q now.");
3019 first_time = 0;
3022 move(0, 0); /* move the cursor out of the way */
3024 c = kgetchar();
3025 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3026 extended = 0; /* no longer */
3027 switch (c) {
3028 case 588:
3029 case 'A': /* up */
3030 if (curr_item > 0)
3031 --curr_item;
3032 break;
3034 case 596:
3035 case 'B': /* down */
3036 if (curr_item < 2)
3037 ++curr_item;
3038 break;
3041 else {
3042 switch(c) {
3043 case '\033':
3044 extended = 1;
3045 break;
3047 case '[': /* cheat : always preceeds cursor move */
3048 case 'O': /* ANSI application key mode */
3049 if (extended == 1)
3050 extended = 2;
3051 else
3052 extended = 0;
3053 break;
3055 case -1:
3056 case 'Q':
3057 case 'q':
3058 clear();
3059 return 1; /* user requests exit */
3061 case '1': /* select an item */
3062 case 'S':
3063 case 's':
3064 curr_item = 0;
3065 break;
3066 case '2':
3067 case 'V':
3068 case 'v':
3069 curr_item = 1;
3070 break;
3071 case '3':
3072 case 'C':
3073 case 'c':
3074 curr_item = 2;
3075 break;
3077 case 'U': /* up */
3078 case 'u':
3079 case 'P':
3080 case 'p':
3081 if (curr_item > 0)
3082 --curr_item;
3083 break;
3085 case 'D': /* down */
3086 case 'd':
3087 case 'N':
3088 case 'n':
3089 if (curr_item < 2)
3090 ++curr_item;
3091 break;
3093 case '\r':
3094 case '\n':
3095 clear();
3096 if (!curr_item)
3097 return 1;
3098 else if (curr_item == 1)
3099 return visuserconfig();
3100 else {
3101 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3102 /* enable quitfunc */
3103 userconfig_boot_parsing=0;
3104 move (0, 3);
3105 boothowto |= RB_CONFIG; /* force -c */
3106 return 0;
3108 break;
3112 #endif
3115 #if NPNP > 0
3116 static int
3117 lspnp(void)
3119 struct pnp_cinfo *c;
3120 int i, first = 1;
3123 for (i=0; i< MAX_PNP_LDN; i++) {
3124 c = &pnp_ldn_overrides[i];
3125 if (c->csn >0 && c->csn != 255) {
3126 int pmax, mmax;
3127 static char pfmt[] =
3128 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3129 static char mfmt[] =
3130 "mem 0x%x 0x%x 0x%x 0x%x";
3131 char buf[256];
3132 if (lineno >= 23) {
3133 if (!userconfig_boot_parsing) {
3134 kprintf("<More> ");
3135 if (kgetchar() == 'q') {
3136 kprintf("quit\n");
3137 return (1);
3139 kprintf("\n");
3141 lineno = 0;
3143 if (lineno == 0 || first)
3144 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3145 first = 0 ;
3146 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3147 c->csn, c->ldn,
3148 c->override ? "OS ":"BIOS",
3149 c->enable ? "Y":"N",
3150 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3151 if (c->flags)
3152 kprintf("flags 0x%08lx ",c->flags);
3153 for (pmax = 7; pmax >=0 ; pmax--)
3154 if (c->port[pmax]!=0) break;
3155 for (mmax = 3; mmax >=0 ; mmax--)
3156 if (c->mem[mmax].base!=0) break;
3157 if (pmax>=0) {
3158 strcpy(buf, pfmt);
3159 buf[10 + 5*pmax]='\0';
3160 kprintf(buf,
3161 c->port[0], c->port[1], c->port[2], c->port[3],
3162 c->port[4], c->port[5], c->port[6], c->port[7]);
3164 if (mmax>=0) {
3165 strcpy(buf, mfmt);
3166 buf[8 + 5*mmax]='\0';
3167 kprintf(buf,
3168 c->mem[0].base, c->mem[1].base,
3169 c->mem[2].base, c->mem[3].base);
3171 kprintf("\n");
3174 return 0 ;
3176 #endif /* NPNP */
3178 static int
3179 lsdevtab(struct uc_device *dt)
3181 for (; dt->id_id != 0; dt++) {
3182 char dname[80];
3184 if (lineno >= 23) {
3185 kprintf("<More> ");
3186 if (!userconfig_boot_parsing) {
3187 if (kgetchar() == 'q') {
3188 kprintf("quit\n");
3189 return (1);
3191 kprintf("\n");
3193 lineno = 0;
3195 if (lineno == 0) {
3196 kprintf(
3197 "Device port irq drq iomem iosize unit flags enab\n"
3199 ++lineno;
3201 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3202 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3203 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3204 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3205 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3206 dt->id_enabled ? "Yes" : "No");
3207 ++lineno;
3209 return(0);
3212 static void
3213 load_devtab(void)
3215 int i, val;
3216 int count = resource_count();
3217 int id = 1;
3218 int dt;
3219 char *name;
3220 int unit;
3222 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3223 M_WAITOK | M_ZERO);
3224 dt = 0;
3225 for (i = 0; i < count; i++) {
3226 name = resource_query_name(i);
3227 unit = resource_query_unit(i);
3228 if (unit < 0)
3229 continue; /* skip wildcards */
3230 uc_devtab[dt].id_id = id++;
3231 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3232 val = 0;
3233 resource_int_value(name, unit, "irq", &val);
3234 uc_devtab[dt].id_irq = (1 << val);
3235 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3236 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3237 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3238 uc_devtab[dt].id_unit = unit;
3239 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3240 val = 0;
3241 resource_int_value(name, unit, "disabled", &val);
3242 uc_devtab[dt].id_enabled = !val;
3243 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3244 strcpy(uc_devtab[dt].id_name, name);
3245 dt++;
3249 static void
3250 free_devtab(void)
3252 int i;
3253 int count = resource_count();
3255 for (i = 0; i < count; i++)
3256 if (uc_devtab[i].id_name)
3257 kfree(uc_devtab[i].id_name, M_DEVL);
3258 kfree(uc_devtab, M_DEVL);
3261 static struct uc_device *
3262 find_device(char *devname, int unit)
3264 struct uc_device *ret;
3266 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3267 return ret;
3268 return NULL;
3271 static struct uc_device *
3272 search_devtable(struct uc_device *dt, char *devname, int unit)
3274 int i;
3276 for (i = 0; dt->id_id != 0; dt++)
3277 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3278 return dt;
3279 return NULL;
3282 static void
3283 cngets(char *input, int maxin)
3285 int c, nchars = 0;
3287 while (1) {
3288 c = kgetchar();
3289 /* Treat ^H or ^? as backspace */
3290 if ((c == '\010' || c == '\177')) {
3291 if (nchars) {
3292 kprintf("\010 \010");
3293 *--input = '\0', --nchars;
3295 continue;
3297 /* Treat ^U or ^X as kill line */
3298 else if ((c == '\025' || c == '\030')) {
3299 while (nchars) {
3300 kprintf("\010 \010");
3301 *--input = '\0', --nchars;
3303 continue;
3305 kprintf("%c", c);
3306 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3307 *input = '\0';
3308 break;
3310 *input++ = (u_char)c;
3315 #if 0
3316 /* scsi: Support for displaying configured SCSI devices.
3317 * There is no way to edit them, and this is inconsistent
3318 * with the ISA method. This is here as a basis for further work.
3320 static char *
3321 type_text(char *name) /* XXX: This is bogus */
3323 if (strcmp(name, "sd") == 0)
3324 return "disk";
3326 if (strcmp(name, "st") == 0)
3327 return "tape";
3329 return "device";
3332 id_put(char *desc, int id)
3334 if (id != SCCONF_UNSPEC)
3336 if (desc)
3337 kprintf("%s", desc);
3339 if (id == SCCONF_ANY)
3340 kprintf("?");
3341 else
3342 kprintf("%d", id);
3346 static void
3347 lsscsi(void)
3349 int i;
3351 kprintf("scsi: (can't be edited):\n");
3353 for (i = 0; scsi_cinit[i].driver; i++)
3355 id_put("controller scbus", scsi_cinit[i].scbus);
3357 if (scsi_cinit[i].unit != -1)
3359 kprintf(" at ");
3360 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3363 kprintf("\n");
3366 for (i = 0; scsi_dinit[i].name; i++)
3368 kprintf("%s ", type_text(scsi_dinit[i].name));
3370 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3371 id_put(" at scbus", scsi_dinit[i].cunit);
3372 id_put(" target ", scsi_dinit[i].target);
3373 id_put(" lun ", scsi_dinit[i].lun);
3375 if (scsi_dinit[i].flags)
3376 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3378 kprintf("\n");
3382 static int
3383 list_scsi(CmdParm *parms)
3385 lineno = 0;
3386 lsscsi();
3387 return 0;
3389 #endif
3391 static void
3392 save_resource(struct uc_device *idev)
3394 char *name;
3395 int unit;
3397 name = idev->id_name;
3398 unit = idev->id_unit;
3399 resource_set_int(name, unit, "port", idev->id_iobase);
3400 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3401 resource_set_int(name, unit, "drq", idev->id_drq);
3402 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3403 resource_set_int(name, unit, "msize", idev->id_msize);
3404 resource_set_int(name, unit, "flags", idev->id_flags);
3405 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3408 static int
3409 save_dev(struct uc_device *idev)
3411 struct uc_device *id_p,*id_pn;
3412 char *name = idev->id_name;
3414 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3415 if (id_p->id_id == idev->id_id) {
3416 id_pn = id_p->id_next;
3417 if (id_p->id_name)
3418 kfree(id_p->id_name, M_DEVL);
3419 bcopy(idev,id_p,sizeof(struct uc_device));
3420 save_resource(idev);
3421 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3422 strcpy(id_p->id_name, name);
3423 id_p->id_next = id_pn;
3424 return 1;
3427 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3428 bcopy(idev,id_pn,sizeof(struct uc_device));
3429 save_resource(idev);
3430 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3431 strcpy(id_pn->id_name, name);
3432 id_pn->id_next = uc_devlist;
3433 uc_devlist = id_pn;
3434 return 0;