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.15 2008/01/05 14:02:41 swildner Exp $
56 ** Kernel boot-time configuration manipulation tool for FreeBSD.
58 ** Two modes of operation are supported : the default is the line-editor mode,
59 ** the command "visual" invokes the fullscreen mode.
61 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
62 ** fullscreen mode requires syscons or a minimal-ansi serial console.
66 ** USERCONFIG, visual mode.
70 ** Look for "EDIT THIS LIST" to add to the list of known devices
73 ** There are a number of assumptions made in this code.
75 ** - That the console supports a minimal set of ANSI escape sequences
76 ** (See the screen manipulation section for a summary)
77 ** and has at least 24 rows.
78 ** - That values less than or equal to zero for any of the device
79 ** parameters indicate that the driver does not use the parameter.
80 ** - That flags are _always_ editable.
82 ** Devices marked as disabled are imported as such.
84 ** For this tool to be useful, the list of devices below _MUST_ be updated
85 ** when a new driver is brought into the kernel. It is not possible to
86 ** extract this information from the drivers in the kernel.
90 ** - Display _what_ a device conflicts with.
91 ** - Implement page up/down (as what?)
92 ** - Wizard mode (no restrictions)
93 ** - Find out how to put syscons back into low-intensity mode so that the
94 ** !b escape is useful on the console. (It seems to be that it actually
95 ** gets low/high intensity backwards. That looks OK.)
97 ** - Only display headings with devices under them. (difficult)
100 #include "opt_userconfig.h"
101 #define COMPAT_OLDISA /* get the definitions */
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/kernel.h>
106 #include <sys/malloc.h>
107 #include <sys/reboot.h>
108 #include <sys/linker.h>
109 #include <sys/sysctl.h>
111 #include <sys/cons.h>
113 #include <machine/md_var.h>
114 #include <machine/limits.h>
116 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
122 #include <machine_base/isa/pnp.h>
125 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
127 #include <machine/uc_device.h>
128 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
129 static struct uc_device *uc_devtab; /* fake uc_device table */
131 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
133 static void load_devtab(void);
134 static void free_devtab(void);
135 static void save_resource(struct uc_device *);
138 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
140 struct uc_device *id;
148 error+=sizeof(struct uc_device)+8;
151 return(SYSCTL_OUT(req,0,error));
153 /* Output the data. The buffer is filled with consecutive
154 * struct uc_device and char buf[8], containing the name
155 * (not guaranteed to end with '\0').
159 error=sysctl_handle_opaque(oidp,id,
160 sizeof(struct uc_device),req);
161 if(error) return(error);
162 strncpy(name,id->id_name,8);
163 error=sysctl_handle_opaque(oidp,name,
165 if(error) return(error);
172 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
173 0, 0, sysctl_machdep_uc_devlist, "A",
174 "List of ISA devices changed in UserConfig");
177 ** Obtain command input.
179 ** Initially, input is read from a possibly-loaded script.
180 ** At the end of the script, or if no script is supplied,
181 ** behaviour is determined by the RB_CONFIG (-c) flag. If
182 ** the flag is set, user input is read from the console; if
183 ** unset, the 'quit' command is invoked and userconfig
186 ** Note that quit commands encountered in the script will be
187 ** ignored if the RB_CONFIG flag is supplied.
189 static const char *config_script;
190 static int config_script_size; /* use of int for -ve magic value */
192 #define has_config_script() (config_script_size > 0)
195 init_config_script(void)
197 caddr_t autoentry, autoattr;
199 /* Look for loaded userconfig script */
200 autoentry = preload_search_by_type("userconfig_script");
201 if (autoentry != NULL) {
202 /* We have one, get size and data */
203 config_script_size = 0;
204 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
205 config_script_size = (size_t)*(u_int32_t *)autoattr;
206 config_script = NULL;
207 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
208 config_script = *(const char **)autoattr;
210 if ((config_script_size == 0) || (config_script == NULL)) {
211 config_script_size = 0;
212 config_script = NULL;
215 return has_config_script();
222 #ifdef INTRO_USERCONFIG
223 static int intro = 0;
226 if (has_config_script())
228 /* Consume character from loaded userconfig script, display */
229 userconfig_boot_parsing = 1;
232 config_script_size--;
236 #ifdef INTRO_USERCONFIG
237 if (userconfig_boot_parsing) {
238 if (!(boothowto & RB_CONFIG)) {
239 /* userconfig_script, !RB_CONFIG -> quit */
242 config_script = "uit\n";
243 config_script_size = strlen(config_script);
244 /* userconfig_script will be 1 on the next pass */
247 /* userconfig_script, RB_CONFIG -> cngetc() */
250 if (!(boothowto & RB_CONFIG)) {
251 /* no userconfig_script, !RB_CONFIG -> show intro */
255 config_script = "ntro\n";
256 config_script_size = strlen(config_script);
257 /* userconfig_script will be 1 on the next pass */
260 /* no userconfig_script, RB_CONFIG -> cngetc() */
263 #else /* !INTRO_USERCONFIG */
264 /* assert(boothowto & RB_CONFIG) */
265 #endif /* INTRO_USERCONFIG */
266 userconfig_boot_parsing = 0;
275 #define TRUE (!FALSE)
278 #ifdef VISUAL_USERCONFIG
282 char dev[16]; /* device basename */
283 char name[60]; /* long name */
284 int attrib; /* things to do with the device */
285 int class; /* device classification */
288 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
289 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
290 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
291 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
292 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
293 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
294 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
295 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
296 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
298 #define CLS_STORAGE 1 /* storage devices */
299 #define CLS_NETWORK 2 /* network interfaces */
300 #define CLS_COMMS 3 /* serial, parallel ports */
301 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
302 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
303 #define CLS_MISC 255 /* none of the above */
312 static DEVCLASS_INFO devclass_names[] = {
313 { "Storage : ", CLS_STORAGE},
314 { "Network : ", CLS_NETWORK},
315 { "Communications : ", CLS_COMMS},
316 { "Input : ", CLS_INPUT},
317 { "Multimedia : ", CLS_MMEDIA},
318 { "Miscellaneous : ", CLS_MISC},
322 /********************* EDIT THIS LIST **********************/
326 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
327 ** - XXX The list below should be reviewed by the driver authors to verify
328 ** that the correct flags have been set for each driver, and that the
329 ** descriptions are accurate.
332 static DEV_INFO device_info[] = {
333 /*---Name----- ---Description---------------------------------------------- */
334 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
335 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE},
336 {"aha", "Adaptec 154x SCSI controller", 0, CLS_STORAGE},
337 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE},
338 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
339 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
340 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
341 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
342 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
343 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
344 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE},
345 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
346 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
347 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
349 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
350 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
351 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
352 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
353 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
354 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
355 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
356 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
357 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
358 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
359 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
360 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
361 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
363 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
364 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
365 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
366 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
367 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
368 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
369 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
370 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
371 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
372 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
374 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
375 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
376 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
377 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
378 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
379 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
381 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
382 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
383 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
384 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
385 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
386 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
387 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
388 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
389 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
390 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
391 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
392 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
393 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
394 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
395 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
396 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
397 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
398 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
399 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
400 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
401 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
402 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
404 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
405 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
406 {"pcic", "PC-card controller", 0, CLS_MISC},
407 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
408 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
412 typedef struct _devlist_struct
415 int attrib; /* flag values as per the FLG_* defines above */
416 int class; /* disk, etc as per the CLS_* defines above */
418 int iobase,irq,drq,maddr,msize,unit,flags,id;
419 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
420 int conflicts; /* set/reset by findconflict, count of conflicts */
421 int changed; /* nonzero if the device has been edited */
422 struct uc_device *device;
423 struct _devlist_struct *prev,*next;
428 #define DEV_COMMENT 1
431 #define LIST_CURRENT (1<<0)
432 #define LIST_SELECTED (1<<1)
434 #define KEY_EXIT 0 /* return codes from dolist() and friends */
440 #define KEY_UP 5 /* these only returned from editval() */
444 #define KEY_NULL 9 /* this allows us to spin & redraw */
446 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
447 #define KEY_UNZOOM 11
449 #define KEY_HELP 12 /* duh? */
451 static void redraw(void);
452 static void insdev(DEV_LIST *dev, DEV_LIST *list);
453 static int devinfo(DEV_LIST *dev);
454 static int visuserconfig(void);
456 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
457 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
458 static DEV_LIST scratch; /* scratch record */
459 static int conflicts; /* total conflict count */
462 static char lines[] = "--------------------------------------------------------------------------------";
463 static char spaces[] = " ";
467 ** Device manipulation stuff : find, describe, configure.
473 ** Sets the device referenced by (*dev) to the parameters in the struct,
474 ** and the enable flag according to (enabled)
477 setdev(DEV_LIST *dev, int enabled)
479 dev->device->id_iobase = dev->iobase; /* copy happy */
480 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
481 dev->device->id_drq = (short)dev->drq;
482 dev->device->id_maddr = (caddr_t)dev->maddr;
483 dev->device->id_msize = dev->msize;
484 dev->device->id_flags = dev->flags;
485 dev->device->id_enabled = enabled;
492 ** Walk the kernel device tables and build the active and inactive lists
498 struct uc_device *ap;
500 ap = uc_devtab; /* pointer to array of devices */
501 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
503 scratch.unit = ap[i].id_unit; /* device parameters */
504 strcpy(scratch.dev,ap[i].id_name);
505 scratch.iobase = ap[i].id_iobase;
506 scratch.irq = ffs(ap[i].id_irq)-1;
507 scratch.drq = ap[i].id_drq;
508 scratch.maddr = (int)ap[i].id_maddr;
509 scratch.msize = ap[i].id_msize;
510 scratch.flags = ap[i].id_flags;
512 scratch.comment = DEV_DEVICE; /* admin stuff */
513 scratch.conflicts = 0;
514 scratch.device = &ap[i]; /* save pointer for later reference */
516 if (!devinfo(&scratch)) /* get more info on the device */
517 insdev(&scratch,ap[i].id_enabled?active:inactive);
525 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
526 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
528 ** If the device is marked "invisible", return nonzero; the caller should
529 ** not insert any such device into either list.
533 devinfo(DEV_LIST *dev)
537 for (i = 0; device_info[i].class; i++)
539 if (!strcmp(dev->dev,device_info[i].dev))
541 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
543 strcpy(dev->name,device_info[i].name); /* get the name */
544 dev->attrib = device_info[i].attrib;
545 dev->class = device_info[i].class;
549 strcpy(dev->name,"Unknown device");
551 dev->class = CLS_MISC;
557 ** List manipulation stuff : add, move, initialise, free, traverse
559 ** Note that there are assumptions throughout this code that
560 ** the first entry in a list will never move. (assumed to be
568 ** appends a copy of (dev) to the end of (*list)
571 addev(DEV_LIST *dev, DEV_LIST **list)
576 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
577 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
579 if (*list) /* list exists */
583 ap = ap->next; /* scoot to end of list */
587 }else{ /* list does not yet exist */
589 lp->prev = lp->next = NULL; /* list now exists */
597 ** Finds the 'appropriate' place for (dev) in (list)
599 ** 'Appropriate' means in numeric order with other devices of the same type,
600 ** or in alphabetic order following a comment of the appropriate type.
601 ** or at the end of the list if an appropriate comment is not found. (this should
603 ** (Note that the appropriate point is never the top, but may be the bottom)
606 findspot(DEV_LIST *dev, DEV_LIST *list)
610 /* search for a previous instance of the same device */
611 for (ap = list; ap; ap = ap->next)
613 if (ap->comment != DEV_DEVICE) /* ignore comments */
615 if (!strcmp(dev->dev,ap->dev)) /* same base device */
617 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
618 || !ap->next) /* or end of list */
620 ap = ap->prev; /* back up one */
621 break; /* done here */
623 if (ap->next) /* if the next item exists */
625 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
627 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
633 if (!ap) /* not sure yet */
635 /* search for a class that the device might belong to */
636 for (ap = list; ap; ap = ap->next)
638 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
640 if (dev->class != ap->class) /* of same class too 8) */
642 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
644 ap = ap->prev; /* back up one */
645 break; /* done here */
647 if (ap->next) /* if the next item exists */
648 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
653 if (!ap) /* didn't find a match */
655 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
656 if ((ap->comment != DEV_DEVICE)
657 && (ap->class == dev->class)) /* appropriate place? */
659 } /* or just put up with last */
668 ** Inserts a copy of (dev) at the appropriate point in (list)
671 insdev(DEV_LIST *dev, DEV_LIST *list)
675 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
676 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
678 ap = findspot(lp,list); /* find appropriate spot */
679 lp->next = ap->next; /* point to next */
681 ap->next->prev = lp; /* point next to new */
682 lp->prev = ap; /* point new to current */
683 ap->next = lp; /* and current to new */
690 ** Moves (dev) from its current list to an appropriate place in (list)
691 ** (dev) may not come from the top of a list, but it may from the bottom.
694 movedev(DEV_LIST *dev, DEV_LIST *list)
698 ap = findspot(dev,list);
699 dev->prev->next = dev->next; /* remove from old list */
701 dev->next->prev = dev->prev;
703 dev->next = ap->next; /* insert in new list */
705 ap->next->prev = dev; /* point next to new */
706 dev->prev = ap; /* point new to current */
707 ap->next = dev; /* and current to new */
714 ** Initialises (*list) with the basic headings
717 initlist(DEV_LIST **list)
721 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
723 strcpy(scratch.name,devclass_names[i].name);
724 scratch.comment = DEV_ZOOMED;
725 scratch.class = devclass_names[i].number;
726 scratch.attrib = FLG_MANDATORY; /* can't be moved */
727 addev(&scratch,list); /* add to the list */
735 ** Walks (list) and saves the settings of any entry marked as changed.
737 ** The device's active field is set according to (active).
739 ** Builds the uc_devlist used by kget to extract the changed device information.
740 ** The code for this was taken almost verbatim from the original module.
743 savelist(DEV_LIST *list, int active)
745 struct uc_device *id_p,*id_pn;
750 if ((list->comment == DEV_DEVICE) && /* is a device */
751 (list->changed) && /* has been changed */
752 (list->device != NULL)) { /* has an uc_device structure */
754 setdev(list,active); /* set the device itself */
757 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
758 { /* look on the list for it */
759 if (id_p->id_id == list->device->id_id)
761 name = list->device->id_name;
762 id_pn = id_p->id_next;
764 kfree(id_p->id_name, M_DEVL);
765 bcopy(list->device,id_p,sizeof(struct uc_device));
766 save_resource(list->device);
767 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
768 strcpy(id_p->id_name, name);
769 id_pn->id_next = uc_devlist;
770 id_p->id_next = id_pn;
774 if (!id_pn) /* not already on the list */
776 name = list->device->id_name;
777 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
778 bcopy(list->device,id_pn,sizeof(struct uc_device));
779 save_resource(list->device);
780 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
781 strcpy(id_pn->id_name, name);
782 id_pn->id_next = uc_devlist;
783 uc_devlist = id_pn; /* park at top of list */
794 ** Frees all storage in use by a (list).
797 nukelist(DEV_LIST *list)
803 while(list->prev) /* walk to head of list */
818 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
819 ** if there is no previous entry. (Only possible if list->prev == NULL given the
820 ** premise that there is always a comment at the head of the list)
823 prevent(DEV_LIST *list)
829 dp = list->prev; /* start back one */
832 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
833 return(dp); /* so skip to comment */
834 if (dp->comment == DEV_COMMENT) /* not zoomed */
835 return(list->prev); /* one back as normal */
836 dp = dp->prev; /* backpedal */
838 return(dp); /* NULL, we can assume */
845 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
846 ** if there is no next entry. (Possible if the current entry is last, or
847 ** if the current entry is the last heading and it's collapsed)
850 nextent(DEV_LIST *list)
856 if (list->comment != DEV_ZOOMED) /* no reason to skip */
861 if (dp->comment != DEV_DEVICE) /* found another heading */
865 return(dp); /* back we go */
872 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
875 ofsent(int ofs, DEV_LIST *list)
877 while (ofs-- && list)
878 list = nextent(list);
886 ** Scans every element of (list) and sets the conflict tags appropriately
887 ** Returns the number of conflicts found.
890 findconflict(DEV_LIST *list)
892 int count = 0; /* number of conflicts found */
895 for (dp = list; dp; dp = dp->next) /* over the whole list */
897 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
900 dp->conflicts = 0; /* assume the best */
901 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
903 if (sp->comment != DEV_DEVICE) /* likewise */
906 if (sp == dp) /* always conflict with itself */
909 if ((dp->iobase > 0) && /* iobase conflict? */
910 (dp->iobase == sp->iobase))
912 if ((dp->irq > 0) && /* irq conflict? */
913 (dp->irq == sp->irq))
915 if ((dp->drq > 0) && /* drq conflict? */
916 (dp->drq == sp->drq))
918 if ((sp->maddr > 0) && /* maddr/msize conflict? */
920 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
921 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
924 count += dp->conflicts; /* count conflicts */
933 ** Unzooms all headings in (list)
936 expandlist(DEV_LIST *list)
940 if (list->comment == DEV_COMMENT)
941 list->comment = DEV_ZOOMED;
950 ** Zooms all headings in (list)
953 collapselist(DEV_LIST *list)
957 if (list->comment == DEV_ZOOMED)
958 list->comment = DEV_COMMENT;
965 ** Screen-manipulation stuff
967 ** This is the basic screen layout :
969 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
970 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
971 ** +--------------------------------------------------------------------------------+
972 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
973 ** 1 -| ........................ ....... .. 0x....|
974 ** 2 -| ........................ ....... .. 0x....|
975 ** 3 -| ........................ ....... .. 0x....|
976 ** 4 -| ........................ ....... .. 0x....|
977 ** 5 -| ........................ ....... .. 0x....|
978 ** 6 -| ........................ ....... .. 0x....|
979 ** 7 -| ........................ ....... .. 0x....|
980 ** 8 -| ........................ ....... .. 0x....|
981 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
982 ** 10-| ........................ ....... |
983 ** 11-| ........................ ....... |
984 ** 12-| ........................ ....... |
985 ** 13-| ........................ ....... |
986 ** 14-| ........................ ....... |
987 ** 15-| ........................ ....... |
988 ** 16-| ........................ ....... |
989 ** 17-|------------------------------------------------------UP-DOWN-------------------|
990 ** 18-| Relevant parameters for the current device |
993 ** 21-|--------------------------------------------------------------------------------|
994 ** 22-| Help texts go here |
996 ** +--------------------------------------------------------------------------------+
1000 ** On a collapsed comment :
1002 ** [Enter] Expand device list [z] Expand all lists
1003 ** [TAB] Change fields [Q] Save and Exit
1005 ** On an expanded comment :
1007 ** [Enter] Collapse device list [Z] Collapse all lists
1008 ** [TAB] Change fields [Q] Save and Exit
1010 ** On a comment with no followers
1013 ** [TAB] Change fields [Q] Save and Exit
1015 ** On a device in the active list
1017 ** [Enter] Edit device parameters [DEL] Disable device
1018 ** [TAB] Change fields [Q] Save and Exit [?] Help
1020 ** On a device in the inactive list
1022 ** [Enter] Enable device
1023 ** [TAB] Change fields [Q] Save and Exit [?] Help
1025 ** While editing parameters
1027 ** <parameter-specific help here>
1028 ** [TAB] Change fields [Q] Save device parameters
1035 ** The base-level screen primitives :
1037 ** bold() - enter bold mode \E[1m (md)
1038 ** inverse() - enter inverse mode \E[7m (so)
1039 ** normal() - clear bold/inverse mode \E[m (se)
1040 ** clear() - clear the screen \E[H\E[J (ce)
1041 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1066 kprintf("\033[H\033[J");
1072 kprintf("\033[%d;%dH",y+1,x+1);
1078 ** High-level screen primitives :
1080 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1081 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1082 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1083 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1084 ** putmsg(str) - put (str) in the message area
1085 ** puthelp(str) - put (str) in the upper helpline
1086 ** pad(str,len) - pad (str) to (len) with spaces
1087 ** drawline(row,detail,list,inverse,*dhelp)
1088 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1089 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1090 ** draw the line in inverse video, and display (*dhelp) on the
1092 ** drawlist(row,num,detail,list)
1093 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1094 ** through to drawline().
1095 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1096 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1097 ** redraw(); - Redraws the entire screen layout, including the
1098 ** - two list panels.
1103 ** writes (str) at x,y onscreen
1105 ** writes up to (len) of (str) at x,y onscreen.
1107 ** Supports embedded formatting :
1108 ** !i - inverse mode.
1110 ** !n - normal mode.
1113 putxyl(int x, int y, char *str, int len)
1118 while((*str) && (len--))
1120 if (*str == '!') /* format escape? */
1122 switch(*(str+1)) /* depending on the next character */
1126 str +=2; /* skip formatting */
1127 len++; /* doesn't count for length */
1132 str +=2; /* skip formatting */
1133 len++; /* doesn't count for length */
1138 str +=2; /* skip formatting */
1139 len++; /* doesn't count for length */
1143 kprintf("%c", *str++); /* not an escape */
1146 kprintf("%c", *str++); /* emit the character */
1151 #define putxy(x,y,str) putxyl(x,y,str,-1)
1157 ** Erases the region (x,y,w,h)
1160 erase(int x, int y, int w, int h)
1165 for (i = 0; i < h; i++)
1166 putxyl(x,y++,spaces,w);
1173 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1174 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1177 txtbox(int x, int y, int w, int h, char *str)
1182 while((str[i]) && h)
1184 if (str[i] == '\n') /* newline */
1186 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1187 y++; /* move down */
1188 h--; /* room for one less */
1189 str += (i+1); /* skip first newline */
1190 i = 0; /* zero offset */
1192 i++; /* next character */
1195 if (h) /* end of string, not region */
1203 ** writes (msg) in the helptext area
1208 erase(0,18,80,3); /* clear area */
1209 txtbox(0,18,80,3,msg);
1216 ** Writes (msg) in the helpline area
1229 ** Draws the help message at the bottom of the screen
1232 masterhelp(char *msg)
1242 ** space-pads a (str) to (len) characters
1245 pad(char *str, int len)
1249 for (i = 0; str[i]; i++) /* find the end of the string */
1251 if (i >= len) /* no padding needed */
1253 while(i < len) /* pad */
1262 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1263 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1265 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1266 ** help is shown for normal or zoomed comments
1269 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1271 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1273 if (list->comment == DEV_DEVICE)
1276 strncpy(nb+1,list->name,57);
1278 strncpy(nb,list->name,58);
1279 if ((list->comment == DEV_ZOOMED) && (list->next))
1280 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1281 strcat(nb," (Collapsed)");
1285 if (list->conflicts) /* device in conflict? */
1289 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1291 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1294 if (list->comment == DEV_DEVICE)
1296 ksprintf(db,"%s%d",list->dev,list->unit);
1301 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1303 ksprintf(ib," %d",list->irq);
1308 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1310 ksprintf(pb,"0x%x",list->iobase);
1316 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1318 putxyl(0,row,lbuf,80);
1321 switch(list->comment)
1323 case DEV_DEVICE: /* ordinary device */
1329 if (list->next->comment == DEV_DEVICE)
1330 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1335 if (list->next->comment == DEV_DEVICE)
1336 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1339 puthelp(" WARNING: This list entry corrupted!");
1343 move(0,row); /* put the cursor somewhere relevant */
1350 ** Displays (num) lines of the contents of (list) at (row), optionally
1351 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1354 drawlist(int row, int num, int detail, DEV_LIST *list)
1358 for(ofs = 0; ofs < num; ofs++)
1362 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1363 list = nextent(list); /* move down visible list */
1365 erase(0,row+ofs,80,1);
1374 ** Redraws the active list
1383 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1386 putxyl(45,0,lines,16);
1388 drawlist(1,8,1,alist); /* draw device lists */
1394 ** Redraws the inactive list
1397 redrawinactive(void)
1399 drawlist(10,7,0,ilist); /* draw device lists */
1406 ** Clear the screen and redraw the entire layout
1413 putxy(3,0,"!bActive!n-!bDrivers");
1414 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1416 putxy(3,9,"!bInactive!n-!bDrivers");
1417 putxy(63,9,"!bDev");
1420 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1430 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1431 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1434 yesnocancel(char *str)
1460 ** Show device parameters in the region below the lists
1462 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1463 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1464 ** +--------------------------------------------------------------------------------+
1465 ** 17-|--------------------------------------------------------------------------------|
1466 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1467 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1468 ** 20-| Flags : 0x0000 DRQ number : 00 |
1469 ** 21-|--------------------------------------------------------------------------------|
1472 showparams(DEV_LIST *dev)
1476 erase(0,18,80,3); /* clear area */
1479 if (dev->comment != DEV_DEVICE)
1483 if (dev->iobase > 0)
1485 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1491 ksprintf(buf,"IRQ number : %d",dev->irq);
1494 ksprintf(buf,"Flags : 0x%x",dev->flags);
1498 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1503 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1509 ksprintf(buf,"DRQ number : %d",dev->drq);
1516 ** Editing functions for device parameters
1518 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1519 ** onscreen. Refuse values outsise (min) and (max).
1520 ** editparams(dev) - Edit the parameters for (dev)
1524 #define VetRet(code) \
1526 if ((i >= min) && (i <= max)) /* legit? */ \
1529 ksprintf(buf,hex?"0x%x":"%d",i); \
1530 putxy(hex?x-2:x,y,buf); \
1531 return(code); /* all done and exit */ \
1533 i = *val; /* restore original value */ \
1534 delta = 1; /* restore other stuff */ \
1541 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1542 ** in a field (width) wide. (Allow one space)
1543 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1545 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1548 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1550 int i = *val; /* work with copy of the value */
1551 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1552 int xp = 0; /* cursor offset into text copy */
1553 int delta = 1; /* force redraw first time in */
1555 int extended = 0; /* stage counter for extended key sequences */
1557 if (hex) /* we presume there's a leading 0x onscreen */
1558 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1562 if (delta) /* only update if necessary */
1564 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1565 ksprintf(buf,"!i%s",tc); /* format for printing */
1566 erase(x,y,width,1); /* clear the area */
1567 putxy(x,y,buf); /* write */
1568 xp = strlen(tc); /* cursor always at end */
1569 move(x+xp,y); /* position the cursor */
1574 switch(extended) /* escape handling */
1577 if (c == 0x1b) /* esc? */
1579 extended = 1; /* flag and spin */
1583 break; /* nope, drop through */
1585 case 1: /* there was an escape prefix */
1586 if (c == '[' || c == 'O') /* second character in sequence */
1592 return(KEY_EXIT); /* double esc exits */
1594 break; /* nup, not a sequence. */
1598 switch(c) /* looks like the real McCoy */
1601 VetRet(KEY_UP); /* leave if OK */
1604 VetRet(KEY_DOWN); /* leave if OK */
1607 VetRet(KEY_RIGHT); /* leave if OK */
1610 VetRet(KEY_LEFT); /* leave if OK */
1620 case '\t': /* trying to tab off */
1621 VetRet(KEY_TAB); /* verify and maybe return */
1631 case '\177': /* BS or DEL */
1632 if (ro) /* readonly? */
1634 puthelp(" !iThis value cannot be edited (Press ESC)");
1635 while(kgetchar() != 0x1b); /* wait for key */
1636 return(KEY_NULL); /* spin */
1638 if (xp) /* still something left to delete */
1640 i = (hex ? i/0x10u : i/10); /* strip last digit */
1641 delta = 1; /* force update */
1664 if (ro) /* readonly? */
1666 puthelp(" !iThis value cannot be edited (Press ESC)");
1667 while(kgetchar() != 0x1b); /* wait for key */
1668 return(KEY_NULL); /* spin */
1670 if (xp >= width) /* no room for more characters anyway */
1674 if ((c >= '0') && (c <= '9'))
1676 i = i*0x10 + (c-'0'); /* update value */
1680 if ((c >= 'a') && (c <= 'f'))
1682 i = i*0x10 + (c-'a'+0xa);
1686 if ((c >= 'A') && (c <= 'F'))
1688 i = i*0x10 + (c-'A'+0xa);
1693 if ((c >= '0') && (c <= '9'))
1695 i = i*10 + (c-'0'); /* update value */
1696 delta = 1; /* force redraw */
1709 ** Edit the parameters for (dev)
1711 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1712 ** possible for this to spin in an endless loop...
1713 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1714 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1715 ** +--------------------------------------------------------------------------------+
1716 ** 17-|--------------------------------------------------------------------------------|
1717 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1718 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1719 ** 20-| Flags : 0x0000 DRQ number : 00 |
1720 ** 21-|--------------------------------------------------------------------------------|
1722 ** The "intelligence" in this function that hops around based on the directional
1723 ** returns from editval isn't very smart, and depends on the layout above.
1726 editparams(DEV_LIST *dev)
1729 char buf[16]; /* needs to fit the device name */
1731 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1732 ksprintf(buf,"!b%s",dev->dev);
1739 if (dev->iobase > 0)
1741 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1742 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1762 puthelp(" Interrupt number (Decimal, 1-15)");
1763 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1775 if (dev->iobase > 0)
1786 puthelp(" Device-specific flag values.");
1787 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1801 if (dev->iobase > 0)
1821 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1822 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1829 if (dev->iobase > 0)
1851 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1852 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1881 puthelp(" Device DMA request number (Decimal, 1-7)");
1882 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1905 dev->changed = 1; /* mark as changed */
1908 static char *helptext[] =
1910 " Using the UserConfig kernel settings editor",
1911 " -------------------------------------------",
1917 "The screen displays a list of available drivers, divided into two",
1918 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1919 "by default collapsed and can be expanded to show all the drivers",
1920 "available in each category. The parameters for the currently selected",
1921 "driver are shown at the bottom of the screen.",
1923 "- - Moving around -",
1925 "To move in the current list, use the UP and DOWN cursor keys to select",
1926 "an item (the selected item will be highlighted). If the item is a",
1927 "category name, you may alternatively expand or collapse the list of",
1928 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1929 "expanded, you can select each driver in the same manner and either:",
1931 " - change its parameters using [!bENTER!n]",
1932 " - move it to the Inactive list using [!bDEL!n]",
1934 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1935 "you need to move a driver from the Inactive list back to the Active",
1936 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1937 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1938 "its place in the Active list.",
1940 "- - Altering the list/parameters -",
1942 "Any drivers for devices not installed in your system should be moved",
1943 "to the Inactive list, until there are no remaining parameter conflicts",
1944 "between the drivers, as indicated at the top.",
1946 "Once the list of Active drivers only contains entries for the devices",
1947 "present in your system, you can set their parameters (Interrupt, DMA",
1948 "channel, I/O addresses). To do this, select the driver and press",
1949 "[!bENTER!n]: it is now possible to edit the settings at the",
1950 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1951 "finished, use [!bQ!n] to return to the list.",
1953 "- - Saving changes -",
1955 "When all settings seem correct, and you wish to proceed with the",
1956 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1957 "confirm your choice.",
1966 ** Displays help text onscreen for people that are confused, using a simple
1972 int topline = 0; /* where we are in the text */
1973 int line = 0; /* last line we displayed */
1977 for (;;) /* loop until user quits */
1979 /* display help text */
1982 clear(); /* remove everything else */
1983 for (line = topline;
1984 (line < (topline + 24)) && (helptext[line]);
1986 putxy(0,line-topline,helptext[line]);
1991 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1994 c = kgetchar(); /* so what do they say? */
2001 case 'B': /* wired into 'more' users' fingers */
2002 if (topline > 0) /* room to go up? */
2005 if (topline < 0) /* don't go too far */
2013 case ' ': /* expected by most people */
2014 if (helptext[line]) /* maybe more below? */
2023 redraw(); /* restore the screen */
2031 ** High-level control functions
2038 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2039 ** (num) lines, starting at (*ofs) offset from row onscreen.
2040 ** Pass (detail) on to drawing routines.
2042 ** If the user hits a key other than a cursor key, maybe return a code.
2044 ** (*list) points to the device at the top line in the region, (*ofs) is the
2045 ** position of the highlight within the region. All routines below
2046 ** this take only a device and an absolute row : use ofsent() to find the
2047 ** device, and add (*ofs) to (row) to find the absolute row.
2050 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2061 showparams(ofsent(*ofs,*list)); /* show device parameters */
2062 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2066 c = kgetchar(); /* get a character */
2067 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2069 extended = 0; /* no longer */
2072 case 588: /* syscons' idea of 'up' */
2074 if (*ofs) /* just a move onscreen */
2076 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2077 (*ofs)--; /* move up */
2079 lp = prevent(*list); /* can we go up? */
2082 *list = lp; /* yes, move up list */
2083 drawlist(row,num,detail,*list);
2088 case 596: /* dooby-do */
2089 case 'B': /* down */
2090 lp = ofsent(*ofs,*list); /* get current item */
2092 break; /* nothing more to move to */
2093 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2094 if (*ofs < (num-1)) /* room to move onscreen? */
2098 *list = nextent(*list); /* scroll region down */
2099 drawlist(row,num,detail,*list);
2111 case '[': /* cheat : always preceeds cursor move */
2112 case 'O': /* ANSI application key mode */
2121 return(KEY_EXIT); /* user requests exit */
2125 return(KEY_DO); /* "do" something */
2130 return(KEY_DEL); /* "delete" response */
2134 return(KEY_UNZOOM); /* expand everything */
2138 return(KEY_ZOOM); /* collapse everything */
2141 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2142 return(KEY_TAB); /* "move" response */
2144 case '\014': /* ^L, redraw */
2147 case '?': /* helptext */
2159 ** Do the fullscreen config thang
2164 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2168 initlist(&inactive);
2174 conflicts = findconflict(active); /* find conflicts in the active list only */
2182 case 0: /* active devices */
2183 ret = dolist(1,8,1,&actofs,&alist,
2184 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2188 mode = 1; /* swap lists */
2205 collapselist(active);
2210 dp = ofsent(actofs,alist); /* get current device */
2211 if (dp) /* paranoia... */
2213 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2215 if (dp == alist) /* moving top item on list? */
2219 alist = dp->next; /* point list to non-moving item */
2221 alist = dp->prev; /* end of list, go back instead */
2224 if (!dp->next) /* moving last item on list? */
2227 dp->conflicts = 0; /* no conflicts on the inactive list */
2228 movedev(dp,inactive); /* shift to inactive list */
2229 conflicts = findconflict(active); /* update conflict tags */
2231 redrawactive(); /* redraw */
2236 case KEY_DO: /* edit device parameters */
2237 dp = ofsent(actofs,alist); /* get current device */
2238 if (dp) /* paranoia... */
2240 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2242 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2244 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2246 conflicts = findconflict(active); /* update conflict tags */
2247 }else{ /* DO on comment = zoom */
2248 switch(dp->comment) /* Depends on current state */
2250 case DEV_COMMENT: /* not currently zoomed */
2251 dp->comment = DEV_ZOOMED;
2255 dp->comment = DEV_COMMENT;
2265 case 1: /* inactive devices */
2266 ret = dolist(10,7,0,&inactofs,&ilist,
2267 " [!bEnter!n] Enable device ");
2281 expandlist(inactive);
2288 collapselist(inactive);
2293 dp = ofsent(inactofs,ilist); /* get current device */
2294 if (dp) /* paranoia... */
2296 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2298 if (dp == ilist) /* moving top of list? */
2302 ilist = dp->next; /* point list to non-moving item */
2304 ilist = dp->prev; /* can't go down, go up instead */
2307 if (!dp->next) /* last entry on list? */
2308 inactofs--; /* shift cursor up one */
2311 movedev(dp,active); /* shift to active list */
2312 conflicts = findconflict(active); /* update conflict tags */
2314 alist = dp; /* put at top and current */
2316 while(dp->comment == DEV_DEVICE)
2317 dp = dp->prev; /* forcibly unzoom section */
2318 dp ->comment = DEV_COMMENT;
2319 mode = 0; /* and swap modes to follow it */
2321 }else{ /* DO on comment = zoom */
2322 switch(dp->comment) /* Depends on current state */
2324 case DEV_COMMENT: /* not currently zoomed */
2325 dp->comment = DEV_ZOOMED;
2329 dp->comment = DEV_COMMENT;
2333 redrawactive(); /* redraw */
2338 default: /* nothing else relevant here */
2343 mode = 0; /* shouldn't happen... */
2346 /* handle returns that are the same for both modes */
2353 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2356 case 2: /* cancel */
2360 case 1: /* save and exit */
2362 savelist(inactive,0);
2365 nukelist(active); /* clean up after ourselves */
2375 #endif /* VISUAL_USERCONFIG */
2378 * Copyright (c) 1991 Regents of the University of California.
2379 * All rights reserved.
2380 * Copyright (c) 1994 Jordan K. Hubbard
2381 * All rights reserved.
2382 * Copyright (c) 1994 David Greenman
2383 * All rights reserved.
2385 * Many additional changes by Bruce Evans
2387 * This code is derived from software contributed by the
2388 * University of California Berkeley, Jordan K. Hubbard,
2389 * David Greenman and Bruce Evans.
2391 * Redistribution and use in source and binary forms, with or without
2392 * modification, are permitted provided that the following conditions
2394 * 1. Redistributions of source code must retain the above copyright
2395 * notice, this list of conditions and the following disclaimer.
2396 * 2. Redistributions in binary form must reproduce the above copyright
2397 * notice, this list of conditions and the following disclaimer in the
2398 * documentation and/or other materials provided with the distribution.
2399 * 3. All advertising materials mentioning features or use of this software
2400 * must display the following acknowledgement:
2401 * This product includes software developed by the University of
2402 * California, Berkeley and its contributors.
2403 * 4. Neither the name of the University nor the names of its contributors
2404 * may be used to endorse or promote products derived from this software
2405 * without specific prior written permission.
2407 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2408 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2409 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2410 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2411 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2412 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2413 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2414 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2415 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2416 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2419 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2422 #include "use_scbus.h"
2424 #define PARM_DEVSPEC 0x1
2425 #define PARM_INT 0x2
2426 #define PARM_ADDR 0x3
2427 #define PARM_STRING 0x4
2429 typedef struct _cmdparm {
2432 struct uc_device *dparm;
2441 typedef int (*CmdFunc)(CmdParm *);
2443 typedef struct _cmd {
2451 static void lsscsi(void);
2452 static int list_scsi(CmdParm *);
2455 static int lsdevtab(struct uc_device *);
2456 static struct uc_device *find_device(char *, int);
2457 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2458 static void cngets(char *, int);
2459 static Cmd *parse_cmd(char *);
2460 static int parse_args(const char *, CmdParm *);
2461 static int save_dev(struct uc_device *);
2463 static int list_devices(CmdParm *);
2464 static int set_device_ioaddr(CmdParm *);
2465 static int set_device_irq(CmdParm *);
2466 static int set_device_drq(CmdParm *);
2467 static int set_device_iosize(CmdParm *);
2468 static int set_device_mem(CmdParm *);
2469 static int set_device_flags(CmdParm *);
2470 static int set_device_enable(CmdParm *);
2471 static int set_device_disable(CmdParm *);
2472 static int quitfunc(CmdParm *);
2473 static int helpfunc(CmdParm *);
2474 static int introfunc(CmdParm *);
2477 static int lspnp(void);
2478 static int set_pnp_parms(CmdParm *);
2483 #include "use_eisa.h"
2487 #include <bus/eisa/eisaconf.h>
2489 static int set_num_eisa_slots(CmdParm *);
2491 #endif /* NEISA > 0 */
2493 static CmdParm addr_parms[] = {
2494 { PARM_DEVSPEC, {} },
2499 static CmdParm int_parms[] = {
2500 { PARM_DEVSPEC, {} },
2505 static CmdParm dev_parms[] = {
2506 { PARM_DEVSPEC, {} },
2511 static CmdParm string_arg[] = {
2512 { PARM_STRING, {} },
2518 static CmdParm int_arg[] = {
2522 #endif /* NEISA > 0 */
2524 static Cmd CmdList[] = {
2525 { "?", helpfunc, NULL }, /* ? (help) */
2526 { "di", set_device_disable, dev_parms }, /* disable dev */
2527 { "dr", set_device_drq, int_parms }, /* drq dev # */
2529 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2530 #endif /* NEISA > 0 */
2531 { "en", set_device_enable, dev_parms }, /* enable dev */
2532 { "ex", quitfunc, NULL }, /* exit (quit) */
2533 { "f", set_device_flags, int_parms }, /* flags dev mask */
2534 { "h", helpfunc, NULL }, /* help */
2535 { "intro", introfunc, NULL }, /* intro screen */
2536 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2537 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2538 { "ir", set_device_irq, int_parms }, /* irq dev # */
2539 { "l", list_devices, NULL }, /* ls, list */
2541 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2543 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2544 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2545 { "q", quitfunc, NULL }, /* quit */
2547 { "s", list_scsi, NULL }, /* scsi */
2549 #ifdef VISUAL_USERCONFIG
2550 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2552 { NULL, NULL, NULL },
2558 static char banner = 1;
2564 init_config_script();
2567 /* Only display signon banner if we are about to go interactive */
2568 if (!has_config_script()) {
2569 if (!(boothowto & RB_CONFIG))
2570 #ifdef INTRO_USERCONFIG
2577 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2578 " Type \"help\" for help"
2579 #ifdef VISUAL_USERCONFIG
2580 " or \"visual\" to go to the visual\n"
2581 " configuration interface (requires MGA/VGA display or\n"
2582 " serial terminal capable of displaying ANSI graphics)"
2588 kprintf("config> ");
2590 if (input[0] == '\0')
2592 cmd = parse_cmd(input);
2594 kprintf("Invalid command or syntax. Type `?' for help.\n");
2597 rval = (*cmd->handler)(cmd->parms);
2606 parse_cmd(char *cmd)
2610 for (cp = CmdList; cp->name; cp++) {
2611 int len = strlen(cp->name);
2613 if (!strncmp(cp->name, cmd, len)) {
2614 while (*cmd && *cmd != ' ' && *cmd != '\t')
2616 if (parse_args(cmd, cp->parms))
2626 parse_args(const char *cmd, CmdParm *parms)
2631 if (*cmd == ' ' || *cmd == '\t') {
2635 if (parms == NULL || parms->type == -1) {
2638 kprintf("Extra arg(s): %s\n", cmd);
2641 if (parms->type == PARM_DEVSPEC) {
2646 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2647 (*cmd >= '0' && *cmd <= '9')))
2648 devname[i++] = *(cmd++);
2650 if (*cmd >= '0' && *cmd <= '9') {
2651 unit = strtoul(cmd, &ptr, 10);
2653 kprintf("Invalid device number\n");
2654 /* XXX should print invalid token here and elsewhere. */
2657 /* XXX else should require end of token. */
2660 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2661 kprintf("No such device: %s%d\n", devname, unit);
2667 if (parms->type == PARM_INT) {
2668 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2670 kprintf("Invalid numeric argument\n");
2677 if (parms->type == PARM_ADDR) {
2678 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2680 kprintf("Invalid address argument\n");
2687 if (parms->type == PARM_STRING) {
2688 parms->parm.u.sparm = cmd;
2696 list_devices(CmdParm *parms)
2699 if (lsdevtab(uc_devtab)) return 0;
2701 if (lspnp()) return 0;
2704 kprintf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2705 #endif /* NEISA > 0 */
2710 set_device_ioaddr(CmdParm *parms)
2712 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2713 save_dev(parms[0].parm.dparm);
2718 set_device_irq(CmdParm *parms)
2722 irq = parms[1].parm.iparm;
2724 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2727 else if (irq != -1 && irq > 15) {
2728 kprintf("An IRQ > 15 would be invalid.\n");
2731 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2732 save_dev(parms[0].parm.dparm);
2737 set_device_drq(CmdParm *parms)
2742 * The bounds checking is just to ensure that the value can be printed
2743 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2745 drq = parms[1].parm.iparm;
2746 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2747 save_dev(parms[0].parm.dparm);
2752 set_device_iosize(CmdParm *parms)
2754 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2755 save_dev(parms[0].parm.dparm);
2760 set_device_mem(CmdParm *parms)
2762 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2763 save_dev(parms[0].parm.dparm);
2768 set_device_flags(CmdParm *parms)
2770 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2771 save_dev(parms[0].parm.dparm);
2776 set_device_enable(CmdParm *parms)
2778 parms[0].parm.dparm->id_enabled = TRUE;
2779 save_dev(parms[0].parm.dparm);
2784 set_device_disable(CmdParm *parms)
2786 parms[0].parm.dparm->id_enabled = FALSE;
2787 save_dev(parms[0].parm.dparm);
2794 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2800 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2803 * Output the pnp_ldn_overrides[] table.
2805 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2806 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2807 if(error) return(error);
2812 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2813 0, 0, sysctl_machdep_uc_pnplist, "A",
2814 "List of PnP overrides changed in UserConfig");
2817 * this function sets the kernel table to override bios PnP
2821 set_pnp_parms(CmdParm *parms)
2823 u_long idx, val, ldn, csn;
2826 const char *p = parms[0].parm.u.sparm;
2829 csn=strtoul(p,&q, 0);
2830 ldn=strtoul(q,&q, 0);
2831 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2832 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2833 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2836 for (i=0; i < MAX_PNP_LDN; i++) {
2837 if (pnp_ldn_overrides[i].csn == csn &&
2838 pnp_ldn_overrides[i].ldn == ldn)
2841 if (i==MAX_PNP_LDN) {
2842 for (i=0; i < MAX_PNP_LDN; i++) {
2843 if (pnp_ldn_overrides[i].csn <1 ||
2844 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2848 if (i==MAX_PNP_LDN) {
2849 kprintf("sorry, no PnP entries available, try delete one\n");
2852 d = pnp_ldn_overrides[i] ;
2858 if (!strncmp(p,"irq",3)) {
2859 idx=strtoul(p+3,&q, 0);
2860 val=strtoul(q,&q, 0);
2861 if (idx >=0 && idx < 2) d.irq[idx] = val;
2862 } else if (!strncmp(p,"flags",5)) {
2863 idx=strtoul(p+5,&q, 0);
2865 } else if (!strncmp(p,"drq",3)) {
2866 idx=strtoul(p+3,&q, 0);
2867 val=strtoul(q,&q, 0);
2868 if (idx >=0 && idx < 2) d.drq[idx] = val;
2869 } else if (!strncmp(p,"port",4)) {
2870 idx=strtoul(p+4,&q, 0);
2871 val=strtoul(q,&q, 0);
2872 if (idx >=0 && idx < 8) d.port[idx] = val;
2873 } else if (!strncmp(p,"mem",3)) {
2874 idx=strtoul(p+3,&q, 0);
2875 val=strtoul(q,&q, 0);
2876 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2877 } else if (!strncmp(p,"bios",4)) {
2880 } else if (!strncmp(p,"os",2)) {
2883 } else if (!strncmp(p,"disable",7)) {
2886 } else if (!strncmp(p,"enable",6)) {
2889 } else if (!strncmp(p,"delete",6)) {
2890 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2891 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2894 kprintf("unknown command <%s>\n", p);
2897 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2899 pnp_ldn_overrides[i] = d ;
2906 set_num_eisa_slots(CmdParm *parms)
2910 num_slots = parms[0].parm.iparm;
2911 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
2914 #endif /* NEISA > 0 */
2917 quitfunc(CmdParm *parms)
2920 * If kernel config supplied, and we are parsing it, and -c also supplied,
2921 * ignore a quit command, This provides a safety mechanism to allow
2922 * recovery from a damaged/buggy kernel config.
2924 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2930 helpfunc(CmdParm *parms)
2933 "Command\t\t\tDescription\n"
2934 "-------\t\t\t-----------\n"
2935 "ls\t\t\tList currently configured devices\n"
2936 "port <devname> <addr>\tSet device port (i/o address)\n"
2937 "irq <devname> <number>\tSet device irq\n"
2938 "drq <devname> <number>\tSet device drq\n"
2939 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2940 "iosize <devname> <size>\tSet device memory size\n"
2941 "flags <devname> <mask>\tSet device flags\n"
2942 "enable <devname>\tEnable device\n"
2943 "disable <devname>\tDisable device (will not be probed)\n");
2946 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2947 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2948 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2949 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2950 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2951 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2954 kprintf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2955 #endif /* NEISA > 0 */
2957 "quit\t\t\tExit this configuration utility\n"
2958 "reset\t\t\tReset CPU\n");
2959 #ifdef VISUAL_USERCONFIG
2960 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2963 "help\t\t\tThis message\n\n"
2964 "Commands may be abbreviated to a unique prefix\n");
2968 #if defined (VISUAL_USERCONFIG)
2970 center(int y, char *str)
2972 putxy((80 - strlen(str)) / 2, y, str);
2977 introfunc(CmdParm *parms)
2979 #if defined (VISUAL_USERCONFIG)
2980 int curr_item, first_time, extended = 0;
2981 static char *choices[] = {
2982 " Skip kernel configuration and continue with installation ",
2983 " Start kernel configuration in full-screen visual mode ",
2984 " Start kernel configuration in CLI mode ",
2988 center(2, "!bKernel Configuration Menu!n");
2997 for (i = 0; i < 3; i++) {
3001 strcat(tmp, choices[i]);
3004 putxy(10, 5 + i, tmp);
3008 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3009 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3010 putxy(2, 12, "match your hardware configuration.");
3011 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3012 putxy(2, 15, "(press Down-Arrow then ENTER).");
3013 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3014 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3015 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3016 putxy(2, 21, "then simply press ENTER or Q now.");
3020 move(0, 0); /* move the cursor out of the way */
3023 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3024 extended = 0; /* no longer */
3033 case 'B': /* down */
3045 case '[': /* cheat : always preceeds cursor move */
3046 case 'O': /* ANSI application key mode */
3057 return 1; /* user requests exit */
3059 case '1': /* select an item */
3083 case 'D': /* down */
3096 else if (curr_item == 1)
3097 return visuserconfig();
3099 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3100 /* enable quitfunc */
3101 userconfig_boot_parsing=0;
3103 boothowto |= RB_CONFIG; /* force -c */
3117 struct pnp_cinfo *c;
3121 for (i=0; i< MAX_PNP_LDN; i++) {
3122 c = &pnp_ldn_overrides[i];
3123 if (c->csn >0 && c->csn != 255) {
3125 static char pfmt[] =
3126 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3127 static char mfmt[] =
3128 "mem 0x%x 0x%x 0x%x 0x%x";
3131 if (!userconfig_boot_parsing) {
3133 if (kgetchar() == 'q') {
3141 if (lineno == 0 || first)
3142 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3144 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3146 c->override ? "OS ":"BIOS",
3147 c->enable ? "Y":"N",
3148 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3150 kprintf("flags 0x%08lx ",c->flags);
3151 for (pmax = 7; pmax >=0 ; pmax--)
3152 if (c->port[pmax]!=0) break;
3153 for (mmax = 3; mmax >=0 ; mmax--)
3154 if (c->mem[mmax].base!=0) break;
3157 buf[10 + 5*pmax]='\0';
3159 c->port[0], c->port[1], c->port[2], c->port[3],
3160 c->port[4], c->port[5], c->port[6], c->port[7]);
3164 buf[8 + 5*mmax]='\0';
3166 c->mem[0].base, c->mem[1].base,
3167 c->mem[2].base, c->mem[3].base);
3177 lsdevtab(struct uc_device *dt)
3179 for (; dt->id_id != 0; dt++) {
3184 if (!userconfig_boot_parsing) {
3185 if (kgetchar() == 'q') {
3195 "Device port irq drq iomem iosize unit flags enab\n"
3199 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3200 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3201 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3202 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3203 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3204 dt->id_enabled ? "Yes" : "No");
3214 int count = resource_count();
3220 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3223 for (i = 0; i < count; i++) {
3224 name = resource_query_name(i);
3225 unit = resource_query_unit(i);
3227 continue; /* skip wildcards */
3228 uc_devtab[dt].id_id = id++;
3229 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3231 resource_int_value(name, unit, "irq", &val);
3232 uc_devtab[dt].id_irq = (1 << val);
3233 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3234 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3235 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3236 uc_devtab[dt].id_unit = unit;
3237 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3239 resource_int_value(name, unit, "disabled", &val);
3240 uc_devtab[dt].id_enabled = !val;
3241 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3242 strcpy(uc_devtab[dt].id_name, name);
3251 int count = resource_count();
3253 for (i = 0; i < count; i++)
3254 if (uc_devtab[i].id_name)
3255 kfree(uc_devtab[i].id_name, M_DEVL);
3256 kfree(uc_devtab, M_DEVL);
3259 static struct uc_device *
3260 find_device(char *devname, int unit)
3262 struct uc_device *ret;
3264 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3269 static struct uc_device *
3270 search_devtable(struct uc_device *dt, char *devname, int unit)
3274 for (i = 0; dt->id_id != 0; dt++)
3275 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3281 cngets(char *input, int maxin)
3287 /* Treat ^H or ^? as backspace */
3288 if ((c == '\010' || c == '\177')) {
3290 kprintf("\010 \010");
3291 *--input = '\0', --nchars;
3295 /* Treat ^U or ^X as kill line */
3296 else if ((c == '\025' || c == '\030')) {
3298 kprintf("\010 \010");
3299 *--input = '\0', --nchars;
3304 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3308 *input++ = (u_char)c;
3314 /* scsi: Support for displaying configured SCSI devices.
3315 * There is no way to edit them, and this is inconsistent
3316 * with the ISA method. This is here as a basis for further work.
3319 type_text(char *name) /* XXX: This is bogus */
3321 if (strcmp(name, "sd") == 0)
3324 if (strcmp(name, "st") == 0)
3330 id_put(char *desc, int id)
3332 if (id != SCCONF_UNSPEC)
3335 kprintf("%s", desc);
3337 if (id == SCCONF_ANY)
3349 kprintf("scsi: (can't be edited):\n");
3351 for (i = 0; scsi_cinit[i].driver; i++)
3353 id_put("controller scbus", scsi_cinit[i].scbus);
3355 if (scsi_cinit[i].unit != -1)
3358 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3364 for (i = 0; scsi_dinit[i].name; i++)
3366 kprintf("%s ", type_text(scsi_dinit[i].name));
3368 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3369 id_put(" at scbus", scsi_dinit[i].cunit);
3370 id_put(" target ", scsi_dinit[i].target);
3371 id_put(" lun ", scsi_dinit[i].lun);
3373 if (scsi_dinit[i].flags)
3374 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3381 list_scsi(CmdParm *parms)
3390 save_resource(struct uc_device *idev)
3395 name = idev->id_name;
3396 unit = idev->id_unit;
3397 resource_set_int(name, unit, "port", idev->id_iobase);
3398 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3399 resource_set_int(name, unit, "drq", idev->id_drq);
3400 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3401 resource_set_int(name, unit, "msize", idev->id_msize);
3402 resource_set_int(name, unit, "flags", idev->id_flags);
3403 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3407 save_dev(struct uc_device *idev)
3409 struct uc_device *id_p,*id_pn;
3410 char *name = idev->id_name;
3412 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3413 if (id_p->id_id == idev->id_id) {
3414 id_pn = id_p->id_next;
3416 kfree(id_p->id_name, M_DEVL);
3417 bcopy(idev,id_p,sizeof(struct uc_device));
3418 save_resource(idev);
3419 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3420 strcpy(id_p->id_name, name);
3421 id_p->id_next = id_pn;
3425 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3426 bcopy(idev,id_pn,sizeof(struct uc_device));
3427 save_resource(idev);
3428 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3429 strcpy(id_pn->id_name, name);
3430 id_pn->id_next = uc_devlist;