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.4 2005/01/31 23:44:35 joerg 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 _I386_ISA_ISA_DEVICE_H_
122 #include <i386/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 #define putchar(x) cnputc(x)
135 static void load_devtab(void);
136 static void free_devtab(void);
137 static void save_resource(struct uc_device *);
140 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
142 struct uc_device *id;
150 error+=sizeof(struct uc_device)+8;
153 return(SYSCTL_OUT(req,0,error));
155 /* Output the data. The buffer is filled with consecutive
156 * struct uc_device and char buf[8], containing the name
157 * (not guaranteed to end with '\0').
161 error=sysctl_handle_opaque(oidp,id,
162 sizeof(struct uc_device),req);
163 if(error) return(error);
164 strncpy(name,id->id_name,8);
165 error=sysctl_handle_opaque(oidp,name,
167 if(error) return(error);
174 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
175 0, 0, sysctl_machdep_uc_devlist, "A",
176 "List of ISA devices changed in UserConfig");
179 ** Obtain command input.
181 ** Initially, input is read from a possibly-loaded script.
182 ** At the end of the script, or if no script is supplied,
183 ** behaviour is determined by the RB_CONFIG (-c) flag. If
184 ** the flag is set, user input is read from the console; if
185 ** unset, the 'quit' command is invoked and userconfig
188 ** Note that quit commands encountered in the script will be
189 ** ignored if the RB_CONFIG flag is supplied.
191 static const char *config_script;
192 static int config_script_size; /* use of int for -ve magic value */
194 #define has_config_script() (config_script_size > 0)
197 init_config_script(void)
199 caddr_t autoentry, autoattr;
201 /* Look for loaded userconfig script */
202 autoentry = preload_search_by_type("userconfig_script");
203 if (autoentry != NULL) {
204 /* We have one, get size and data */
205 config_script_size = 0;
206 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
207 config_script_size = (size_t)*(u_int32_t *)autoattr;
208 config_script = NULL;
209 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
210 config_script = *(const char **)autoattr;
212 if ((config_script_size == 0) || (config_script == NULL)) {
213 config_script_size = 0;
214 config_script = NULL;
217 return has_config_script();
224 #ifdef INTRO_USERCONFIG
225 static int intro = 0;
228 if (has_config_script())
230 /* Consume character from loaded userconfig script, display */
231 userconfig_boot_parsing = 1;
234 config_script_size--;
238 #ifdef INTRO_USERCONFIG
239 if (userconfig_boot_parsing) {
240 if (!(boothowto & RB_CONFIG)) {
241 /* userconfig_script, !RB_CONFIG -> quit */
244 config_script = "uit\n";
245 config_script_size = strlen(config_script);
246 /* userconfig_script will be 1 on the next pass */
249 /* userconfig_script, RB_CONFIG -> cngetc() */
252 if (!(boothowto & RB_CONFIG)) {
253 /* no userconfig_script, !RB_CONFIG -> show intro */
257 config_script = "ntro\n";
258 config_script_size = strlen(config_script);
259 /* userconfig_script will be 1 on the next pass */
262 /* no userconfig_script, RB_CONFIG -> cngetc() */
265 #else /* !INTRO_USERCONFIG */
266 /* assert(boothowto & RB_CONFIG) */
267 #endif /* INTRO_USERCONFIG */
268 userconfig_boot_parsing = 0;
277 #define TRUE (!FALSE)
280 #ifdef VISUAL_USERCONFIG
284 char dev[16]; /* device basename */
285 char name[60]; /* long name */
286 int attrib; /* things to do with the device */
287 int class; /* device classification */
290 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
291 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
292 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
293 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
294 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
295 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
296 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
297 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
298 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
300 #define CLS_STORAGE 1 /* storage devices */
301 #define CLS_NETWORK 2 /* network interfaces */
302 #define CLS_COMMS 3 /* serial, parallel ports */
303 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
304 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
305 #define CLS_MISC 255 /* none of the above */
314 static DEVCLASS_INFO devclass_names[] = {
315 { "Storage : ", CLS_STORAGE},
316 { "Network : ", CLS_NETWORK},
317 { "Communications : ", CLS_COMMS},
318 { "Input : ", CLS_INPUT},
319 { "Multimedia : ", CLS_MMEDIA},
320 { "Miscellaneous : ", CLS_MISC},
324 /********************* EDIT THIS LIST **********************/
328 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
329 ** - XXX The list below should be reviewed by the driver authors to verify
330 ** that the correct flags have been set for each driver, and that the
331 ** descriptions are accurate.
334 static DEV_INFO device_info[] = {
335 /*---Name----- ---Description---------------------------------------------- */
336 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
337 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE},
338 {"aha", "Adaptec 154x SCSI controller", 0, CLS_STORAGE},
339 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE},
340 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
341 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
342 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
343 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
344 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
345 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
346 {"mcd", "Mitsumi CD-ROM", 0, CLS_STORAGE},
347 {"scd", "Sony CD-ROM", 0, CLS_STORAGE},
348 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE},
349 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
350 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
351 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
353 {"cm", "SMC COM90Cx6-based Arcnet adapters", 0, CLS_NETWORK},
354 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
355 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
356 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
357 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
358 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
359 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
360 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
361 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
362 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
363 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
364 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
365 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
366 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
368 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
369 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
370 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
371 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
372 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
373 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
374 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
375 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
376 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
377 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
379 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
380 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
381 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
382 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
383 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
384 {"vt", "PCVT console driver", FLG_IMMUTABLE, CLS_INPUT},
385 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
387 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
388 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
389 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
390 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
391 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
392 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
393 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
394 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
395 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
396 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
397 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
398 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
399 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
400 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
401 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
402 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
403 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
404 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
405 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
406 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
407 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
408 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
410 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
411 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
412 {"pcic", "PC-card controller", 0, CLS_MISC},
413 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
414 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
418 typedef struct _devlist_struct
421 int attrib; /* flag values as per the FLG_* defines above */
422 int class; /* disk, etc as per the CLS_* defines above */
424 int iobase,irq,drq,maddr,msize,unit,flags,id;
425 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
426 int conflicts; /* set/reset by findconflict, count of conflicts */
427 int changed; /* nonzero if the device has been edited */
428 struct uc_device *device;
429 struct _devlist_struct *prev,*next;
434 #define DEV_COMMENT 1
437 #define LIST_CURRENT (1<<0)
438 #define LIST_SELECTED (1<<1)
440 #define KEY_EXIT 0 /* return codes from dolist() and friends */
446 #define KEY_UP 5 /* these only returned from editval() */
450 #define KEY_NULL 9 /* this allows us to spin & redraw */
452 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
453 #define KEY_UNZOOM 11
455 #define KEY_HELP 12 /* duh? */
457 static void redraw(void);
458 static void insdev(DEV_LIST *dev, DEV_LIST *list);
459 static int devinfo(DEV_LIST *dev);
460 static int visuserconfig(void);
462 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
463 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
464 static DEV_LIST scratch; /* scratch record */
465 static int conflicts; /* total conflict count */
468 static char lines[] = "--------------------------------------------------------------------------------";
469 static char spaces[] = " ";
473 ** Device manipulation stuff : find, describe, configure.
479 ** Sets the device referenced by (*dev) to the parameters in the struct,
480 ** and the enable flag according to (enabled)
483 setdev(DEV_LIST *dev, int enabled)
485 dev->device->id_iobase = dev->iobase; /* copy happy */
486 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
487 dev->device->id_drq = (short)dev->drq;
488 dev->device->id_maddr = (caddr_t)dev->maddr;
489 dev->device->id_msize = dev->msize;
490 dev->device->id_flags = dev->flags;
491 dev->device->id_enabled = enabled;
498 ** Walk the kernel device tables and build the active and inactive lists
504 struct uc_device *ap;
506 ap = uc_devtab; /* pointer to array of devices */
507 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
509 scratch.unit = ap[i].id_unit; /* device parameters */
510 strcpy(scratch.dev,ap[i].id_name);
511 scratch.iobase = ap[i].id_iobase;
512 scratch.irq = ffs(ap[i].id_irq)-1;
513 scratch.drq = ap[i].id_drq;
514 scratch.maddr = (int)ap[i].id_maddr;
515 scratch.msize = ap[i].id_msize;
516 scratch.flags = ap[i].id_flags;
518 scratch.comment = DEV_DEVICE; /* admin stuff */
519 scratch.conflicts = 0;
520 scratch.device = &ap[i]; /* save pointer for later reference */
522 if (!devinfo(&scratch)) /* get more info on the device */
523 insdev(&scratch,ap[i].id_enabled?active:inactive);
531 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
532 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
534 ** If the device is marked "invisible", return nonzero; the caller should
535 ** not insert any such device into either list.
539 devinfo(DEV_LIST *dev)
543 for (i = 0; device_info[i].class; i++)
545 if (!strcmp(dev->dev,device_info[i].dev))
547 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
549 strcpy(dev->name,device_info[i].name); /* get the name */
550 dev->attrib = device_info[i].attrib;
551 dev->class = device_info[i].class;
555 strcpy(dev->name,"Unknown device");
557 dev->class = CLS_MISC;
563 ** List manipulation stuff : add, move, initialise, free, traverse
565 ** Note that there are assumptions throughout this code that
566 ** the first entry in a list will never move. (assumed to be
574 ** appends a copy of (dev) to the end of (*list)
577 addev(DEV_LIST *dev, DEV_LIST **list)
582 lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
583 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
585 if (*list) /* list exists */
589 ap = ap->next; /* scoot to end of list */
593 }else{ /* list does not yet exist */
595 lp->prev = lp->next = NULL; /* list now exists */
603 ** Finds the 'appropriate' place for (dev) in (list)
605 ** 'Appropriate' means in numeric order with other devices of the same type,
606 ** or in alphabetic order following a comment of the appropriate type.
607 ** or at the end of the list if an appropriate comment is not found. (this should
609 ** (Note that the appropriate point is never the top, but may be the bottom)
612 findspot(DEV_LIST *dev, DEV_LIST *list)
616 /* search for a previous instance of the same device */
617 for (ap = list; ap; ap = ap->next)
619 if (ap->comment != DEV_DEVICE) /* ignore comments */
621 if (!strcmp(dev->dev,ap->dev)) /* same base device */
623 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
624 || !ap->next) /* or end of list */
626 ap = ap->prev; /* back up one */
627 break; /* done here */
629 if (ap->next) /* if the next item exists */
631 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
633 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
639 if (!ap) /* not sure yet */
641 /* search for a class that the device might belong to */
642 for (ap = list; ap; ap = ap->next)
644 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
646 if (dev->class != ap->class) /* of same class too 8) */
648 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
650 ap = ap->prev; /* back up one */
651 break; /* done here */
653 if (ap->next) /* if the next item exists */
654 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
659 if (!ap) /* didn't find a match */
661 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
662 if ((ap->comment != DEV_DEVICE)
663 && (ap->class == dev->class)) /* appropriate place? */
665 } /* or just put up with last */
674 ** Inserts a copy of (dev) at the appropriate point in (list)
677 insdev(DEV_LIST *dev, DEV_LIST *list)
681 lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
682 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
684 ap = findspot(lp,list); /* find appropriate spot */
685 lp->next = ap->next; /* point to next */
687 ap->next->prev = lp; /* point next to new */
688 lp->prev = ap; /* point new to current */
689 ap->next = lp; /* and current to new */
696 ** Moves (dev) from its current list to an appropriate place in (list)
697 ** (dev) may not come from the top of a list, but it may from the bottom.
700 movedev(DEV_LIST *dev, DEV_LIST *list)
704 ap = findspot(dev,list);
705 dev->prev->next = dev->next; /* remove from old list */
707 dev->next->prev = dev->prev;
709 dev->next = ap->next; /* insert in new list */
711 ap->next->prev = dev; /* point next to new */
712 dev->prev = ap; /* point new to current */
713 ap->next = dev; /* and current to new */
720 ** Initialises (*list) with the basic headings
723 initlist(DEV_LIST **list)
727 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
729 strcpy(scratch.name,devclass_names[i].name);
730 scratch.comment = DEV_ZOOMED;
731 scratch.class = devclass_names[i].number;
732 scratch.attrib = FLG_MANDATORY; /* can't be moved */
733 addev(&scratch,list); /* add to the list */
741 ** Walks (list) and saves the settings of any entry marked as changed.
743 ** The device's active field is set according to (active).
745 ** Builds the uc_devlist used by kget to extract the changed device information.
746 ** The code for this was taken almost verbatim from the original module.
749 savelist(DEV_LIST *list, int active)
751 struct uc_device *id_p,*id_pn;
756 if ((list->comment == DEV_DEVICE) && /* is a device */
757 (list->changed) && /* has been changed */
758 (list->device != NULL)) { /* has an uc_device structure */
760 setdev(list,active); /* set the device itself */
763 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
764 { /* look on the list for it */
765 if (id_p->id_id == list->device->id_id)
767 name = list->device->id_name;
768 id_pn = id_p->id_next;
770 free(id_p->id_name, M_DEVL);
771 bcopy(list->device,id_p,sizeof(struct uc_device));
772 save_resource(list->device);
773 id_p->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
774 strcpy(id_p->id_name, name);
775 id_pn->id_next = uc_devlist;
776 id_p->id_next = id_pn;
780 if (!id_pn) /* not already on the list */
782 name = list->device->id_name;
783 id_pn = malloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
784 bcopy(list->device,id_pn,sizeof(struct uc_device));
785 save_resource(list->device);
786 id_pn->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
787 strcpy(id_pn->id_name, name);
788 id_pn->id_next = uc_devlist;
789 uc_devlist = id_pn; /* park at top of list */
800 ** Frees all storage in use by a (list).
803 nukelist(DEV_LIST *list)
809 while(list->prev) /* walk to head of list */
824 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
825 ** if there is no previous entry. (Only possible if list->prev == NULL given the
826 ** premise that there is always a comment at the head of the list)
829 prevent(DEV_LIST *list)
835 dp = list->prev; /* start back one */
838 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
839 return(dp); /* so skip to comment */
840 if (dp->comment == DEV_COMMENT) /* not zoomed */
841 return(list->prev); /* one back as normal */
842 dp = dp->prev; /* backpedal */
844 return(dp); /* NULL, we can assume */
851 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
852 ** if there is no next entry. (Possible if the current entry is last, or
853 ** if the current entry is the last heading and it's collapsed)
856 nextent(DEV_LIST *list)
862 if (list->comment != DEV_ZOOMED) /* no reason to skip */
867 if (dp->comment != DEV_DEVICE) /* found another heading */
871 return(dp); /* back we go */
878 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
881 ofsent(int ofs, DEV_LIST *list)
883 while (ofs-- && list)
884 list = nextent(list);
892 ** Scans every element of (list) and sets the conflict tags appropriately
893 ** Returns the number of conflicts found.
896 findconflict(DEV_LIST *list)
898 int count = 0; /* number of conflicts found */
901 for (dp = list; dp; dp = dp->next) /* over the whole list */
903 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
906 dp->conflicts = 0; /* assume the best */
907 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
909 if (sp->comment != DEV_DEVICE) /* likewise */
912 if (sp == dp) /* always conflict with itself */
915 if ((dp->iobase > 0) && /* iobase conflict? */
916 (dp->iobase == sp->iobase))
918 if ((dp->irq > 0) && /* irq conflict? */
919 (dp->irq == sp->irq))
921 if ((dp->drq > 0) && /* drq conflict? */
922 (dp->drq == sp->drq))
924 if ((sp->maddr > 0) && /* maddr/msize conflict? */
926 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
927 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
930 count += dp->conflicts; /* count conflicts */
939 ** Unzooms all headings in (list)
942 expandlist(DEV_LIST *list)
946 if (list->comment == DEV_COMMENT)
947 list->comment = DEV_ZOOMED;
956 ** Zooms all headings in (list)
959 collapselist(DEV_LIST *list)
963 if (list->comment == DEV_ZOOMED)
964 list->comment = DEV_COMMENT;
971 ** Screen-manipulation stuff
973 ** This is the basic screen layout :
975 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
976 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
977 ** +--------------------------------------------------------------------------------+
978 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
979 ** 1 -| ........................ ....... .. 0x....|
980 ** 2 -| ........................ ....... .. 0x....|
981 ** 3 -| ........................ ....... .. 0x....|
982 ** 4 -| ........................ ....... .. 0x....|
983 ** 5 -| ........................ ....... .. 0x....|
984 ** 6 -| ........................ ....... .. 0x....|
985 ** 7 -| ........................ ....... .. 0x....|
986 ** 8 -| ........................ ....... .. 0x....|
987 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
988 ** 10-| ........................ ....... |
989 ** 11-| ........................ ....... |
990 ** 12-| ........................ ....... |
991 ** 13-| ........................ ....... |
992 ** 14-| ........................ ....... |
993 ** 15-| ........................ ....... |
994 ** 16-| ........................ ....... |
995 ** 17-|------------------------------------------------------UP-DOWN-------------------|
996 ** 18-| Relevant parameters for the current device |
999 ** 21-|--------------------------------------------------------------------------------|
1000 ** 22-| Help texts go here |
1002 ** +--------------------------------------------------------------------------------+
1006 ** On a collapsed comment :
1008 ** [Enter] Expand device list [z] Expand all lists
1009 ** [TAB] Change fields [Q] Save and Exit
1011 ** On an expanded comment :
1013 ** [Enter] Collapse device list [Z] Collapse all lists
1014 ** [TAB] Change fields [Q] Save and Exit
1016 ** On a comment with no followers
1019 ** [TAB] Change fields [Q] Save and Exit
1021 ** On a device in the active list
1023 ** [Enter] Edit device parameters [DEL] Disable device
1024 ** [TAB] Change fields [Q] Save and Exit [?] Help
1026 ** On a device in the inactive list
1028 ** [Enter] Enable device
1029 ** [TAB] Change fields [Q] Save and Exit [?] Help
1031 ** While editing parameters
1033 ** <parameter-specific help here>
1034 ** [TAB] Change fields [Q] Save device parameters
1041 ** The base-level screen primitives :
1043 ** bold() - enter bold mode \E[1m (md)
1044 ** inverse() - enter inverse mode \E[7m (so)
1045 ** normal() - clear bold/inverse mode \E[m (se)
1046 ** clear() - clear the screen \E[H\E[J (ce)
1047 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1072 printf("\033[H\033[J");
1078 printf("\033[%d;%dH",y+1,x+1);
1084 ** High-level screen primitives :
1086 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1087 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1088 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1089 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1090 ** putmsg(str) - put (str) in the message area
1091 ** puthelp(str) - put (str) in the upper helpline
1092 ** pad(str,len) - pad (str) to (len) with spaces
1093 ** drawline(row,detail,list,inverse,*dhelp)
1094 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1095 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1096 ** draw the line in inverse video, and display (*dhelp) on the
1098 ** drawlist(row,num,detail,list)
1099 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1100 ** through to drawline().
1101 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1102 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1103 ** redraw(); - Redraws the entire screen layout, including the
1104 ** - two list panels.
1109 ** writes (str) at x,y onscreen
1111 ** writes up to (len) of (str) at x,y onscreen.
1113 ** Supports embedded formatting :
1114 ** !i - inverse mode.
1116 ** !n - normal mode.
1119 putxyl(int x, int y, char *str, int len)
1124 while((*str) && (len--))
1126 if (*str == '!') /* format escape? */
1128 switch(*(str+1)) /* depending on the next character */
1132 str +=2; /* skip formatting */
1133 len++; /* doesn't count for length */
1138 str +=2; /* skip formatting */
1139 len++; /* doesn't count for length */
1144 str +=2; /* skip formatting */
1145 len++; /* doesn't count for length */
1149 putchar(*str++); /* not an escape */
1152 putchar(*str++); /* emit the character */
1157 #define putxy(x,y,str) putxyl(x,y,str,-1)
1163 ** Erases the region (x,y,w,h)
1166 erase(int x, int y, int w, int h)
1171 for (i = 0; i < h; i++)
1172 putxyl(x,y++,spaces,w);
1179 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1180 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1183 txtbox(int x, int y, int w, int h, char *str)
1188 while((str[i]) && h)
1190 if (str[i] == '\n') /* newline */
1192 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1193 y++; /* move down */
1194 h--; /* room for one less */
1195 str += (i+1); /* skip first newline */
1196 i = 0; /* zero offset */
1198 i++; /* next character */
1201 if (h) /* end of string, not region */
1209 ** writes (msg) in the helptext area
1214 erase(0,18,80,3); /* clear area */
1215 txtbox(0,18,80,3,msg);
1222 ** Writes (msg) in the helpline area
1235 ** Draws the help message at the bottom of the screen
1238 masterhelp(char *msg)
1248 ** space-pads a (str) to (len) characters
1251 pad(char *str, int len)
1255 for (i = 0; str[i]; i++) /* find the end of the string */
1257 if (i >= len) /* no padding needed */
1259 while(i < len) /* pad */
1268 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1269 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1271 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1272 ** help is shown for normal or zoomed comments
1275 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1277 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1279 if (list->comment == DEV_DEVICE)
1282 strncpy(nb+1,list->name,57);
1284 strncpy(nb,list->name,58);
1285 if ((list->comment == DEV_ZOOMED) && (list->next))
1286 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1287 strcat(nb," (Collapsed)");
1291 if (list->conflicts) /* device in conflict? */
1295 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1297 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1300 if (list->comment == DEV_DEVICE)
1302 sprintf(db,"%s%d",list->dev,list->unit);
1307 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1309 sprintf(ib," %d",list->irq);
1314 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1316 sprintf(pb,"0x%x",list->iobase);
1322 sprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1324 putxyl(0,row,lbuf,80);
1327 switch(list->comment)
1329 case DEV_DEVICE: /* ordinary device */
1335 if (list->next->comment == DEV_DEVICE)
1336 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1341 if (list->next->comment == DEV_DEVICE)
1342 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1345 puthelp(" WARNING: This list entry corrupted!");
1349 move(0,row); /* put the cursor somewhere relevant */
1356 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1357 ** port and IRQ fields as well if (detail) is nonzero
1359 ** printf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1362 drawlist(int row, int num, int detail, DEV_LIST *list)
1366 for(ofs = 0; ofs < num; ofs++)
1370 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1371 list = nextent(list); /* move down visible list */
1373 erase(0,row+ofs,80,1);
1382 ** Redraws the active list
1391 sprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1394 putxyl(45,0,lines,16);
1396 drawlist(1,8,1,alist); /* draw device lists */
1402 ** Redraws the inactive list
1405 redrawinactive(void)
1407 drawlist(10,7,0,ilist); /* draw device lists */
1414 ** Clear the screen and redraw the entire layout
1421 putxy(3,0,"!bActive!n-!bDrivers");
1422 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1424 putxy(3,9,"!bInactive!n-!bDrivers");
1425 putxy(63,9,"!bDev");
1428 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1438 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1439 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1442 yesnocancel(char *str)
1468 ** Show device parameters in the region below the lists
1470 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1471 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1472 ** +--------------------------------------------------------------------------------+
1473 ** 17-|--------------------------------------------------------------------------------|
1474 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1475 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1476 ** 20-| Flags : 0x0000 DRQ number : 00 |
1477 ** 21-|--------------------------------------------------------------------------------|
1480 showparams(DEV_LIST *dev)
1484 erase(0,18,80,3); /* clear area */
1487 if (dev->comment != DEV_DEVICE)
1491 if (dev->iobase > 0)
1493 sprintf(buf,"Port address : 0x%x",dev->iobase);
1499 sprintf(buf,"IRQ number : %d",dev->irq);
1502 sprintf(buf,"Flags : 0x%x",dev->flags);
1506 sprintf(buf,"Memory address : 0x%x",dev->maddr);
1511 sprintf(buf,"Memory size : 0x%x",dev->msize);
1517 sprintf(buf,"DRQ number : %d",dev->drq);
1524 ** Editing functions for device parameters
1526 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1527 ** onscreen. Refuse values outsise (min) and (max).
1528 ** editparams(dev) - Edit the parameters for (dev)
1532 #define VetRet(code) \
1534 if ((i >= min) && (i <= max)) /* legit? */ \
1537 sprintf(buf,hex?"0x%x":"%d",i); \
1538 putxy(hex?x-2:x,y,buf); \
1539 return(code); /* all done and exit */ \
1541 i = *val; /* restore original value */ \
1542 delta = 1; /* restore other stuff */ \
1549 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1550 ** in a field (width) wide. (Allow one space)
1551 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1553 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1556 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1558 int i = *val; /* work with copy of the value */
1559 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1560 int xp = 0; /* cursor offset into text copy */
1561 int delta = 1; /* force redraw first time in */
1563 int extended = 0; /* stage counter for extended key sequences */
1565 if (hex) /* we presume there's a leading 0x onscreen */
1566 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1570 if (delta) /* only update if necessary */
1572 sprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1573 sprintf(buf,"!i%s",tc); /* format for printing */
1574 erase(x,y,width,1); /* clear the area */
1575 putxy(x,y,buf); /* write */
1576 xp = strlen(tc); /* cursor always at end */
1577 move(x+xp,y); /* position the cursor */
1582 switch(extended) /* escape handling */
1585 if (c == 0x1b) /* esc? */
1587 extended = 1; /* flag and spin */
1591 break; /* nope, drop through */
1593 case 1: /* there was an escape prefix */
1594 if (c == '[' || c == 'O') /* second character in sequence */
1600 return(KEY_EXIT); /* double esc exits */
1602 break; /* nup, not a sequence. */
1606 switch(c) /* looks like the real McCoy */
1609 VetRet(KEY_UP); /* leave if OK */
1612 VetRet(KEY_DOWN); /* leave if OK */
1615 VetRet(KEY_RIGHT); /* leave if OK */
1618 VetRet(KEY_LEFT); /* leave if OK */
1628 case '\t': /* trying to tab off */
1629 VetRet(KEY_TAB); /* verify and maybe return */
1639 case '\177': /* BS or DEL */
1640 if (ro) /* readonly? */
1642 puthelp(" !iThis value cannot be edited (Press ESC)");
1643 while(getchar() != 0x1b); /* wait for key */
1644 return(KEY_NULL); /* spin */
1646 if (xp) /* still something left to delete */
1648 i = (hex ? i/0x10u : i/10); /* strip last digit */
1649 delta = 1; /* force update */
1672 if (ro) /* readonly? */
1674 puthelp(" !iThis value cannot be edited (Press ESC)");
1675 while(getchar() != 0x1b); /* wait for key */
1676 return(KEY_NULL); /* spin */
1678 if (xp >= width) /* no room for more characters anyway */
1682 if ((c >= '0') && (c <= '9'))
1684 i = i*0x10 + (c-'0'); /* update value */
1688 if ((c >= 'a') && (c <= 'f'))
1690 i = i*0x10 + (c-'a'+0xa);
1694 if ((c >= 'A') && (c <= 'F'))
1696 i = i*0x10 + (c-'A'+0xa);
1701 if ((c >= '0') && (c <= '9'))
1703 i = i*10 + (c-'0'); /* update value */
1704 delta = 1; /* force redraw */
1717 ** Edit the parameters for (dev)
1719 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1720 ** possible for this to spin in an endless loop...
1721 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1722 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1723 ** +--------------------------------------------------------------------------------+
1724 ** 17-|--------------------------------------------------------------------------------|
1725 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1726 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1727 ** 20-| Flags : 0x0000 DRQ number : 00 |
1728 ** 21-|--------------------------------------------------------------------------------|
1730 ** The "intelligence" in this function that hops around based on the directional
1731 ** returns from editval isn't very smart, and depends on the layout above.
1734 editparams(DEV_LIST *dev)
1737 char buf[16]; /* needs to fit the device name */
1739 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1740 sprintf(buf,"!b%s",dev->dev);
1747 if (dev->iobase > 0)
1749 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1750 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1770 puthelp(" Interrupt number (Decimal, 1-15)");
1771 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1783 if (dev->iobase > 0)
1794 puthelp(" Device-specific flag values.");
1795 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1809 if (dev->iobase > 0)
1829 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1830 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1837 if (dev->iobase > 0)
1859 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1860 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1889 puthelp(" Device DMA request number (Decimal, 1-7)");
1890 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1913 dev->changed = 1; /* mark as changed */
1916 static char *helptext[] =
1918 " Using the UserConfig kernel settings editor",
1919 " -------------------------------------------",
1925 "The screen displays a list of available drivers, divided into two",
1926 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1927 "by default collapsed and can be expanded to show all the drivers",
1928 "available in each category. The parameters for the currently selected",
1929 "driver are shown at the bottom of the screen.",
1931 "- - Moving around -",
1933 "To move in the current list, use the UP and DOWN cursor keys to select",
1934 "an item (the selected item will be highlighted). If the item is a",
1935 "category name, you may alternatively expand or collapse the list of",
1936 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1937 "expanded, you can select each driver in the same manner and either:",
1939 " - change its parameters using [!bENTER!n]",
1940 " - move it to the Inactive list using [!bDEL!n]",
1942 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1943 "you need to move a driver from the Inactive list back to the Active",
1944 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1945 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1946 "its place in the Active list.",
1948 "- - Altering the list/parameters -",
1950 "Any drivers for devices not installed in your system should be moved",
1951 "to the Inactive list, until there are no remaining parameter conflicts",
1952 "between the drivers, as indicated at the top.",
1954 "Once the list of Active drivers only contains entries for the devices",
1955 "present in your system, you can set their parameters (Interrupt, DMA",
1956 "channel, I/O addresses). To do this, select the driver and press",
1957 "[!bENTER!n]: it is now possible to edit the settings at the",
1958 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1959 "finished, use [!bQ!n] to return to the list.",
1961 "- - Saving changes -",
1963 "When all settings seem correct, and you wish to proceed with the",
1964 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1965 "confirm your choice.",
1974 ** Displays help text onscreen for people that are confused, using a simple
1980 int topline = 0; /* where we are in the text */
1981 int line = 0; /* last line we displayed */
1985 for (;;) /* loop until user quits */
1987 /* display help text */
1990 clear(); /* remove everything else */
1991 for (line = topline;
1992 (line < (topline + 24)) && (helptext[line]);
1994 putxy(0,line-topline,helptext[line]);
1999 sprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
2002 c = getchar(); /* so what do they say? */
2009 case 'B': /* wired into 'more' users' fingers */
2010 if (topline > 0) /* room to go up? */
2013 if (topline < 0) /* don't go too far */
2021 case ' ': /* expected by most people */
2022 if (helptext[line]) /* maybe more below? */
2031 redraw(); /* restore the screen */
2039 ** High-level control functions
2046 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2047 ** (num) lines, starting at (*ofs) offset from row onscreen.
2048 ** Pass (detail) on to drawing routines.
2050 ** If the user hits a key other than a cursor key, maybe return a code.
2052 ** (*list) points to the device at the top line in the region, (*ofs) is the
2053 ** position of the highlight within the region. All routines below
2054 ** this take only a device and an absolute row : use ofsent() to find the
2055 ** device, and add (*ofs) to (row) to find the absolute row.
2058 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2069 showparams(ofsent(*ofs,*list)); /* show device parameters */
2070 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2074 c = getchar(); /* get a character */
2075 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2077 extended = 0; /* no longer */
2080 case 588: /* syscons' idea of 'up' */
2082 if (*ofs) /* just a move onscreen */
2084 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2085 (*ofs)--; /* move up */
2087 lp = prevent(*list); /* can we go up? */
2090 *list = lp; /* yes, move up list */
2091 drawlist(row,num,detail,*list);
2096 case 596: /* dooby-do */
2097 case 'B': /* down */
2098 lp = ofsent(*ofs,*list); /* get current item */
2100 break; /* nothing more to move to */
2101 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2102 if (*ofs < (num-1)) /* room to move onscreen? */
2106 *list = nextent(*list); /* scroll region down */
2107 drawlist(row,num,detail,*list);
2119 case '[': /* cheat : always preceeds cursor move */
2120 case 'O': /* ANSI application key mode */
2129 return(KEY_EXIT); /* user requests exit */
2133 return(KEY_DO); /* "do" something */
2138 return(KEY_DEL); /* "delete" response */
2142 return(KEY_UNZOOM); /* expand everything */
2146 return(KEY_ZOOM); /* collapse everything */
2149 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2150 return(KEY_TAB); /* "move" response */
2152 case '\014': /* ^L, redraw */
2155 case '?': /* helptext */
2167 ** Do the fullscreen config thang
2172 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2176 initlist(&inactive);
2182 conflicts = findconflict(active); /* find conflicts in the active list only */
2190 case 0: /* active devices */
2191 ret = dolist(1,8,1,&actofs,&alist,
2192 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2196 mode = 1; /* swap lists */
2213 collapselist(active);
2218 dp = ofsent(actofs,alist); /* get current device */
2219 if (dp) /* paranoia... */
2221 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2223 if (dp == alist) /* moving top item on list? */
2227 alist = dp->next; /* point list to non-moving item */
2229 alist = dp->prev; /* end of list, go back instead */
2232 if (!dp->next) /* moving last item on list? */
2235 dp->conflicts = 0; /* no conflicts on the inactive list */
2236 movedev(dp,inactive); /* shift to inactive list */
2237 conflicts = findconflict(active); /* update conflict tags */
2239 redrawactive(); /* redraw */
2244 case KEY_DO: /* edit device parameters */
2245 dp = ofsent(actofs,alist); /* get current device */
2246 if (dp) /* paranoia... */
2248 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2250 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2252 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2254 conflicts = findconflict(active); /* update conflict tags */
2255 }else{ /* DO on comment = zoom */
2256 switch(dp->comment) /* Depends on current state */
2258 case DEV_COMMENT: /* not currently zoomed */
2259 dp->comment = DEV_ZOOMED;
2263 dp->comment = DEV_COMMENT;
2273 case 1: /* inactive devices */
2274 ret = dolist(10,7,0,&inactofs,&ilist,
2275 " [!bEnter!n] Enable device ");
2289 expandlist(inactive);
2296 collapselist(inactive);
2301 dp = ofsent(inactofs,ilist); /* get current device */
2302 if (dp) /* paranoia... */
2304 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2306 if (dp == ilist) /* moving top of list? */
2310 ilist = dp->next; /* point list to non-moving item */
2312 ilist = dp->prev; /* can't go down, go up instead */
2315 if (!dp->next) /* last entry on list? */
2316 inactofs--; /* shift cursor up one */
2319 movedev(dp,active); /* shift to active list */
2320 conflicts = findconflict(active); /* update conflict tags */
2322 alist = dp; /* put at top and current */
2324 while(dp->comment == DEV_DEVICE)
2325 dp = dp->prev; /* forcibly unzoom section */
2326 dp ->comment = DEV_COMMENT;
2327 mode = 0; /* and swap modes to follow it */
2329 }else{ /* DO on comment = zoom */
2330 switch(dp->comment) /* Depends on current state */
2332 case DEV_COMMENT: /* not currently zoomed */
2333 dp->comment = DEV_ZOOMED;
2337 dp->comment = DEV_COMMENT;
2341 redrawactive(); /* redraw */
2346 default: /* nothing else relevant here */
2351 mode = 0; /* shouldn't happen... */
2354 /* handle returns that are the same for both modes */
2361 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2364 case 2: /* cancel */
2368 case 1: /* save and exit */
2370 savelist(inactive,0);
2373 nukelist(active); /* clean up after ourselves */
2383 #endif /* VISUAL_USERCONFIG */
2386 * Copyright (c) 1991 Regents of the University of California.
2387 * All rights reserved.
2388 * Copyright (c) 1994 Jordan K. Hubbard
2389 * All rights reserved.
2390 * Copyright (c) 1994 David Greenman
2391 * All rights reserved.
2393 * Many additional changes by Bruce Evans
2395 * This code is derived from software contributed by the
2396 * University of California Berkeley, Jordan K. Hubbard,
2397 * David Greenman and Bruce Evans.
2399 * Redistribution and use in source and binary forms, with or without
2400 * modification, are permitted provided that the following conditions
2402 * 1. Redistributions of source code must retain the above copyright
2403 * notice, this list of conditions and the following disclaimer.
2404 * 2. Redistributions in binary form must reproduce the above copyright
2405 * notice, this list of conditions and the following disclaimer in the
2406 * documentation and/or other materials provided with the distribution.
2407 * 3. All advertising materials mentioning features or use of this software
2408 * must display the following acknowledgement:
2409 * This product includes software developed by the University of
2410 * California, Berkeley and its contributors.
2411 * 4. Neither the name of the University nor the names of its contributors
2412 * may be used to endorse or promote products derived from this software
2413 * without specific prior written permission.
2415 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2416 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2417 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2418 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2419 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2420 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2421 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2422 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2423 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2424 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2427 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2430 #include "use_scbus.h"
2432 #define PARM_DEVSPEC 0x1
2433 #define PARM_INT 0x2
2434 #define PARM_ADDR 0x3
2435 #define PARM_STRING 0x4
2437 typedef struct _cmdparm {
2440 struct uc_device *dparm;
2449 typedef int (*CmdFunc)(CmdParm *);
2451 typedef struct _cmd {
2459 static void lsscsi(void);
2460 static int list_scsi(CmdParm *);
2463 static int lsdevtab(struct uc_device *);
2464 static struct uc_device *find_device(char *, int);
2465 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2466 static void cngets(char *, int);
2467 static Cmd *parse_cmd(char *);
2468 static int parse_args(const char *, CmdParm *);
2469 static int save_dev(struct uc_device *);
2471 static int list_devices(CmdParm *);
2472 static int set_device_ioaddr(CmdParm *);
2473 static int set_device_irq(CmdParm *);
2474 static int set_device_drq(CmdParm *);
2475 static int set_device_iosize(CmdParm *);
2476 static int set_device_mem(CmdParm *);
2477 static int set_device_flags(CmdParm *);
2478 static int set_device_enable(CmdParm *);
2479 static int set_device_disable(CmdParm *);
2480 static int quitfunc(CmdParm *);
2481 static int helpfunc(CmdParm *);
2482 static int introfunc(CmdParm *);
2485 static int lspnp(void);
2486 static int set_pnp_parms(CmdParm *);
2491 #include "use_eisa.h"
2495 #include <bus/eisa/eisaconf.h>
2497 static int set_num_eisa_slots(CmdParm *);
2499 #endif /* NEISA > 0 */
2501 static CmdParm addr_parms[] = {
2502 { PARM_DEVSPEC, {} },
2507 static CmdParm int_parms[] = {
2508 { PARM_DEVSPEC, {} },
2513 static CmdParm dev_parms[] = {
2514 { PARM_DEVSPEC, {} },
2519 static CmdParm string_arg[] = {
2520 { PARM_STRING, {} },
2526 static CmdParm int_arg[] = {
2530 #endif /* NEISA > 0 */
2532 static Cmd CmdList[] = {
2533 { "?", helpfunc, NULL }, /* ? (help) */
2534 { "di", set_device_disable, dev_parms }, /* disable dev */
2535 { "dr", set_device_drq, int_parms }, /* drq dev # */
2537 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2538 #endif /* NEISA > 0 */
2539 { "en", set_device_enable, dev_parms }, /* enable dev */
2540 { "ex", quitfunc, NULL }, /* exit (quit) */
2541 { "f", set_device_flags, int_parms }, /* flags dev mask */
2542 { "h", helpfunc, NULL }, /* help */
2543 { "intro", introfunc, NULL }, /* intro screen */
2544 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2545 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2546 { "ir", set_device_irq, int_parms }, /* irq dev # */
2547 { "l", list_devices, NULL }, /* ls, list */
2549 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2551 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2552 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2553 { "q", quitfunc, NULL }, /* quit */
2555 { "s", list_scsi, NULL }, /* scsi */
2557 #ifdef VISUAL_USERCONFIG
2558 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2560 { NULL, NULL, NULL },
2566 static char banner = 1;
2572 init_config_script();
2575 /* Only display signon banner if we are about to go interactive */
2576 if (!has_config_script()) {
2577 if (!(boothowto & RB_CONFIG))
2578 #ifdef INTRO_USERCONFIG
2585 printf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2586 " Type \"help\" for help"
2587 #ifdef VISUAL_USERCONFIG
2588 " or \"visual\" to go to the visual\n"
2589 " configuration interface (requires MGA/VGA display or\n"
2590 " serial terminal capable of displaying ANSI graphics)"
2598 if (input[0] == '\0')
2600 cmd = parse_cmd(input);
2602 printf("Invalid command or syntax. Type `?' for help.\n");
2605 rval = (*cmd->handler)(cmd->parms);
2614 parse_cmd(char *cmd)
2618 for (cp = CmdList; cp->name; cp++) {
2619 int len = strlen(cp->name);
2621 if (!strncmp(cp->name, cmd, len)) {
2622 while (*cmd && *cmd != ' ' && *cmd != '\t')
2624 if (parse_args(cmd, cp->parms))
2634 parse_args(const char *cmd, CmdParm *parms)
2639 if (*cmd == ' ' || *cmd == '\t') {
2643 if (parms == NULL || parms->type == -1) {
2646 printf("Extra arg(s): %s\n", cmd);
2649 if (parms->type == PARM_DEVSPEC) {
2654 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2655 (*cmd >= '0' && *cmd <= '9')))
2656 devname[i++] = *(cmd++);
2658 if (*cmd >= '0' && *cmd <= '9') {
2659 unit = strtoul(cmd, &ptr, 10);
2661 printf("Invalid device number\n");
2662 /* XXX should print invalid token here and elsewhere. */
2665 /* XXX else should require end of token. */
2668 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2669 printf("No such device: %s%d\n", devname, unit);
2675 if (parms->type == PARM_INT) {
2676 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2678 printf("Invalid numeric argument\n");
2685 if (parms->type == PARM_ADDR) {
2686 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2688 printf("Invalid address argument\n");
2695 if (parms->type == PARM_STRING) {
2696 parms->parm.u.sparm = cmd;
2704 list_devices(CmdParm *parms)
2707 if (lsdevtab(uc_devtab)) return 0;
2709 if (lspnp()) return 0;
2712 printf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2713 #endif /* NEISA > 0 */
2718 set_device_ioaddr(CmdParm *parms)
2720 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2721 save_dev(parms[0].parm.dparm);
2726 set_device_irq(CmdParm *parms)
2730 irq = parms[1].parm.iparm;
2732 printf("Warning: Remapping IRQ 2 to IRQ 9\n");
2735 else if (irq != -1 && irq > 15) {
2736 printf("An IRQ > 15 would be invalid.\n");
2739 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2740 save_dev(parms[0].parm.dparm);
2745 set_device_drq(CmdParm *parms)
2750 * The bounds checking is just to ensure that the value can be printed
2751 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2753 drq = parms[1].parm.iparm;
2754 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2755 save_dev(parms[0].parm.dparm);
2760 set_device_iosize(CmdParm *parms)
2762 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2763 save_dev(parms[0].parm.dparm);
2768 set_device_mem(CmdParm *parms)
2770 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2771 save_dev(parms[0].parm.dparm);
2776 set_device_flags(CmdParm *parms)
2778 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2779 save_dev(parms[0].parm.dparm);
2784 set_device_enable(CmdParm *parms)
2786 parms[0].parm.dparm->id_enabled = TRUE;
2787 save_dev(parms[0].parm.dparm);
2792 set_device_disable(CmdParm *parms)
2794 parms[0].parm.dparm->id_enabled = FALSE;
2795 save_dev(parms[0].parm.dparm);
2802 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2808 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2811 * Output the pnp_ldn_overrides[] table.
2813 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2814 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2815 if(error) return(error);
2820 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2821 0, 0, sysctl_machdep_uc_pnplist, "A",
2822 "List of PnP overrides changed in UserConfig");
2825 * this function sets the kernel table to override bios PnP
2829 set_pnp_parms(CmdParm *parms)
2831 u_long idx, val, ldn, csn;
2834 const char *p = parms[0].parm.u.sparm;
2837 csn=strtoul(p,&q, 0);
2838 ldn=strtoul(q,&q, 0);
2839 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2840 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2841 printf("bad csn/ldn %ld:%ld\n", csn, ldn);
2844 for (i=0; i < MAX_PNP_LDN; i++) {
2845 if (pnp_ldn_overrides[i].csn == csn &&
2846 pnp_ldn_overrides[i].ldn == ldn)
2849 if (i==MAX_PNP_LDN) {
2850 for (i=0; i < MAX_PNP_LDN; i++) {
2851 if (pnp_ldn_overrides[i].csn <1 ||
2852 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2856 if (i==MAX_PNP_LDN) {
2857 printf("sorry, no PnP entries available, try delete one\n");
2860 d = pnp_ldn_overrides[i] ;
2866 if (!strncmp(p,"irq",3)) {
2867 idx=strtoul(p+3,&q, 0);
2868 val=strtoul(q,&q, 0);
2869 if (idx >=0 && idx < 2) d.irq[idx] = val;
2870 } else if (!strncmp(p,"flags",5)) {
2871 idx=strtoul(p+5,&q, 0);
2873 } else if (!strncmp(p,"drq",3)) {
2874 idx=strtoul(p+3,&q, 0);
2875 val=strtoul(q,&q, 0);
2876 if (idx >=0 && idx < 2) d.drq[idx] = val;
2877 } else if (!strncmp(p,"port",4)) {
2878 idx=strtoul(p+4,&q, 0);
2879 val=strtoul(q,&q, 0);
2880 if (idx >=0 && idx < 8) d.port[idx] = val;
2881 } else if (!strncmp(p,"mem",3)) {
2882 idx=strtoul(p+3,&q, 0);
2883 val=strtoul(q,&q, 0);
2884 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2885 } else if (!strncmp(p,"bios",4)) {
2888 } else if (!strncmp(p,"os",2)) {
2891 } else if (!strncmp(p,"disable",7)) {
2894 } else if (!strncmp(p,"enable",6)) {
2897 } else if (!strncmp(p,"delete",6)) {
2898 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2899 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2902 printf("unknown command <%s>\n", p);
2905 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2907 pnp_ldn_overrides[i] = d ;
2914 set_num_eisa_slots(CmdParm *parms)
2918 num_slots = parms[0].parm.iparm;
2919 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2922 #endif /* NEISA > 0 */
2925 quitfunc(CmdParm *parms)
2928 * If kernel config supplied, and we are parsing it, and -c also supplied,
2929 * ignore a quit command, This provides a safety mechanism to allow
2930 * recovery from a damaged/buggy kernel config.
2932 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2938 helpfunc(CmdParm *parms)
2941 "Command\t\t\tDescription\n"
2942 "-------\t\t\t-----------\n"
2943 "ls\t\t\tList currently configured devices\n"
2944 "port <devname> <addr>\tSet device port (i/o address)\n"
2945 "irq <devname> <number>\tSet device irq\n"
2946 "drq <devname> <number>\tSet device drq\n"
2947 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2948 "iosize <devname> <size>\tSet device memory size\n"
2949 "flags <devname> <mask>\tSet device flags\n"
2950 "enable <devname>\tEnable device\n"
2951 "disable <devname>\tDisable device (will not be probed)\n");
2954 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2955 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2956 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2957 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2958 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2959 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2962 printf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2963 #endif /* NEISA > 0 */
2965 "quit\t\t\tExit this configuration utility\n"
2966 "reset\t\t\tReset CPU\n");
2967 #ifdef VISUAL_USERCONFIG
2968 printf("visual\t\t\tGo to fullscreen mode.\n");
2971 "help\t\t\tThis message\n\n"
2972 "Commands may be abbreviated to a unique prefix\n");
2976 #if defined (VISUAL_USERCONFIG)
2978 center(int y, char *str)
2980 putxy((80 - strlen(str)) / 2, y, str);
2985 introfunc(CmdParm *parms)
2987 #if defined (VISUAL_USERCONFIG)
2988 int curr_item, first_time, extended = 0;
2989 static char *choices[] = {
2990 " Skip kernel configuration and continue with installation ",
2991 " Start kernel configuration in full-screen visual mode ",
2992 " Start kernel configuration in CLI mode ",
2996 center(2, "!bKernel Configuration Menu!n");
3005 for (i = 0; i < 3; i++) {
3009 strcat(tmp, choices[i]);
3012 putxy(10, 5 + i, tmp);
3016 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3017 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3018 putxy(2, 12, "match your hardware configuration.");
3019 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3020 putxy(2, 15, "(press Down-Arrow then ENTER).");
3021 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3022 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3023 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3024 putxy(2, 21, "then simply press ENTER or Q now.");
3028 move(0, 0); /* move the cursor out of the way */
3031 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3032 extended = 0; /* no longer */
3041 case 'B': /* down */
3053 case '[': /* cheat : always preceeds cursor move */
3054 case 'O': /* ANSI application key mode */
3065 return 1; /* user requests exit */
3067 case '1': /* select an item */
3091 case 'D': /* down */
3104 else if (curr_item == 1)
3105 return visuserconfig();
3107 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3108 /* enable quitfunc */
3109 userconfig_boot_parsing=0;
3111 boothowto |= RB_CONFIG; /* force -c */
3125 struct pnp_cinfo *c;
3129 for (i=0; i< MAX_PNP_LDN; i++) {
3130 c = &pnp_ldn_overrides[i];
3131 if (c->csn >0 && c->csn != 255) {
3133 static char pfmt[] =
3134 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3135 static char mfmt[] =
3136 "mem 0x%x 0x%x 0x%x 0x%x";
3139 if (!userconfig_boot_parsing) {
3141 if (getchar() == 'q') {
3149 if (lineno == 0 || first)
3150 printf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3152 printf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3154 c->override ? "OS ":"BIOS",
3155 c->enable ? "Y":"N",
3156 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3158 printf("flags 0x%08lx ",c->flags);
3159 for (pmax = 7; pmax >=0 ; pmax--)
3160 if (c->port[pmax]!=0) break;
3161 for (mmax = 3; mmax >=0 ; mmax--)
3162 if (c->mem[mmax].base!=0) break;
3165 buf[10 + 5*pmax]='\0';
3167 c->port[0], c->port[1], c->port[2], c->port[3],
3168 c->port[4], c->port[5], c->port[6], c->port[7]);
3172 buf[8 + 5*mmax]='\0';
3174 c->mem[0].base, c->mem[1].base,
3175 c->mem[2].base, c->mem[3].base);
3185 lsdevtab(struct uc_device *dt)
3187 for (; dt->id_id != 0; dt++) {
3192 if (!userconfig_boot_parsing) {
3193 if (getchar() == 'q') {
3203 "Device port irq drq iomem iosize unit flags enab\n"
3207 sprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3208 printf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3209 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3210 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3211 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3212 dt->id_enabled ? "Yes" : "No");
3222 int count = resource_count();
3228 uc_devtab = malloc(sizeof(struct uc_device)*(count + 1),M_DEVL,M_WAITOK);
3229 bzero(uc_devtab, sizeof(struct uc_device) * (count + 1));
3231 for (i = 0; i < count; i++) {
3232 name = resource_query_name(i);
3233 unit = resource_query_unit(i);
3235 continue; /* skip wildcards */
3236 uc_devtab[dt].id_id = id++;
3237 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3239 resource_int_value(name, unit, "irq", &val);
3240 uc_devtab[dt].id_irq = (1 << val);
3241 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3242 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3243 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3244 uc_devtab[dt].id_unit = unit;
3245 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3247 resource_int_value(name, unit, "disabled", &val);
3248 uc_devtab[dt].id_enabled = !val;
3249 uc_devtab[dt].id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3250 strcpy(uc_devtab[dt].id_name, name);
3259 int count = resource_count();
3261 for (i = 0; i < count; i++)
3262 if (uc_devtab[i].id_name)
3263 free(uc_devtab[i].id_name, M_DEVL);
3264 free(uc_devtab, M_DEVL);
3267 static struct uc_device *
3268 find_device(char *devname, int unit)
3270 struct uc_device *ret;
3272 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3277 static struct uc_device *
3278 search_devtable(struct uc_device *dt, char *devname, int unit)
3282 for (i = 0; dt->id_id != 0; dt++)
3283 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3289 cngets(char *input, int maxin)
3295 /* Treat ^H or ^? as backspace */
3296 if ((c == '\010' || c == '\177')) {
3298 printf("\010 \010");
3299 *--input = '\0', --nchars;
3303 /* Treat ^U or ^X as kill line */
3304 else if ((c == '\025' || c == '\030')) {
3306 printf("\010 \010");
3307 *--input = '\0', --nchars;
3312 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3316 *input++ = (u_char)c;
3322 /* scsi: Support for displaying configured SCSI devices.
3323 * There is no way to edit them, and this is inconsistent
3324 * with the ISA method. This is here as a basis for further work.
3327 type_text(char *name) /* XXX: This is bogus */
3329 if (strcmp(name, "sd") == 0)
3332 if (strcmp(name, "st") == 0)
3338 id_put(char *desc, int id)
3340 if (id != SCCONF_UNSPEC)
3345 if (id == SCCONF_ANY)
3357 printf("scsi: (can't be edited):\n");
3359 for (i = 0; scsi_cinit[i].driver; i++)
3361 id_put("controller scbus", scsi_cinit[i].scbus);
3363 if (scsi_cinit[i].unit != -1)
3366 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3372 for (i = 0; scsi_dinit[i].name; i++)
3374 printf("%s ", type_text(scsi_dinit[i].name));
3376 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3377 id_put(" at scbus", scsi_dinit[i].cunit);
3378 id_put(" target ", scsi_dinit[i].target);
3379 id_put(" lun ", scsi_dinit[i].lun);
3381 if (scsi_dinit[i].flags)
3382 printf(" flags 0x%x\n", scsi_dinit[i].flags);
3389 list_scsi(CmdParm *parms)
3398 save_resource(struct uc_device *idev)
3403 name = idev->id_name;
3404 unit = idev->id_unit;
3405 resource_set_int(name, unit, "port", idev->id_iobase);
3406 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3407 resource_set_int(name, unit, "drq", idev->id_drq);
3408 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3409 resource_set_int(name, unit, "msize", idev->id_msize);
3410 resource_set_int(name, unit, "flags", idev->id_flags);
3411 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3416 struct uc_device *idev;
3418 struct uc_device *id_p,*id_pn;
3419 char *name = idev->id_name;
3421 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3422 if (id_p->id_id == idev->id_id) {
3423 id_pn = id_p->id_next;
3425 free(id_p->id_name, M_DEVL);
3426 bcopy(idev,id_p,sizeof(struct uc_device));
3427 save_resource(idev);
3428 id_p->id_name = malloc(strlen(name)+1, M_DEVL,M_WAITOK);
3429 strcpy(id_p->id_name, name);
3430 id_p->id_next = id_pn;
3434 id_pn = malloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3435 bcopy(idev,id_pn,sizeof(struct uc_device));
3436 save_resource(idev);
3437 id_pn->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3438 strcpy(id_pn->id_name, name);
3439 id_pn->id_next = uc_devlist;