3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
5 ** This code contains a module marked :
7 * Copyright (c) 1991 Regents of the University of California.
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.
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
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.13 2007/05/17 19:26:06 swildner Exp $
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.
66 ** USERCONFIG, visual mode.
70 ** Look for "EDIT THIS LIST" to add to the list of known devices
73 ** There are a number of assumptions made in this code.
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.
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)
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>
111 #include <sys/cons.h>
113 #include <machine/md_var.h>
114 #include <machine/limits.h>
116 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
122 #include <machine_base/isa/pnp.h>
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 *);
138 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
140 struct uc_device *id;
148 error+=sizeof(struct uc_device)+8;
151 return(SYSCTL_OUT(req,0,error));
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').
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,
165 if(error) return(error);
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
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)
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;
210 if ((config_script_size == 0) || (config_script == NULL)) {
211 config_script_size = 0;
212 config_script = NULL;
215 return has_config_script();
222 #ifdef INTRO_USERCONFIG
223 static int intro = 0;
226 if (has_config_script())
228 /* Consume character from loaded userconfig script, display */
229 userconfig_boot_parsing = 1;
232 config_script_size--;
236 #ifdef INTRO_USERCONFIG
237 if (userconfig_boot_parsing) {
238 if (!(boothowto & RB_CONFIG)) {
239 /* userconfig_script, !RB_CONFIG -> quit */
242 config_script = "uit\n";
243 config_script_size = strlen(config_script);
244 /* userconfig_script will be 1 on the next pass */
247 /* userconfig_script, RB_CONFIG -> cngetc() */
250 if (!(boothowto & RB_CONFIG)) {
251 /* no userconfig_script, !RB_CONFIG -> show intro */
255 config_script = "ntro\n";
256 config_script_size = strlen(config_script);
257 /* userconfig_script will be 1 on the next pass */
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;
275 #define TRUE (!FALSE)
278 #ifdef VISUAL_USERCONFIG
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 */
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 */
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},
322 /********************* EDIT THIS LIST **********************/
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 {"cm", "SMC COM90Cx6-based Arcnet adapters", 0, CLS_NETWORK},
350 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
351 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
352 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
353 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
354 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
355 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
356 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
357 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
358 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
359 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
360 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
361 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
362 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
364 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
365 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
366 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
367 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
368 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
369 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
370 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
371 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
372 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
373 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
375 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
376 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
377 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
378 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
379 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
380 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
382 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
383 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
384 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
385 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
386 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
387 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
388 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
389 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
390 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
391 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
392 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
393 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
394 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
395 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
396 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
397 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
398 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
399 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
400 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
401 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
402 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
403 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
405 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
406 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
407 {"pcic", "PC-card controller", 0, CLS_MISC},
408 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
409 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
413 typedef struct _devlist_struct
416 int attrib; /* flag values as per the FLG_* defines above */
417 int class; /* disk, etc as per the CLS_* defines above */
419 int iobase,irq,drq,maddr,msize,unit,flags,id;
420 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
421 int conflicts; /* set/reset by findconflict, count of conflicts */
422 int changed; /* nonzero if the device has been edited */
423 struct uc_device *device;
424 struct _devlist_struct *prev,*next;
429 #define DEV_COMMENT 1
432 #define LIST_CURRENT (1<<0)
433 #define LIST_SELECTED (1<<1)
435 #define KEY_EXIT 0 /* return codes from dolist() and friends */
441 #define KEY_UP 5 /* these only returned from editval() */
445 #define KEY_NULL 9 /* this allows us to spin & redraw */
447 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
448 #define KEY_UNZOOM 11
450 #define KEY_HELP 12 /* duh? */
452 static void redraw(void);
453 static void insdev(DEV_LIST *dev, DEV_LIST *list);
454 static int devinfo(DEV_LIST *dev);
455 static int visuserconfig(void);
457 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
458 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
459 static DEV_LIST scratch; /* scratch record */
460 static int conflicts; /* total conflict count */
463 static char lines[] = "--------------------------------------------------------------------------------";
464 static char spaces[] = " ";
468 ** Device manipulation stuff : find, describe, configure.
474 ** Sets the device referenced by (*dev) to the parameters in the struct,
475 ** and the enable flag according to (enabled)
478 setdev(DEV_LIST *dev, int enabled)
480 dev->device->id_iobase = dev->iobase; /* copy happy */
481 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
482 dev->device->id_drq = (short)dev->drq;
483 dev->device->id_maddr = (caddr_t)dev->maddr;
484 dev->device->id_msize = dev->msize;
485 dev->device->id_flags = dev->flags;
486 dev->device->id_enabled = enabled;
493 ** Walk the kernel device tables and build the active and inactive lists
499 struct uc_device *ap;
501 ap = uc_devtab; /* pointer to array of devices */
502 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
504 scratch.unit = ap[i].id_unit; /* device parameters */
505 strcpy(scratch.dev,ap[i].id_name);
506 scratch.iobase = ap[i].id_iobase;
507 scratch.irq = ffs(ap[i].id_irq)-1;
508 scratch.drq = ap[i].id_drq;
509 scratch.maddr = (int)ap[i].id_maddr;
510 scratch.msize = ap[i].id_msize;
511 scratch.flags = ap[i].id_flags;
513 scratch.comment = DEV_DEVICE; /* admin stuff */
514 scratch.conflicts = 0;
515 scratch.device = &ap[i]; /* save pointer for later reference */
517 if (!devinfo(&scratch)) /* get more info on the device */
518 insdev(&scratch,ap[i].id_enabled?active:inactive);
526 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
527 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
529 ** If the device is marked "invisible", return nonzero; the caller should
530 ** not insert any such device into either list.
534 devinfo(DEV_LIST *dev)
538 for (i = 0; device_info[i].class; i++)
540 if (!strcmp(dev->dev,device_info[i].dev))
542 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
544 strcpy(dev->name,device_info[i].name); /* get the name */
545 dev->attrib = device_info[i].attrib;
546 dev->class = device_info[i].class;
550 strcpy(dev->name,"Unknown device");
552 dev->class = CLS_MISC;
558 ** List manipulation stuff : add, move, initialise, free, traverse
560 ** Note that there are assumptions throughout this code that
561 ** the first entry in a list will never move. (assumed to be
569 ** appends a copy of (dev) to the end of (*list)
572 addev(DEV_LIST *dev, DEV_LIST **list)
577 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
578 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
580 if (*list) /* list exists */
584 ap = ap->next; /* scoot to end of list */
588 }else{ /* list does not yet exist */
590 lp->prev = lp->next = NULL; /* list now exists */
598 ** Finds the 'appropriate' place for (dev) in (list)
600 ** 'Appropriate' means in numeric order with other devices of the same type,
601 ** or in alphabetic order following a comment of the appropriate type.
602 ** or at the end of the list if an appropriate comment is not found. (this should
604 ** (Note that the appropriate point is never the top, but may be the bottom)
607 findspot(DEV_LIST *dev, DEV_LIST *list)
611 /* search for a previous instance of the same device */
612 for (ap = list; ap; ap = ap->next)
614 if (ap->comment != DEV_DEVICE) /* ignore comments */
616 if (!strcmp(dev->dev,ap->dev)) /* same base device */
618 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
619 || !ap->next) /* or end of list */
621 ap = ap->prev; /* back up one */
622 break; /* done here */
624 if (ap->next) /* if the next item exists */
626 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
628 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
634 if (!ap) /* not sure yet */
636 /* search for a class that the device might belong to */
637 for (ap = list; ap; ap = ap->next)
639 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
641 if (dev->class != ap->class) /* of same class too 8) */
643 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
645 ap = ap->prev; /* back up one */
646 break; /* done here */
648 if (ap->next) /* if the next item exists */
649 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
654 if (!ap) /* didn't find a match */
656 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
657 if ((ap->comment != DEV_DEVICE)
658 && (ap->class == dev->class)) /* appropriate place? */
660 } /* or just put up with last */
669 ** Inserts a copy of (dev) at the appropriate point in (list)
672 insdev(DEV_LIST *dev, DEV_LIST *list)
676 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
677 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
679 ap = findspot(lp,list); /* find appropriate spot */
680 lp->next = ap->next; /* point to next */
682 ap->next->prev = lp; /* point next to new */
683 lp->prev = ap; /* point new to current */
684 ap->next = lp; /* and current to new */
691 ** Moves (dev) from its current list to an appropriate place in (list)
692 ** (dev) may not come from the top of a list, but it may from the bottom.
695 movedev(DEV_LIST *dev, DEV_LIST *list)
699 ap = findspot(dev,list);
700 dev->prev->next = dev->next; /* remove from old list */
702 dev->next->prev = dev->prev;
704 dev->next = ap->next; /* insert in new list */
706 ap->next->prev = dev; /* point next to new */
707 dev->prev = ap; /* point new to current */
708 ap->next = dev; /* and current to new */
715 ** Initialises (*list) with the basic headings
718 initlist(DEV_LIST **list)
722 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
724 strcpy(scratch.name,devclass_names[i].name);
725 scratch.comment = DEV_ZOOMED;
726 scratch.class = devclass_names[i].number;
727 scratch.attrib = FLG_MANDATORY; /* can't be moved */
728 addev(&scratch,list); /* add to the list */
736 ** Walks (list) and saves the settings of any entry marked as changed.
738 ** The device's active field is set according to (active).
740 ** Builds the uc_devlist used by kget to extract the changed device information.
741 ** The code for this was taken almost verbatim from the original module.
744 savelist(DEV_LIST *list, int active)
746 struct uc_device *id_p,*id_pn;
751 if ((list->comment == DEV_DEVICE) && /* is a device */
752 (list->changed) && /* has been changed */
753 (list->device != NULL)) { /* has an uc_device structure */
755 setdev(list,active); /* set the device itself */
758 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
759 { /* look on the list for it */
760 if (id_p->id_id == list->device->id_id)
762 name = list->device->id_name;
763 id_pn = id_p->id_next;
765 kfree(id_p->id_name, M_DEVL);
766 bcopy(list->device,id_p,sizeof(struct uc_device));
767 save_resource(list->device);
768 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
769 strcpy(id_p->id_name, name);
770 id_pn->id_next = uc_devlist;
771 id_p->id_next = id_pn;
775 if (!id_pn) /* not already on the list */
777 name = list->device->id_name;
778 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
779 bcopy(list->device,id_pn,sizeof(struct uc_device));
780 save_resource(list->device);
781 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
782 strcpy(id_pn->id_name, name);
783 id_pn->id_next = uc_devlist;
784 uc_devlist = id_pn; /* park at top of list */
795 ** Frees all storage in use by a (list).
798 nukelist(DEV_LIST *list)
804 while(list->prev) /* walk to head of list */
819 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
820 ** if there is no previous entry. (Only possible if list->prev == NULL given the
821 ** premise that there is always a comment at the head of the list)
824 prevent(DEV_LIST *list)
830 dp = list->prev; /* start back one */
833 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
834 return(dp); /* so skip to comment */
835 if (dp->comment == DEV_COMMENT) /* not zoomed */
836 return(list->prev); /* one back as normal */
837 dp = dp->prev; /* backpedal */
839 return(dp); /* NULL, we can assume */
846 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
847 ** if there is no next entry. (Possible if the current entry is last, or
848 ** if the current entry is the last heading and it's collapsed)
851 nextent(DEV_LIST *list)
857 if (list->comment != DEV_ZOOMED) /* no reason to skip */
862 if (dp->comment != DEV_DEVICE) /* found another heading */
866 return(dp); /* back we go */
873 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
876 ofsent(int ofs, DEV_LIST *list)
878 while (ofs-- && list)
879 list = nextent(list);
887 ** Scans every element of (list) and sets the conflict tags appropriately
888 ** Returns the number of conflicts found.
891 findconflict(DEV_LIST *list)
893 int count = 0; /* number of conflicts found */
896 for (dp = list; dp; dp = dp->next) /* over the whole list */
898 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
901 dp->conflicts = 0; /* assume the best */
902 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
904 if (sp->comment != DEV_DEVICE) /* likewise */
907 if (sp == dp) /* always conflict with itself */
910 if ((dp->iobase > 0) && /* iobase conflict? */
911 (dp->iobase == sp->iobase))
913 if ((dp->irq > 0) && /* irq conflict? */
914 (dp->irq == sp->irq))
916 if ((dp->drq > 0) && /* drq conflict? */
917 (dp->drq == sp->drq))
919 if ((sp->maddr > 0) && /* maddr/msize conflict? */
921 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
922 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
925 count += dp->conflicts; /* count conflicts */
934 ** Unzooms all headings in (list)
937 expandlist(DEV_LIST *list)
941 if (list->comment == DEV_COMMENT)
942 list->comment = DEV_ZOOMED;
951 ** Zooms all headings in (list)
954 collapselist(DEV_LIST *list)
958 if (list->comment == DEV_ZOOMED)
959 list->comment = DEV_COMMENT;
966 ** Screen-manipulation stuff
968 ** This is the basic screen layout :
970 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
971 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
972 ** +--------------------------------------------------------------------------------+
973 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
974 ** 1 -| ........................ ....... .. 0x....|
975 ** 2 -| ........................ ....... .. 0x....|
976 ** 3 -| ........................ ....... .. 0x....|
977 ** 4 -| ........................ ....... .. 0x....|
978 ** 5 -| ........................ ....... .. 0x....|
979 ** 6 -| ........................ ....... .. 0x....|
980 ** 7 -| ........................ ....... .. 0x....|
981 ** 8 -| ........................ ....... .. 0x....|
982 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
983 ** 10-| ........................ ....... |
984 ** 11-| ........................ ....... |
985 ** 12-| ........................ ....... |
986 ** 13-| ........................ ....... |
987 ** 14-| ........................ ....... |
988 ** 15-| ........................ ....... |
989 ** 16-| ........................ ....... |
990 ** 17-|------------------------------------------------------UP-DOWN-------------------|
991 ** 18-| Relevant parameters for the current device |
994 ** 21-|--------------------------------------------------------------------------------|
995 ** 22-| Help texts go here |
997 ** +--------------------------------------------------------------------------------+
1001 ** On a collapsed comment :
1003 ** [Enter] Expand device list [z] Expand all lists
1004 ** [TAB] Change fields [Q] Save and Exit
1006 ** On an expanded comment :
1008 ** [Enter] Collapse device list [Z] Collapse all lists
1009 ** [TAB] Change fields [Q] Save and Exit
1011 ** On a comment with no followers
1014 ** [TAB] Change fields [Q] Save and Exit
1016 ** On a device in the active list
1018 ** [Enter] Edit device parameters [DEL] Disable device
1019 ** [TAB] Change fields [Q] Save and Exit [?] Help
1021 ** On a device in the inactive list
1023 ** [Enter] Enable device
1024 ** [TAB] Change fields [Q] Save and Exit [?] Help
1026 ** While editing parameters
1028 ** <parameter-specific help here>
1029 ** [TAB] Change fields [Q] Save device parameters
1036 ** The base-level screen primitives :
1038 ** bold() - enter bold mode \E[1m (md)
1039 ** inverse() - enter inverse mode \E[7m (so)
1040 ** normal() - clear bold/inverse mode \E[m (se)
1041 ** clear() - clear the screen \E[H\E[J (ce)
1042 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1067 kprintf("\033[H\033[J");
1073 kprintf("\033[%d;%dH",y+1,x+1);
1079 ** High-level screen primitives :
1081 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1082 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1083 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1084 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1085 ** putmsg(str) - put (str) in the message area
1086 ** puthelp(str) - put (str) in the upper helpline
1087 ** pad(str,len) - pad (str) to (len) with spaces
1088 ** drawline(row,detail,list,inverse,*dhelp)
1089 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1090 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1091 ** draw the line in inverse video, and display (*dhelp) on the
1093 ** drawlist(row,num,detail,list)
1094 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1095 ** through to drawline().
1096 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1097 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1098 ** redraw(); - Redraws the entire screen layout, including the
1099 ** - two list panels.
1104 ** writes (str) at x,y onscreen
1106 ** writes up to (len) of (str) at x,y onscreen.
1108 ** Supports embedded formatting :
1109 ** !i - inverse mode.
1111 ** !n - normal mode.
1114 putxyl(int x, int y, char *str, int len)
1119 while((*str) && (len--))
1121 if (*str == '!') /* format escape? */
1123 switch(*(str+1)) /* depending on the next character */
1127 str +=2; /* skip formatting */
1128 len++; /* doesn't count for length */
1133 str +=2; /* skip formatting */
1134 len++; /* doesn't count for length */
1139 str +=2; /* skip formatting */
1140 len++; /* doesn't count for length */
1144 cnputc(*str++); /* not an escape */
1147 cnputc(*str++); /* emit the character */
1152 #define putxy(x,y,str) putxyl(x,y,str,-1)
1158 ** Erases the region (x,y,w,h)
1161 erase(int x, int y, int w, int h)
1166 for (i = 0; i < h; i++)
1167 putxyl(x,y++,spaces,w);
1174 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1175 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1178 txtbox(int x, int y, int w, int h, char *str)
1183 while((str[i]) && h)
1185 if (str[i] == '\n') /* newline */
1187 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1188 y++; /* move down */
1189 h--; /* room for one less */
1190 str += (i+1); /* skip first newline */
1191 i = 0; /* zero offset */
1193 i++; /* next character */
1196 if (h) /* end of string, not region */
1204 ** writes (msg) in the helptext area
1209 erase(0,18,80,3); /* clear area */
1210 txtbox(0,18,80,3,msg);
1217 ** Writes (msg) in the helpline area
1230 ** Draws the help message at the bottom of the screen
1233 masterhelp(char *msg)
1243 ** space-pads a (str) to (len) characters
1246 pad(char *str, int len)
1250 for (i = 0; str[i]; i++) /* find the end of the string */
1252 if (i >= len) /* no padding needed */
1254 while(i < len) /* pad */
1263 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1264 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1266 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1267 ** help is shown for normal or zoomed comments
1270 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1272 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1274 if (list->comment == DEV_DEVICE)
1277 strncpy(nb+1,list->name,57);
1279 strncpy(nb,list->name,58);
1280 if ((list->comment == DEV_ZOOMED) && (list->next))
1281 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1282 strcat(nb," (Collapsed)");
1286 if (list->conflicts) /* device in conflict? */
1290 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1292 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1295 if (list->comment == DEV_DEVICE)
1297 ksprintf(db,"%s%d",list->dev,list->unit);
1302 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1304 ksprintf(ib," %d",list->irq);
1309 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1311 ksprintf(pb,"0x%x",list->iobase);
1317 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1319 putxyl(0,row,lbuf,80);
1322 switch(list->comment)
1324 case DEV_DEVICE: /* ordinary device */
1330 if (list->next->comment == DEV_DEVICE)
1331 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1336 if (list->next->comment == DEV_DEVICE)
1337 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1340 puthelp(" WARNING: This list entry corrupted!");
1344 move(0,row); /* put the cursor somewhere relevant */
1351 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1352 ** port and IRQ fields as well if (detail) is nonzero
1354 ** kprintf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1357 drawlist(int row, int num, int detail, DEV_LIST *list)
1361 for(ofs = 0; ofs < num; ofs++)
1365 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1366 list = nextent(list); /* move down visible list */
1368 erase(0,row+ofs,80,1);
1377 ** Redraws the active list
1386 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1389 putxyl(45,0,lines,16);
1391 drawlist(1,8,1,alist); /* draw device lists */
1397 ** Redraws the inactive list
1400 redrawinactive(void)
1402 drawlist(10,7,0,ilist); /* draw device lists */
1409 ** Clear the screen and redraw the entire layout
1416 putxy(3,0,"!bActive!n-!bDrivers");
1417 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1419 putxy(3,9,"!bInactive!n-!bDrivers");
1420 putxy(63,9,"!bDev");
1423 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1433 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1434 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1437 yesnocancel(char *str)
1463 ** Show device parameters in the region below the lists
1465 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1466 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1467 ** +--------------------------------------------------------------------------------+
1468 ** 17-|--------------------------------------------------------------------------------|
1469 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1470 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1471 ** 20-| Flags : 0x0000 DRQ number : 00 |
1472 ** 21-|--------------------------------------------------------------------------------|
1475 showparams(DEV_LIST *dev)
1479 erase(0,18,80,3); /* clear area */
1482 if (dev->comment != DEV_DEVICE)
1486 if (dev->iobase > 0)
1488 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1494 ksprintf(buf,"IRQ number : %d",dev->irq);
1497 ksprintf(buf,"Flags : 0x%x",dev->flags);
1501 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1506 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1512 ksprintf(buf,"DRQ number : %d",dev->drq);
1519 ** Editing functions for device parameters
1521 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1522 ** onscreen. Refuse values outsise (min) and (max).
1523 ** editparams(dev) - Edit the parameters for (dev)
1527 #define VetRet(code) \
1529 if ((i >= min) && (i <= max)) /* legit? */ \
1532 ksprintf(buf,hex?"0x%x":"%d",i); \
1533 putxy(hex?x-2:x,y,buf); \
1534 return(code); /* all done and exit */ \
1536 i = *val; /* restore original value */ \
1537 delta = 1; /* restore other stuff */ \
1544 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1545 ** in a field (width) wide. (Allow one space)
1546 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1548 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1551 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1553 int i = *val; /* work with copy of the value */
1554 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1555 int xp = 0; /* cursor offset into text copy */
1556 int delta = 1; /* force redraw first time in */
1558 int extended = 0; /* stage counter for extended key sequences */
1560 if (hex) /* we presume there's a leading 0x onscreen */
1561 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1565 if (delta) /* only update if necessary */
1567 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1568 ksprintf(buf,"!i%s",tc); /* format for printing */
1569 erase(x,y,width,1); /* clear the area */
1570 putxy(x,y,buf); /* write */
1571 xp = strlen(tc); /* cursor always at end */
1572 move(x+xp,y); /* position the cursor */
1577 switch(extended) /* escape handling */
1580 if (c == 0x1b) /* esc? */
1582 extended = 1; /* flag and spin */
1586 break; /* nope, drop through */
1588 case 1: /* there was an escape prefix */
1589 if (c == '[' || c == 'O') /* second character in sequence */
1595 return(KEY_EXIT); /* double esc exits */
1597 break; /* nup, not a sequence. */
1601 switch(c) /* looks like the real McCoy */
1604 VetRet(KEY_UP); /* leave if OK */
1607 VetRet(KEY_DOWN); /* leave if OK */
1610 VetRet(KEY_RIGHT); /* leave if OK */
1613 VetRet(KEY_LEFT); /* leave if OK */
1623 case '\t': /* trying to tab off */
1624 VetRet(KEY_TAB); /* verify and maybe return */
1634 case '\177': /* BS or DEL */
1635 if (ro) /* readonly? */
1637 puthelp(" !iThis value cannot be edited (Press ESC)");
1638 while(kgetchar() != 0x1b); /* wait for key */
1639 return(KEY_NULL); /* spin */
1641 if (xp) /* still something left to delete */
1643 i = (hex ? i/0x10u : i/10); /* strip last digit */
1644 delta = 1; /* force update */
1667 if (ro) /* readonly? */
1669 puthelp(" !iThis value cannot be edited (Press ESC)");
1670 while(kgetchar() != 0x1b); /* wait for key */
1671 return(KEY_NULL); /* spin */
1673 if (xp >= width) /* no room for more characters anyway */
1677 if ((c >= '0') && (c <= '9'))
1679 i = i*0x10 + (c-'0'); /* update value */
1683 if ((c >= 'a') && (c <= 'f'))
1685 i = i*0x10 + (c-'a'+0xa);
1689 if ((c >= 'A') && (c <= 'F'))
1691 i = i*0x10 + (c-'A'+0xa);
1696 if ((c >= '0') && (c <= '9'))
1698 i = i*10 + (c-'0'); /* update value */
1699 delta = 1; /* force redraw */
1712 ** Edit the parameters for (dev)
1714 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1715 ** possible for this to spin in an endless loop...
1716 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1717 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1718 ** +--------------------------------------------------------------------------------+
1719 ** 17-|--------------------------------------------------------------------------------|
1720 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1721 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1722 ** 20-| Flags : 0x0000 DRQ number : 00 |
1723 ** 21-|--------------------------------------------------------------------------------|
1725 ** The "intelligence" in this function that hops around based on the directional
1726 ** returns from editval isn't very smart, and depends on the layout above.
1729 editparams(DEV_LIST *dev)
1732 char buf[16]; /* needs to fit the device name */
1734 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1735 ksprintf(buf,"!b%s",dev->dev);
1742 if (dev->iobase > 0)
1744 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1745 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1765 puthelp(" Interrupt number (Decimal, 1-15)");
1766 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1778 if (dev->iobase > 0)
1789 puthelp(" Device-specific flag values.");
1790 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1804 if (dev->iobase > 0)
1824 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1825 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1832 if (dev->iobase > 0)
1854 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1855 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1884 puthelp(" Device DMA request number (Decimal, 1-7)");
1885 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1908 dev->changed = 1; /* mark as changed */
1911 static char *helptext[] =
1913 " Using the UserConfig kernel settings editor",
1914 " -------------------------------------------",
1920 "The screen displays a list of available drivers, divided into two",
1921 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1922 "by default collapsed and can be expanded to show all the drivers",
1923 "available in each category. The parameters for the currently selected",
1924 "driver are shown at the bottom of the screen.",
1926 "- - Moving around -",
1928 "To move in the current list, use the UP and DOWN cursor keys to select",
1929 "an item (the selected item will be highlighted). If the item is a",
1930 "category name, you may alternatively expand or collapse the list of",
1931 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1932 "expanded, you can select each driver in the same manner and either:",
1934 " - change its parameters using [!bENTER!n]",
1935 " - move it to the Inactive list using [!bDEL!n]",
1937 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1938 "you need to move a driver from the Inactive list back to the Active",
1939 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1940 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1941 "its place in the Active list.",
1943 "- - Altering the list/parameters -",
1945 "Any drivers for devices not installed in your system should be moved",
1946 "to the Inactive list, until there are no remaining parameter conflicts",
1947 "between the drivers, as indicated at the top.",
1949 "Once the list of Active drivers only contains entries for the devices",
1950 "present in your system, you can set their parameters (Interrupt, DMA",
1951 "channel, I/O addresses). To do this, select the driver and press",
1952 "[!bENTER!n]: it is now possible to edit the settings at the",
1953 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1954 "finished, use [!bQ!n] to return to the list.",
1956 "- - Saving changes -",
1958 "When all settings seem correct, and you wish to proceed with the",
1959 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1960 "confirm your choice.",
1969 ** Displays help text onscreen for people that are confused, using a simple
1975 int topline = 0; /* where we are in the text */
1976 int line = 0; /* last line we displayed */
1980 for (;;) /* loop until user quits */
1982 /* display help text */
1985 clear(); /* remove everything else */
1986 for (line = topline;
1987 (line < (topline + 24)) && (helptext[line]);
1989 putxy(0,line-topline,helptext[line]);
1994 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1997 c = kgetchar(); /* so what do they say? */
2004 case 'B': /* wired into 'more' users' fingers */
2005 if (topline > 0) /* room to go up? */
2008 if (topline < 0) /* don't go too far */
2016 case ' ': /* expected by most people */
2017 if (helptext[line]) /* maybe more below? */
2026 redraw(); /* restore the screen */
2034 ** High-level control functions
2041 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2042 ** (num) lines, starting at (*ofs) offset from row onscreen.
2043 ** Pass (detail) on to drawing routines.
2045 ** If the user hits a key other than a cursor key, maybe return a code.
2047 ** (*list) points to the device at the top line in the region, (*ofs) is the
2048 ** position of the highlight within the region. All routines below
2049 ** this take only a device and an absolute row : use ofsent() to find the
2050 ** device, and add (*ofs) to (row) to find the absolute row.
2053 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2064 showparams(ofsent(*ofs,*list)); /* show device parameters */
2065 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2069 c = kgetchar(); /* get a character */
2070 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2072 extended = 0; /* no longer */
2075 case 588: /* syscons' idea of 'up' */
2077 if (*ofs) /* just a move onscreen */
2079 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2080 (*ofs)--; /* move up */
2082 lp = prevent(*list); /* can we go up? */
2085 *list = lp; /* yes, move up list */
2086 drawlist(row,num,detail,*list);
2091 case 596: /* dooby-do */
2092 case 'B': /* down */
2093 lp = ofsent(*ofs,*list); /* get current item */
2095 break; /* nothing more to move to */
2096 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2097 if (*ofs < (num-1)) /* room to move onscreen? */
2101 *list = nextent(*list); /* scroll region down */
2102 drawlist(row,num,detail,*list);
2114 case '[': /* cheat : always preceeds cursor move */
2115 case 'O': /* ANSI application key mode */
2124 return(KEY_EXIT); /* user requests exit */
2128 return(KEY_DO); /* "do" something */
2133 return(KEY_DEL); /* "delete" response */
2137 return(KEY_UNZOOM); /* expand everything */
2141 return(KEY_ZOOM); /* collapse everything */
2144 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2145 return(KEY_TAB); /* "move" response */
2147 case '\014': /* ^L, redraw */
2150 case '?': /* helptext */
2162 ** Do the fullscreen config thang
2167 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2171 initlist(&inactive);
2177 conflicts = findconflict(active); /* find conflicts in the active list only */
2185 case 0: /* active devices */
2186 ret = dolist(1,8,1,&actofs,&alist,
2187 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2191 mode = 1; /* swap lists */
2208 collapselist(active);
2213 dp = ofsent(actofs,alist); /* get current device */
2214 if (dp) /* paranoia... */
2216 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2218 if (dp == alist) /* moving top item on list? */
2222 alist = dp->next; /* point list to non-moving item */
2224 alist = dp->prev; /* end of list, go back instead */
2227 if (!dp->next) /* moving last item on list? */
2230 dp->conflicts = 0; /* no conflicts on the inactive list */
2231 movedev(dp,inactive); /* shift to inactive list */
2232 conflicts = findconflict(active); /* update conflict tags */
2234 redrawactive(); /* redraw */
2239 case KEY_DO: /* edit device parameters */
2240 dp = ofsent(actofs,alist); /* get current device */
2241 if (dp) /* paranoia... */
2243 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2245 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2247 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2249 conflicts = findconflict(active); /* update conflict tags */
2250 }else{ /* DO on comment = zoom */
2251 switch(dp->comment) /* Depends on current state */
2253 case DEV_COMMENT: /* not currently zoomed */
2254 dp->comment = DEV_ZOOMED;
2258 dp->comment = DEV_COMMENT;
2268 case 1: /* inactive devices */
2269 ret = dolist(10,7,0,&inactofs,&ilist,
2270 " [!bEnter!n] Enable device ");
2284 expandlist(inactive);
2291 collapselist(inactive);
2296 dp = ofsent(inactofs,ilist); /* get current device */
2297 if (dp) /* paranoia... */
2299 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2301 if (dp == ilist) /* moving top of list? */
2305 ilist = dp->next; /* point list to non-moving item */
2307 ilist = dp->prev; /* can't go down, go up instead */
2310 if (!dp->next) /* last entry on list? */
2311 inactofs--; /* shift cursor up one */
2314 movedev(dp,active); /* shift to active list */
2315 conflicts = findconflict(active); /* update conflict tags */
2317 alist = dp; /* put at top and current */
2319 while(dp->comment == DEV_DEVICE)
2320 dp = dp->prev; /* forcibly unzoom section */
2321 dp ->comment = DEV_COMMENT;
2322 mode = 0; /* and swap modes to follow it */
2324 }else{ /* DO on comment = zoom */
2325 switch(dp->comment) /* Depends on current state */
2327 case DEV_COMMENT: /* not currently zoomed */
2328 dp->comment = DEV_ZOOMED;
2332 dp->comment = DEV_COMMENT;
2336 redrawactive(); /* redraw */
2341 default: /* nothing else relevant here */
2346 mode = 0; /* shouldn't happen... */
2349 /* handle returns that are the same for both modes */
2356 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2359 case 2: /* cancel */
2363 case 1: /* save and exit */
2365 savelist(inactive,0);
2368 nukelist(active); /* clean up after ourselves */
2378 #endif /* VISUAL_USERCONFIG */
2381 * Copyright (c) 1991 Regents of the University of California.
2382 * All rights reserved.
2383 * Copyright (c) 1994 Jordan K. Hubbard
2384 * All rights reserved.
2385 * Copyright (c) 1994 David Greenman
2386 * All rights reserved.
2388 * Many additional changes by Bruce Evans
2390 * This code is derived from software contributed by the
2391 * University of California Berkeley, Jordan K. Hubbard,
2392 * David Greenman and Bruce Evans.
2394 * Redistribution and use in source and binary forms, with or without
2395 * modification, are permitted provided that the following conditions
2397 * 1. Redistributions of source code must retain the above copyright
2398 * notice, this list of conditions and the following disclaimer.
2399 * 2. Redistributions in binary form must reproduce the above copyright
2400 * notice, this list of conditions and the following disclaimer in the
2401 * documentation and/or other materials provided with the distribution.
2402 * 3. All advertising materials mentioning features or use of this software
2403 * must display the following acknowledgement:
2404 * This product includes software developed by the University of
2405 * California, Berkeley and its contributors.
2406 * 4. Neither the name of the University nor the names of its contributors
2407 * may be used to endorse or promote products derived from this software
2408 * without specific prior written permission.
2410 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2411 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2412 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2414 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2415 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2416 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2417 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2418 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2419 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2422 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2425 #include "use_scbus.h"
2427 #define PARM_DEVSPEC 0x1
2428 #define PARM_INT 0x2
2429 #define PARM_ADDR 0x3
2430 #define PARM_STRING 0x4
2432 typedef struct _cmdparm {
2435 struct uc_device *dparm;
2444 typedef int (*CmdFunc)(CmdParm *);
2446 typedef struct _cmd {
2454 static void lsscsi(void);
2455 static int list_scsi(CmdParm *);
2458 static int lsdevtab(struct uc_device *);
2459 static struct uc_device *find_device(char *, int);
2460 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2461 static void cngets(char *, int);
2462 static Cmd *parse_cmd(char *);
2463 static int parse_args(const char *, CmdParm *);
2464 static int save_dev(struct uc_device *);
2466 static int list_devices(CmdParm *);
2467 static int set_device_ioaddr(CmdParm *);
2468 static int set_device_irq(CmdParm *);
2469 static int set_device_drq(CmdParm *);
2470 static int set_device_iosize(CmdParm *);
2471 static int set_device_mem(CmdParm *);
2472 static int set_device_flags(CmdParm *);
2473 static int set_device_enable(CmdParm *);
2474 static int set_device_disable(CmdParm *);
2475 static int quitfunc(CmdParm *);
2476 static int helpfunc(CmdParm *);
2477 static int introfunc(CmdParm *);
2480 static int lspnp(void);
2481 static int set_pnp_parms(CmdParm *);
2486 #include "use_eisa.h"
2490 #include <bus/eisa/eisaconf.h>
2492 static int set_num_eisa_slots(CmdParm *);
2494 #endif /* NEISA > 0 */
2496 static CmdParm addr_parms[] = {
2497 { PARM_DEVSPEC, {} },
2502 static CmdParm int_parms[] = {
2503 { PARM_DEVSPEC, {} },
2508 static CmdParm dev_parms[] = {
2509 { PARM_DEVSPEC, {} },
2514 static CmdParm string_arg[] = {
2515 { PARM_STRING, {} },
2521 static CmdParm int_arg[] = {
2525 #endif /* NEISA > 0 */
2527 static Cmd CmdList[] = {
2528 { "?", helpfunc, NULL }, /* ? (help) */
2529 { "di", set_device_disable, dev_parms }, /* disable dev */
2530 { "dr", set_device_drq, int_parms }, /* drq dev # */
2532 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2533 #endif /* NEISA > 0 */
2534 { "en", set_device_enable, dev_parms }, /* enable dev */
2535 { "ex", quitfunc, NULL }, /* exit (quit) */
2536 { "f", set_device_flags, int_parms }, /* flags dev mask */
2537 { "h", helpfunc, NULL }, /* help */
2538 { "intro", introfunc, NULL }, /* intro screen */
2539 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2540 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2541 { "ir", set_device_irq, int_parms }, /* irq dev # */
2542 { "l", list_devices, NULL }, /* ls, list */
2544 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2546 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2547 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2548 { "q", quitfunc, NULL }, /* quit */
2550 { "s", list_scsi, NULL }, /* scsi */
2552 #ifdef VISUAL_USERCONFIG
2553 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2555 { NULL, NULL, NULL },
2561 static char banner = 1;
2567 init_config_script();
2570 /* Only display signon banner if we are about to go interactive */
2571 if (!has_config_script()) {
2572 if (!(boothowto & RB_CONFIG))
2573 #ifdef INTRO_USERCONFIG
2580 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2581 " Type \"help\" for help"
2582 #ifdef VISUAL_USERCONFIG
2583 " or \"visual\" to go to the visual\n"
2584 " configuration interface (requires MGA/VGA display or\n"
2585 " serial terminal capable of displaying ANSI graphics)"
2591 kprintf("config> ");
2593 if (input[0] == '\0')
2595 cmd = parse_cmd(input);
2597 kprintf("Invalid command or syntax. Type `?' for help.\n");
2600 rval = (*cmd->handler)(cmd->parms);
2609 parse_cmd(char *cmd)
2613 for (cp = CmdList; cp->name; cp++) {
2614 int len = strlen(cp->name);
2616 if (!strncmp(cp->name, cmd, len)) {
2617 while (*cmd && *cmd != ' ' && *cmd != '\t')
2619 if (parse_args(cmd, cp->parms))
2629 parse_args(const char *cmd, CmdParm *parms)
2634 if (*cmd == ' ' || *cmd == '\t') {
2638 if (parms == NULL || parms->type == -1) {
2641 kprintf("Extra arg(s): %s\n", cmd);
2644 if (parms->type == PARM_DEVSPEC) {
2649 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2650 (*cmd >= '0' && *cmd <= '9')))
2651 devname[i++] = *(cmd++);
2653 if (*cmd >= '0' && *cmd <= '9') {
2654 unit = strtoul(cmd, &ptr, 10);
2656 kprintf("Invalid device number\n");
2657 /* XXX should print invalid token here and elsewhere. */
2660 /* XXX else should require end of token. */
2663 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2664 kprintf("No such device: %s%d\n", devname, unit);
2670 if (parms->type == PARM_INT) {
2671 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2673 kprintf("Invalid numeric argument\n");
2680 if (parms->type == PARM_ADDR) {
2681 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2683 kprintf("Invalid address argument\n");
2690 if (parms->type == PARM_STRING) {
2691 parms->parm.u.sparm = cmd;
2699 list_devices(CmdParm *parms)
2702 if (lsdevtab(uc_devtab)) return 0;
2704 if (lspnp()) return 0;
2707 kprintf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2708 #endif /* NEISA > 0 */
2713 set_device_ioaddr(CmdParm *parms)
2715 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2716 save_dev(parms[0].parm.dparm);
2721 set_device_irq(CmdParm *parms)
2725 irq = parms[1].parm.iparm;
2727 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2730 else if (irq != -1 && irq > 15) {
2731 kprintf("An IRQ > 15 would be invalid.\n");
2734 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2735 save_dev(parms[0].parm.dparm);
2740 set_device_drq(CmdParm *parms)
2745 * The bounds checking is just to ensure that the value can be printed
2746 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2748 drq = parms[1].parm.iparm;
2749 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2750 save_dev(parms[0].parm.dparm);
2755 set_device_iosize(CmdParm *parms)
2757 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2758 save_dev(parms[0].parm.dparm);
2763 set_device_mem(CmdParm *parms)
2765 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2766 save_dev(parms[0].parm.dparm);
2771 set_device_flags(CmdParm *parms)
2773 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2774 save_dev(parms[0].parm.dparm);
2779 set_device_enable(CmdParm *parms)
2781 parms[0].parm.dparm->id_enabled = TRUE;
2782 save_dev(parms[0].parm.dparm);
2787 set_device_disable(CmdParm *parms)
2789 parms[0].parm.dparm->id_enabled = FALSE;
2790 save_dev(parms[0].parm.dparm);
2797 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2803 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2806 * Output the pnp_ldn_overrides[] table.
2808 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2809 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2810 if(error) return(error);
2815 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2816 0, 0, sysctl_machdep_uc_pnplist, "A",
2817 "List of PnP overrides changed in UserConfig");
2820 * this function sets the kernel table to override bios PnP
2824 set_pnp_parms(CmdParm *parms)
2826 u_long idx, val, ldn, csn;
2829 const char *p = parms[0].parm.u.sparm;
2832 csn=strtoul(p,&q, 0);
2833 ldn=strtoul(q,&q, 0);
2834 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2835 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2836 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2839 for (i=0; i < MAX_PNP_LDN; i++) {
2840 if (pnp_ldn_overrides[i].csn == csn &&
2841 pnp_ldn_overrides[i].ldn == ldn)
2844 if (i==MAX_PNP_LDN) {
2845 for (i=0; i < MAX_PNP_LDN; i++) {
2846 if (pnp_ldn_overrides[i].csn <1 ||
2847 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2851 if (i==MAX_PNP_LDN) {
2852 kprintf("sorry, no PnP entries available, try delete one\n");
2855 d = pnp_ldn_overrides[i] ;
2861 if (!strncmp(p,"irq",3)) {
2862 idx=strtoul(p+3,&q, 0);
2863 val=strtoul(q,&q, 0);
2864 if (idx >=0 && idx < 2) d.irq[idx] = val;
2865 } else if (!strncmp(p,"flags",5)) {
2866 idx=strtoul(p+5,&q, 0);
2868 } else if (!strncmp(p,"drq",3)) {
2869 idx=strtoul(p+3,&q, 0);
2870 val=strtoul(q,&q, 0);
2871 if (idx >=0 && idx < 2) d.drq[idx] = val;
2872 } else if (!strncmp(p,"port",4)) {
2873 idx=strtoul(p+4,&q, 0);
2874 val=strtoul(q,&q, 0);
2875 if (idx >=0 && idx < 8) d.port[idx] = val;
2876 } else if (!strncmp(p,"mem",3)) {
2877 idx=strtoul(p+3,&q, 0);
2878 val=strtoul(q,&q, 0);
2879 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2880 } else if (!strncmp(p,"bios",4)) {
2883 } else if (!strncmp(p,"os",2)) {
2886 } else if (!strncmp(p,"disable",7)) {
2889 } else if (!strncmp(p,"enable",6)) {
2892 } else if (!strncmp(p,"delete",6)) {
2893 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2894 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2897 kprintf("unknown command <%s>\n", p);
2900 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2902 pnp_ldn_overrides[i] = d ;
2909 set_num_eisa_slots(CmdParm *parms)
2913 num_slots = parms[0].parm.iparm;
2914 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2917 #endif /* NEISA > 0 */
2920 quitfunc(CmdParm *parms)
2923 * If kernel config supplied, and we are parsing it, and -c also supplied,
2924 * ignore a quit command, This provides a safety mechanism to allow
2925 * recovery from a damaged/buggy kernel config.
2927 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2933 helpfunc(CmdParm *parms)
2936 "Command\t\t\tDescription\n"
2937 "-------\t\t\t-----------\n"
2938 "ls\t\t\tList currently configured devices\n"
2939 "port <devname> <addr>\tSet device port (i/o address)\n"
2940 "irq <devname> <number>\tSet device irq\n"
2941 "drq <devname> <number>\tSet device drq\n"
2942 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2943 "iosize <devname> <size>\tSet device memory size\n"
2944 "flags <devname> <mask>\tSet device flags\n"
2945 "enable <devname>\tEnable device\n"
2946 "disable <devname>\tDisable device (will not be probed)\n");
2949 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2950 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2951 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2952 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2953 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2954 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2957 kprintf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2958 #endif /* NEISA > 0 */
2960 "quit\t\t\tExit this configuration utility\n"
2961 "reset\t\t\tReset CPU\n");
2962 #ifdef VISUAL_USERCONFIG
2963 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2966 "help\t\t\tThis message\n\n"
2967 "Commands may be abbreviated to a unique prefix\n");
2971 #if defined (VISUAL_USERCONFIG)
2973 center(int y, char *str)
2975 putxy((80 - strlen(str)) / 2, y, str);
2980 introfunc(CmdParm *parms)
2982 #if defined (VISUAL_USERCONFIG)
2983 int curr_item, first_time, extended = 0;
2984 static char *choices[] = {
2985 " Skip kernel configuration and continue with installation ",
2986 " Start kernel configuration in full-screen visual mode ",
2987 " Start kernel configuration in CLI mode ",
2991 center(2, "!bKernel Configuration Menu!n");
3000 for (i = 0; i < 3; i++) {
3004 strcat(tmp, choices[i]);
3007 putxy(10, 5 + i, tmp);
3011 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3012 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3013 putxy(2, 12, "match your hardware configuration.");
3014 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3015 putxy(2, 15, "(press Down-Arrow then ENTER).");
3016 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3017 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3018 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3019 putxy(2, 21, "then simply press ENTER or Q now.");
3023 move(0, 0); /* move the cursor out of the way */
3026 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3027 extended = 0; /* no longer */
3036 case 'B': /* down */
3048 case '[': /* cheat : always preceeds cursor move */
3049 case 'O': /* ANSI application key mode */
3060 return 1; /* user requests exit */
3062 case '1': /* select an item */
3086 case 'D': /* down */
3099 else if (curr_item == 1)
3100 return visuserconfig();
3102 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3103 /* enable quitfunc */
3104 userconfig_boot_parsing=0;
3106 boothowto |= RB_CONFIG; /* force -c */
3120 struct pnp_cinfo *c;
3124 for (i=0; i< MAX_PNP_LDN; i++) {
3125 c = &pnp_ldn_overrides[i];
3126 if (c->csn >0 && c->csn != 255) {
3128 static char pfmt[] =
3129 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3130 static char mfmt[] =
3131 "mem 0x%x 0x%x 0x%x 0x%x";
3134 if (!userconfig_boot_parsing) {
3136 if (kgetchar() == 'q') {
3144 if (lineno == 0 || first)
3145 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3147 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3149 c->override ? "OS ":"BIOS",
3150 c->enable ? "Y":"N",
3151 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3153 kprintf("flags 0x%08lx ",c->flags);
3154 for (pmax = 7; pmax >=0 ; pmax--)
3155 if (c->port[pmax]!=0) break;
3156 for (mmax = 3; mmax >=0 ; mmax--)
3157 if (c->mem[mmax].base!=0) break;
3160 buf[10 + 5*pmax]='\0';
3162 c->port[0], c->port[1], c->port[2], c->port[3],
3163 c->port[4], c->port[5], c->port[6], c->port[7]);
3167 buf[8 + 5*mmax]='\0';
3169 c->mem[0].base, c->mem[1].base,
3170 c->mem[2].base, c->mem[3].base);
3180 lsdevtab(struct uc_device *dt)
3182 for (; dt->id_id != 0; dt++) {
3187 if (!userconfig_boot_parsing) {
3188 if (kgetchar() == 'q') {
3198 "Device port irq drq iomem iosize unit flags enab\n"
3202 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3203 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3204 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3205 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3206 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3207 dt->id_enabled ? "Yes" : "No");
3217 int count = resource_count();
3223 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1),M_DEVL,M_WAITOK);
3224 bzero(uc_devtab, sizeof(struct uc_device) * (count + 1));
3226 for (i = 0; i < count; i++) {
3227 name = resource_query_name(i);
3228 unit = resource_query_unit(i);
3230 continue; /* skip wildcards */
3231 uc_devtab[dt].id_id = id++;
3232 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3234 resource_int_value(name, unit, "irq", &val);
3235 uc_devtab[dt].id_irq = (1 << val);
3236 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3237 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3238 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3239 uc_devtab[dt].id_unit = unit;
3240 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3242 resource_int_value(name, unit, "disabled", &val);
3243 uc_devtab[dt].id_enabled = !val;
3244 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3245 strcpy(uc_devtab[dt].id_name, name);
3254 int count = resource_count();
3256 for (i = 0; i < count; i++)
3257 if (uc_devtab[i].id_name)
3258 kfree(uc_devtab[i].id_name, M_DEVL);
3259 kfree(uc_devtab, M_DEVL);
3262 static struct uc_device *
3263 find_device(char *devname, int unit)
3265 struct uc_device *ret;
3267 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3272 static struct uc_device *
3273 search_devtable(struct uc_device *dt, char *devname, int unit)
3277 for (i = 0; dt->id_id != 0; dt++)
3278 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3284 cngets(char *input, int maxin)
3290 /* Treat ^H or ^? as backspace */
3291 if ((c == '\010' || c == '\177')) {
3293 kprintf("\010 \010");
3294 *--input = '\0', --nchars;
3298 /* Treat ^U or ^X as kill line */
3299 else if ((c == '\025' || c == '\030')) {
3301 kprintf("\010 \010");
3302 *--input = '\0', --nchars;
3307 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3311 *input++ = (u_char)c;
3317 /* scsi: Support for displaying configured SCSI devices.
3318 * There is no way to edit them, and this is inconsistent
3319 * with the ISA method. This is here as a basis for further work.
3322 type_text(char *name) /* XXX: This is bogus */
3324 if (strcmp(name, "sd") == 0)
3327 if (strcmp(name, "st") == 0)
3333 id_put(char *desc, int id)
3335 if (id != SCCONF_UNSPEC)
3338 kprintf("%s", desc);
3340 if (id == SCCONF_ANY)
3352 kprintf("scsi: (can't be edited):\n");
3354 for (i = 0; scsi_cinit[i].driver; i++)
3356 id_put("controller scbus", scsi_cinit[i].scbus);
3358 if (scsi_cinit[i].unit != -1)
3361 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3367 for (i = 0; scsi_dinit[i].name; i++)
3369 kprintf("%s ", type_text(scsi_dinit[i].name));
3371 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3372 id_put(" at scbus", scsi_dinit[i].cunit);
3373 id_put(" target ", scsi_dinit[i].target);
3374 id_put(" lun ", scsi_dinit[i].lun);
3376 if (scsi_dinit[i].flags)
3377 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3384 list_scsi(CmdParm *parms)
3393 save_resource(struct uc_device *idev)
3398 name = idev->id_name;
3399 unit = idev->id_unit;
3400 resource_set_int(name, unit, "port", idev->id_iobase);
3401 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3402 resource_set_int(name, unit, "drq", idev->id_drq);
3403 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3404 resource_set_int(name, unit, "msize", idev->id_msize);
3405 resource_set_int(name, unit, "flags", idev->id_flags);
3406 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3410 save_dev(struct uc_device *idev)
3412 struct uc_device *id_p,*id_pn;
3413 char *name = idev->id_name;
3415 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3416 if (id_p->id_id == idev->id_id) {
3417 id_pn = id_p->id_next;
3419 kfree(id_p->id_name, M_DEVL);
3420 bcopy(idev,id_p,sizeof(struct uc_device));
3421 save_resource(idev);
3422 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3423 strcpy(id_p->id_name, name);
3424 id_p->id_next = id_pn;
3428 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3429 bcopy(idev,id_pn,sizeof(struct uc_device));
3430 save_resource(idev);
3431 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3432 strcpy(id_pn->id_name, name);
3433 id_pn->id_next = uc_devlist;