Rename sprintf -> ksprintf
[dfdiff.git] / sys / platform / pc32 / i386 / userconfig.c
blob174f8efe3edf78e2dd259e7ac4e067a66a6ee0b9
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.11 2006/12/20 18:14:42 dillon 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 {"mcd", "Mitsumi CD-ROM", 0, CLS_STORAGE},
345 {"scd", "Sony CD-ROM", 0, CLS_STORAGE},
346 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE},
347 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
348 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
349 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
351 {"cm", "SMC COM90Cx6-based Arcnet adapters", 0, CLS_NETWORK},
352 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
353 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
354 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
355 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
356 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
357 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
358 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
359 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
360 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
361 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
362 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
363 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
364 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
366 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
367 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
368 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
369 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
370 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
371 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
372 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
373 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
374 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
375 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
377 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
378 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
379 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
380 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
381 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
382 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
384 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
385 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
386 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
387 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
388 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
389 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
390 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
391 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
392 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
393 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
394 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
395 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
396 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
397 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
398 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
399 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
400 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
401 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
402 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
403 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
404 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
405 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
407 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
408 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
409 {"pcic", "PC-card controller", 0, CLS_MISC},
410 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
411 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
412 {"","",0,0}};
415 typedef struct _devlist_struct
417 char name[80];
418 int attrib; /* flag values as per the FLG_* defines above */
419 int class; /* disk, etc as per the CLS_* defines above */
420 char dev[16];
421 int iobase,irq,drq,maddr,msize,unit,flags,id;
422 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
423 int conflicts; /* set/reset by findconflict, count of conflicts */
424 int changed; /* nonzero if the device has been edited */
425 struct uc_device *device;
426 struct _devlist_struct *prev,*next;
427 } DEV_LIST;
430 #define DEV_DEVICE 0
431 #define DEV_COMMENT 1
432 #define DEV_ZOOMED 2
434 #define LIST_CURRENT (1<<0)
435 #define LIST_SELECTED (1<<1)
437 #define KEY_EXIT 0 /* return codes from dolist() and friends */
438 #define KEY_DO 1
439 #define KEY_DEL 2
440 #define KEY_TAB 3
441 #define KEY_REDRAW 4
443 #define KEY_UP 5 /* these only returned from editval() */
444 #define KEY_DOWN 6
445 #define KEY_LEFT 7
446 #define KEY_RIGHT 8
447 #define KEY_NULL 9 /* this allows us to spin & redraw */
449 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
450 #define KEY_UNZOOM 11
452 #define KEY_HELP 12 /* duh? */
454 static void redraw(void);
455 static void insdev(DEV_LIST *dev, DEV_LIST *list);
456 static int devinfo(DEV_LIST *dev);
457 static int visuserconfig(void);
459 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
460 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
461 static DEV_LIST scratch; /* scratch record */
462 static int conflicts; /* total conflict count */
465 static char lines[] = "--------------------------------------------------------------------------------";
466 static char spaces[] = " ";
470 ** Device manipulation stuff : find, describe, configure.
474 ** setdev
476 ** Sets the device referenced by (*dev) to the parameters in the struct,
477 ** and the enable flag according to (enabled)
479 static void
480 setdev(DEV_LIST *dev, int enabled)
482 dev->device->id_iobase = dev->iobase; /* copy happy */
483 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
484 dev->device->id_drq = (short)dev->drq;
485 dev->device->id_maddr = (caddr_t)dev->maddr;
486 dev->device->id_msize = dev->msize;
487 dev->device->id_flags = dev->flags;
488 dev->device->id_enabled = enabled;
493 ** getdevs
495 ** Walk the kernel device tables and build the active and inactive lists
497 static void
498 getdevs(void)
500 int i;
501 struct uc_device *ap;
503 ap = uc_devtab; /* pointer to array of devices */
504 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
506 scratch.unit = ap[i].id_unit; /* device parameters */
507 strcpy(scratch.dev,ap[i].id_name);
508 scratch.iobase = ap[i].id_iobase;
509 scratch.irq = ffs(ap[i].id_irq)-1;
510 scratch.drq = ap[i].id_drq;
511 scratch.maddr = (int)ap[i].id_maddr;
512 scratch.msize = ap[i].id_msize;
513 scratch.flags = ap[i].id_flags;
515 scratch.comment = DEV_DEVICE; /* admin stuff */
516 scratch.conflicts = 0;
517 scratch.device = &ap[i]; /* save pointer for later reference */
518 scratch.changed = 0;
519 if (!devinfo(&scratch)) /* get more info on the device */
520 insdev(&scratch,ap[i].id_enabled?active:inactive);
526 ** Devinfo
528 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
529 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
531 ** If the device is marked "invisible", return nonzero; the caller should
532 ** not insert any such device into either list.
535 static int
536 devinfo(DEV_LIST *dev)
538 int i;
540 for (i = 0; device_info[i].class; i++)
542 if (!strcmp(dev->dev,device_info[i].dev))
544 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
545 return(1);
546 strcpy(dev->name,device_info[i].name); /* get the name */
547 dev->attrib = device_info[i].attrib;
548 dev->class = device_info[i].class;
549 return(0);
552 strcpy(dev->name,"Unknown device");
553 dev->attrib = 0;
554 dev->class = CLS_MISC;
555 return(0);
560 ** List manipulation stuff : add, move, initialise, free, traverse
562 ** Note that there are assumptions throughout this code that
563 ** the first entry in a list will never move. (assumed to be
564 ** a comment).
569 ** Adddev
571 ** appends a copy of (dev) to the end of (*list)
573 static void
574 addev(DEV_LIST *dev, DEV_LIST **list)
577 DEV_LIST *lp,*ap;
579 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
580 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
582 if (*list) /* list exists */
584 ap = *list;
585 while(ap->next)
586 ap = ap->next; /* scoot to end of list */
587 lp->prev = ap;
588 lp->next = NULL;
589 ap->next = lp;
590 }else{ /* list does not yet exist */
591 *list = lp;
592 lp->prev = lp->next = NULL; /* list now exists */
598 ** Findspot
600 ** Finds the 'appropriate' place for (dev) in (list)
602 ** 'Appropriate' means in numeric order with other devices of the same type,
603 ** or in alphabetic order following a comment of the appropriate type.
604 ** or at the end of the list if an appropriate comment is not found. (this should
605 ** never happen)
606 ** (Note that the appropriate point is never the top, but may be the bottom)
608 static DEV_LIST *
609 findspot(DEV_LIST *dev, DEV_LIST *list)
611 DEV_LIST *ap = NULL;
613 /* search for a previous instance of the same device */
614 for (ap = list; ap; ap = ap->next)
616 if (ap->comment != DEV_DEVICE) /* ignore comments */
617 continue;
618 if (!strcmp(dev->dev,ap->dev)) /* same base device */
620 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
621 || !ap->next) /* or end of list */
623 ap = ap->prev; /* back up one */
624 break; /* done here */
626 if (ap->next) /* if the next item exists */
628 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
629 break;
630 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
631 break;
636 if (!ap) /* not sure yet */
638 /* search for a class that the device might belong to */
639 for (ap = list; ap; ap = ap->next)
641 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
642 continue;
643 if (dev->class != ap->class) /* of same class too 8) */
644 continue;
645 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
647 ap = ap->prev; /* back up one */
648 break; /* done here */
650 if (ap->next) /* if the next item exists */
651 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
652 break;
656 if (!ap) /* didn't find a match */
658 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
659 if ((ap->comment != DEV_DEVICE)
660 && (ap->class == dev->class)) /* appropriate place? */
661 break;
662 } /* or just put up with last */
664 return(ap);
669 ** Insdev
671 ** Inserts a copy of (dev) at the appropriate point in (list)
673 static void
674 insdev(DEV_LIST *dev, DEV_LIST *list)
676 DEV_LIST *lp,*ap;
678 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
679 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
681 ap = findspot(lp,list); /* find appropriate spot */
682 lp->next = ap->next; /* point to next */
683 if (ap->next)
684 ap->next->prev = lp; /* point next to new */
685 lp->prev = ap; /* point new to current */
686 ap->next = lp; /* and current to new */
691 ** Movedev
693 ** Moves (dev) from its current list to an appropriate place in (list)
694 ** (dev) may not come from the top of a list, but it may from the bottom.
696 static void
697 movedev(DEV_LIST *dev, DEV_LIST *list)
699 DEV_LIST *ap;
701 ap = findspot(dev,list);
702 dev->prev->next = dev->next; /* remove from old list */
703 if (dev->next)
704 dev->next->prev = dev->prev;
706 dev->next = ap->next; /* insert in new list */
707 if (ap->next)
708 ap->next->prev = dev; /* point next to new */
709 dev->prev = ap; /* point new to current */
710 ap->next = dev; /* and current to new */
715 ** Initlist
717 ** Initialises (*list) with the basic headings
719 static void
720 initlist(DEV_LIST **list)
722 int i;
724 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
726 strcpy(scratch.name,devclass_names[i].name);
727 scratch.comment = DEV_ZOOMED;
728 scratch.class = devclass_names[i].number;
729 scratch.attrib = FLG_MANDATORY; /* can't be moved */
730 addev(&scratch,list); /* add to the list */
736 ** savelist
738 ** Walks (list) and saves the settings of any entry marked as changed.
740 ** The device's active field is set according to (active).
742 ** Builds the uc_devlist used by kget to extract the changed device information.
743 ** The code for this was taken almost verbatim from the original module.
745 static void
746 savelist(DEV_LIST *list, int active)
748 struct uc_device *id_p,*id_pn;
749 char *name;
751 while (list)
753 if ((list->comment == DEV_DEVICE) && /* is a device */
754 (list->changed) && /* has been changed */
755 (list->device != NULL)) { /* has an uc_device structure */
757 setdev(list,active); /* set the device itself */
759 id_pn = NULL;
760 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
761 { /* look on the list for it */
762 if (id_p->id_id == list->device->id_id)
764 name = list->device->id_name;
765 id_pn = id_p->id_next;
766 if (id_p->id_name)
767 kfree(id_p->id_name, M_DEVL);
768 bcopy(list->device,id_p,sizeof(struct uc_device));
769 save_resource(list->device);
770 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
771 strcpy(id_p->id_name, name);
772 id_pn->id_next = uc_devlist;
773 id_p->id_next = id_pn;
774 break;
777 if (!id_pn) /* not already on the list */
779 name = list->device->id_name;
780 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
781 bcopy(list->device,id_pn,sizeof(struct uc_device));
782 save_resource(list->device);
783 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
784 strcpy(id_pn->id_name, name);
785 id_pn->id_next = uc_devlist;
786 uc_devlist = id_pn; /* park at top of list */
789 list = list->next;
795 ** nukelist
797 ** Frees all storage in use by a (list).
799 static void
800 nukelist(DEV_LIST *list)
802 DEV_LIST *dp;
804 if (!list)
805 return;
806 while(list->prev) /* walk to head of list */
807 list = list->prev;
809 while(list)
811 dp = list;
812 list = list->next;
813 kfree(dp,M_DEVL);
819 ** prevent
821 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
822 ** if there is no previous entry. (Only possible if list->prev == NULL given the
823 ** premise that there is always a comment at the head of the list)
825 static DEV_LIST *
826 prevent(DEV_LIST *list)
828 DEV_LIST *dp;
830 if (!list)
831 return(NULL);
832 dp = list->prev; /* start back one */
833 while(dp)
835 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
836 return(dp); /* so skip to comment */
837 if (dp->comment == DEV_COMMENT) /* not zoomed */
838 return(list->prev); /* one back as normal */
839 dp = dp->prev; /* backpedal */
841 return(dp); /* NULL, we can assume */
846 ** nextent
848 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
849 ** if there is no next entry. (Possible if the current entry is last, or
850 ** if the current entry is the last heading and it's collapsed)
852 static DEV_LIST *
853 nextent(DEV_LIST *list)
855 DEV_LIST *dp;
857 if (!list)
858 return(NULL);
859 if (list->comment != DEV_ZOOMED) /* no reason to skip */
860 return(list->next);
861 dp = list->next;
862 while(dp)
864 if (dp->comment != DEV_DEVICE) /* found another heading */
865 break;
866 dp = dp->next;
868 return(dp); /* back we go */
873 ** ofsent
875 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
877 static DEV_LIST *
878 ofsent(int ofs, DEV_LIST *list)
880 while (ofs-- && list)
881 list = nextent(list);
882 return(list);
887 ** findconflict
889 ** Scans every element of (list) and sets the conflict tags appropriately
890 ** Returns the number of conflicts found.
892 static int
893 findconflict(DEV_LIST *list)
895 int count = 0; /* number of conflicts found */
896 DEV_LIST *dp,*sp;
898 for (dp = list; dp; dp = dp->next) /* over the whole list */
900 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
901 continue;
903 dp->conflicts = 0; /* assume the best */
904 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
906 if (sp->comment != DEV_DEVICE) /* likewise */
907 continue;
909 if (sp == dp) /* always conflict with itself */
910 continue;
912 if ((dp->iobase > 0) && /* iobase conflict? */
913 (dp->iobase == sp->iobase))
914 dp->conflicts = 1;
915 if ((dp->irq > 0) && /* irq conflict? */
916 (dp->irq == sp->irq))
917 dp->conflicts = 1;
918 if ((dp->drq > 0) && /* drq conflict? */
919 (dp->drq == sp->drq))
920 dp->conflicts = 1;
921 if ((sp->maddr > 0) && /* maddr/msize conflict? */
922 (dp->maddr > 0) &&
923 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
924 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
925 dp->conflicts = 1;
927 count += dp->conflicts; /* count conflicts */
929 return(count);
934 ** expandlist
936 ** Unzooms all headings in (list)
938 static void
939 expandlist(DEV_LIST *list)
941 while(list)
943 if (list->comment == DEV_COMMENT)
944 list->comment = DEV_ZOOMED;
945 list = list->next;
951 ** collapselist
953 ** Zooms all headings in (list)
955 static void
956 collapselist(DEV_LIST *list)
958 while(list)
960 if (list->comment == DEV_ZOOMED)
961 list->comment = DEV_COMMENT;
962 list = list->next;
968 ** Screen-manipulation stuff
970 ** This is the basic screen layout :
972 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
973 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
974 ** +--------------------------------------------------------------------------------+
975 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
976 ** 1 -| ........................ ....... .. 0x....|
977 ** 2 -| ........................ ....... .. 0x....|
978 ** 3 -| ........................ ....... .. 0x....|
979 ** 4 -| ........................ ....... .. 0x....|
980 ** 5 -| ........................ ....... .. 0x....|
981 ** 6 -| ........................ ....... .. 0x....|
982 ** 7 -| ........................ ....... .. 0x....|
983 ** 8 -| ........................ ....... .. 0x....|
984 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
985 ** 10-| ........................ ....... |
986 ** 11-| ........................ ....... |
987 ** 12-| ........................ ....... |
988 ** 13-| ........................ ....... |
989 ** 14-| ........................ ....... |
990 ** 15-| ........................ ....... |
991 ** 16-| ........................ ....... |
992 ** 17-|------------------------------------------------------UP-DOWN-------------------|
993 ** 18-| Relevant parameters for the current device |
994 ** 19-| |
995 ** 20-| |
996 ** 21-|--------------------------------------------------------------------------------|
997 ** 22-| Help texts go here |
998 ** 23-| |
999 ** +--------------------------------------------------------------------------------+
1001 ** Help texts
1003 ** On a collapsed comment :
1005 ** [Enter] Expand device list [z] Expand all lists
1006 ** [TAB] Change fields [Q] Save and Exit
1008 ** On an expanded comment :
1010 ** [Enter] Collapse device list [Z] Collapse all lists
1011 ** [TAB] Change fields [Q] Save and Exit
1013 ** On a comment with no followers
1016 ** [TAB] Change fields [Q] Save and Exit
1018 ** On a device in the active list
1020 ** [Enter] Edit device parameters [DEL] Disable device
1021 ** [TAB] Change fields [Q] Save and Exit [?] Help
1023 ** On a device in the inactive list
1025 ** [Enter] Enable device
1026 ** [TAB] Change fields [Q] Save and Exit [?] Help
1028 ** While editing parameters
1030 ** <parameter-specific help here>
1031 ** [TAB] Change fields [Q] Save device parameters
1038 ** The base-level screen primitives :
1040 ** bold() - enter bold mode \E[1m (md)
1041 ** inverse() - enter inverse mode \E[7m (so)
1042 ** normal() - clear bold/inverse mode \E[m (se)
1043 ** clear() - clear the screen \E[H\E[J (ce)
1044 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1047 static void
1048 bold(void)
1050 printf("\033[1m");
1053 static void
1054 inverse(void)
1056 printf("\033[7m");
1059 static void
1060 normal(void)
1062 printf("\033[m");
1065 static void
1066 clear(void)
1068 normal();
1069 printf("\033[H\033[J");
1072 static void
1073 move(int x, int y)
1075 printf("\033[%d;%dH",y+1,x+1);
1081 ** High-level screen primitives :
1083 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1084 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1085 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1086 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1087 ** putmsg(str) - put (str) in the message area
1088 ** puthelp(str) - put (str) in the upper helpline
1089 ** pad(str,len) - pad (str) to (len) with spaces
1090 ** drawline(row,detail,list,inverse,*dhelp)
1091 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1092 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1093 ** draw the line in inverse video, and display (*dhelp) on the
1094 ** helpline.
1095 ** drawlist(row,num,detail,list)
1096 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1097 ** through to drawline().
1098 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1099 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1100 ** redraw(); - Redraws the entire screen layout, including the
1101 ** - two list panels.
1104 /**
1105 ** putxy
1106 ** writes (str) at x,y onscreen
1107 ** putxyl
1108 ** writes up to (len) of (str) at x,y onscreen.
1110 ** Supports embedded formatting :
1111 ** !i - inverse mode.
1112 ** !b - bold mode.
1113 ** !n - normal mode.
1115 static void
1116 putxyl(int x, int y, char *str, int len)
1118 move(x,y);
1119 normal();
1121 while((*str) && (len--))
1123 if (*str == '!') /* format escape? */
1125 switch(*(str+1)) /* depending on the next character */
1127 case 'i':
1128 inverse();
1129 str +=2; /* skip formatting */
1130 len++; /* doesn't count for length */
1131 break;
1133 case 'b':
1134 bold();
1135 str +=2; /* skip formatting */
1136 len++; /* doesn't count for length */
1137 break;
1139 case 'n':
1140 normal();
1141 str +=2; /* skip formatting */
1142 len++; /* doesn't count for length */
1143 break;
1145 default:
1146 cnputc(*str++); /* not an escape */
1148 }else{
1149 cnputc(*str++); /* emit the character */
1154 #define putxy(x,y,str) putxyl(x,y,str,-1)
1158 ** erase
1160 ** Erases the region (x,y,w,h)
1162 static void
1163 erase(int x, int y, int w, int h)
1165 int i;
1167 normal();
1168 for (i = 0; i < h; i++)
1169 putxyl(x,y++,spaces,w);
1173 /**
1174 ** txtbox
1176 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1177 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1179 static void
1180 txtbox(int x, int y, int w, int h, char *str)
1182 int i = 0;
1184 h--;
1185 while((str[i]) && h)
1187 if (str[i] == '\n') /* newline */
1189 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1190 y++; /* move down */
1191 h--; /* room for one less */
1192 str += (i+1); /* skip first newline */
1193 i = 0; /* zero offset */
1194 }else{
1195 i++; /* next character */
1198 if (h) /* end of string, not region */
1199 putxyl(x,y,str,w);
1204 ** putmsg
1206 ** writes (msg) in the helptext area
1208 static void
1209 putmsg(char *msg)
1211 erase(0,18,80,3); /* clear area */
1212 txtbox(0,18,80,3,msg);
1217 ** puthelp
1219 ** Writes (msg) in the helpline area
1221 static void
1222 puthelp(char *msg)
1224 erase(0,22,80,1);
1225 putxy(0,22,msg);
1230 ** masterhelp
1232 ** Draws the help message at the bottom of the screen
1234 static void
1235 masterhelp(char *msg)
1237 erase(0,23,80,1);
1238 putxy(0,23,msg);
1243 ** pad
1245 ** space-pads a (str) to (len) characters
1247 static void
1248 pad(char *str, int len)
1250 int i;
1252 for (i = 0; str[i]; i++) /* find the end of the string */
1254 if (i >= len) /* no padding needed */
1255 return;
1256 while(i < len) /* pad */
1257 str[i++] = ' ';
1258 str[i] = '\0';
1263 ** drawline
1265 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1266 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1268 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1269 ** help is shown for normal or zoomed comments
1271 static void
1272 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1274 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1276 if (list->comment == DEV_DEVICE)
1278 nb[0] = ' ';
1279 strncpy(nb+1,list->name,57);
1280 }else{
1281 strncpy(nb,list->name,58);
1282 if ((list->comment == DEV_ZOOMED) && (list->next))
1283 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1284 strcat(nb," (Collapsed)");
1286 nb[58] = '\0';
1287 pad(nb,60);
1288 if (list->conflicts) /* device in conflict? */
1290 if (inverse)
1292 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1293 }else{
1294 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1297 if (list->comment == DEV_DEVICE)
1299 ksprintf(db,"%s%d",list->dev,list->unit);
1300 pad(db,8);
1301 }else{
1302 strcpy(db," ");
1304 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1306 ksprintf(ib," %d",list->irq);
1307 pad(ib,4);
1308 }else{
1309 strcpy(ib," ");
1311 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1313 ksprintf(pb,"0x%x",list->iobase);
1314 pad(pb,7);
1315 }else{
1316 strcpy(pb," ");
1319 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1321 putxyl(0,row,lbuf,80);
1322 if (dhelp)
1324 switch(list->comment)
1326 case DEV_DEVICE: /* ordinary device */
1327 puthelp(dhelp);
1328 break;
1329 case DEV_COMMENT:
1330 puthelp("");
1331 if (list->next)
1332 if (list->next->comment == DEV_DEVICE)
1333 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1334 break;
1335 case DEV_ZOOMED:
1336 puthelp("");
1337 if (list->next)
1338 if (list->next->comment == DEV_DEVICE)
1339 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1340 break;
1341 default:
1342 puthelp(" WARNING: This list entry corrupted!");
1343 break;
1346 move(0,row); /* put the cursor somewhere relevant */
1351 ** drawlist
1353 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1354 ** port and IRQ fields as well if (detail) is nonzero
1356 ** printf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1358 static void
1359 drawlist(int row, int num, int detail, DEV_LIST *list)
1361 int ofs;
1363 for(ofs = 0; ofs < num; ofs++)
1365 if (list)
1367 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1368 list = nextent(list); /* move down visible list */
1369 }else{
1370 erase(0,row+ofs,80,1);
1377 ** redrawactive
1379 ** Redraws the active list
1381 static void
1382 redrawactive(void)
1384 char cbuf[16];
1386 if (conflicts)
1388 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1389 putxy(45,0,cbuf);
1390 }else{
1391 putxyl(45,0,lines,16);
1393 drawlist(1,8,1,alist); /* draw device lists */
1397 ** redrawinactive
1399 ** Redraws the inactive list
1401 static void
1402 redrawinactive(void)
1404 drawlist(10,7,0,ilist); /* draw device lists */
1409 ** redraw
1411 ** Clear the screen and redraw the entire layout
1413 static void
1414 redraw(void)
1416 clear();
1417 putxy(0,0,lines);
1418 putxy(3,0,"!bActive!n-!bDrivers");
1419 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1420 putxy(0,9,lines);
1421 putxy(3,9,"!bInactive!n-!bDrivers");
1422 putxy(63,9,"!bDev");
1423 putxy(0,17,lines);
1424 putxy(0,21,lines);
1425 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1427 redrawactive();
1428 redrawinactive();
1433 ** yesnocancel
1435 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1436 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1438 static int
1439 yesnocancel(char *str)
1442 putmsg(str);
1443 for(;;)
1444 switch(kgetchar())
1446 case -1:
1447 case 'n':
1448 case 'N':
1449 return(0);
1451 case 'y':
1452 case 'Y':
1453 return(1);
1455 case 'c':
1456 case 'C':
1457 return(2);
1463 ** showparams
1465 ** Show device parameters in the region below the lists
1467 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1468 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1469 ** +--------------------------------------------------------------------------------+
1470 ** 17-|--------------------------------------------------------------------------------|
1471 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1472 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1473 ** 20-| Flags : 0x0000 DRQ number : 00 |
1474 ** 21-|--------------------------------------------------------------------------------|
1476 static void
1477 showparams(DEV_LIST *dev)
1479 char buf[80];
1481 erase(0,18,80,3); /* clear area */
1482 if (!dev)
1483 return;
1484 if (dev->comment != DEV_DEVICE)
1485 return;
1488 if (dev->iobase > 0)
1490 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1491 putxy(1,18,buf);
1494 if (dev->irq > 0)
1496 ksprintf(buf,"IRQ number : %d",dev->irq);
1497 putxy(1,19,buf);
1499 ksprintf(buf,"Flags : 0x%x",dev->flags);
1500 putxy(1,20,buf);
1501 if (dev->maddr > 0)
1503 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1504 putxy(26,18,buf);
1506 if (dev->msize > 0)
1508 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1509 putxy(26,19,buf);
1512 if (dev->drq > 0)
1514 ksprintf(buf,"DRQ number : %d",dev->drq);
1515 putxy(26,20,buf);
1521 ** Editing functions for device parameters
1523 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1524 ** onscreen. Refuse values outsise (min) and (max).
1525 ** editparams(dev) - Edit the parameters for (dev)
1529 #define VetRet(code) \
1531 if ((i >= min) && (i <= max)) /* legit? */ \
1533 *val = i; \
1534 ksprintf(buf,hex?"0x%x":"%d",i); \
1535 putxy(hex?x-2:x,y,buf); \
1536 return(code); /* all done and exit */ \
1538 i = *val; /* restore original value */ \
1539 delta = 1; /* restore other stuff */ \
1544 ** editval
1546 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1547 ** in a field (width) wide. (Allow one space)
1548 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1550 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1552 static int
1553 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1555 int i = *val; /* work with copy of the value */
1556 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1557 int xp = 0; /* cursor offset into text copy */
1558 int delta = 1; /* force redraw first time in */
1559 int c;
1560 int extended = 0; /* stage counter for extended key sequences */
1562 if (hex) /* we presume there's a leading 0x onscreen */
1563 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1565 for (;;)
1567 if (delta) /* only update if necessary */
1569 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1570 ksprintf(buf,"!i%s",tc); /* format for printing */
1571 erase(x,y,width,1); /* clear the area */
1572 putxy(x,y,buf); /* write */
1573 xp = strlen(tc); /* cursor always at end */
1574 move(x+xp,y); /* position the cursor */
1577 c = kgetchar();
1579 switch(extended) /* escape handling */
1581 case 0:
1582 if (c == 0x1b) /* esc? */
1584 extended = 1; /* flag and spin */
1585 continue;
1587 extended = 0;
1588 break; /* nope, drop through */
1590 case 1: /* there was an escape prefix */
1591 if (c == '[' || c == 'O') /* second character in sequence */
1593 extended = 2;
1594 continue;
1596 if (c == 0x1b)
1597 return(KEY_EXIT); /* double esc exits */
1598 extended = 0;
1599 break; /* nup, not a sequence. */
1601 case 2:
1602 extended = 0;
1603 switch(c) /* looks like the real McCoy */
1605 case 'A':
1606 VetRet(KEY_UP); /* leave if OK */
1607 continue;
1608 case 'B':
1609 VetRet(KEY_DOWN); /* leave if OK */
1610 continue;
1611 case 'C':
1612 VetRet(KEY_RIGHT); /* leave if OK */
1613 continue;
1614 case 'D':
1615 VetRet(KEY_LEFT); /* leave if OK */
1616 continue;
1618 default:
1619 continue;
1623 switch(c)
1625 case '\t': /* trying to tab off */
1626 VetRet(KEY_TAB); /* verify and maybe return */
1627 break;
1629 case -1:
1630 case 'q':
1631 case 'Q':
1632 VetRet(KEY_EXIT);
1633 break;
1635 case '\b':
1636 case '\177': /* BS or DEL */
1637 if (ro) /* readonly? */
1639 puthelp(" !iThis value cannot be edited (Press ESC)");
1640 while(kgetchar() != 0x1b); /* wait for key */
1641 return(KEY_NULL); /* spin */
1643 if (xp) /* still something left to delete */
1645 i = (hex ? i/0x10u : i/10); /* strip last digit */
1646 delta = 1; /* force update */
1648 break;
1650 case 588:
1651 VetRet(KEY_UP);
1652 break;
1654 case '\r':
1655 case '\n':
1656 case 596:
1657 VetRet(KEY_DOWN);
1658 break;
1660 case 591:
1661 VetRet(KEY_LEFT);
1662 break;
1664 case 593:
1665 VetRet(KEY_RIGHT);
1666 break;
1668 default:
1669 if (ro) /* readonly? */
1671 puthelp(" !iThis value cannot be edited (Press ESC)");
1672 while(kgetchar() != 0x1b); /* wait for key */
1673 return(KEY_NULL); /* spin */
1675 if (xp >= width) /* no room for more characters anyway */
1676 break;
1677 if (hex)
1679 if ((c >= '0') && (c <= '9'))
1681 i = i*0x10 + (c-'0'); /* update value */
1682 delta = 1;
1683 break;
1685 if ((c >= 'a') && (c <= 'f'))
1687 i = i*0x10 + (c-'a'+0xa);
1688 delta = 1;
1689 break;
1691 if ((c >= 'A') && (c <= 'F'))
1693 i = i*0x10 + (c-'A'+0xa);
1694 delta = 1;
1695 break;
1697 }else{
1698 if ((c >= '0') && (c <= '9'))
1700 i = i*10 + (c-'0'); /* update value */
1701 delta = 1; /* force redraw */
1702 break;
1705 break;
1712 ** editparams
1714 ** Edit the parameters for (dev)
1716 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1717 ** possible for this to spin in an endless loop...
1718 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1719 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1720 ** +--------------------------------------------------------------------------------+
1721 ** 17-|--------------------------------------------------------------------------------|
1722 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1723 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1724 ** 20-| Flags : 0x0000 DRQ number : 00 |
1725 ** 21-|--------------------------------------------------------------------------------|
1727 ** The "intelligence" in this function that hops around based on the directional
1728 ** returns from editval isn't very smart, and depends on the layout above.
1730 static void
1731 editparams(DEV_LIST *dev)
1733 int ret;
1734 char buf[16]; /* needs to fit the device name */
1736 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1737 ksprintf(buf,"!b%s",dev->dev);
1738 putxy(24,17,buf);
1740 erase(1,22,80,1);
1741 for (;;)
1743 ep_iobase:
1744 if (dev->iobase > 0)
1746 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1747 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1748 switch(ret)
1750 case KEY_EXIT:
1751 goto ep_exit;
1753 case KEY_RIGHT:
1754 if (dev->maddr > 0)
1755 goto ep_maddr;
1756 break;
1758 case KEY_TAB:
1759 case KEY_DOWN:
1760 goto ep_irq;
1762 goto ep_iobase;
1764 ep_irq:
1765 if (dev->irq > 0)
1767 puthelp(" Interrupt number (Decimal, 1-15)");
1768 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1769 switch(ret)
1771 case KEY_EXIT:
1772 goto ep_exit;
1774 case KEY_RIGHT:
1775 if (dev->msize > 0)
1776 goto ep_msize;
1777 break;
1779 case KEY_UP:
1780 if (dev->iobase > 0)
1781 goto ep_iobase;
1782 break;
1784 case KEY_TAB:
1785 case KEY_DOWN:
1786 goto ep_flags;
1788 goto ep_irq;
1790 ep_flags:
1791 puthelp(" Device-specific flag values.");
1792 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1793 switch(ret)
1795 case KEY_EXIT:
1796 goto ep_exit;
1798 case KEY_RIGHT:
1799 if (dev->drq > 0)
1800 goto ep_drq;
1801 break;
1803 case KEY_UP:
1804 if (dev->irq > 0)
1805 goto ep_irq;
1806 if (dev->iobase > 0)
1807 goto ep_iobase;
1808 break;
1810 case KEY_DOWN:
1811 if (dev->maddr > 0)
1812 goto ep_maddr;
1813 if (dev->msize > 0)
1814 goto ep_msize;
1815 if (dev->drq > 0)
1816 goto ep_drq;
1817 break;
1819 case KEY_TAB:
1820 goto ep_maddr;
1822 goto ep_flags;
1823 ep_maddr:
1824 if (dev->maddr > 0)
1826 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1827 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1828 switch(ret)
1830 case KEY_EXIT:
1831 goto ep_exit;
1833 case KEY_LEFT:
1834 if (dev->iobase > 0)
1835 goto ep_iobase;
1836 break;
1838 case KEY_UP:
1839 goto ep_flags;
1841 case KEY_DOWN:
1842 if (dev->msize > 0)
1843 goto ep_msize;
1844 if (dev->drq > 0)
1845 goto ep_drq;
1846 break;
1848 case KEY_TAB:
1849 goto ep_msize;
1851 goto ep_maddr;
1853 ep_msize:
1854 if (dev->msize > 0)
1856 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1857 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1858 switch(ret)
1860 case KEY_EXIT:
1861 goto ep_exit;
1863 case KEY_LEFT:
1864 if (dev->irq > 0)
1865 goto ep_irq;
1866 break;
1868 case KEY_UP:
1869 if (dev->maddr > 0)
1870 goto ep_maddr;
1871 goto ep_flags;
1873 case KEY_DOWN:
1874 if (dev->drq > 0)
1875 goto ep_drq;
1876 break;
1878 case KEY_TAB:
1879 goto ep_drq;
1881 goto ep_msize;
1883 ep_drq:
1884 if (dev->drq > 0)
1886 puthelp(" Device DMA request number (Decimal, 1-7)");
1887 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1888 switch(ret)
1890 case KEY_EXIT:
1891 goto ep_exit;
1893 case KEY_LEFT:
1894 goto ep_flags;
1896 case KEY_UP:
1897 if (dev->msize > 0)
1898 goto ep_msize;
1899 if (dev->maddr > 0)
1900 goto ep_maddr;
1901 goto ep_flags;
1903 case KEY_TAB:
1904 goto ep_iobase;
1906 goto ep_drq;
1909 ep_exit:
1910 dev->changed = 1; /* mark as changed */
1913 static char *helptext[] =
1915 " Using the UserConfig kernel settings editor",
1916 " -------------------------------------------",
1918 "VISUAL MODE:",
1920 "- - Layout -",
1922 "The screen displays a list of available drivers, divided into two",
1923 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1924 "by default collapsed and can be expanded to show all the drivers",
1925 "available in each category. The parameters for the currently selected",
1926 "driver are shown at the bottom of the screen.",
1928 "- - Moving around -",
1930 "To move in the current list, use the UP and DOWN cursor keys to select",
1931 "an item (the selected item will be highlighted). If the item is a",
1932 "category name, you may alternatively expand or collapse the list of",
1933 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1934 "expanded, you can select each driver in the same manner and either:",
1936 " - change its parameters using [!bENTER!n]",
1937 " - move it to the Inactive list using [!bDEL!n]",
1939 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1940 "you need to move a driver from the Inactive list back to the Active",
1941 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1942 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1943 "its place in the Active list.",
1945 "- - Altering the list/parameters -",
1947 "Any drivers for devices not installed in your system should be moved",
1948 "to the Inactive list, until there are no remaining parameter conflicts",
1949 "between the drivers, as indicated at the top.",
1951 "Once the list of Active drivers only contains entries for the devices",
1952 "present in your system, you can set their parameters (Interrupt, DMA",
1953 "channel, I/O addresses). To do this, select the driver and press",
1954 "[!bENTER!n]: it is now possible to edit the settings at the",
1955 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1956 "finished, use [!bQ!n] to return to the list.",
1958 "- - Saving changes -",
1960 "When all settings seem correct, and you wish to proceed with the",
1961 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1962 "confirm your choice.",
1964 NULL
1969 ** helpscreen
1971 ** Displays help text onscreen for people that are confused, using a simple
1972 ** pager.
1974 static void
1975 helpscreen(void)
1977 int topline = 0; /* where we are in the text */
1978 int line = 0; /* last line we displayed */
1979 int c, delta = 1;
1980 char prompt[80];
1982 for (;;) /* loop until user quits */
1984 /* display help text */
1985 if (delta)
1987 clear(); /* remove everything else */
1988 for (line = topline;
1989 (line < (topline + 24)) && (helptext[line]);
1990 line++)
1991 putxy(0,line-topline,helptext[line]);
1992 delta = 0;
1995 /* prompt */
1996 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1997 putxy(0,24,prompt);
1999 c = kgetchar(); /* so what do they say? */
2001 switch (c)
2003 case 'u':
2004 case 'U':
2005 case 'b':
2006 case 'B': /* wired into 'more' users' fingers */
2007 if (topline > 0) /* room to go up? */
2009 topline -= 24;
2010 if (topline < 0) /* don't go too far */
2011 topline = 0;
2012 delta = 1;
2014 break;
2016 case 'd':
2017 case 'D':
2018 case ' ': /* expected by most people */
2019 if (helptext[line]) /* maybe more below? */
2021 topline += 24;
2022 delta = 1;
2024 break;
2026 case 'q':
2027 case 'Q':
2028 redraw(); /* restore the screen */
2029 return;
2035 /**
2036 ** High-level control functions
2041 ** dolist
2043 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2044 ** (num) lines, starting at (*ofs) offset from row onscreen.
2045 ** Pass (detail) on to drawing routines.
2047 ** If the user hits a key other than a cursor key, maybe return a code.
2049 ** (*list) points to the device at the top line in the region, (*ofs) is the
2050 ** position of the highlight within the region. All routines below
2051 ** this take only a device and an absolute row : use ofsent() to find the
2052 ** device, and add (*ofs) to (row) to find the absolute row.
2054 static int
2055 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2057 int extended = 0;
2058 int c;
2059 DEV_LIST *lp;
2060 int delta = 1;
2062 for(;;)
2064 if (delta)
2066 showparams(ofsent(*ofs,*list)); /* show device parameters */
2067 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2068 delta = 0;
2071 c = kgetchar(); /* get a character */
2072 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2074 extended = 0; /* no longer */
2075 switch(c)
2077 case 588: /* syscons' idea of 'up' */
2078 case 'A': /* up */
2079 if (*ofs) /* just a move onscreen */
2081 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2082 (*ofs)--; /* move up */
2083 }else{
2084 lp = prevent(*list); /* can we go up? */
2085 if (!lp) /* no */
2086 break;
2087 *list = lp; /* yes, move up list */
2088 drawlist(row,num,detail,*list);
2090 delta = 1;
2091 break;
2093 case 596: /* dooby-do */
2094 case 'B': /* down */
2095 lp = ofsent(*ofs,*list); /* get current item */
2096 if (!nextent(lp))
2097 break; /* nothing more to move to */
2098 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2099 if (*ofs < (num-1)) /* room to move onscreen? */
2101 (*ofs)++;
2102 }else{
2103 *list = nextent(*list); /* scroll region down */
2104 drawlist(row,num,detail,*list);
2106 delta = 1;
2107 break;
2109 }else{
2110 switch(c)
2112 case '\033':
2113 extended=1;
2114 break;
2116 case '[': /* cheat : always preceeds cursor move */
2117 case 'O': /* ANSI application key mode */
2118 if (extended==1)
2119 extended=2;
2120 else
2121 extended=0;
2122 break;
2124 case 'Q':
2125 case 'q':
2126 return(KEY_EXIT); /* user requests exit */
2128 case '\r':
2129 case '\n':
2130 return(KEY_DO); /* "do" something */
2132 case '\b':
2133 case '\177':
2134 case 599:
2135 return(KEY_DEL); /* "delete" response */
2137 case 'X':
2138 case 'x':
2139 return(KEY_UNZOOM); /* expand everything */
2141 case 'C':
2142 case 'c':
2143 return(KEY_ZOOM); /* collapse everything */
2145 case '\t':
2146 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2147 return(KEY_TAB); /* "move" response */
2149 case '\014': /* ^L, redraw */
2150 return(KEY_REDRAW);
2152 case '?': /* helptext */
2153 return(KEY_HELP);
2162 ** visuserconfig
2164 ** Do the fullscreen config thang
2166 static int
2167 visuserconfig(void)
2169 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2170 DEV_LIST *dp;
2172 initlist(&active);
2173 initlist(&inactive);
2174 alist = active;
2175 ilist = inactive;
2177 getdevs();
2179 conflicts = findconflict(active); /* find conflicts in the active list only */
2181 redraw();
2183 for(;;)
2185 switch(mode)
2187 case 0: /* active devices */
2188 ret = dolist(1,8,1,&actofs,&alist,
2189 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2190 switch(ret)
2192 case KEY_TAB:
2193 mode = 1; /* swap lists */
2194 break;
2196 case KEY_REDRAW:
2197 redraw();
2198 break;
2200 case KEY_ZOOM:
2201 alist = active;
2202 actofs = 0;
2203 expandlist(active);
2204 redrawactive();
2205 break;
2207 case KEY_UNZOOM:
2208 alist = active;
2209 actofs = 0;
2210 collapselist(active);
2211 redrawactive();
2212 break;
2214 case KEY_DEL:
2215 dp = ofsent(actofs,alist); /* get current device */
2216 if (dp) /* paranoia... */
2218 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2219 break;
2220 if (dp == alist) /* moving top item on list? */
2222 if (dp->next)
2224 alist = dp->next; /* point list to non-moving item */
2225 }else{
2226 alist = dp->prev; /* end of list, go back instead */
2228 }else{
2229 if (!dp->next) /* moving last item on list? */
2230 actofs--;
2232 dp->conflicts = 0; /* no conflicts on the inactive list */
2233 movedev(dp,inactive); /* shift to inactive list */
2234 conflicts = findconflict(active); /* update conflict tags */
2235 dp->changed = 1;
2236 redrawactive(); /* redraw */
2237 redrawinactive();
2239 break;
2241 case KEY_DO: /* edit device parameters */
2242 dp = ofsent(actofs,alist); /* get current device */
2243 if (dp) /* paranoia... */
2245 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2247 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2248 editparams(dp);
2249 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2250 putxy(0,17,lines);
2251 conflicts = findconflict(active); /* update conflict tags */
2252 }else{ /* DO on comment = zoom */
2253 switch(dp->comment) /* Depends on current state */
2255 case DEV_COMMENT: /* not currently zoomed */
2256 dp->comment = DEV_ZOOMED;
2257 break;
2259 case DEV_ZOOMED:
2260 dp->comment = DEV_COMMENT;
2261 break;
2264 redrawactive();
2266 break;
2268 break;
2270 case 1: /* inactive devices */
2271 ret = dolist(10,7,0,&inactofs,&ilist,
2272 " [!bEnter!n] Enable device ");
2273 switch(ret)
2275 case KEY_TAB:
2276 mode = 0;
2277 break;
2279 case KEY_REDRAW:
2280 redraw();
2281 break;
2283 case KEY_ZOOM:
2284 ilist = inactive;
2285 inactofs = 0;
2286 expandlist(inactive);
2287 redrawinactive();
2288 break;
2290 case KEY_UNZOOM:
2291 ilist = inactive;
2292 inactofs = 0;
2293 collapselist(inactive);
2294 redrawinactive();
2295 break;
2297 case KEY_DO:
2298 dp = ofsent(inactofs,ilist); /* get current device */
2299 if (dp) /* paranoia... */
2301 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2303 if (dp == ilist) /* moving top of list? */
2305 if (dp->next)
2307 ilist = dp->next; /* point list to non-moving item */
2308 }else{
2309 ilist = dp->prev; /* can't go down, go up instead */
2311 }else{
2312 if (!dp->next) /* last entry on list? */
2313 inactofs--; /* shift cursor up one */
2316 movedev(dp,active); /* shift to active list */
2317 conflicts = findconflict(active); /* update conflict tags */
2318 dp->changed = 1;
2319 alist = dp; /* put at top and current */
2320 actofs = 0;
2321 while(dp->comment == DEV_DEVICE)
2322 dp = dp->prev; /* forcibly unzoom section */
2323 dp ->comment = DEV_COMMENT;
2324 mode = 0; /* and swap modes to follow it */
2326 }else{ /* DO on comment = zoom */
2327 switch(dp->comment) /* Depends on current state */
2329 case DEV_COMMENT: /* not currently zoomed */
2330 dp->comment = DEV_ZOOMED;
2331 break;
2333 case DEV_ZOOMED:
2334 dp->comment = DEV_COMMENT;
2335 break;
2338 redrawactive(); /* redraw */
2339 redrawinactive();
2341 break;
2343 default: /* nothing else relevant here */
2344 break;
2346 break;
2347 default:
2348 mode = 0; /* shouldn't happen... */
2351 /* handle returns that are the same for both modes */
2352 switch (ret) {
2353 case KEY_HELP:
2354 helpscreen();
2355 break;
2357 case KEY_EXIT:
2358 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2359 switch(i)
2361 case 2: /* cancel */
2362 redraw();
2363 break;
2365 case 1: /* save and exit */
2366 savelist(active,1);
2367 savelist(inactive,0);
2369 case 0: /* exit */
2370 nukelist(active); /* clean up after ourselves */
2371 nukelist(inactive);
2372 normal();
2373 clear();
2374 return(1);
2376 break;
2380 #endif /* VISUAL_USERCONFIG */
2383 * Copyright (c) 1991 Regents of the University of California.
2384 * All rights reserved.
2385 * Copyright (c) 1994 Jordan K. Hubbard
2386 * All rights reserved.
2387 * Copyright (c) 1994 David Greenman
2388 * All rights reserved.
2390 * Many additional changes by Bruce Evans
2392 * This code is derived from software contributed by the
2393 * University of California Berkeley, Jordan K. Hubbard,
2394 * David Greenman and Bruce Evans.
2396 * Redistribution and use in source and binary forms, with or without
2397 * modification, are permitted provided that the following conditions
2398 * are met:
2399 * 1. Redistributions of source code must retain the above copyright
2400 * notice, this list of conditions and the following disclaimer.
2401 * 2. Redistributions in binary form must reproduce the above copyright
2402 * notice, this list of conditions and the following disclaimer in the
2403 * documentation and/or other materials provided with the distribution.
2404 * 3. All advertising materials mentioning features or use of this software
2405 * must display the following acknowledgement:
2406 * This product includes software developed by the University of
2407 * California, Berkeley and its contributors.
2408 * 4. Neither the name of the University nor the names of its contributors
2409 * may be used to endorse or promote products derived from this software
2410 * without specific prior written permission.
2412 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2413 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2414 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2415 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2416 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2417 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2418 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2419 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2420 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2421 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2422 * SUCH DAMAGE.
2424 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2427 #include "use_scbus.h"
2429 #define PARM_DEVSPEC 0x1
2430 #define PARM_INT 0x2
2431 #define PARM_ADDR 0x3
2432 #define PARM_STRING 0x4
2434 typedef struct _cmdparm {
2435 int type;
2436 union {
2437 struct uc_device *dparm;
2438 int iparm;
2439 union {
2440 void *aparm;
2441 const char *sparm;
2442 } u;
2443 } parm;
2444 } CmdParm;
2446 typedef int (*CmdFunc)(CmdParm *);
2448 typedef struct _cmd {
2449 char *name;
2450 CmdFunc handler;
2451 CmdParm *parms;
2452 } Cmd;
2455 #if 0
2456 static void lsscsi(void);
2457 static int list_scsi(CmdParm *);
2458 #endif
2460 static int lsdevtab(struct uc_device *);
2461 static struct uc_device *find_device(char *, int);
2462 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2463 static void cngets(char *, int);
2464 static Cmd *parse_cmd(char *);
2465 static int parse_args(const char *, CmdParm *);
2466 static int save_dev(struct uc_device *);
2468 static int list_devices(CmdParm *);
2469 static int set_device_ioaddr(CmdParm *);
2470 static int set_device_irq(CmdParm *);
2471 static int set_device_drq(CmdParm *);
2472 static int set_device_iosize(CmdParm *);
2473 static int set_device_mem(CmdParm *);
2474 static int set_device_flags(CmdParm *);
2475 static int set_device_enable(CmdParm *);
2476 static int set_device_disable(CmdParm *);
2477 static int quitfunc(CmdParm *);
2478 static int helpfunc(CmdParm *);
2479 static int introfunc(CmdParm *);
2481 #if NPNP > 0
2482 static int lspnp(void);
2483 static int set_pnp_parms(CmdParm *);
2484 #endif
2486 static int lineno;
2488 #include "use_eisa.h"
2490 #if NEISA > 0
2492 #include <bus/eisa/eisaconf.h>
2494 static int set_num_eisa_slots(CmdParm *);
2496 #endif /* NEISA > 0 */
2498 static CmdParm addr_parms[] = {
2499 { PARM_DEVSPEC, {} },
2500 { PARM_ADDR, {} },
2501 { -1, {} },
2504 static CmdParm int_parms[] = {
2505 { PARM_DEVSPEC, {} },
2506 { PARM_INT, {} },
2507 { -1, {} },
2510 static CmdParm dev_parms[] = {
2511 { PARM_DEVSPEC, {} },
2512 { -1, {} },
2515 #if NPNP > 0
2516 static CmdParm string_arg[] = {
2517 { PARM_STRING, {} },
2518 { -1, {} },
2520 #endif
2522 #if NEISA > 0
2523 static CmdParm int_arg[] = {
2524 { PARM_INT, {} },
2525 { -1, {} },
2527 #endif /* NEISA > 0 */
2529 static Cmd CmdList[] = {
2530 { "?", helpfunc, NULL }, /* ? (help) */
2531 { "di", set_device_disable, dev_parms }, /* disable dev */
2532 { "dr", set_device_drq, int_parms }, /* drq dev # */
2533 #if NEISA > 0
2534 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2535 #endif /* NEISA > 0 */
2536 { "en", set_device_enable, dev_parms }, /* enable dev */
2537 { "ex", quitfunc, NULL }, /* exit (quit) */
2538 { "f", set_device_flags, int_parms }, /* flags dev mask */
2539 { "h", helpfunc, NULL }, /* help */
2540 { "intro", introfunc, NULL }, /* intro screen */
2541 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2542 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2543 { "ir", set_device_irq, int_parms }, /* irq dev # */
2544 { "l", list_devices, NULL }, /* ls, list */
2545 #if NPNP > 0
2546 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2547 #endif
2548 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2549 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2550 { "q", quitfunc, NULL }, /* quit */
2551 #if 0
2552 { "s", list_scsi, NULL }, /* scsi */
2553 #endif
2554 #ifdef VISUAL_USERCONFIG
2555 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2556 #endif
2557 { NULL, NULL, NULL },
2560 void
2561 userconfig(void)
2563 static char banner = 1;
2564 char input[80];
2565 int rval;
2566 Cmd *cmd;
2568 load_devtab();
2569 init_config_script();
2570 while (1) {
2572 /* Only display signon banner if we are about to go interactive */
2573 if (!has_config_script()) {
2574 if (!(boothowto & RB_CONFIG))
2575 #ifdef INTRO_USERCONFIG
2576 banner = 0;
2577 #else
2578 return;
2579 #endif
2580 if (banner) {
2581 banner = 0;
2582 printf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2583 " Type \"help\" for help"
2584 #ifdef VISUAL_USERCONFIG
2585 " or \"visual\" to go to the visual\n"
2586 " configuration interface (requires MGA/VGA display or\n"
2587 " serial terminal capable of displaying ANSI graphics)"
2588 #endif
2589 ".\n");
2593 printf("config> ");
2594 cngets(input, 80);
2595 if (input[0] == '\0')
2596 continue;
2597 cmd = parse_cmd(input);
2598 if (!cmd) {
2599 printf("Invalid command or syntax. Type `?' for help.\n");
2600 continue;
2602 rval = (*cmd->handler)(cmd->parms);
2603 if (rval) {
2604 free_devtab();
2605 return;
2610 static Cmd *
2611 parse_cmd(char *cmd)
2613 Cmd *cp;
2615 for (cp = CmdList; cp->name; cp++) {
2616 int len = strlen(cp->name);
2618 if (!strncmp(cp->name, cmd, len)) {
2619 while (*cmd && *cmd != ' ' && *cmd != '\t')
2620 ++cmd;
2621 if (parse_args(cmd, cp->parms))
2622 return NULL;
2623 else
2624 return cp;
2627 return NULL;
2630 static int
2631 parse_args(const char *cmd, CmdParm *parms)
2633 while (1) {
2634 char *ptr;
2636 if (*cmd == ' ' || *cmd == '\t') {
2637 ++cmd;
2638 continue;
2640 if (parms == NULL || parms->type == -1) {
2641 if (*cmd == '\0')
2642 return 0;
2643 printf("Extra arg(s): %s\n", cmd);
2644 return 1;
2646 if (parms->type == PARM_DEVSPEC) {
2647 int i = 0;
2648 char devname[64];
2649 int unit = 0;
2651 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2652 (*cmd >= '0' && *cmd <= '9')))
2653 devname[i++] = *(cmd++);
2654 devname[i] = '\0';
2655 if (*cmd >= '0' && *cmd <= '9') {
2656 unit = strtoul(cmd, &ptr, 10);
2657 if (cmd == ptr) {
2658 printf("Invalid device number\n");
2659 /* XXX should print invalid token here and elsewhere. */
2660 return 1;
2662 /* XXX else should require end of token. */
2663 cmd = ptr;
2665 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2666 printf("No such device: %s%d\n", devname, unit);
2667 return 1;
2669 ++parms;
2670 continue;
2672 if (parms->type == PARM_INT) {
2673 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2674 if (cmd == ptr) {
2675 printf("Invalid numeric argument\n");
2676 return 1;
2678 cmd = ptr;
2679 ++parms;
2680 continue;
2682 if (parms->type == PARM_ADDR) {
2683 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2684 if (cmd == ptr) {
2685 printf("Invalid address argument\n");
2686 return 1;
2688 cmd = ptr;
2689 ++parms;
2690 continue;
2692 if (parms->type == PARM_STRING) {
2693 parms->parm.u.sparm = cmd;
2694 return 0;
2697 return 0;
2700 static int
2701 list_devices(CmdParm *parms)
2703 lineno = 0;
2704 if (lsdevtab(uc_devtab)) return 0;
2705 #if NPNP > 0
2706 if (lspnp()) return 0;
2707 #endif
2708 #if NEISA > 0
2709 printf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2710 #endif /* NEISA > 0 */
2711 return 0;
2714 static int
2715 set_device_ioaddr(CmdParm *parms)
2717 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2718 save_dev(parms[0].parm.dparm);
2719 return 0;
2722 static int
2723 set_device_irq(CmdParm *parms)
2725 unsigned irq;
2727 irq = parms[1].parm.iparm;
2728 if (irq == 2) {
2729 printf("Warning: Remapping IRQ 2 to IRQ 9\n");
2730 irq = 9;
2732 else if (irq != -1 && irq > 15) {
2733 printf("An IRQ > 15 would be invalid.\n");
2734 return 0;
2736 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2737 save_dev(parms[0].parm.dparm);
2738 return 0;
2741 static int
2742 set_device_drq(CmdParm *parms)
2744 unsigned drq;
2747 * The bounds checking is just to ensure that the value can be printed
2748 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2750 drq = parms[1].parm.iparm;
2751 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2752 save_dev(parms[0].parm.dparm);
2753 return 0;
2756 static int
2757 set_device_iosize(CmdParm *parms)
2759 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2760 save_dev(parms[0].parm.dparm);
2761 return 0;
2764 static int
2765 set_device_mem(CmdParm *parms)
2767 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2768 save_dev(parms[0].parm.dparm);
2769 return 0;
2772 static int
2773 set_device_flags(CmdParm *parms)
2775 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2776 save_dev(parms[0].parm.dparm);
2777 return 0;
2780 static int
2781 set_device_enable(CmdParm *parms)
2783 parms[0].parm.dparm->id_enabled = TRUE;
2784 save_dev(parms[0].parm.dparm);
2785 return 0;
2788 static int
2789 set_device_disable(CmdParm *parms)
2791 parms[0].parm.dparm->id_enabled = FALSE;
2792 save_dev(parms[0].parm.dparm);
2793 return 0;
2796 #if NPNP > 0
2798 static int
2799 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2801 int error=0;
2803 if(!req->oldptr) {
2804 /* Only sizing */
2805 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2806 } else {
2808 * Output the pnp_ldn_overrides[] table.
2810 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2811 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2812 if(error) return(error);
2813 return(0);
2817 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2818 0, 0, sysctl_machdep_uc_pnplist, "A",
2819 "List of PnP overrides changed in UserConfig");
2822 * this function sets the kernel table to override bios PnP
2823 * configuration.
2825 static int
2826 set_pnp_parms(CmdParm *parms)
2828 u_long idx, val, ldn, csn;
2829 int i;
2830 char *q;
2831 const char *p = parms[0].parm.u.sparm;
2832 struct pnp_cinfo d;
2834 csn=strtoul(p,&q, 0);
2835 ldn=strtoul(q,&q, 0);
2836 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2837 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2838 printf("bad csn/ldn %ld:%ld\n", csn, ldn);
2839 return 0;
2841 for (i=0; i < MAX_PNP_LDN; i++) {
2842 if (pnp_ldn_overrides[i].csn == csn &&
2843 pnp_ldn_overrides[i].ldn == ldn)
2844 break;
2846 if (i==MAX_PNP_LDN) {
2847 for (i=0; i < MAX_PNP_LDN; i++) {
2848 if (pnp_ldn_overrides[i].csn <1 ||
2849 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2850 break;
2853 if (i==MAX_PNP_LDN) {
2854 printf("sorry, no PnP entries available, try delete one\n");
2855 return 0 ;
2857 d = pnp_ldn_overrides[i] ;
2858 d.csn = csn;
2859 d.ldn = ldn ;
2860 while (*p) {
2861 idx = 0;
2862 val = 0;
2863 if (!strncmp(p,"irq",3)) {
2864 idx=strtoul(p+3,&q, 0);
2865 val=strtoul(q,&q, 0);
2866 if (idx >=0 && idx < 2) d.irq[idx] = val;
2867 } else if (!strncmp(p,"flags",5)) {
2868 idx=strtoul(p+5,&q, 0);
2869 d.flags = idx;
2870 } else if (!strncmp(p,"drq",3)) {
2871 idx=strtoul(p+3,&q, 0);
2872 val=strtoul(q,&q, 0);
2873 if (idx >=0 && idx < 2) d.drq[idx] = val;
2874 } else if (!strncmp(p,"port",4)) {
2875 idx=strtoul(p+4,&q, 0);
2876 val=strtoul(q,&q, 0);
2877 if (idx >=0 && idx < 8) d.port[idx] = val;
2878 } else if (!strncmp(p,"mem",3)) {
2879 idx=strtoul(p+3,&q, 0);
2880 val=strtoul(q,&q, 0);
2881 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2882 } else if (!strncmp(p,"bios",4)) {
2883 q = p+ 4;
2884 d.override = 0 ;
2885 } else if (!strncmp(p,"os",2)) {
2886 q = p+2 ;
2887 d.override = 1 ;
2888 } else if (!strncmp(p,"disable",7)) {
2889 q = p+7 ;
2890 d.enable = 0 ;
2891 } else if (!strncmp(p,"enable",6)) {
2892 q = p+6;
2893 d.enable = 1 ;
2894 } else if (!strncmp(p,"delete",6)) {
2895 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2896 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2897 return 0;
2898 } else {
2899 printf("unknown command <%s>\n", p);
2900 break;
2902 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2904 pnp_ldn_overrides[i] = d ;
2905 return 0;
2907 #endif /* NPNP */
2909 #if NEISA > 0
2910 static int
2911 set_num_eisa_slots(CmdParm *parms)
2913 int num_slots;
2915 num_slots = parms[0].parm.iparm;
2916 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2917 return 0;
2919 #endif /* NEISA > 0 */
2921 static int
2922 quitfunc(CmdParm *parms)
2925 * If kernel config supplied, and we are parsing it, and -c also supplied,
2926 * ignore a quit command, This provides a safety mechanism to allow
2927 * recovery from a damaged/buggy kernel config.
2929 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2930 return 0;
2931 return 1;
2934 static int
2935 helpfunc(CmdParm *parms)
2937 printf(
2938 "Command\t\t\tDescription\n"
2939 "-------\t\t\t-----------\n"
2940 "ls\t\t\tList currently configured devices\n"
2941 "port <devname> <addr>\tSet device port (i/o address)\n"
2942 "irq <devname> <number>\tSet device irq\n"
2943 "drq <devname> <number>\tSet device drq\n"
2944 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2945 "iosize <devname> <size>\tSet device memory size\n"
2946 "flags <devname> <mask>\tSet device flags\n"
2947 "enable <devname>\tEnable device\n"
2948 "disable <devname>\tDisable device (will not be probed)\n");
2949 #if NPNP > 0
2950 printf(
2951 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2952 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2953 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2954 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2955 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2956 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2957 #endif
2958 #if NEISA > 0
2959 printf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2960 #endif /* NEISA > 0 */
2961 printf(
2962 "quit\t\t\tExit this configuration utility\n"
2963 "reset\t\t\tReset CPU\n");
2964 #ifdef VISUAL_USERCONFIG
2965 printf("visual\t\t\tGo to fullscreen mode.\n");
2966 #endif
2967 printf(
2968 "help\t\t\tThis message\n\n"
2969 "Commands may be abbreviated to a unique prefix\n");
2970 return 0;
2973 #if defined (VISUAL_USERCONFIG)
2974 static void
2975 center(int y, char *str)
2977 putxy((80 - strlen(str)) / 2, y, str);
2979 #endif
2981 static int
2982 introfunc(CmdParm *parms)
2984 #if defined (VISUAL_USERCONFIG)
2985 int curr_item, first_time, extended = 0;
2986 static char *choices[] = {
2987 " Skip kernel configuration and continue with installation ",
2988 " Start kernel configuration in full-screen visual mode ",
2989 " Start kernel configuration in CLI mode ",
2992 clear();
2993 center(2, "!bKernel Configuration Menu!n");
2995 curr_item = 0;
2996 first_time = 1;
2997 while (1) {
2998 char tmp[80];
2999 int c, i;
3001 if (!extended) {
3002 for (i = 0; i < 3; i++) {
3003 tmp[0] = '\0';
3004 if (curr_item == i)
3005 strcpy(tmp, "!i");
3006 strcat(tmp, choices[i]);
3007 if (curr_item == i)
3008 strcat(tmp, "!n");
3009 putxy(10, 5 + i, tmp);
3012 if (first_time) {
3013 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3014 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3015 putxy(2, 12, "match your hardware configuration.");
3016 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3017 putxy(2, 15, "(press Down-Arrow then ENTER).");
3018 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3019 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3020 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3021 putxy(2, 21, "then simply press ENTER or Q now.");
3022 first_time = 0;
3025 move(0, 0); /* move the cursor out of the way */
3027 c = kgetchar();
3028 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3029 extended = 0; /* no longer */
3030 switch (c) {
3031 case 588:
3032 case 'A': /* up */
3033 if (curr_item > 0)
3034 --curr_item;
3035 break;
3037 case 596:
3038 case 'B': /* down */
3039 if (curr_item < 2)
3040 ++curr_item;
3041 break;
3044 else {
3045 switch(c) {
3046 case '\033':
3047 extended = 1;
3048 break;
3050 case '[': /* cheat : always preceeds cursor move */
3051 case 'O': /* ANSI application key mode */
3052 if (extended == 1)
3053 extended = 2;
3054 else
3055 extended = 0;
3056 break;
3058 case -1:
3059 case 'Q':
3060 case 'q':
3061 clear();
3062 return 1; /* user requests exit */
3064 case '1': /* select an item */
3065 case 'S':
3066 case 's':
3067 curr_item = 0;
3068 break;
3069 case '2':
3070 case 'V':
3071 case 'v':
3072 curr_item = 1;
3073 break;
3074 case '3':
3075 case 'C':
3076 case 'c':
3077 curr_item = 2;
3078 break;
3080 case 'U': /* up */
3081 case 'u':
3082 case 'P':
3083 case 'p':
3084 if (curr_item > 0)
3085 --curr_item;
3086 break;
3088 case 'D': /* down */
3089 case 'd':
3090 case 'N':
3091 case 'n':
3092 if (curr_item < 2)
3093 ++curr_item;
3094 break;
3096 case '\r':
3097 case '\n':
3098 clear();
3099 if (!curr_item)
3100 return 1;
3101 else if (curr_item == 1)
3102 return visuserconfig();
3103 else {
3104 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3105 /* enable quitfunc */
3106 userconfig_boot_parsing=0;
3107 move (0, 3);
3108 boothowto |= RB_CONFIG; /* force -c */
3109 return 0;
3111 break;
3115 #endif
3118 #if NPNP > 0
3119 static int
3120 lspnp(void)
3122 struct pnp_cinfo *c;
3123 int i, first = 1;
3126 for (i=0; i< MAX_PNP_LDN; i++) {
3127 c = &pnp_ldn_overrides[i];
3128 if (c->csn >0 && c->csn != 255) {
3129 int pmax, mmax;
3130 static char pfmt[] =
3131 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3132 static char mfmt[] =
3133 "mem 0x%x 0x%x 0x%x 0x%x";
3134 char buf[256];
3135 if (lineno >= 23) {
3136 if (!userconfig_boot_parsing) {
3137 printf("<More> ");
3138 if (kgetchar() == 'q') {
3139 printf("quit\n");
3140 return (1);
3142 printf("\n");
3144 lineno = 0;
3146 if (lineno == 0 || first)
3147 printf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3148 first = 0 ;
3149 printf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3150 c->csn, c->ldn,
3151 c->override ? "OS ":"BIOS",
3152 c->enable ? "Y":"N",
3153 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3154 if (c->flags)
3155 printf("flags 0x%08lx ",c->flags);
3156 for (pmax = 7; pmax >=0 ; pmax--)
3157 if (c->port[pmax]!=0) break;
3158 for (mmax = 3; mmax >=0 ; mmax--)
3159 if (c->mem[mmax].base!=0) break;
3160 if (pmax>=0) {
3161 strcpy(buf, pfmt);
3162 buf[10 + 5*pmax]='\0';
3163 printf(buf,
3164 c->port[0], c->port[1], c->port[2], c->port[3],
3165 c->port[4], c->port[5], c->port[6], c->port[7]);
3167 if (mmax>=0) {
3168 strcpy(buf, mfmt);
3169 buf[8 + 5*mmax]='\0';
3170 printf(buf,
3171 c->mem[0].base, c->mem[1].base,
3172 c->mem[2].base, c->mem[3].base);
3174 printf("\n");
3177 return 0 ;
3179 #endif /* NPNP */
3181 static int
3182 lsdevtab(struct uc_device *dt)
3184 for (; dt->id_id != 0; dt++) {
3185 char dname[80];
3187 if (lineno >= 23) {
3188 printf("<More> ");
3189 if (!userconfig_boot_parsing) {
3190 if (kgetchar() == 'q') {
3191 printf("quit\n");
3192 return (1);
3194 printf("\n");
3196 lineno = 0;
3198 if (lineno == 0) {
3199 printf(
3200 "Device port irq drq iomem iosize unit flags enab\n"
3202 ++lineno;
3204 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3205 printf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3206 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3207 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3208 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3209 dt->id_enabled ? "Yes" : "No");
3210 ++lineno;
3212 return(0);
3215 static void
3216 load_devtab(void)
3218 int i, val;
3219 int count = resource_count();
3220 int id = 1;
3221 int dt;
3222 char *name;
3223 int unit;
3225 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1),M_DEVL,M_WAITOK);
3226 bzero(uc_devtab, sizeof(struct uc_device) * (count + 1));
3227 dt = 0;
3228 for (i = 0; i < count; i++) {
3229 name = resource_query_name(i);
3230 unit = resource_query_unit(i);
3231 if (unit < 0)
3232 continue; /* skip wildcards */
3233 uc_devtab[dt].id_id = id++;
3234 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3235 val = 0;
3236 resource_int_value(name, unit, "irq", &val);
3237 uc_devtab[dt].id_irq = (1 << val);
3238 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3239 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3240 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3241 uc_devtab[dt].id_unit = unit;
3242 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3243 val = 0;
3244 resource_int_value(name, unit, "disabled", &val);
3245 uc_devtab[dt].id_enabled = !val;
3246 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3247 strcpy(uc_devtab[dt].id_name, name);
3248 dt++;
3252 static void
3253 free_devtab(void)
3255 int i;
3256 int count = resource_count();
3258 for (i = 0; i < count; i++)
3259 if (uc_devtab[i].id_name)
3260 kfree(uc_devtab[i].id_name, M_DEVL);
3261 kfree(uc_devtab, M_DEVL);
3264 static struct uc_device *
3265 find_device(char *devname, int unit)
3267 struct uc_device *ret;
3269 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3270 return ret;
3271 return NULL;
3274 static struct uc_device *
3275 search_devtable(struct uc_device *dt, char *devname, int unit)
3277 int i;
3279 for (i = 0; dt->id_id != 0; dt++)
3280 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3281 return dt;
3282 return NULL;
3285 static void
3286 cngets(char *input, int maxin)
3288 int c, nchars = 0;
3290 while (1) {
3291 c = kgetchar();
3292 /* Treat ^H or ^? as backspace */
3293 if ((c == '\010' || c == '\177')) {
3294 if (nchars) {
3295 printf("\010 \010");
3296 *--input = '\0', --nchars;
3298 continue;
3300 /* Treat ^U or ^X as kill line */
3301 else if ((c == '\025' || c == '\030')) {
3302 while (nchars) {
3303 printf("\010 \010");
3304 *--input = '\0', --nchars;
3306 continue;
3308 printf("%c", c);
3309 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3310 *input = '\0';
3311 break;
3313 *input++ = (u_char)c;
3318 #if 0
3319 /* scsi: Support for displaying configured SCSI devices.
3320 * There is no way to edit them, and this is inconsistent
3321 * with the ISA method. This is here as a basis for further work.
3323 static char *
3324 type_text(char *name) /* XXX: This is bogus */
3326 if (strcmp(name, "sd") == 0)
3327 return "disk";
3329 if (strcmp(name, "st") == 0)
3330 return "tape";
3332 return "device";
3335 id_put(char *desc, int id)
3337 if (id != SCCONF_UNSPEC)
3339 if (desc)
3340 printf("%s", desc);
3342 if (id == SCCONF_ANY)
3343 printf("?");
3344 else
3345 printf("%d", id);
3349 static void
3350 lsscsi(void)
3352 int i;
3354 printf("scsi: (can't be edited):\n");
3356 for (i = 0; scsi_cinit[i].driver; i++)
3358 id_put("controller scbus", scsi_cinit[i].scbus);
3360 if (scsi_cinit[i].unit != -1)
3362 printf(" at ");
3363 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3366 printf("\n");
3369 for (i = 0; scsi_dinit[i].name; i++)
3371 printf("%s ", type_text(scsi_dinit[i].name));
3373 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3374 id_put(" at scbus", scsi_dinit[i].cunit);
3375 id_put(" target ", scsi_dinit[i].target);
3376 id_put(" lun ", scsi_dinit[i].lun);
3378 if (scsi_dinit[i].flags)
3379 printf(" flags 0x%x\n", scsi_dinit[i].flags);
3381 printf("\n");
3385 static int
3386 list_scsi(CmdParm *parms)
3388 lineno = 0;
3389 lsscsi();
3390 return 0;
3392 #endif
3394 static void
3395 save_resource(struct uc_device *idev)
3397 char *name;
3398 int unit;
3400 name = idev->id_name;
3401 unit = idev->id_unit;
3402 resource_set_int(name, unit, "port", idev->id_iobase);
3403 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3404 resource_set_int(name, unit, "drq", idev->id_drq);
3405 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3406 resource_set_int(name, unit, "msize", idev->id_msize);
3407 resource_set_int(name, unit, "flags", idev->id_flags);
3408 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3411 static int
3412 save_dev(struct uc_device *idev)
3414 struct uc_device *id_p,*id_pn;
3415 char *name = idev->id_name;
3417 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3418 if (id_p->id_id == idev->id_id) {
3419 id_pn = id_p->id_next;
3420 if (id_p->id_name)
3421 kfree(id_p->id_name, M_DEVL);
3422 bcopy(idev,id_p,sizeof(struct uc_device));
3423 save_resource(idev);
3424 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3425 strcpy(id_p->id_name, name);
3426 id_p->id_next = id_pn;
3427 return 1;
3430 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3431 bcopy(idev,id_pn,sizeof(struct uc_device));
3432 save_resource(idev);
3433 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3434 strcpy(id_pn->id_name, name);
3435 id_pn->id_next = uc_devlist;
3436 uc_devlist = id_pn;
3437 return 0;