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/i386/i386/Attic/userconfig.c,v 1.5 2005/05/07 17:38:34 swildner Exp $
56 ** Kernel boot-time configuration manipulation tool for FreeBSD.
58 ** Two modes of operation are supported : the default is the line-editor mode,
59 ** the command "visual" invokes the fullscreen mode.
61 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
62 ** fullscreen mode requires syscons or a minimal-ansi serial console.
66 ** USERCONFIG, visual mode.
70 ** Look for "EDIT THIS LIST" to add to the list of known devices
73 ** There are a number of assumptions made in this code.
75 ** - That the console supports a minimal set of ANSI escape sequences
76 ** (See the screen manipulation section for a summary)
77 ** and has at least 24 rows.
78 ** - That values less than or equal to zero for any of the device
79 ** parameters indicate that the driver does not use the parameter.
80 ** - That flags are _always_ editable.
82 ** Devices marked as disabled are imported as such.
84 ** For this tool to be useful, the list of devices below _MUST_ be updated
85 ** when a new driver is brought into the kernel. It is not possible to
86 ** extract this information from the drivers in the kernel.
90 ** - Display _what_ a device conflicts with.
91 ** - Implement page up/down (as what?)
92 ** - Wizard mode (no restrictions)
93 ** - Find out how to put syscons back into low-intensity mode so that the
94 ** !b escape is useful on the console. (It seems to be that it actually
95 ** gets low/high intensity backwards. That looks OK.)
97 ** - Only display headings with devices under them. (difficult)
100 #include "opt_userconfig.h"
101 #define COMPAT_OLDISA /* get the definitions */
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/kernel.h>
106 #include <sys/malloc.h>
107 #include <sys/reboot.h>
108 #include <sys/linker.h>
109 #include <sys/sysctl.h>
111 #include <sys/cons.h>
113 #include <machine/md_var.h>
114 #include <machine/limits.h>
116 #define _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 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
386 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
387 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
388 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
389 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
390 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
391 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
392 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
393 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
394 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
395 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
396 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
397 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
398 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
399 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
400 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
401 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
402 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
403 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
404 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
405 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
406 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
407 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
409 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
410 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
411 {"pcic", "PC-card controller", 0, CLS_MISC},
412 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
413 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
417 typedef struct _devlist_struct
420 int attrib; /* flag values as per the FLG_* defines above */
421 int class; /* disk, etc as per the CLS_* defines above */
423 int iobase,irq,drq,maddr,msize,unit,flags,id;
424 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
425 int conflicts; /* set/reset by findconflict, count of conflicts */
426 int changed; /* nonzero if the device has been edited */
427 struct uc_device *device;
428 struct _devlist_struct *prev,*next;
433 #define DEV_COMMENT 1
436 #define LIST_CURRENT (1<<0)
437 #define LIST_SELECTED (1<<1)
439 #define KEY_EXIT 0 /* return codes from dolist() and friends */
445 #define KEY_UP 5 /* these only returned from editval() */
449 #define KEY_NULL 9 /* this allows us to spin & redraw */
451 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
452 #define KEY_UNZOOM 11
454 #define KEY_HELP 12 /* duh? */
456 static void redraw(void);
457 static void insdev(DEV_LIST *dev, DEV_LIST *list);
458 static int devinfo(DEV_LIST *dev);
459 static int visuserconfig(void);
461 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
462 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
463 static DEV_LIST scratch; /* scratch record */
464 static int conflicts; /* total conflict count */
467 static char lines[] = "--------------------------------------------------------------------------------";
468 static char spaces[] = " ";
472 ** Device manipulation stuff : find, describe, configure.
478 ** Sets the device referenced by (*dev) to the parameters in the struct,
479 ** and the enable flag according to (enabled)
482 setdev(DEV_LIST *dev, int enabled)
484 dev->device->id_iobase = dev->iobase; /* copy happy */
485 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
486 dev->device->id_drq = (short)dev->drq;
487 dev->device->id_maddr = (caddr_t)dev->maddr;
488 dev->device->id_msize = dev->msize;
489 dev->device->id_flags = dev->flags;
490 dev->device->id_enabled = enabled;
497 ** Walk the kernel device tables and build the active and inactive lists
503 struct uc_device *ap;
505 ap = uc_devtab; /* pointer to array of devices */
506 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
508 scratch.unit = ap[i].id_unit; /* device parameters */
509 strcpy(scratch.dev,ap[i].id_name);
510 scratch.iobase = ap[i].id_iobase;
511 scratch.irq = ffs(ap[i].id_irq)-1;
512 scratch.drq = ap[i].id_drq;
513 scratch.maddr = (int)ap[i].id_maddr;
514 scratch.msize = ap[i].id_msize;
515 scratch.flags = ap[i].id_flags;
517 scratch.comment = DEV_DEVICE; /* admin stuff */
518 scratch.conflicts = 0;
519 scratch.device = &ap[i]; /* save pointer for later reference */
521 if (!devinfo(&scratch)) /* get more info on the device */
522 insdev(&scratch,ap[i].id_enabled?active:inactive);
530 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
531 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
533 ** If the device is marked "invisible", return nonzero; the caller should
534 ** not insert any such device into either list.
538 devinfo(DEV_LIST *dev)
542 for (i = 0; device_info[i].class; i++)
544 if (!strcmp(dev->dev,device_info[i].dev))
546 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
548 strcpy(dev->name,device_info[i].name); /* get the name */
549 dev->attrib = device_info[i].attrib;
550 dev->class = device_info[i].class;
554 strcpy(dev->name,"Unknown device");
556 dev->class = CLS_MISC;
562 ** List manipulation stuff : add, move, initialise, free, traverse
564 ** Note that there are assumptions throughout this code that
565 ** the first entry in a list will never move. (assumed to be
573 ** appends a copy of (dev) to the end of (*list)
576 addev(DEV_LIST *dev, DEV_LIST **list)
581 lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
582 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
584 if (*list) /* list exists */
588 ap = ap->next; /* scoot to end of list */
592 }else{ /* list does not yet exist */
594 lp->prev = lp->next = NULL; /* list now exists */
602 ** Finds the 'appropriate' place for (dev) in (list)
604 ** 'Appropriate' means in numeric order with other devices of the same type,
605 ** or in alphabetic order following a comment of the appropriate type.
606 ** or at the end of the list if an appropriate comment is not found. (this should
608 ** (Note that the appropriate point is never the top, but may be the bottom)
611 findspot(DEV_LIST *dev, DEV_LIST *list)
615 /* search for a previous instance of the same device */
616 for (ap = list; ap; ap = ap->next)
618 if (ap->comment != DEV_DEVICE) /* ignore comments */
620 if (!strcmp(dev->dev,ap->dev)) /* same base device */
622 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
623 || !ap->next) /* or end of list */
625 ap = ap->prev; /* back up one */
626 break; /* done here */
628 if (ap->next) /* if the next item exists */
630 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
632 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
638 if (!ap) /* not sure yet */
640 /* search for a class that the device might belong to */
641 for (ap = list; ap; ap = ap->next)
643 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
645 if (dev->class != ap->class) /* of same class too 8) */
647 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
649 ap = ap->prev; /* back up one */
650 break; /* done here */
652 if (ap->next) /* if the next item exists */
653 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
658 if (!ap) /* didn't find a match */
660 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
661 if ((ap->comment != DEV_DEVICE)
662 && (ap->class == dev->class)) /* appropriate place? */
664 } /* or just put up with last */
673 ** Inserts a copy of (dev) at the appropriate point in (list)
676 insdev(DEV_LIST *dev, DEV_LIST *list)
680 lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
681 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
683 ap = findspot(lp,list); /* find appropriate spot */
684 lp->next = ap->next; /* point to next */
686 ap->next->prev = lp; /* point next to new */
687 lp->prev = ap; /* point new to current */
688 ap->next = lp; /* and current to new */
695 ** Moves (dev) from its current list to an appropriate place in (list)
696 ** (dev) may not come from the top of a list, but it may from the bottom.
699 movedev(DEV_LIST *dev, DEV_LIST *list)
703 ap = findspot(dev,list);
704 dev->prev->next = dev->next; /* remove from old list */
706 dev->next->prev = dev->prev;
708 dev->next = ap->next; /* insert in new list */
710 ap->next->prev = dev; /* point next to new */
711 dev->prev = ap; /* point new to current */
712 ap->next = dev; /* and current to new */
719 ** Initialises (*list) with the basic headings
722 initlist(DEV_LIST **list)
726 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
728 strcpy(scratch.name,devclass_names[i].name);
729 scratch.comment = DEV_ZOOMED;
730 scratch.class = devclass_names[i].number;
731 scratch.attrib = FLG_MANDATORY; /* can't be moved */
732 addev(&scratch,list); /* add to the list */
740 ** Walks (list) and saves the settings of any entry marked as changed.
742 ** The device's active field is set according to (active).
744 ** Builds the uc_devlist used by kget to extract the changed device information.
745 ** The code for this was taken almost verbatim from the original module.
748 savelist(DEV_LIST *list, int active)
750 struct uc_device *id_p,*id_pn;
755 if ((list->comment == DEV_DEVICE) && /* is a device */
756 (list->changed) && /* has been changed */
757 (list->device != NULL)) { /* has an uc_device structure */
759 setdev(list,active); /* set the device itself */
762 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
763 { /* look on the list for it */
764 if (id_p->id_id == list->device->id_id)
766 name = list->device->id_name;
767 id_pn = id_p->id_next;
769 free(id_p->id_name, M_DEVL);
770 bcopy(list->device,id_p,sizeof(struct uc_device));
771 save_resource(list->device);
772 id_p->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
773 strcpy(id_p->id_name, name);
774 id_pn->id_next = uc_devlist;
775 id_p->id_next = id_pn;
779 if (!id_pn) /* not already on the list */
781 name = list->device->id_name;
782 id_pn = malloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
783 bcopy(list->device,id_pn,sizeof(struct uc_device));
784 save_resource(list->device);
785 id_pn->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
786 strcpy(id_pn->id_name, name);
787 id_pn->id_next = uc_devlist;
788 uc_devlist = id_pn; /* park at top of list */
799 ** Frees all storage in use by a (list).
802 nukelist(DEV_LIST *list)
808 while(list->prev) /* walk to head of list */
823 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
824 ** if there is no previous entry. (Only possible if list->prev == NULL given the
825 ** premise that there is always a comment at the head of the list)
828 prevent(DEV_LIST *list)
834 dp = list->prev; /* start back one */
837 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
838 return(dp); /* so skip to comment */
839 if (dp->comment == DEV_COMMENT) /* not zoomed */
840 return(list->prev); /* one back as normal */
841 dp = dp->prev; /* backpedal */
843 return(dp); /* NULL, we can assume */
850 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
851 ** if there is no next entry. (Possible if the current entry is last, or
852 ** if the current entry is the last heading and it's collapsed)
855 nextent(DEV_LIST *list)
861 if (list->comment != DEV_ZOOMED) /* no reason to skip */
866 if (dp->comment != DEV_DEVICE) /* found another heading */
870 return(dp); /* back we go */
877 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
880 ofsent(int ofs, DEV_LIST *list)
882 while (ofs-- && list)
883 list = nextent(list);
891 ** Scans every element of (list) and sets the conflict tags appropriately
892 ** Returns the number of conflicts found.
895 findconflict(DEV_LIST *list)
897 int count = 0; /* number of conflicts found */
900 for (dp = list; dp; dp = dp->next) /* over the whole list */
902 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
905 dp->conflicts = 0; /* assume the best */
906 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
908 if (sp->comment != DEV_DEVICE) /* likewise */
911 if (sp == dp) /* always conflict with itself */
914 if ((dp->iobase > 0) && /* iobase conflict? */
915 (dp->iobase == sp->iobase))
917 if ((dp->irq > 0) && /* irq conflict? */
918 (dp->irq == sp->irq))
920 if ((dp->drq > 0) && /* drq conflict? */
921 (dp->drq == sp->drq))
923 if ((sp->maddr > 0) && /* maddr/msize conflict? */
925 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
926 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
929 count += dp->conflicts; /* count conflicts */
938 ** Unzooms all headings in (list)
941 expandlist(DEV_LIST *list)
945 if (list->comment == DEV_COMMENT)
946 list->comment = DEV_ZOOMED;
955 ** Zooms all headings in (list)
958 collapselist(DEV_LIST *list)
962 if (list->comment == DEV_ZOOMED)
963 list->comment = DEV_COMMENT;
970 ** Screen-manipulation stuff
972 ** This is the basic screen layout :
974 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
975 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
976 ** +--------------------------------------------------------------------------------+
977 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
978 ** 1 -| ........................ ....... .. 0x....|
979 ** 2 -| ........................ ....... .. 0x....|
980 ** 3 -| ........................ ....... .. 0x....|
981 ** 4 -| ........................ ....... .. 0x....|
982 ** 5 -| ........................ ....... .. 0x....|
983 ** 6 -| ........................ ....... .. 0x....|
984 ** 7 -| ........................ ....... .. 0x....|
985 ** 8 -| ........................ ....... .. 0x....|
986 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
987 ** 10-| ........................ ....... |
988 ** 11-| ........................ ....... |
989 ** 12-| ........................ ....... |
990 ** 13-| ........................ ....... |
991 ** 14-| ........................ ....... |
992 ** 15-| ........................ ....... |
993 ** 16-| ........................ ....... |
994 ** 17-|------------------------------------------------------UP-DOWN-------------------|
995 ** 18-| Relevant parameters for the current device |
998 ** 21-|--------------------------------------------------------------------------------|
999 ** 22-| Help texts go here |
1001 ** +--------------------------------------------------------------------------------+
1005 ** On a collapsed comment :
1007 ** [Enter] Expand device list [z] Expand all lists
1008 ** [TAB] Change fields [Q] Save and Exit
1010 ** On an expanded comment :
1012 ** [Enter] Collapse device list [Z] Collapse all lists
1013 ** [TAB] Change fields [Q] Save and Exit
1015 ** On a comment with no followers
1018 ** [TAB] Change fields [Q] Save and Exit
1020 ** On a device in the active list
1022 ** [Enter] Edit device parameters [DEL] Disable device
1023 ** [TAB] Change fields [Q] Save and Exit [?] Help
1025 ** On a device in the inactive list
1027 ** [Enter] Enable device
1028 ** [TAB] Change fields [Q] Save and Exit [?] Help
1030 ** While editing parameters
1032 ** <parameter-specific help here>
1033 ** [TAB] Change fields [Q] Save device parameters
1040 ** The base-level screen primitives :
1042 ** bold() - enter bold mode \E[1m (md)
1043 ** inverse() - enter inverse mode \E[7m (so)
1044 ** normal() - clear bold/inverse mode \E[m (se)
1045 ** clear() - clear the screen \E[H\E[J (ce)
1046 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1071 printf("\033[H\033[J");
1077 printf("\033[%d;%dH",y+1,x+1);
1083 ** High-level screen primitives :
1085 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1086 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1087 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1088 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1089 ** putmsg(str) - put (str) in the message area
1090 ** puthelp(str) - put (str) in the upper helpline
1091 ** pad(str,len) - pad (str) to (len) with spaces
1092 ** drawline(row,detail,list,inverse,*dhelp)
1093 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1094 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1095 ** draw the line in inverse video, and display (*dhelp) on the
1097 ** drawlist(row,num,detail,list)
1098 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1099 ** through to drawline().
1100 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1101 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1102 ** redraw(); - Redraws the entire screen layout, including the
1103 ** - two list panels.
1108 ** writes (str) at x,y onscreen
1110 ** writes up to (len) of (str) at x,y onscreen.
1112 ** Supports embedded formatting :
1113 ** !i - inverse mode.
1115 ** !n - normal mode.
1118 putxyl(int x, int y, char *str, int len)
1123 while((*str) && (len--))
1125 if (*str == '!') /* format escape? */
1127 switch(*(str+1)) /* depending on the next character */
1131 str +=2; /* skip formatting */
1132 len++; /* doesn't count for length */
1137 str +=2; /* skip formatting */
1138 len++; /* doesn't count for length */
1143 str +=2; /* skip formatting */
1144 len++; /* doesn't count for length */
1148 putchar(*str++); /* not an escape */
1151 putchar(*str++); /* emit the character */
1156 #define putxy(x,y,str) putxyl(x,y,str,-1)
1162 ** Erases the region (x,y,w,h)
1165 erase(int x, int y, int w, int h)
1170 for (i = 0; i < h; i++)
1171 putxyl(x,y++,spaces,w);
1178 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1179 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1182 txtbox(int x, int y, int w, int h, char *str)
1187 while((str[i]) && h)
1189 if (str[i] == '\n') /* newline */
1191 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1192 y++; /* move down */
1193 h--; /* room for one less */
1194 str += (i+1); /* skip first newline */
1195 i = 0; /* zero offset */
1197 i++; /* next character */
1200 if (h) /* end of string, not region */
1208 ** writes (msg) in the helptext area
1213 erase(0,18,80,3); /* clear area */
1214 txtbox(0,18,80,3,msg);
1221 ** Writes (msg) in the helpline area
1234 ** Draws the help message at the bottom of the screen
1237 masterhelp(char *msg)
1247 ** space-pads a (str) to (len) characters
1250 pad(char *str, int len)
1254 for (i = 0; str[i]; i++) /* find the end of the string */
1256 if (i >= len) /* no padding needed */
1258 while(i < len) /* pad */
1267 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1268 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1270 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1271 ** help is shown for normal or zoomed comments
1274 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1276 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1278 if (list->comment == DEV_DEVICE)
1281 strncpy(nb+1,list->name,57);
1283 strncpy(nb,list->name,58);
1284 if ((list->comment == DEV_ZOOMED) && (list->next))
1285 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1286 strcat(nb," (Collapsed)");
1290 if (list->conflicts) /* device in conflict? */
1294 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1296 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1299 if (list->comment == DEV_DEVICE)
1301 sprintf(db,"%s%d",list->dev,list->unit);
1306 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1308 sprintf(ib," %d",list->irq);
1313 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1315 sprintf(pb,"0x%x",list->iobase);
1321 sprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1323 putxyl(0,row,lbuf,80);
1326 switch(list->comment)
1328 case DEV_DEVICE: /* ordinary device */
1334 if (list->next->comment == DEV_DEVICE)
1335 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1340 if (list->next->comment == DEV_DEVICE)
1341 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1344 puthelp(" WARNING: This list entry corrupted!");
1348 move(0,row); /* put the cursor somewhere relevant */
1355 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1356 ** port and IRQ fields as well if (detail) is nonzero
1358 ** printf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1361 drawlist(int row, int num, int detail, DEV_LIST *list)
1365 for(ofs = 0; ofs < num; ofs++)
1369 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1370 list = nextent(list); /* move down visible list */
1372 erase(0,row+ofs,80,1);
1381 ** Redraws the active list
1390 sprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1393 putxyl(45,0,lines,16);
1395 drawlist(1,8,1,alist); /* draw device lists */
1401 ** Redraws the inactive list
1404 redrawinactive(void)
1406 drawlist(10,7,0,ilist); /* draw device lists */
1413 ** Clear the screen and redraw the entire layout
1420 putxy(3,0,"!bActive!n-!bDrivers");
1421 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1423 putxy(3,9,"!bInactive!n-!bDrivers");
1424 putxy(63,9,"!bDev");
1427 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1437 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1438 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1441 yesnocancel(char *str)
1467 ** Show device parameters in the region below the lists
1469 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1470 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1471 ** +--------------------------------------------------------------------------------+
1472 ** 17-|--------------------------------------------------------------------------------|
1473 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1474 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1475 ** 20-| Flags : 0x0000 DRQ number : 00 |
1476 ** 21-|--------------------------------------------------------------------------------|
1479 showparams(DEV_LIST *dev)
1483 erase(0,18,80,3); /* clear area */
1486 if (dev->comment != DEV_DEVICE)
1490 if (dev->iobase > 0)
1492 sprintf(buf,"Port address : 0x%x",dev->iobase);
1498 sprintf(buf,"IRQ number : %d",dev->irq);
1501 sprintf(buf,"Flags : 0x%x",dev->flags);
1505 sprintf(buf,"Memory address : 0x%x",dev->maddr);
1510 sprintf(buf,"Memory size : 0x%x",dev->msize);
1516 sprintf(buf,"DRQ number : %d",dev->drq);
1523 ** Editing functions for device parameters
1525 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1526 ** onscreen. Refuse values outsise (min) and (max).
1527 ** editparams(dev) - Edit the parameters for (dev)
1531 #define VetRet(code) \
1533 if ((i >= min) && (i <= max)) /* legit? */ \
1536 sprintf(buf,hex?"0x%x":"%d",i); \
1537 putxy(hex?x-2:x,y,buf); \
1538 return(code); /* all done and exit */ \
1540 i = *val; /* restore original value */ \
1541 delta = 1; /* restore other stuff */ \
1548 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1549 ** in a field (width) wide. (Allow one space)
1550 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1552 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1555 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1557 int i = *val; /* work with copy of the value */
1558 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1559 int xp = 0; /* cursor offset into text copy */
1560 int delta = 1; /* force redraw first time in */
1562 int extended = 0; /* stage counter for extended key sequences */
1564 if (hex) /* we presume there's a leading 0x onscreen */
1565 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1569 if (delta) /* only update if necessary */
1571 sprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1572 sprintf(buf,"!i%s",tc); /* format for printing */
1573 erase(x,y,width,1); /* clear the area */
1574 putxy(x,y,buf); /* write */
1575 xp = strlen(tc); /* cursor always at end */
1576 move(x+xp,y); /* position the cursor */
1581 switch(extended) /* escape handling */
1584 if (c == 0x1b) /* esc? */
1586 extended = 1; /* flag and spin */
1590 break; /* nope, drop through */
1592 case 1: /* there was an escape prefix */
1593 if (c == '[' || c == 'O') /* second character in sequence */
1599 return(KEY_EXIT); /* double esc exits */
1601 break; /* nup, not a sequence. */
1605 switch(c) /* looks like the real McCoy */
1608 VetRet(KEY_UP); /* leave if OK */
1611 VetRet(KEY_DOWN); /* leave if OK */
1614 VetRet(KEY_RIGHT); /* leave if OK */
1617 VetRet(KEY_LEFT); /* leave if OK */
1627 case '\t': /* trying to tab off */
1628 VetRet(KEY_TAB); /* verify and maybe return */
1638 case '\177': /* BS or DEL */
1639 if (ro) /* readonly? */
1641 puthelp(" !iThis value cannot be edited (Press ESC)");
1642 while(getchar() != 0x1b); /* wait for key */
1643 return(KEY_NULL); /* spin */
1645 if (xp) /* still something left to delete */
1647 i = (hex ? i/0x10u : i/10); /* strip last digit */
1648 delta = 1; /* force update */
1671 if (ro) /* readonly? */
1673 puthelp(" !iThis value cannot be edited (Press ESC)");
1674 while(getchar() != 0x1b); /* wait for key */
1675 return(KEY_NULL); /* spin */
1677 if (xp >= width) /* no room for more characters anyway */
1681 if ((c >= '0') && (c <= '9'))
1683 i = i*0x10 + (c-'0'); /* update value */
1687 if ((c >= 'a') && (c <= 'f'))
1689 i = i*0x10 + (c-'a'+0xa);
1693 if ((c >= 'A') && (c <= 'F'))
1695 i = i*0x10 + (c-'A'+0xa);
1700 if ((c >= '0') && (c <= '9'))
1702 i = i*10 + (c-'0'); /* update value */
1703 delta = 1; /* force redraw */
1716 ** Edit the parameters for (dev)
1718 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1719 ** possible for this to spin in an endless loop...
1720 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1721 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1722 ** +--------------------------------------------------------------------------------+
1723 ** 17-|--------------------------------------------------------------------------------|
1724 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1725 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1726 ** 20-| Flags : 0x0000 DRQ number : 00 |
1727 ** 21-|--------------------------------------------------------------------------------|
1729 ** The "intelligence" in this function that hops around based on the directional
1730 ** returns from editval isn't very smart, and depends on the layout above.
1733 editparams(DEV_LIST *dev)
1736 char buf[16]; /* needs to fit the device name */
1738 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1739 sprintf(buf,"!b%s",dev->dev);
1746 if (dev->iobase > 0)
1748 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1749 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1769 puthelp(" Interrupt number (Decimal, 1-15)");
1770 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1782 if (dev->iobase > 0)
1793 puthelp(" Device-specific flag values.");
1794 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1808 if (dev->iobase > 0)
1828 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1829 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1836 if (dev->iobase > 0)
1858 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1859 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1888 puthelp(" Device DMA request number (Decimal, 1-7)");
1889 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1912 dev->changed = 1; /* mark as changed */
1915 static char *helptext[] =
1917 " Using the UserConfig kernel settings editor",
1918 " -------------------------------------------",
1924 "The screen displays a list of available drivers, divided into two",
1925 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1926 "by default collapsed and can be expanded to show all the drivers",
1927 "available in each category. The parameters for the currently selected",
1928 "driver are shown at the bottom of the screen.",
1930 "- - Moving around -",
1932 "To move in the current list, use the UP and DOWN cursor keys to select",
1933 "an item (the selected item will be highlighted). If the item is a",
1934 "category name, you may alternatively expand or collapse the list of",
1935 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1936 "expanded, you can select each driver in the same manner and either:",
1938 " - change its parameters using [!bENTER!n]",
1939 " - move it to the Inactive list using [!bDEL!n]",
1941 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1942 "you need to move a driver from the Inactive list back to the Active",
1943 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1944 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1945 "its place in the Active list.",
1947 "- - Altering the list/parameters -",
1949 "Any drivers for devices not installed in your system should be moved",
1950 "to the Inactive list, until there are no remaining parameter conflicts",
1951 "between the drivers, as indicated at the top.",
1953 "Once the list of Active drivers only contains entries for the devices",
1954 "present in your system, you can set their parameters (Interrupt, DMA",
1955 "channel, I/O addresses). To do this, select the driver and press",
1956 "[!bENTER!n]: it is now possible to edit the settings at the",
1957 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1958 "finished, use [!bQ!n] to return to the list.",
1960 "- - Saving changes -",
1962 "When all settings seem correct, and you wish to proceed with the",
1963 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1964 "confirm your choice.",
1973 ** Displays help text onscreen for people that are confused, using a simple
1979 int topline = 0; /* where we are in the text */
1980 int line = 0; /* last line we displayed */
1984 for (;;) /* loop until user quits */
1986 /* display help text */
1989 clear(); /* remove everything else */
1990 for (line = topline;
1991 (line < (topline + 24)) && (helptext[line]);
1993 putxy(0,line-topline,helptext[line]);
1998 sprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
2001 c = getchar(); /* so what do they say? */
2008 case 'B': /* wired into 'more' users' fingers */
2009 if (topline > 0) /* room to go up? */
2012 if (topline < 0) /* don't go too far */
2020 case ' ': /* expected by most people */
2021 if (helptext[line]) /* maybe more below? */
2030 redraw(); /* restore the screen */
2038 ** High-level control functions
2045 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2046 ** (num) lines, starting at (*ofs) offset from row onscreen.
2047 ** Pass (detail) on to drawing routines.
2049 ** If the user hits a key other than a cursor key, maybe return a code.
2051 ** (*list) points to the device at the top line in the region, (*ofs) is the
2052 ** position of the highlight within the region. All routines below
2053 ** this take only a device and an absolute row : use ofsent() to find the
2054 ** device, and add (*ofs) to (row) to find the absolute row.
2057 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2068 showparams(ofsent(*ofs,*list)); /* show device parameters */
2069 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2073 c = getchar(); /* get a character */
2074 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2076 extended = 0; /* no longer */
2079 case 588: /* syscons' idea of 'up' */
2081 if (*ofs) /* just a move onscreen */
2083 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2084 (*ofs)--; /* move up */
2086 lp = prevent(*list); /* can we go up? */
2089 *list = lp; /* yes, move up list */
2090 drawlist(row,num,detail,*list);
2095 case 596: /* dooby-do */
2096 case 'B': /* down */
2097 lp = ofsent(*ofs,*list); /* get current item */
2099 break; /* nothing more to move to */
2100 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2101 if (*ofs < (num-1)) /* room to move onscreen? */
2105 *list = nextent(*list); /* scroll region down */
2106 drawlist(row,num,detail,*list);
2118 case '[': /* cheat : always preceeds cursor move */
2119 case 'O': /* ANSI application key mode */
2128 return(KEY_EXIT); /* user requests exit */
2132 return(KEY_DO); /* "do" something */
2137 return(KEY_DEL); /* "delete" response */
2141 return(KEY_UNZOOM); /* expand everything */
2145 return(KEY_ZOOM); /* collapse everything */
2148 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2149 return(KEY_TAB); /* "move" response */
2151 case '\014': /* ^L, redraw */
2154 case '?': /* helptext */
2166 ** Do the fullscreen config thang
2171 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2175 initlist(&inactive);
2181 conflicts = findconflict(active); /* find conflicts in the active list only */
2189 case 0: /* active devices */
2190 ret = dolist(1,8,1,&actofs,&alist,
2191 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2195 mode = 1; /* swap lists */
2212 collapselist(active);
2217 dp = ofsent(actofs,alist); /* get current device */
2218 if (dp) /* paranoia... */
2220 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2222 if (dp == alist) /* moving top item on list? */
2226 alist = dp->next; /* point list to non-moving item */
2228 alist = dp->prev; /* end of list, go back instead */
2231 if (!dp->next) /* moving last item on list? */
2234 dp->conflicts = 0; /* no conflicts on the inactive list */
2235 movedev(dp,inactive); /* shift to inactive list */
2236 conflicts = findconflict(active); /* update conflict tags */
2238 redrawactive(); /* redraw */
2243 case KEY_DO: /* edit device parameters */
2244 dp = ofsent(actofs,alist); /* get current device */
2245 if (dp) /* paranoia... */
2247 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2249 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2251 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2253 conflicts = findconflict(active); /* update conflict tags */
2254 }else{ /* DO on comment = zoom */
2255 switch(dp->comment) /* Depends on current state */
2257 case DEV_COMMENT: /* not currently zoomed */
2258 dp->comment = DEV_ZOOMED;
2262 dp->comment = DEV_COMMENT;
2272 case 1: /* inactive devices */
2273 ret = dolist(10,7,0,&inactofs,&ilist,
2274 " [!bEnter!n] Enable device ");
2288 expandlist(inactive);
2295 collapselist(inactive);
2300 dp = ofsent(inactofs,ilist); /* get current device */
2301 if (dp) /* paranoia... */
2303 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2305 if (dp == ilist) /* moving top of list? */
2309 ilist = dp->next; /* point list to non-moving item */
2311 ilist = dp->prev; /* can't go down, go up instead */
2314 if (!dp->next) /* last entry on list? */
2315 inactofs--; /* shift cursor up one */
2318 movedev(dp,active); /* shift to active list */
2319 conflicts = findconflict(active); /* update conflict tags */
2321 alist = dp; /* put at top and current */
2323 while(dp->comment == DEV_DEVICE)
2324 dp = dp->prev; /* forcibly unzoom section */
2325 dp ->comment = DEV_COMMENT;
2326 mode = 0; /* and swap modes to follow it */
2328 }else{ /* DO on comment = zoom */
2329 switch(dp->comment) /* Depends on current state */
2331 case DEV_COMMENT: /* not currently zoomed */
2332 dp->comment = DEV_ZOOMED;
2336 dp->comment = DEV_COMMENT;
2340 redrawactive(); /* redraw */
2345 default: /* nothing else relevant here */
2350 mode = 0; /* shouldn't happen... */
2353 /* handle returns that are the same for both modes */
2360 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2363 case 2: /* cancel */
2367 case 1: /* save and exit */
2369 savelist(inactive,0);
2372 nukelist(active); /* clean up after ourselves */
2382 #endif /* VISUAL_USERCONFIG */
2385 * Copyright (c) 1991 Regents of the University of California.
2386 * All rights reserved.
2387 * Copyright (c) 1994 Jordan K. Hubbard
2388 * All rights reserved.
2389 * Copyright (c) 1994 David Greenman
2390 * All rights reserved.
2392 * Many additional changes by Bruce Evans
2394 * This code is derived from software contributed by the
2395 * University of California Berkeley, Jordan K. Hubbard,
2396 * David Greenman and Bruce Evans.
2398 * Redistribution and use in source and binary forms, with or without
2399 * modification, are permitted provided that the following conditions
2401 * 1. Redistributions of source code must retain the above copyright
2402 * notice, this list of conditions and the following disclaimer.
2403 * 2. Redistributions in binary form must reproduce the above copyright
2404 * notice, this list of conditions and the following disclaimer in the
2405 * documentation and/or other materials provided with the distribution.
2406 * 3. All advertising materials mentioning features or use of this software
2407 * must display the following acknowledgement:
2408 * This product includes software developed by the University of
2409 * California, Berkeley and its contributors.
2410 * 4. Neither the name of the University nor the names of its contributors
2411 * may be used to endorse or promote products derived from this software
2412 * without specific prior written permission.
2414 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2415 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2416 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2417 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2418 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2419 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2420 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2421 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2422 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2423 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2426 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2429 #include "use_scbus.h"
2431 #define PARM_DEVSPEC 0x1
2432 #define PARM_INT 0x2
2433 #define PARM_ADDR 0x3
2434 #define PARM_STRING 0x4
2436 typedef struct _cmdparm {
2439 struct uc_device *dparm;
2448 typedef int (*CmdFunc)(CmdParm *);
2450 typedef struct _cmd {
2458 static void lsscsi(void);
2459 static int list_scsi(CmdParm *);
2462 static int lsdevtab(struct uc_device *);
2463 static struct uc_device *find_device(char *, int);
2464 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2465 static void cngets(char *, int);
2466 static Cmd *parse_cmd(char *);
2467 static int parse_args(const char *, CmdParm *);
2468 static int save_dev(struct uc_device *);
2470 static int list_devices(CmdParm *);
2471 static int set_device_ioaddr(CmdParm *);
2472 static int set_device_irq(CmdParm *);
2473 static int set_device_drq(CmdParm *);
2474 static int set_device_iosize(CmdParm *);
2475 static int set_device_mem(CmdParm *);
2476 static int set_device_flags(CmdParm *);
2477 static int set_device_enable(CmdParm *);
2478 static int set_device_disable(CmdParm *);
2479 static int quitfunc(CmdParm *);
2480 static int helpfunc(CmdParm *);
2481 static int introfunc(CmdParm *);
2484 static int lspnp(void);
2485 static int set_pnp_parms(CmdParm *);
2490 #include "use_eisa.h"
2494 #include <bus/eisa/eisaconf.h>
2496 static int set_num_eisa_slots(CmdParm *);
2498 #endif /* NEISA > 0 */
2500 static CmdParm addr_parms[] = {
2501 { PARM_DEVSPEC, {} },
2506 static CmdParm int_parms[] = {
2507 { PARM_DEVSPEC, {} },
2512 static CmdParm dev_parms[] = {
2513 { PARM_DEVSPEC, {} },
2518 static CmdParm string_arg[] = {
2519 { PARM_STRING, {} },
2525 static CmdParm int_arg[] = {
2529 #endif /* NEISA > 0 */
2531 static Cmd CmdList[] = {
2532 { "?", helpfunc, NULL }, /* ? (help) */
2533 { "di", set_device_disable, dev_parms }, /* disable dev */
2534 { "dr", set_device_drq, int_parms }, /* drq dev # */
2536 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2537 #endif /* NEISA > 0 */
2538 { "en", set_device_enable, dev_parms }, /* enable dev */
2539 { "ex", quitfunc, NULL }, /* exit (quit) */
2540 { "f", set_device_flags, int_parms }, /* flags dev mask */
2541 { "h", helpfunc, NULL }, /* help */
2542 { "intro", introfunc, NULL }, /* intro screen */
2543 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2544 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2545 { "ir", set_device_irq, int_parms }, /* irq dev # */
2546 { "l", list_devices, NULL }, /* ls, list */
2548 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2550 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2551 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2552 { "q", quitfunc, NULL }, /* quit */
2554 { "s", list_scsi, NULL }, /* scsi */
2556 #ifdef VISUAL_USERCONFIG
2557 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2559 { NULL, NULL, NULL },
2565 static char banner = 1;
2571 init_config_script();
2574 /* Only display signon banner if we are about to go interactive */
2575 if (!has_config_script()) {
2576 if (!(boothowto & RB_CONFIG))
2577 #ifdef INTRO_USERCONFIG
2584 printf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2585 " Type \"help\" for help"
2586 #ifdef VISUAL_USERCONFIG
2587 " or \"visual\" to go to the visual\n"
2588 " configuration interface (requires MGA/VGA display or\n"
2589 " serial terminal capable of displaying ANSI graphics)"
2597 if (input[0] == '\0')
2599 cmd = parse_cmd(input);
2601 printf("Invalid command or syntax. Type `?' for help.\n");
2604 rval = (*cmd->handler)(cmd->parms);
2613 parse_cmd(char *cmd)
2617 for (cp = CmdList; cp->name; cp++) {
2618 int len = strlen(cp->name);
2620 if (!strncmp(cp->name, cmd, len)) {
2621 while (*cmd && *cmd != ' ' && *cmd != '\t')
2623 if (parse_args(cmd, cp->parms))
2633 parse_args(const char *cmd, CmdParm *parms)
2638 if (*cmd == ' ' || *cmd == '\t') {
2642 if (parms == NULL || parms->type == -1) {
2645 printf("Extra arg(s): %s\n", cmd);
2648 if (parms->type == PARM_DEVSPEC) {
2653 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2654 (*cmd >= '0' && *cmd <= '9')))
2655 devname[i++] = *(cmd++);
2657 if (*cmd >= '0' && *cmd <= '9') {
2658 unit = strtoul(cmd, &ptr, 10);
2660 printf("Invalid device number\n");
2661 /* XXX should print invalid token here and elsewhere. */
2664 /* XXX else should require end of token. */
2667 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2668 printf("No such device: %s%d\n", devname, unit);
2674 if (parms->type == PARM_INT) {
2675 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2677 printf("Invalid numeric argument\n");
2684 if (parms->type == PARM_ADDR) {
2685 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2687 printf("Invalid address argument\n");
2694 if (parms->type == PARM_STRING) {
2695 parms->parm.u.sparm = cmd;
2703 list_devices(CmdParm *parms)
2706 if (lsdevtab(uc_devtab)) return 0;
2708 if (lspnp()) return 0;
2711 printf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2712 #endif /* NEISA > 0 */
2717 set_device_ioaddr(CmdParm *parms)
2719 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2720 save_dev(parms[0].parm.dparm);
2725 set_device_irq(CmdParm *parms)
2729 irq = parms[1].parm.iparm;
2731 printf("Warning: Remapping IRQ 2 to IRQ 9\n");
2734 else if (irq != -1 && irq > 15) {
2735 printf("An IRQ > 15 would be invalid.\n");
2738 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2739 save_dev(parms[0].parm.dparm);
2744 set_device_drq(CmdParm *parms)
2749 * The bounds checking is just to ensure that the value can be printed
2750 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2752 drq = parms[1].parm.iparm;
2753 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2754 save_dev(parms[0].parm.dparm);
2759 set_device_iosize(CmdParm *parms)
2761 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2762 save_dev(parms[0].parm.dparm);
2767 set_device_mem(CmdParm *parms)
2769 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2770 save_dev(parms[0].parm.dparm);
2775 set_device_flags(CmdParm *parms)
2777 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2778 save_dev(parms[0].parm.dparm);
2783 set_device_enable(CmdParm *parms)
2785 parms[0].parm.dparm->id_enabled = TRUE;
2786 save_dev(parms[0].parm.dparm);
2791 set_device_disable(CmdParm *parms)
2793 parms[0].parm.dparm->id_enabled = FALSE;
2794 save_dev(parms[0].parm.dparm);
2801 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2807 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2810 * Output the pnp_ldn_overrides[] table.
2812 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2813 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2814 if(error) return(error);
2819 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2820 0, 0, sysctl_machdep_uc_pnplist, "A",
2821 "List of PnP overrides changed in UserConfig");
2824 * this function sets the kernel table to override bios PnP
2828 set_pnp_parms(CmdParm *parms)
2830 u_long idx, val, ldn, csn;
2833 const char *p = parms[0].parm.u.sparm;
2836 csn=strtoul(p,&q, 0);
2837 ldn=strtoul(q,&q, 0);
2838 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2839 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2840 printf("bad csn/ldn %ld:%ld\n", csn, ldn);
2843 for (i=0; i < MAX_PNP_LDN; i++) {
2844 if (pnp_ldn_overrides[i].csn == csn &&
2845 pnp_ldn_overrides[i].ldn == ldn)
2848 if (i==MAX_PNP_LDN) {
2849 for (i=0; i < MAX_PNP_LDN; i++) {
2850 if (pnp_ldn_overrides[i].csn <1 ||
2851 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2855 if (i==MAX_PNP_LDN) {
2856 printf("sorry, no PnP entries available, try delete one\n");
2859 d = pnp_ldn_overrides[i] ;
2865 if (!strncmp(p,"irq",3)) {
2866 idx=strtoul(p+3,&q, 0);
2867 val=strtoul(q,&q, 0);
2868 if (idx >=0 && idx < 2) d.irq[idx] = val;
2869 } else if (!strncmp(p,"flags",5)) {
2870 idx=strtoul(p+5,&q, 0);
2872 } else if (!strncmp(p,"drq",3)) {
2873 idx=strtoul(p+3,&q, 0);
2874 val=strtoul(q,&q, 0);
2875 if (idx >=0 && idx < 2) d.drq[idx] = val;
2876 } else if (!strncmp(p,"port",4)) {
2877 idx=strtoul(p+4,&q, 0);
2878 val=strtoul(q,&q, 0);
2879 if (idx >=0 && idx < 8) d.port[idx] = val;
2880 } else if (!strncmp(p,"mem",3)) {
2881 idx=strtoul(p+3,&q, 0);
2882 val=strtoul(q,&q, 0);
2883 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2884 } else if (!strncmp(p,"bios",4)) {
2887 } else if (!strncmp(p,"os",2)) {
2890 } else if (!strncmp(p,"disable",7)) {
2893 } else if (!strncmp(p,"enable",6)) {
2896 } else if (!strncmp(p,"delete",6)) {
2897 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2898 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2901 printf("unknown command <%s>\n", p);
2904 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2906 pnp_ldn_overrides[i] = d ;
2913 set_num_eisa_slots(CmdParm *parms)
2917 num_slots = parms[0].parm.iparm;
2918 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2921 #endif /* NEISA > 0 */
2924 quitfunc(CmdParm *parms)
2927 * If kernel config supplied, and we are parsing it, and -c also supplied,
2928 * ignore a quit command, This provides a safety mechanism to allow
2929 * recovery from a damaged/buggy kernel config.
2931 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2937 helpfunc(CmdParm *parms)
2940 "Command\t\t\tDescription\n"
2941 "-------\t\t\t-----------\n"
2942 "ls\t\t\tList currently configured devices\n"
2943 "port <devname> <addr>\tSet device port (i/o address)\n"
2944 "irq <devname> <number>\tSet device irq\n"
2945 "drq <devname> <number>\tSet device drq\n"
2946 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2947 "iosize <devname> <size>\tSet device memory size\n"
2948 "flags <devname> <mask>\tSet device flags\n"
2949 "enable <devname>\tEnable device\n"
2950 "disable <devname>\tDisable device (will not be probed)\n");
2953 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2954 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2955 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2956 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2957 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2958 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2961 printf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2962 #endif /* NEISA > 0 */
2964 "quit\t\t\tExit this configuration utility\n"
2965 "reset\t\t\tReset CPU\n");
2966 #ifdef VISUAL_USERCONFIG
2967 printf("visual\t\t\tGo to fullscreen mode.\n");
2970 "help\t\t\tThis message\n\n"
2971 "Commands may be abbreviated to a unique prefix\n");
2975 #if defined (VISUAL_USERCONFIG)
2977 center(int y, char *str)
2979 putxy((80 - strlen(str)) / 2, y, str);
2984 introfunc(CmdParm *parms)
2986 #if defined (VISUAL_USERCONFIG)
2987 int curr_item, first_time, extended = 0;
2988 static char *choices[] = {
2989 " Skip kernel configuration and continue with installation ",
2990 " Start kernel configuration in full-screen visual mode ",
2991 " Start kernel configuration in CLI mode ",
2995 center(2, "!bKernel Configuration Menu!n");
3004 for (i = 0; i < 3; i++) {
3008 strcat(tmp, choices[i]);
3011 putxy(10, 5 + i, tmp);
3015 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3016 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3017 putxy(2, 12, "match your hardware configuration.");
3018 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3019 putxy(2, 15, "(press Down-Arrow then ENTER).");
3020 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3021 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3022 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3023 putxy(2, 21, "then simply press ENTER or Q now.");
3027 move(0, 0); /* move the cursor out of the way */
3030 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3031 extended = 0; /* no longer */
3040 case 'B': /* down */
3052 case '[': /* cheat : always preceeds cursor move */
3053 case 'O': /* ANSI application key mode */
3064 return 1; /* user requests exit */
3066 case '1': /* select an item */
3090 case 'D': /* down */
3103 else if (curr_item == 1)
3104 return visuserconfig();
3106 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3107 /* enable quitfunc */
3108 userconfig_boot_parsing=0;
3110 boothowto |= RB_CONFIG; /* force -c */
3124 struct pnp_cinfo *c;
3128 for (i=0; i< MAX_PNP_LDN; i++) {
3129 c = &pnp_ldn_overrides[i];
3130 if (c->csn >0 && c->csn != 255) {
3132 static char pfmt[] =
3133 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3134 static char mfmt[] =
3135 "mem 0x%x 0x%x 0x%x 0x%x";
3138 if (!userconfig_boot_parsing) {
3140 if (getchar() == 'q') {
3148 if (lineno == 0 || first)
3149 printf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3151 printf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3153 c->override ? "OS ":"BIOS",
3154 c->enable ? "Y":"N",
3155 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3157 printf("flags 0x%08lx ",c->flags);
3158 for (pmax = 7; pmax >=0 ; pmax--)
3159 if (c->port[pmax]!=0) break;
3160 for (mmax = 3; mmax >=0 ; mmax--)
3161 if (c->mem[mmax].base!=0) break;
3164 buf[10 + 5*pmax]='\0';
3166 c->port[0], c->port[1], c->port[2], c->port[3],
3167 c->port[4], c->port[5], c->port[6], c->port[7]);
3171 buf[8 + 5*mmax]='\0';
3173 c->mem[0].base, c->mem[1].base,
3174 c->mem[2].base, c->mem[3].base);
3184 lsdevtab(struct uc_device *dt)
3186 for (; dt->id_id != 0; dt++) {
3191 if (!userconfig_boot_parsing) {
3192 if (getchar() == 'q') {
3202 "Device port irq drq iomem iosize unit flags enab\n"
3206 sprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3207 printf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3208 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3209 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3210 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3211 dt->id_enabled ? "Yes" : "No");
3221 int count = resource_count();
3227 uc_devtab = malloc(sizeof(struct uc_device)*(count + 1),M_DEVL,M_WAITOK);
3228 bzero(uc_devtab, sizeof(struct uc_device) * (count + 1));
3230 for (i = 0; i < count; i++) {
3231 name = resource_query_name(i);
3232 unit = resource_query_unit(i);
3234 continue; /* skip wildcards */
3235 uc_devtab[dt].id_id = id++;
3236 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3238 resource_int_value(name, unit, "irq", &val);
3239 uc_devtab[dt].id_irq = (1 << val);
3240 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3241 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3242 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3243 uc_devtab[dt].id_unit = unit;
3244 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3246 resource_int_value(name, unit, "disabled", &val);
3247 uc_devtab[dt].id_enabled = !val;
3248 uc_devtab[dt].id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3249 strcpy(uc_devtab[dt].id_name, name);
3258 int count = resource_count();
3260 for (i = 0; i < count; i++)
3261 if (uc_devtab[i].id_name)
3262 free(uc_devtab[i].id_name, M_DEVL);
3263 free(uc_devtab, M_DEVL);
3266 static struct uc_device *
3267 find_device(char *devname, int unit)
3269 struct uc_device *ret;
3271 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3276 static struct uc_device *
3277 search_devtable(struct uc_device *dt, char *devname, int unit)
3281 for (i = 0; dt->id_id != 0; dt++)
3282 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3288 cngets(char *input, int maxin)
3294 /* Treat ^H or ^? as backspace */
3295 if ((c == '\010' || c == '\177')) {
3297 printf("\010 \010");
3298 *--input = '\0', --nchars;
3302 /* Treat ^U or ^X as kill line */
3303 else if ((c == '\025' || c == '\030')) {
3305 printf("\010 \010");
3306 *--input = '\0', --nchars;
3311 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3315 *input++ = (u_char)c;
3321 /* scsi: Support for displaying configured SCSI devices.
3322 * There is no way to edit them, and this is inconsistent
3323 * with the ISA method. This is here as a basis for further work.
3326 type_text(char *name) /* XXX: This is bogus */
3328 if (strcmp(name, "sd") == 0)
3331 if (strcmp(name, "st") == 0)
3337 id_put(char *desc, int id)
3339 if (id != SCCONF_UNSPEC)
3344 if (id == SCCONF_ANY)
3356 printf("scsi: (can't be edited):\n");
3358 for (i = 0; scsi_cinit[i].driver; i++)
3360 id_put("controller scbus", scsi_cinit[i].scbus);
3362 if (scsi_cinit[i].unit != -1)
3365 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3371 for (i = 0; scsi_dinit[i].name; i++)
3373 printf("%s ", type_text(scsi_dinit[i].name));
3375 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3376 id_put(" at scbus", scsi_dinit[i].cunit);
3377 id_put(" target ", scsi_dinit[i].target);
3378 id_put(" lun ", scsi_dinit[i].lun);
3380 if (scsi_dinit[i].flags)
3381 printf(" flags 0x%x\n", scsi_dinit[i].flags);
3388 list_scsi(CmdParm *parms)
3397 save_resource(struct uc_device *idev)
3402 name = idev->id_name;
3403 unit = idev->id_unit;
3404 resource_set_int(name, unit, "port", idev->id_iobase);
3405 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3406 resource_set_int(name, unit, "drq", idev->id_drq);
3407 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3408 resource_set_int(name, unit, "msize", idev->id_msize);
3409 resource_set_int(name, unit, "flags", idev->id_flags);
3410 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3415 struct uc_device *idev;
3417 struct uc_device *id_p,*id_pn;
3418 char *name = idev->id_name;
3420 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3421 if (id_p->id_id == idev->id_id) {
3422 id_pn = id_p->id_next;
3424 free(id_p->id_name, M_DEVL);
3425 bcopy(idev,id_p,sizeof(struct uc_device));
3426 save_resource(idev);
3427 id_p->id_name = malloc(strlen(name)+1, M_DEVL,M_WAITOK);
3428 strcpy(id_p->id_name, name);
3429 id_p->id_next = id_pn;
3433 id_pn = malloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3434 bcopy(idev,id_pn,sizeof(struct uc_device));
3435 save_resource(idev);
3436 id_pn->id_name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3437 strcpy(id_pn->id_name, name);
3438 id_pn->id_next = uc_devlist;