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 $
55 ** Kernel boot-time configuration manipulation tool for FreeBSD.
57 ** Two modes of operation are supported : the default is the line-editor mode,
58 ** the command "visual" invokes the fullscreen mode.
60 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
61 ** fullscreen mode requires syscons or a minimal-ansi serial console.
65 ** USERCONFIG, visual mode.
69 ** Look for "EDIT THIS LIST" to add to the list of known devices
72 ** There are a number of assumptions made in this code.
74 ** - That the console supports a minimal set of ANSI escape sequences
75 ** (See the screen manipulation section for a summary)
76 ** and has at least 24 rows.
77 ** - That values less than or equal to zero for any of the device
78 ** parameters indicate that the driver does not use the parameter.
79 ** - That flags are _always_ editable.
81 ** Devices marked as disabled are imported as such.
83 ** For this tool to be useful, the list of devices below _MUST_ be updated
84 ** when a new driver is brought into the kernel. It is not possible to
85 ** extract this information from the drivers in the kernel.
89 ** - Display _what_ a device conflicts with.
90 ** - Implement page up/down (as what?)
91 ** - Wizard mode (no restrictions)
92 ** - Find out how to put syscons back into low-intensity mode so that the
93 ** !b escape is useful on the console. (It seems to be that it actually
94 ** gets low/high intensity backwards. That looks OK.)
96 ** - Only display headings with devices under them. (difficult)
99 #include "opt_userconfig.h"
100 #define COMPAT_OLDISA /* get the definitions */
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/kernel.h>
105 #include <sys/malloc.h>
106 #include <sys/reboot.h>
107 #include <sys/linker.h>
108 #include <sys/sysctl.h>
110 #include <sys/cons.h>
112 #include <machine/md_var.h>
113 #include <machine/limits.h>
115 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
121 #include <machine_base/isa/pnp.h>
124 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
126 #include <machine/uc_device.h>
127 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
128 static struct uc_device *uc_devtab; /* fake uc_device table */
130 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
132 static void load_devtab(void);
133 static void free_devtab(void);
134 static void save_resource(struct uc_device *);
137 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
139 struct uc_device *id;
147 error+=sizeof(struct uc_device)+8;
150 return(SYSCTL_OUT(req,0,error));
152 /* Output the data. The buffer is filled with consecutive
153 * struct uc_device and char buf[8], containing the name
154 * (not guaranteed to end with '\0').
158 error=sysctl_handle_opaque(oidp,id,
159 sizeof(struct uc_device),req);
160 if(error) return(error);
161 strncpy(name,id->id_name,8);
162 error=sysctl_handle_opaque(oidp,name,
164 if(error) return(error);
171 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
172 0, 0, sysctl_machdep_uc_devlist, "A",
173 "List of ISA devices changed in UserConfig");
176 ** Obtain command input.
178 ** Initially, input is read from a possibly-loaded script.
179 ** At the end of the script, or if no script is supplied,
180 ** behaviour is determined by the RB_CONFIG (-c) flag. If
181 ** the flag is set, user input is read from the console; if
182 ** unset, the 'quit' command is invoked and userconfig
185 ** Note that quit commands encountered in the script will be
186 ** ignored if the RB_CONFIG flag is supplied.
188 static const char *config_script;
189 static int config_script_size; /* use of int for -ve magic value */
191 #define has_config_script() (config_script_size > 0)
194 init_config_script(void)
196 caddr_t autoentry, autoattr;
198 /* Look for loaded userconfig script */
199 autoentry = preload_search_by_type("userconfig_script");
200 if (autoentry != NULL) {
201 /* We have one, get size and data */
202 config_script_size = 0;
203 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
204 config_script_size = (size_t)*(u_int32_t *)autoattr;
205 config_script = NULL;
206 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
207 config_script = *(const char **)autoattr;
209 if ((config_script_size == 0) || (config_script == NULL)) {
210 config_script_size = 0;
211 config_script = NULL;
214 return has_config_script();
221 #ifdef INTRO_USERCONFIG
222 static int intro = 0;
225 if (has_config_script())
227 /* Consume character from loaded userconfig script, display */
228 userconfig_boot_parsing = 1;
231 config_script_size--;
235 #ifdef INTRO_USERCONFIG
236 if (userconfig_boot_parsing) {
237 if (!(boothowto & RB_CONFIG)) {
238 /* userconfig_script, !RB_CONFIG -> quit */
241 config_script = "uit\n";
242 config_script_size = strlen(config_script);
243 /* userconfig_script will be 1 on the next pass */
246 /* userconfig_script, RB_CONFIG -> cngetc() */
249 if (!(boothowto & RB_CONFIG)) {
250 /* no userconfig_script, !RB_CONFIG -> show intro */
254 config_script = "ntro\n";
255 config_script_size = strlen(config_script);
256 /* userconfig_script will be 1 on the next pass */
259 /* no userconfig_script, RB_CONFIG -> cngetc() */
262 #else /* !INTRO_USERCONFIG */
263 /* assert(boothowto & RB_CONFIG) */
264 #endif /* INTRO_USERCONFIG */
265 userconfig_boot_parsing = 0;
274 #define TRUE (!FALSE)
277 #ifdef VISUAL_USERCONFIG
281 char dev[16]; /* device basename */
282 char name[60]; /* long name */
283 int attrib; /* things to do with the device */
284 int class; /* device classification */
287 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
288 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
289 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
290 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
291 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
292 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
293 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
294 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
295 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
297 #define CLS_STORAGE 1 /* storage devices */
298 #define CLS_NETWORK 2 /* network interfaces */
299 #define CLS_COMMS 3 /* serial, parallel ports */
300 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
301 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
302 #define CLS_MISC 255 /* none of the above */
311 static DEVCLASS_INFO devclass_names[] = {
312 { "Storage : ", CLS_STORAGE},
313 { "Network : ", CLS_NETWORK},
314 { "Communications : ", CLS_COMMS},
315 { "Input : ", CLS_INPUT},
316 { "Multimedia : ", CLS_MMEDIA},
317 { "Miscellaneous : ", CLS_MISC},
321 /********************* EDIT THIS LIST **********************/
325 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
326 ** - XXX The list below should be reviewed by the driver authors to verify
327 ** that the correct flags have been set for each driver, and that the
328 ** descriptions are accurate.
331 static DEV_INFO device_info[] = {
332 /*---Name----- ---Description---------------------------------------------- */
333 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
334 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE},
335 {"aha", "Adaptec 154x SCSI controller", 0, CLS_STORAGE},
336 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE},
337 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
338 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
339 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
340 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
341 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
342 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
343 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE},
344 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
345 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
346 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
348 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
349 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
350 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
351 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
352 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
353 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
354 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
355 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
356 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
357 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
358 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
359 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
360 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
362 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
363 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
364 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
365 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
366 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
367 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
368 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
369 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
370 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
371 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
373 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
374 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
375 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
376 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
377 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
378 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
380 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
381 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
382 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
383 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
384 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
385 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
386 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
387 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
388 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
389 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
390 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
391 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
392 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
393 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
394 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
395 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
396 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
397 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
398 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
399 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
400 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
401 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
403 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
404 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
405 {"pcic", "PC-card controller", 0, CLS_MISC},
406 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
407 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
411 typedef struct _devlist_struct
414 int attrib; /* flag values as per the FLG_* defines above */
415 int class; /* disk, etc as per the CLS_* defines above */
417 int iobase,irq,drq,maddr,msize,unit,flags,id;
418 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
419 int conflicts; /* set/reset by findconflict, count of conflicts */
420 int changed; /* nonzero if the device has been edited */
421 struct uc_device *device;
422 struct _devlist_struct *prev,*next;
427 #define DEV_COMMENT 1
430 #define LIST_CURRENT (1<<0)
431 #define LIST_SELECTED (1<<1)
433 #define KEY_EXIT 0 /* return codes from dolist() and friends */
439 #define KEY_UP 5 /* these only returned from editval() */
443 #define KEY_NULL 9 /* this allows us to spin & redraw */
445 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
446 #define KEY_UNZOOM 11
448 #define KEY_HELP 12 /* duh? */
450 static void redraw(void);
451 static void insdev(DEV_LIST *dev, DEV_LIST *list);
452 static int devinfo(DEV_LIST *dev);
453 static int visuserconfig(void);
455 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
456 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
457 static DEV_LIST scratch; /* scratch record */
458 static int conflicts; /* total conflict count */
461 static char lines[] = "--------------------------------------------------------------------------------";
462 static char spaces[] = " ";
466 ** Device manipulation stuff : find, describe, configure.
472 ** Sets the device referenced by (*dev) to the parameters in the struct,
473 ** and the enable flag according to (enabled)
476 setdev(DEV_LIST *dev, int enabled)
478 dev->device->id_iobase = dev->iobase; /* copy happy */
479 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
480 dev->device->id_drq = (short)dev->drq;
481 dev->device->id_maddr = (caddr_t)dev->maddr;
482 dev->device->id_msize = dev->msize;
483 dev->device->id_flags = dev->flags;
484 dev->device->id_enabled = enabled;
491 ** Walk the kernel device tables and build the active and inactive lists
497 struct uc_device *ap;
499 ap = uc_devtab; /* pointer to array of devices */
500 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
502 scratch.unit = ap[i].id_unit; /* device parameters */
503 strcpy(scratch.dev,ap[i].id_name);
504 scratch.iobase = ap[i].id_iobase;
505 scratch.irq = ffs(ap[i].id_irq)-1;
506 scratch.drq = ap[i].id_drq;
507 scratch.maddr = (int)ap[i].id_maddr;
508 scratch.msize = ap[i].id_msize;
509 scratch.flags = ap[i].id_flags;
511 scratch.comment = DEV_DEVICE; /* admin stuff */
512 scratch.conflicts = 0;
513 scratch.device = &ap[i]; /* save pointer for later reference */
515 if (!devinfo(&scratch)) /* get more info on the device */
516 insdev(&scratch,ap[i].id_enabled?active:inactive);
524 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
525 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
527 ** If the device is marked "invisible", return nonzero; the caller should
528 ** not insert any such device into either list.
532 devinfo(DEV_LIST *dev)
536 for (i = 0; device_info[i].class; i++)
538 if (!strcmp(dev->dev,device_info[i].dev))
540 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
542 strcpy(dev->name,device_info[i].name); /* get the name */
543 dev->attrib = device_info[i].attrib;
544 dev->class = device_info[i].class;
548 strcpy(dev->name,"Unknown device");
550 dev->class = CLS_MISC;
556 ** List manipulation stuff : add, move, initialise, free, traverse
558 ** Note that there are assumptions throughout this code that
559 ** the first entry in a list will never move. (assumed to be
567 ** appends a copy of (dev) to the end of (*list)
570 addev(DEV_LIST *dev, DEV_LIST **list)
575 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
576 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
578 if (*list) /* list exists */
582 ap = ap->next; /* scoot to end of list */
586 }else{ /* list does not yet exist */
588 lp->prev = lp->next = NULL; /* list now exists */
596 ** Finds the 'appropriate' place for (dev) in (list)
598 ** 'Appropriate' means in numeric order with other devices of the same type,
599 ** or in alphabetic order following a comment of the appropriate type.
600 ** or at the end of the list if an appropriate comment is not found. (this should
602 ** (Note that the appropriate point is never the top, but may be the bottom)
605 findspot(DEV_LIST *dev, DEV_LIST *list)
609 /* search for a previous instance of the same device */
610 for (ap = list; ap; ap = ap->next)
612 if (ap->comment != DEV_DEVICE) /* ignore comments */
614 if (!strcmp(dev->dev,ap->dev)) /* same base device */
616 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
617 || !ap->next) /* or end of list */
619 ap = ap->prev; /* back up one */
620 break; /* done here */
622 if (ap->next) /* if the next item exists */
624 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
626 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
632 if (!ap) /* not sure yet */
634 /* search for a class that the device might belong to */
635 for (ap = list; ap; ap = ap->next)
637 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
639 if (dev->class != ap->class) /* of same class too 8) */
641 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
643 ap = ap->prev; /* back up one */
644 break; /* done here */
646 if (ap->next) /* if the next item exists */
647 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
652 if (!ap) /* didn't find a match */
654 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
655 if ((ap->comment != DEV_DEVICE)
656 && (ap->class == dev->class)) /* appropriate place? */
658 } /* or just put up with last */
667 ** Inserts a copy of (dev) at the appropriate point in (list)
670 insdev(DEV_LIST *dev, DEV_LIST *list)
674 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
675 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
677 ap = findspot(lp,list); /* find appropriate spot */
678 lp->next = ap->next; /* point to next */
680 ap->next->prev = lp; /* point next to new */
681 lp->prev = ap; /* point new to current */
682 ap->next = lp; /* and current to new */
689 ** Moves (dev) from its current list to an appropriate place in (list)
690 ** (dev) may not come from the top of a list, but it may from the bottom.
693 movedev(DEV_LIST *dev, DEV_LIST *list)
697 ap = findspot(dev,list);
698 dev->prev->next = dev->next; /* remove from old list */
700 dev->next->prev = dev->prev;
702 dev->next = ap->next; /* insert in new list */
704 ap->next->prev = dev; /* point next to new */
705 dev->prev = ap; /* point new to current */
706 ap->next = dev; /* and current to new */
713 ** Initialises (*list) with the basic headings
716 initlist(DEV_LIST **list)
720 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
722 strcpy(scratch.name,devclass_names[i].name);
723 scratch.comment = DEV_ZOOMED;
724 scratch.class = devclass_names[i].number;
725 scratch.attrib = FLG_MANDATORY; /* can't be moved */
726 addev(&scratch,list); /* add to the list */
734 ** Walks (list) and saves the settings of any entry marked as changed.
736 ** The device's active field is set according to (active).
738 ** Builds the uc_devlist used by kget to extract the changed device information.
739 ** The code for this was taken almost verbatim from the original module.
742 savelist(DEV_LIST *list, int active)
744 struct uc_device *id_p,*id_pn;
749 if ((list->comment == DEV_DEVICE) && /* is a device */
750 (list->changed) && /* has been changed */
751 (list->device != NULL)) { /* has an uc_device structure */
753 setdev(list,active); /* set the device itself */
756 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
757 { /* look on the list for it */
758 if (id_p->id_id == list->device->id_id)
760 name = list->device->id_name;
761 id_pn = id_p->id_next;
763 kfree(id_p->id_name, M_DEVL);
764 bcopy(list->device,id_p,sizeof(struct uc_device));
765 save_resource(list->device);
766 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
767 strcpy(id_p->id_name, name);
768 id_pn->id_next = uc_devlist;
769 id_p->id_next = id_pn;
773 if (!id_pn) /* not already on the list */
775 name = list->device->id_name;
776 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
777 bcopy(list->device,id_pn,sizeof(struct uc_device));
778 save_resource(list->device);
779 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
780 strcpy(id_pn->id_name, name);
781 id_pn->id_next = uc_devlist;
782 uc_devlist = id_pn; /* park at top of list */
793 ** Frees all storage in use by a (list).
796 nukelist(DEV_LIST *list)
802 while(list->prev) /* walk to head of list */
817 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
818 ** if there is no previous entry. (Only possible if list->prev == NULL given the
819 ** premise that there is always a comment at the head of the list)
822 prevent(DEV_LIST *list)
828 dp = list->prev; /* start back one */
831 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
832 return(dp); /* so skip to comment */
833 if (dp->comment == DEV_COMMENT) /* not zoomed */
834 return(list->prev); /* one back as normal */
835 dp = dp->prev; /* backpedal */
837 return(dp); /* NULL, we can assume */
844 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
845 ** if there is no next entry. (Possible if the current entry is last, or
846 ** if the current entry is the last heading and it's collapsed)
849 nextent(DEV_LIST *list)
855 if (list->comment != DEV_ZOOMED) /* no reason to skip */
860 if (dp->comment != DEV_DEVICE) /* found another heading */
864 return(dp); /* back we go */
871 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
874 ofsent(int ofs, DEV_LIST *list)
876 while (ofs-- && list)
877 list = nextent(list);
885 ** Scans every element of (list) and sets the conflict tags appropriately
886 ** Returns the number of conflicts found.
889 findconflict(DEV_LIST *list)
891 int count = 0; /* number of conflicts found */
894 for (dp = list; dp; dp = dp->next) /* over the whole list */
896 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
899 dp->conflicts = 0; /* assume the best */
900 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
902 if (sp->comment != DEV_DEVICE) /* likewise */
905 if (sp == dp) /* always conflict with itself */
908 if ((dp->iobase > 0) && /* iobase conflict? */
909 (dp->iobase == sp->iobase))
911 if ((dp->irq > 0) && /* irq conflict? */
912 (dp->irq == sp->irq))
914 if ((dp->drq > 0) && /* drq conflict? */
915 (dp->drq == sp->drq))
917 if ((sp->maddr > 0) && /* maddr/msize conflict? */
919 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
920 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
923 count += dp->conflicts; /* count conflicts */
932 ** Unzooms all headings in (list)
935 expandlist(DEV_LIST *list)
939 if (list->comment == DEV_COMMENT)
940 list->comment = DEV_ZOOMED;
949 ** Zooms all headings in (list)
952 collapselist(DEV_LIST *list)
956 if (list->comment == DEV_ZOOMED)
957 list->comment = DEV_COMMENT;
964 ** Screen-manipulation stuff
966 ** This is the basic screen layout :
968 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
969 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
970 ** +--------------------------------------------------------------------------------+
971 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
972 ** 1 -| ........................ ....... .. 0x....|
973 ** 2 -| ........................ ....... .. 0x....|
974 ** 3 -| ........................ ....... .. 0x....|
975 ** 4 -| ........................ ....... .. 0x....|
976 ** 5 -| ........................ ....... .. 0x....|
977 ** 6 -| ........................ ....... .. 0x....|
978 ** 7 -| ........................ ....... .. 0x....|
979 ** 8 -| ........................ ....... .. 0x....|
980 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
981 ** 10-| ........................ ....... |
982 ** 11-| ........................ ....... |
983 ** 12-| ........................ ....... |
984 ** 13-| ........................ ....... |
985 ** 14-| ........................ ....... |
986 ** 15-| ........................ ....... |
987 ** 16-| ........................ ....... |
988 ** 17-|------------------------------------------------------UP-DOWN-------------------|
989 ** 18-| Relevant parameters for the current device |
992 ** 21-|--------------------------------------------------------------------------------|
993 ** 22-| Help texts go here |
995 ** +--------------------------------------------------------------------------------+
999 ** On a collapsed comment :
1001 ** [Enter] Expand device list [z] Expand all lists
1002 ** [TAB] Change fields [Q] Save and Exit
1004 ** On an expanded comment :
1006 ** [Enter] Collapse device list [Z] Collapse all lists
1007 ** [TAB] Change fields [Q] Save and Exit
1009 ** On a comment with no followers
1012 ** [TAB] Change fields [Q] Save and Exit
1014 ** On a device in the active list
1016 ** [Enter] Edit device parameters [DEL] Disable device
1017 ** [TAB] Change fields [Q] Save and Exit [?] Help
1019 ** On a device in the inactive list
1021 ** [Enter] Enable device
1022 ** [TAB] Change fields [Q] Save and Exit [?] Help
1024 ** While editing parameters
1026 ** <parameter-specific help here>
1027 ** [TAB] Change fields [Q] Save device parameters
1034 ** The base-level screen primitives :
1036 ** bold() - enter bold mode \E[1m (md)
1037 ** inverse() - enter inverse mode \E[7m (so)
1038 ** normal() - clear bold/inverse mode \E[m (se)
1039 ** clear() - clear the screen \E[H\E[J (ce)
1040 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1065 kprintf("\033[H\033[J");
1071 kprintf("\033[%d;%dH",y+1,x+1);
1077 ** High-level screen primitives :
1079 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1080 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1081 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1082 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1083 ** putmsg(str) - put (str) in the message area
1084 ** puthelp(str) - put (str) in the upper helpline
1085 ** pad(str,len) - pad (str) to (len) with spaces
1086 ** drawline(row,detail,list,inverse,*dhelp)
1087 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1088 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1089 ** draw the line in inverse video, and display (*dhelp) on the
1091 ** drawlist(row,num,detail,list)
1092 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1093 ** through to drawline().
1094 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1095 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1096 ** redraw(); - Redraws the entire screen layout, including the
1097 ** - two list panels.
1102 ** writes (str) at x,y onscreen
1104 ** writes up to (len) of (str) at x,y onscreen.
1106 ** Supports embedded formatting :
1107 ** !i - inverse mode.
1109 ** !n - normal mode.
1112 putxyl(int x, int y, char *str, int len)
1117 while((*str) && (len--))
1119 if (*str == '!') /* format escape? */
1121 switch(*(str+1)) /* depending on the next character */
1125 str +=2; /* skip formatting */
1126 len++; /* doesn't count for length */
1131 str +=2; /* skip formatting */
1132 len++; /* doesn't count for length */
1137 str +=2; /* skip formatting */
1138 len++; /* doesn't count for length */
1142 kprintf("%c", *str++); /* not an escape */
1145 kprintf("%c", *str++); /* emit the character */
1150 #define putxy(x,y,str) putxyl(x,y,str,-1)
1156 ** Erases the region (x,y,w,h)
1159 erase(int x, int y, int w, int h)
1164 for (i = 0; i < h; i++)
1165 putxyl(x,y++,spaces,w);
1172 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1173 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1176 txtbox(int x, int y, int w, int h, char *str)
1181 while((str[i]) && h)
1183 if (str[i] == '\n') /* newline */
1185 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1186 y++; /* move down */
1187 h--; /* room for one less */
1188 str += (i+1); /* skip first newline */
1189 i = 0; /* zero offset */
1191 i++; /* next character */
1194 if (h) /* end of string, not region */
1202 ** writes (msg) in the helptext area
1207 erase(0,18,80,3); /* clear area */
1208 txtbox(0,18,80,3,msg);
1215 ** Writes (msg) in the helpline area
1228 ** Draws the help message at the bottom of the screen
1231 masterhelp(char *msg)
1241 ** space-pads a (str) to (len) characters
1244 pad(char *str, int len)
1248 for (i = 0; str[i]; i++) /* find the end of the string */
1250 if (i >= len) /* no padding needed */
1252 while(i < len) /* pad */
1261 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1262 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1264 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1265 ** help is shown for normal or zoomed comments
1268 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1270 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1272 if (list->comment == DEV_DEVICE)
1275 strncpy(nb+1,list->name,57);
1277 strncpy(nb,list->name,58);
1278 if ((list->comment == DEV_ZOOMED) && (list->next))
1279 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1280 strcat(nb," (Collapsed)");
1284 if (list->conflicts) /* device in conflict? */
1288 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1290 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1293 if (list->comment == DEV_DEVICE)
1295 ksprintf(db,"%s%d",list->dev,list->unit);
1300 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1302 ksprintf(ib," %d",list->irq);
1307 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1309 ksprintf(pb,"0x%x",list->iobase);
1315 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1317 putxyl(0,row,lbuf,80);
1320 switch(list->comment)
1322 case DEV_DEVICE: /* ordinary device */
1328 if (list->next->comment == DEV_DEVICE)
1329 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1334 if (list->next->comment == DEV_DEVICE)
1335 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1338 puthelp(" WARNING: This list entry corrupted!");
1342 move(0,row); /* put the cursor somewhere relevant */
1349 ** Displays (num) lines of the contents of (list) at (row), optionally
1350 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1353 drawlist(int row, int num, int detail, DEV_LIST *list)
1357 for(ofs = 0; ofs < num; ofs++)
1361 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1362 list = nextent(list); /* move down visible list */
1364 erase(0,row+ofs,80,1);
1373 ** Redraws the active list
1382 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1385 putxyl(45,0,lines,16);
1387 drawlist(1,8,1,alist); /* draw device lists */
1393 ** Redraws the inactive list
1396 redrawinactive(void)
1398 drawlist(10,7,0,ilist); /* draw device lists */
1405 ** Clear the screen and redraw the entire layout
1412 putxy(3,0,"!bActive!n-!bDrivers");
1413 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1415 putxy(3,9,"!bInactive!n-!bDrivers");
1416 putxy(63,9,"!bDev");
1419 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1429 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1430 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1433 yesnocancel(char *str)
1459 ** Show device parameters in the region below the lists
1461 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1462 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1463 ** +--------------------------------------------------------------------------------+
1464 ** 17-|--------------------------------------------------------------------------------|
1465 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1466 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1467 ** 20-| Flags : 0x0000 DRQ number : 00 |
1468 ** 21-|--------------------------------------------------------------------------------|
1471 showparams(DEV_LIST *dev)
1475 erase(0,18,80,3); /* clear area */
1478 if (dev->comment != DEV_DEVICE)
1482 if (dev->iobase > 0)
1484 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1490 ksprintf(buf,"IRQ number : %d",dev->irq);
1493 ksprintf(buf,"Flags : 0x%x",dev->flags);
1497 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1502 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1508 ksprintf(buf,"DRQ number : %d",dev->drq);
1515 ** Editing functions for device parameters
1517 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1518 ** onscreen. Refuse values outsise (min) and (max).
1519 ** editparams(dev) - Edit the parameters for (dev)
1523 #define VetRet(code) \
1525 if ((i >= min) && (i <= max)) /* legit? */ \
1528 ksprintf(buf,hex?"0x%x":"%d",i); \
1529 putxy(hex?x-2:x,y,buf); \
1530 return(code); /* all done and exit */ \
1532 i = *val; /* restore original value */ \
1533 delta = 1; /* restore other stuff */ \
1540 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1541 ** in a field (width) wide. (Allow one space)
1542 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1544 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1547 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1549 int i = *val; /* work with copy of the value */
1550 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1551 int xp = 0; /* cursor offset into text copy */
1552 int delta = 1; /* force redraw first time in */
1554 int extended = 0; /* stage counter for extended key sequences */
1556 if (hex) /* we presume there's a leading 0x onscreen */
1557 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1561 if (delta) /* only update if necessary */
1563 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1564 ksprintf(buf,"!i%s",tc); /* format for printing */
1565 erase(x,y,width,1); /* clear the area */
1566 putxy(x,y,buf); /* write */
1567 xp = strlen(tc); /* cursor always at end */
1568 move(x+xp,y); /* position the cursor */
1573 switch(extended) /* escape handling */
1576 if (c == 0x1b) /* esc? */
1578 extended = 1; /* flag and spin */
1582 break; /* nope, drop through */
1584 case 1: /* there was an escape prefix */
1585 if (c == '[' || c == 'O') /* second character in sequence */
1591 return(KEY_EXIT); /* double esc exits */
1593 break; /* nup, not a sequence. */
1597 switch(c) /* looks like the real McCoy */
1600 VetRet(KEY_UP); /* leave if OK */
1603 VetRet(KEY_DOWN); /* leave if OK */
1606 VetRet(KEY_RIGHT); /* leave if OK */
1609 VetRet(KEY_LEFT); /* leave if OK */
1619 case '\t': /* trying to tab off */
1620 VetRet(KEY_TAB); /* verify and maybe return */
1630 case '\177': /* BS or DEL */
1631 if (ro) /* readonly? */
1633 puthelp(" !iThis value cannot be edited (Press ESC)");
1634 while(kgetchar() != 0x1b); /* wait for key */
1635 return(KEY_NULL); /* spin */
1637 if (xp) /* still something left to delete */
1639 i = (hex ? i/0x10u : i/10); /* strip last digit */
1640 delta = 1; /* force update */
1663 if (ro) /* readonly? */
1665 puthelp(" !iThis value cannot be edited (Press ESC)");
1666 while(kgetchar() != 0x1b); /* wait for key */
1667 return(KEY_NULL); /* spin */
1669 if (xp >= width) /* no room for more characters anyway */
1673 if ((c >= '0') && (c <= '9'))
1675 i = i*0x10 + (c-'0'); /* update value */
1679 if ((c >= 'a') && (c <= 'f'))
1681 i = i*0x10 + (c-'a'+0xa);
1685 if ((c >= 'A') && (c <= 'F'))
1687 i = i*0x10 + (c-'A'+0xa);
1692 if ((c >= '0') && (c <= '9'))
1694 i = i*10 + (c-'0'); /* update value */
1695 delta = 1; /* force redraw */
1708 ** Edit the parameters for (dev)
1710 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1711 ** possible for this to spin in an endless loop...
1712 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1713 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1714 ** +--------------------------------------------------------------------------------+
1715 ** 17-|--------------------------------------------------------------------------------|
1716 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1717 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1718 ** 20-| Flags : 0x0000 DRQ number : 00 |
1719 ** 21-|--------------------------------------------------------------------------------|
1721 ** The "intelligence" in this function that hops around based on the directional
1722 ** returns from editval isn't very smart, and depends on the layout above.
1725 editparams(DEV_LIST *dev)
1728 char buf[16]; /* needs to fit the device name */
1730 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1731 ksprintf(buf,"!b%s",dev->dev);
1738 if (dev->iobase > 0)
1740 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1741 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1761 puthelp(" Interrupt number (Decimal, 1-15)");
1762 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1774 if (dev->iobase > 0)
1785 puthelp(" Device-specific flag values.");
1786 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1800 if (dev->iobase > 0)
1820 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1821 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1828 if (dev->iobase > 0)
1850 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1851 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1880 puthelp(" Device DMA request number (Decimal, 1-7)");
1881 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1904 dev->changed = 1; /* mark as changed */
1907 static char *helptext[] =
1909 " Using the UserConfig kernel settings editor",
1910 " -------------------------------------------",
1916 "The screen displays a list of available drivers, divided into two",
1917 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1918 "by default collapsed and can be expanded to show all the drivers",
1919 "available in each category. The parameters for the currently selected",
1920 "driver are shown at the bottom of the screen.",
1922 "- - Moving around -",
1924 "To move in the current list, use the UP and DOWN cursor keys to select",
1925 "an item (the selected item will be highlighted). If the item is a",
1926 "category name, you may alternatively expand or collapse the list of",
1927 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1928 "expanded, you can select each driver in the same manner and either:",
1930 " - change its parameters using [!bENTER!n]",
1931 " - move it to the Inactive list using [!bDEL!n]",
1933 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1934 "you need to move a driver from the Inactive list back to the Active",
1935 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1936 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1937 "its place in the Active list.",
1939 "- - Altering the list/parameters -",
1941 "Any drivers for devices not installed in your system should be moved",
1942 "to the Inactive list, until there are no remaining parameter conflicts",
1943 "between the drivers, as indicated at the top.",
1945 "Once the list of Active drivers only contains entries for the devices",
1946 "present in your system, you can set their parameters (Interrupt, DMA",
1947 "channel, I/O addresses). To do this, select the driver and press",
1948 "[!bENTER!n]: it is now possible to edit the settings at the",
1949 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1950 "finished, use [!bQ!n] to return to the list.",
1952 "- - Saving changes -",
1954 "When all settings seem correct, and you wish to proceed with the",
1955 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1956 "confirm your choice.",
1965 ** Displays help text onscreen for people that are confused, using a simple
1971 int topline = 0; /* where we are in the text */
1972 int line = 0; /* last line we displayed */
1976 for (;;) /* loop until user quits */
1978 /* display help text */
1981 clear(); /* remove everything else */
1982 for (line = topline;
1983 (line < (topline + 24)) && (helptext[line]);
1985 putxy(0,line-topline,helptext[line]);
1990 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1993 c = kgetchar(); /* so what do they say? */
2000 case 'B': /* wired into 'more' users' fingers */
2001 if (topline > 0) /* room to go up? */
2004 if (topline < 0) /* don't go too far */
2012 case ' ': /* expected by most people */
2013 if (helptext[line]) /* maybe more below? */
2022 redraw(); /* restore the screen */
2030 ** High-level control functions
2037 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2038 ** (num) lines, starting at (*ofs) offset from row onscreen.
2039 ** Pass (detail) on to drawing routines.
2041 ** If the user hits a key other than a cursor key, maybe return a code.
2043 ** (*list) points to the device at the top line in the region, (*ofs) is the
2044 ** position of the highlight within the region. All routines below
2045 ** this take only a device and an absolute row : use ofsent() to find the
2046 ** device, and add (*ofs) to (row) to find the absolute row.
2049 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2060 showparams(ofsent(*ofs,*list)); /* show device parameters */
2061 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2065 c = kgetchar(); /* get a character */
2066 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2068 extended = 0; /* no longer */
2071 case 588: /* syscons' idea of 'up' */
2073 if (*ofs) /* just a move onscreen */
2075 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2076 (*ofs)--; /* move up */
2078 lp = prevent(*list); /* can we go up? */
2081 *list = lp; /* yes, move up list */
2082 drawlist(row,num,detail,*list);
2087 case 596: /* dooby-do */
2088 case 'B': /* down */
2089 lp = ofsent(*ofs,*list); /* get current item */
2091 break; /* nothing more to move to */
2092 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2093 if (*ofs < (num-1)) /* room to move onscreen? */
2097 *list = nextent(*list); /* scroll region down */
2098 drawlist(row,num,detail,*list);
2110 case '[': /* cheat : always preceeds cursor move */
2111 case 'O': /* ANSI application key mode */
2120 return(KEY_EXIT); /* user requests exit */
2124 return(KEY_DO); /* "do" something */
2129 return(KEY_DEL); /* "delete" response */
2133 return(KEY_UNZOOM); /* expand everything */
2137 return(KEY_ZOOM); /* collapse everything */
2140 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2141 return(KEY_TAB); /* "move" response */
2143 case '\014': /* ^L, redraw */
2146 case '?': /* helptext */
2158 ** Do the fullscreen config thang
2163 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2167 initlist(&inactive);
2173 conflicts = findconflict(active); /* find conflicts in the active list only */
2181 case 0: /* active devices */
2182 ret = dolist(1,8,1,&actofs,&alist,
2183 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2187 mode = 1; /* swap lists */
2204 collapselist(active);
2209 dp = ofsent(actofs,alist); /* get current device */
2210 if (dp) /* paranoia... */
2212 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2214 if (dp == alist) /* moving top item on list? */
2218 alist = dp->next; /* point list to non-moving item */
2220 alist = dp->prev; /* end of list, go back instead */
2223 if (!dp->next) /* moving last item on list? */
2226 dp->conflicts = 0; /* no conflicts on the inactive list */
2227 movedev(dp,inactive); /* shift to inactive list */
2228 conflicts = findconflict(active); /* update conflict tags */
2230 redrawactive(); /* redraw */
2235 case KEY_DO: /* edit device parameters */
2236 dp = ofsent(actofs,alist); /* get current device */
2237 if (dp) /* paranoia... */
2239 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2241 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2243 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2245 conflicts = findconflict(active); /* update conflict tags */
2246 }else{ /* DO on comment = zoom */
2247 switch(dp->comment) /* Depends on current state */
2249 case DEV_COMMENT: /* not currently zoomed */
2250 dp->comment = DEV_ZOOMED;
2254 dp->comment = DEV_COMMENT;
2264 case 1: /* inactive devices */
2265 ret = dolist(10,7,0,&inactofs,&ilist,
2266 " [!bEnter!n] Enable device ");
2280 expandlist(inactive);
2287 collapselist(inactive);
2292 dp = ofsent(inactofs,ilist); /* get current device */
2293 if (dp) /* paranoia... */
2295 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2297 if (dp == ilist) /* moving top of list? */
2301 ilist = dp->next; /* point list to non-moving item */
2303 ilist = dp->prev; /* can't go down, go up instead */
2306 if (!dp->next) /* last entry on list? */
2307 inactofs--; /* shift cursor up one */
2310 movedev(dp,active); /* shift to active list */
2311 conflicts = findconflict(active); /* update conflict tags */
2313 alist = dp; /* put at top and current */
2315 while(dp->comment == DEV_DEVICE)
2316 dp = dp->prev; /* forcibly unzoom section */
2317 dp ->comment = DEV_COMMENT;
2318 mode = 0; /* and swap modes to follow it */
2320 }else{ /* DO on comment = zoom */
2321 switch(dp->comment) /* Depends on current state */
2323 case DEV_COMMENT: /* not currently zoomed */
2324 dp->comment = DEV_ZOOMED;
2328 dp->comment = DEV_COMMENT;
2332 redrawactive(); /* redraw */
2337 default: /* nothing else relevant here */
2342 mode = 0; /* shouldn't happen... */
2345 /* handle returns that are the same for both modes */
2352 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2355 case 2: /* cancel */
2359 case 1: /* save and exit */
2361 savelist(inactive,0);
2364 nukelist(active); /* clean up after ourselves */
2374 #endif /* VISUAL_USERCONFIG */
2377 * Copyright (c) 1991 Regents of the University of California.
2378 * All rights reserved.
2379 * Copyright (c) 1994 Jordan K. Hubbard
2380 * All rights reserved.
2381 * Copyright (c) 1994 David Greenman
2382 * All rights reserved.
2384 * Many additional changes by Bruce Evans
2386 * This code is derived from software contributed by the
2387 * University of California Berkeley, Jordan K. Hubbard,
2388 * David Greenman and Bruce Evans.
2390 * Redistribution and use in source and binary forms, with or without
2391 * modification, are permitted provided that the following conditions
2393 * 1. Redistributions of source code must retain the above copyright
2394 * notice, this list of conditions and the following disclaimer.
2395 * 2. Redistributions in binary form must reproduce the above copyright
2396 * notice, this list of conditions and the following disclaimer in the
2397 * documentation and/or other materials provided with the distribution.
2398 * 3. All advertising materials mentioning features or use of this software
2399 * must display the following acknowledgement:
2400 * This product includes software developed by the University of
2401 * California, Berkeley and its contributors.
2402 * 4. Neither the name of the University nor the names of its contributors
2403 * may be used to endorse or promote products derived from this software
2404 * without specific prior written permission.
2406 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2407 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2408 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2409 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2410 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2411 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2412 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2414 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2415 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2418 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2421 #define PARM_DEVSPEC 0x1
2422 #define PARM_INT 0x2
2423 #define PARM_ADDR 0x3
2424 #define PARM_STRING 0x4
2426 typedef struct _cmdparm {
2429 struct uc_device *dparm;
2438 typedef int (*CmdFunc)(CmdParm *);
2440 typedef struct _cmd {
2448 static void lsscsi(void);
2449 static int list_scsi(CmdParm *);
2452 static int lsdevtab(struct uc_device *);
2453 static struct uc_device *find_device(char *, int);
2454 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2455 static void cngets(char *, int);
2456 static Cmd *parse_cmd(char *);
2457 static int parse_args(const char *, CmdParm *);
2458 static int save_dev(struct uc_device *);
2460 static int list_devices(CmdParm *);
2461 static int set_device_ioaddr(CmdParm *);
2462 static int set_device_irq(CmdParm *);
2463 static int set_device_drq(CmdParm *);
2464 static int set_device_iosize(CmdParm *);
2465 static int set_device_mem(CmdParm *);
2466 static int set_device_flags(CmdParm *);
2467 static int set_device_enable(CmdParm *);
2468 static int set_device_disable(CmdParm *);
2469 static int quitfunc(CmdParm *);
2470 static int helpfunc(CmdParm *);
2471 static int introfunc(CmdParm *);
2474 static int lspnp(void);
2475 static int set_pnp_parms(CmdParm *);
2480 #include "use_eisa.h"
2484 #include <bus/eisa/eisaconf.h>
2486 static int set_num_eisa_slots(CmdParm *);
2488 #endif /* NEISA > 0 */
2490 static CmdParm addr_parms[] = {
2491 { PARM_DEVSPEC, {} },
2496 static CmdParm int_parms[] = {
2497 { PARM_DEVSPEC, {} },
2502 static CmdParm dev_parms[] = {
2503 { PARM_DEVSPEC, {} },
2508 static CmdParm string_arg[] = {
2509 { PARM_STRING, {} },
2515 static CmdParm int_arg[] = {
2519 #endif /* NEISA > 0 */
2521 static Cmd CmdList[] = {
2522 { "?", helpfunc, NULL }, /* ? (help) */
2523 { "di", set_device_disable, dev_parms }, /* disable dev */
2524 { "dr", set_device_drq, int_parms }, /* drq dev # */
2526 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2527 #endif /* NEISA > 0 */
2528 { "en", set_device_enable, dev_parms }, /* enable dev */
2529 { "ex", quitfunc, NULL }, /* exit (quit) */
2530 { "f", set_device_flags, int_parms }, /* flags dev mask */
2531 { "h", helpfunc, NULL }, /* help */
2532 { "intro", introfunc, NULL }, /* intro screen */
2533 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2534 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2535 { "ir", set_device_irq, int_parms }, /* irq dev # */
2536 { "l", list_devices, NULL }, /* ls, list */
2538 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2540 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2541 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2542 { "q", quitfunc, NULL }, /* quit */
2544 { "s", list_scsi, NULL }, /* scsi */
2546 #ifdef VISUAL_USERCONFIG
2547 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2549 { NULL, NULL, NULL },
2555 static char banner = 1;
2561 init_config_script();
2564 /* Only display signon banner if we are about to go interactive */
2565 if (!has_config_script()) {
2566 if (!(boothowto & RB_CONFIG))
2567 #ifdef INTRO_USERCONFIG
2574 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2575 " Type \"help\" for help"
2576 #ifdef VISUAL_USERCONFIG
2577 " or \"visual\" to go to the visual\n"
2578 " configuration interface (requires MGA/VGA display or\n"
2579 " serial terminal capable of displaying ANSI graphics)"
2585 kprintf("config> ");
2587 if (input[0] == '\0')
2589 cmd = parse_cmd(input);
2591 kprintf("Invalid command or syntax. Type `?' for help.\n");
2594 rval = (*cmd->handler)(cmd->parms);
2603 parse_cmd(char *cmd)
2607 for (cp = CmdList; cp->name; cp++) {
2608 int len = strlen(cp->name);
2610 if (!strncmp(cp->name, cmd, len)) {
2611 while (*cmd && *cmd != ' ' && *cmd != '\t')
2613 if (parse_args(cmd, cp->parms))
2623 parse_args(const char *cmd, CmdParm *parms)
2628 if (*cmd == ' ' || *cmd == '\t') {
2632 if (parms == NULL || parms->type == -1) {
2635 kprintf("Extra arg(s): %s\n", cmd);
2638 if (parms->type == PARM_DEVSPEC) {
2643 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2644 (*cmd >= '0' && *cmd <= '9')))
2645 devname[i++] = *(cmd++);
2647 if (*cmd >= '0' && *cmd <= '9') {
2648 unit = strtoul(cmd, &ptr, 10);
2650 kprintf("Invalid device number\n");
2651 /* XXX should print invalid token here and elsewhere. */
2654 /* XXX else should require end of token. */
2657 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2658 kprintf("No such device: %s%d\n", devname, unit);
2664 if (parms->type == PARM_INT) {
2665 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2667 kprintf("Invalid numeric argument\n");
2674 if (parms->type == PARM_ADDR) {
2675 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2677 kprintf("Invalid address argument\n");
2684 if (parms->type == PARM_STRING) {
2685 parms->parm.u.sparm = cmd;
2693 list_devices(CmdParm *parms)
2696 if (lsdevtab(uc_devtab)) return 0;
2698 if (lspnp()) return 0;
2701 kprintf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2702 #endif /* NEISA > 0 */
2707 set_device_ioaddr(CmdParm *parms)
2709 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2710 save_dev(parms[0].parm.dparm);
2715 set_device_irq(CmdParm *parms)
2719 irq = parms[1].parm.iparm;
2721 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2724 else if (irq != -1 && irq > 15) {
2725 kprintf("An IRQ > 15 would be invalid.\n");
2728 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2729 save_dev(parms[0].parm.dparm);
2734 set_device_drq(CmdParm *parms)
2739 * The bounds checking is just to ensure that the value can be printed
2740 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2742 drq = parms[1].parm.iparm;
2743 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2744 save_dev(parms[0].parm.dparm);
2749 set_device_iosize(CmdParm *parms)
2751 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2752 save_dev(parms[0].parm.dparm);
2757 set_device_mem(CmdParm *parms)
2759 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2760 save_dev(parms[0].parm.dparm);
2765 set_device_flags(CmdParm *parms)
2767 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2768 save_dev(parms[0].parm.dparm);
2773 set_device_enable(CmdParm *parms)
2775 parms[0].parm.dparm->id_enabled = TRUE;
2776 save_dev(parms[0].parm.dparm);
2781 set_device_disable(CmdParm *parms)
2783 parms[0].parm.dparm->id_enabled = FALSE;
2784 save_dev(parms[0].parm.dparm);
2791 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2797 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2800 * Output the pnp_ldn_overrides[] table.
2802 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2803 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2804 if(error) return(error);
2809 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2810 0, 0, sysctl_machdep_uc_pnplist, "A",
2811 "List of PnP overrides changed in UserConfig");
2814 * this function sets the kernel table to override bios PnP
2818 set_pnp_parms(CmdParm *parms)
2820 u_long idx, val, ldn, csn;
2823 const char *p = parms[0].parm.u.sparm;
2826 csn=strtoul(p,&q, 0);
2827 ldn=strtoul(q,&q, 0);
2828 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2829 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2830 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2833 for (i=0; i < MAX_PNP_LDN; i++) {
2834 if (pnp_ldn_overrides[i].csn == csn &&
2835 pnp_ldn_overrides[i].ldn == ldn)
2838 if (i==MAX_PNP_LDN) {
2839 for (i=0; i < MAX_PNP_LDN; i++) {
2840 if (pnp_ldn_overrides[i].csn <1 ||
2841 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2845 if (i==MAX_PNP_LDN) {
2846 kprintf("sorry, no PnP entries available, try delete one\n");
2849 d = pnp_ldn_overrides[i] ;
2855 if (!strncmp(p,"irq",3)) {
2856 idx=strtoul(p+3,&q, 0);
2857 val=strtoul(q,&q, 0);
2858 if (idx >=0 && idx < 2) d.irq[idx] = val;
2859 } else if (!strncmp(p,"flags",5)) {
2860 idx=strtoul(p+5,&q, 0);
2862 } else if (!strncmp(p,"drq",3)) {
2863 idx=strtoul(p+3,&q, 0);
2864 val=strtoul(q,&q, 0);
2865 if (idx >=0 && idx < 2) d.drq[idx] = val;
2866 } else if (!strncmp(p,"port",4)) {
2867 idx=strtoul(p+4,&q, 0);
2868 val=strtoul(q,&q, 0);
2869 if (idx >=0 && idx < 8) d.port[idx] = val;
2870 } else if (!strncmp(p,"mem",3)) {
2871 idx=strtoul(p+3,&q, 0);
2872 val=strtoul(q,&q, 0);
2873 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2874 } else if (!strncmp(p,"bios",4)) {
2877 } else if (!strncmp(p,"os",2)) {
2880 } else if (!strncmp(p,"disable",7)) {
2883 } else if (!strncmp(p,"enable",6)) {
2886 } else if (!strncmp(p,"delete",6)) {
2887 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2888 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2891 kprintf("unknown command <%s>\n", p);
2894 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2896 pnp_ldn_overrides[i] = d ;
2903 set_num_eisa_slots(CmdParm *parms)
2907 num_slots = parms[0].parm.iparm;
2908 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2911 #endif /* NEISA > 0 */
2914 quitfunc(CmdParm *parms)
2917 * If kernel config supplied, and we are parsing it, and -c also supplied,
2918 * ignore a quit command, This provides a safety mechanism to allow
2919 * recovery from a damaged/buggy kernel config.
2921 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2927 helpfunc(CmdParm *parms)
2930 "Command\t\t\tDescription\n"
2931 "-------\t\t\t-----------\n"
2932 "ls\t\t\tList currently configured devices\n"
2933 "port <devname> <addr>\tSet device port (i/o address)\n"
2934 "irq <devname> <number>\tSet device irq\n"
2935 "drq <devname> <number>\tSet device drq\n"
2936 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2937 "iosize <devname> <size>\tSet device memory size\n"
2938 "flags <devname> <mask>\tSet device flags\n"
2939 "enable <devname>\tEnable device\n"
2940 "disable <devname>\tDisable device (will not be probed)\n");
2943 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2944 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2945 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2946 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2947 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2948 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2951 kprintf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2952 #endif /* NEISA > 0 */
2954 "quit\t\t\tExit this configuration utility\n"
2955 "reset\t\t\tReset CPU\n");
2956 #ifdef VISUAL_USERCONFIG
2957 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2960 "help\t\t\tThis message\n\n"
2961 "Commands may be abbreviated to a unique prefix\n");
2965 #if defined (VISUAL_USERCONFIG)
2967 center(int y, char *str)
2969 putxy((80 - strlen(str)) / 2, y, str);
2974 introfunc(CmdParm *parms)
2976 #if defined (VISUAL_USERCONFIG)
2977 int curr_item, first_time, extended = 0;
2978 static char *choices[] = {
2979 " Skip kernel configuration and continue with installation ",
2980 " Start kernel configuration in full-screen visual mode ",
2981 " Start kernel configuration in CLI mode ",
2985 center(2, "!bKernel Configuration Menu!n");
2994 for (i = 0; i < 3; i++) {
2998 strcat(tmp, choices[i]);
3001 putxy(10, 5 + i, tmp);
3005 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3006 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3007 putxy(2, 12, "match your hardware configuration.");
3008 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3009 putxy(2, 15, "(press Down-Arrow then ENTER).");
3010 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3011 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3012 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3013 putxy(2, 21, "then simply press ENTER or Q now.");
3017 move(0, 0); /* move the cursor out of the way */
3020 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3021 extended = 0; /* no longer */
3030 case 'B': /* down */
3042 case '[': /* cheat : always preceeds cursor move */
3043 case 'O': /* ANSI application key mode */
3054 return 1; /* user requests exit */
3056 case '1': /* select an item */
3080 case 'D': /* down */
3093 else if (curr_item == 1)
3094 return visuserconfig();
3096 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3097 /* enable quitfunc */
3098 userconfig_boot_parsing=0;
3100 boothowto |= RB_CONFIG; /* force -c */
3114 struct pnp_cinfo *c;
3118 for (i=0; i< MAX_PNP_LDN; i++) {
3119 c = &pnp_ldn_overrides[i];
3120 if (c->csn >0 && c->csn != 255) {
3122 static char pfmt[] =
3123 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3124 static char mfmt[] =
3125 "mem 0x%x 0x%x 0x%x 0x%x";
3128 if (!userconfig_boot_parsing) {
3130 if (kgetchar() == 'q') {
3138 if (lineno == 0 || first)
3139 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3141 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3143 c->override ? "OS ":"BIOS",
3144 c->enable ? "Y":"N",
3145 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3147 kprintf("flags 0x%08lx ",c->flags);
3148 for (pmax = 7; pmax >=0 ; pmax--)
3149 if (c->port[pmax]!=0) break;
3150 for (mmax = 3; mmax >=0 ; mmax--)
3151 if (c->mem[mmax].base!=0) break;
3154 buf[10 + 5*pmax]='\0';
3156 c->port[0], c->port[1], c->port[2], c->port[3],
3157 c->port[4], c->port[5], c->port[6], c->port[7]);
3161 buf[8 + 5*mmax]='\0';
3163 c->mem[0].base, c->mem[1].base,
3164 c->mem[2].base, c->mem[3].base);
3174 lsdevtab(struct uc_device *dt)
3176 for (; dt->id_id != 0; dt++) {
3181 if (!userconfig_boot_parsing) {
3182 if (kgetchar() == 'q') {
3192 "Device port irq drq iomem iosize unit flags enab\n"
3196 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3197 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3198 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3199 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3200 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3201 dt->id_enabled ? "Yes" : "No");
3211 int count = resource_count();
3217 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3220 for (i = 0; i < count; i++) {
3221 name = resource_query_name(i);
3222 unit = resource_query_unit(i);
3224 continue; /* skip wildcards */
3225 uc_devtab[dt].id_id = id++;
3226 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3228 resource_int_value(name, unit, "irq", &val);
3229 uc_devtab[dt].id_irq = (1 << val);
3230 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3231 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3232 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3233 uc_devtab[dt].id_unit = unit;
3234 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3236 resource_int_value(name, unit, "disabled", &val);
3237 uc_devtab[dt].id_enabled = !val;
3238 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3239 strcpy(uc_devtab[dt].id_name, name);
3248 int count = resource_count();
3250 for (i = 0; i < count; i++)
3251 if (uc_devtab[i].id_name)
3252 kfree(uc_devtab[i].id_name, M_DEVL);
3253 kfree(uc_devtab, M_DEVL);
3256 static struct uc_device *
3257 find_device(char *devname, int unit)
3259 struct uc_device *ret;
3261 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3266 static struct uc_device *
3267 search_devtable(struct uc_device *dt, char *devname, int unit)
3271 for (i = 0; dt->id_id != 0; dt++)
3272 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3278 cngets(char *input, int maxin)
3284 /* Treat ^H or ^? as backspace */
3285 if ((c == '\010' || c == '\177')) {
3287 kprintf("\010 \010");
3288 *--input = '\0', --nchars;
3292 /* Treat ^U or ^X as kill line */
3293 else if ((c == '\025' || c == '\030')) {
3295 kprintf("\010 \010");
3296 *--input = '\0', --nchars;
3301 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3305 *input++ = (u_char)c;
3311 /* scsi: Support for displaying configured SCSI devices.
3312 * There is no way to edit them, and this is inconsistent
3313 * with the ISA method. This is here as a basis for further work.
3316 type_text(char *name) /* XXX: This is bogus */
3318 if (strcmp(name, "sd") == 0)
3321 if (strcmp(name, "st") == 0)
3327 id_put(char *desc, int id)
3329 if (id != SCCONF_UNSPEC)
3332 kprintf("%s", desc);
3334 if (id == SCCONF_ANY)
3346 kprintf("scsi: (can't be edited):\n");
3348 for (i = 0; scsi_cinit[i].driver; i++)
3350 id_put("controller scbus", scsi_cinit[i].scbus);
3352 if (scsi_cinit[i].unit != -1)
3355 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3361 for (i = 0; scsi_dinit[i].name; i++)
3363 kprintf("%s ", type_text(scsi_dinit[i].name));
3365 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3366 id_put(" at scbus", scsi_dinit[i].cunit);
3367 id_put(" target ", scsi_dinit[i].target);
3368 id_put(" lun ", scsi_dinit[i].lun);
3370 if (scsi_dinit[i].flags)
3371 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3378 list_scsi(CmdParm *parms)
3387 save_resource(struct uc_device *idev)
3392 name = idev->id_name;
3393 unit = idev->id_unit;
3394 resource_set_int(name, unit, "port", idev->id_iobase);
3395 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3396 resource_set_int(name, unit, "drq", idev->id_drq);
3397 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3398 resource_set_int(name, unit, "msize", idev->id_msize);
3399 resource_set_int(name, unit, "flags", idev->id_flags);
3400 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3404 save_dev(struct uc_device *idev)
3406 struct uc_device *id_p,*id_pn;
3407 char *name = idev->id_name;
3409 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3410 if (id_p->id_id == idev->id_id) {
3411 id_pn = id_p->id_next;
3413 kfree(id_p->id_name, M_DEVL);
3414 bcopy(idev,id_p,sizeof(struct uc_device));
3415 save_resource(idev);
3416 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3417 strcpy(id_p->id_name, name);
3418 id_p->id_next = id_pn;
3422 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3423 bcopy(idev,id_pn,sizeof(struct uc_device));
3424 save_resource(idev);
3425 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3426 strcpy(id_pn->id_name, name);
3427 id_pn->id_next = uc_devlist;