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 ** $Id: userconfig.c,v 1.85 1999/07/26 12:14:59 kato Exp $
55 ** Kernel boot-time configuration manipulation tool for FreeBSD.
57 ** Two modes of operation are supported : the default is the line-editor mode,
58 ** the command "visual" invokes the fullscreen mode.
60 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
61 ** fullscreen mode requires syscons or a minimal-ansi serial console.
65 ** USERCONFIG, visual mode.
69 ** Look for "EDIT THIS LIST" to add to the list of known devices
72 ** There are a number of assumptions made in this code.
74 ** - That the console supports a minimal set of ANSI escape sequences
75 ** (See the screen manipulation section for a summary)
76 ** and has at least 24 rows.
77 ** - That values less than or equal to zero for any of the device
78 ** parameters indicate that the driver does not use the parameter.
79 ** - That the only tunable parameter for PCI devices are their flags.
80 ** - That flags are _always_ editable.
82 ** Devices marked as disabled are imported as such. PCI devices are
83 ** listed under a seperate heading for informational purposes only.
84 ** To date, there is no means for changing the behaviour of PCI drivers
87 ** Note that some EISA devices probably fall into this category as well,
88 ** and in fact the actual bus supported by some drivers is less than clear.
89 ** A longer-term goal might be to list drivers by instance rather than
92 ** For this tool to be useful, the list of devices below _MUST_ be updated
93 ** when a new driver is brought into the kernel. It is not possible to
94 ** extract this information from the drivers in the kernel.
98 ** - Display _what_ a device conflicts with.
99 ** - Implement page up/down (as what?)
100 ** - Wizard mode (no restrictions)
101 ** - Find out how to put syscons back into low-intensity mode so that the
102 ** !b escape is useful on the console. (It seems to be that it actually
103 ** gets low/high intensity backwards. That looks OK.)
105 ** - Only display headings with devices under them. (difficult)
109 * PC-9801 port by KATO Takenori <kato@eclogite.eps.nagoya-u.ac.jp>
112 #include "opt_userconfig.h"
115 #include <sys/param.h>
116 #include <sys/systm.h>
117 #include <sys/kernel.h>
118 #include <sys/malloc.h>
119 #include <sys/reboot.h>
120 #include <sys/linker.h>
121 #include <sys/sysctl.h>
123 #include <sys/cons.h>
125 #include <machine/md_var.h>
126 #include <machine/limits.h>
129 #include <i386/isa/isa_device.h>
133 #include <i386/isa/pnp.h>
137 #include <pci/pcivar.h>
140 static MALLOC_DEFINE(M_DEVL, "isa_devlist", "isa_device lists in userconfig()");
142 static struct isa_device *isa_devlist; /* list read by kget to extract changes */
143 static struct isa_device *isa_devtab; /* fake isa_device table */
144 static struct isa_driver *isa_drvtab; /* fake driver list */
146 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
148 #define putchar(x) cnputc(x)
150 static void load_devtab(void);
151 static void free_devtab(void);
152 static void save_resource(struct isa_device *);
155 sysctl_machdep_uc_devlist SYSCTL_HANDLER_ARGS
157 struct isa_device *id;
165 error+=sizeof(struct isa_device)+8;
168 return(SYSCTL_OUT(req,0,error));
170 /* Output the data. The buffer is filled with consecutive
171 * struct isa_device and char buf[8], containing the name
172 * (not guaranteed to end with '\0').
176 error=sysctl_handle_opaque(oidp,id,
177 sizeof(struct isa_device),req);
178 if(error) return(error);
179 strncpy(name,id->id_driver->name,8);
180 error=sysctl_handle_opaque(oidp,name,
182 if(error) return(error);
189 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
190 0, 0, sysctl_machdep_uc_devlist, "A",
191 "List of ISA devices changed in UserConfig");
194 ** Obtain command input.
196 ** Initially, input is read from a possibly-loaded script.
197 ** At the end of the script, or if no script is supplied,
198 ** behaviour is determined by the RB_CONFIG (-c) flag. If
199 ** the flag is set, user input is read from the console; if
200 ** unset, the 'quit' command is invoked and userconfig
203 ** Note that quit commands encountered in the script will be
204 ** ignored if the RB_CONFIG flag is supplied.
206 static const char *config_script;
207 static int config_script_size; /* use of int for -ve magic value */
209 #define has_config_script() (config_script_size > 0)
212 init_config_script(void)
214 caddr_t autoentry, autoattr;
216 /* Look for loaded userconfig script */
217 autoentry = preload_search_by_type("userconfig_script");
218 if (autoentry != NULL) {
219 /* We have one, get size and data */
220 config_script_size = 0;
221 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
222 config_script_size = (size_t)*(u_int32_t *)autoattr;
223 config_script = NULL;
224 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
225 config_script = *(const char **)autoattr;
227 if ((config_script_size == 0) || (config_script == NULL)) {
228 config_script_size = 0;
229 config_script = NULL;
232 return has_config_script();
239 #ifdef INTRO_USERCONFIG
240 static int intro = 0;
243 if (has_config_script())
245 /* Consume character from loaded userconfig script, display */
246 userconfig_boot_parsing = 1;
249 config_script_size--;
253 #ifdef INTRO_USERCONFIG
254 if (userconfig_boot_parsing) {
255 if (!(boothowto & RB_CONFIG)) {
256 /* userconfig_script, !RB_CONFIG -> quit */
259 config_script = "uit\n";
260 config_script_size = strlen(config_script);
261 /* userconfig_script will be 1 on the next pass */
264 /* userconfig_script, RB_CONFIG -> cngetc() */
267 if (!(boothowto & RB_CONFIG)) {
268 /* no userconfig_script, !RB_CONFIG -> show intro */
272 config_script = "ntro\n";
273 config_script_size = strlen(config_script);
274 /* userconfig_script will be 1 on the next pass */
277 /* no userconfig_script, RB_CONFIG -> cngetc() */
280 #else /* !INTRO_USERCONFIG */
281 /* assert(boothowto & RB_CONFIG) */
282 #endif /* INTRO_USERCONFIG */
283 userconfig_boot_parsing = 0;
292 #define TRUE (!FALSE)
295 #ifdef VISUAL_USERCONFIG
299 char dev[16]; /* device basename */
300 char name[60]; /* long name */
301 int attrib; /* things to do with the device */
302 int class; /* device classification */
305 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
306 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
307 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
308 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
309 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
310 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
311 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
312 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
313 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
315 #define CLS_STORAGE 1 /* storage devices */
316 #define CLS_NETWORK 2 /* network interfaces */
317 #define CLS_COMMS 3 /* serial, parallel ports */
318 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
319 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
320 #define CLS_PCI 254 /* PCI devices */
321 #define CLS_MISC 255 /* none of the above */
330 static DEVCLASS_INFO devclass_names[] = {
331 { "Storage : ", CLS_STORAGE},
332 { "Network : ", CLS_NETWORK},
333 { "Communications : ", CLS_COMMS},
334 { "Input : ", CLS_INPUT},
335 { "Multimedia : ", CLS_MMEDIA},
336 { "PCI : ", CLS_PCI},
337 { "Miscellaneous : ", CLS_MISC},
341 /********************* EDIT THIS LIST **********************/
345 ** - PCI devices should be marked FLG_IMMUTABLE. They should not be movable
346 ** or editable, and have no attributes. This is handled in getdevs() and
347 ** devinfo(), so drivers that have a presence on busses other than PCI
348 ** should have appropriate flags set below.
349 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
350 ** - XXX The list below should be reviewed by the driver authors to verify
351 ** that the correct flags have been set for each driver, and that the
352 ** descriptions are accurate.
355 static DEV_INFO device_info[] = {
356 /*---Name----- ---Description---------------------------------------------- */
358 {"bs", "PC-9801-55 SCSI Interface", 0, CLS_STORAGE},
360 {"isp", "QLogic ISP SCSI Controller", FLG_IMMUTABLE, CLS_STORAGE},
361 {"dpt", "DPT SCSI RAID Controller", FLG_IMMUTABLE, CLS_STORAGE},
362 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
363 {"adw", "AdvanSys SCSI WIDE controller", 0, CLS_STORAGE},
364 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE},
365 {"ahc", "Adaptec 274x/284x/294x SCSI controller", 0, CLS_STORAGE},
366 {"ahb", "Adaptec 174x SCSI controller", 0, CLS_STORAGE},
367 {"aha", "Adaptec 154x SCSI controller", 0, CLS_STORAGE},
368 {"uha", "Ultrastor 14F/24F/34F SCSI controller",0, CLS_STORAGE},
369 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE},
370 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
371 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
372 {"wds", "Western Digitial WD7000 SCSI controller", 0, CLS_STORAGE},
373 {"ncr", "NCR/Symbios 53C810/15/25/60/75 SCSI controller",FLG_FIXED,CLS_STORAGE},
374 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
375 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
376 {"mcd", "Mitsumi CD-ROM", 0, CLS_STORAGE},
377 {"scd", "Sony CD-ROM", 0, CLS_STORAGE},
378 {"matcd", "Matsushita/Panasonic/Creative CDROM", 0, CLS_STORAGE},
379 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE},
380 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
381 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
382 {"amd", "Tekram DC-390(T) / AMD 53c974 based PCI SCSI", FLG_FIXED, CLS_STORAGE},
384 {"plip", "Parallel Port IP link", FLG_FIXED, CLS_NETWORK},
385 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
387 {"ed", "NS8390 Ethernet adapters", 0, CLS_NETWORK},
389 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
391 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK},
392 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
393 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
394 {"fe", "Fujitsu MD86960A/MB869685A Ethernet adapters", 0, CLS_NETWORK},
395 {"fea", "DEC DEFEA EISA FDDI adapter", 0, CLS_NETWORK},
396 {"fxp", "Intel EtherExpress Pro/100B Ethernet adapter", 0, CLS_NETWORK},
397 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK},
398 {"ix", "Intel EtherExpress Ethernet adapter", 0, CLS_NETWORK},
399 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK},
400 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
401 {"sf", "Adaptec AIC-6915 PCI Ethernet adapters", 0,CLS_NETWORK},
402 {"sk", "SysKonnect SK-984x gigabit Ethernet adapters", 0,CLS_NETWORK},
403 {"ti", "Alteon Networks Tigon gigabit Ethernet adapters", 0,CLS_NETWORK},
404 {"tl", "Texas Instruments ThunderLAN Ethernet adapters", 0,CLS_NETWORK},
405 {"tx", "SMC 9432TX Ethernet adapters", 0, CLS_NETWORK},
406 {"vx", "3COM 3C590/3C595 Ethernet adapters", 0, CLS_NETWORK},
407 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
408 {"ze", "IBM/National Semiconductor PCMCIA Ethernet adapter",0, CLS_NETWORK},
409 {"zp", "3COM PCMCIA Etherlink III Ethernet adapter", 0, CLS_NETWORK},
410 {"al", "ADMtek AL981 ethernet adapter", FLG_FIXED, CLS_NETWORK},
411 {"ax", "ASIX AX88140A ethernet adapter", FLG_FIXED, CLS_NETWORK},
412 {"de", "DEC DC21040 Ethernet adapter", FLG_FIXED, CLS_NETWORK},
413 {"fpa", "DEC DEFPA PCI FDDI adapter", FLG_FIXED, CLS_NETWORK},
414 {"rl", "RealTek 8129/8139 ethernet adapter", FLG_FIXED, CLS_NETWORK},
415 {"mx", "Macronix PMAC ethernet adapter", FLG_FIXED, CLS_NETWORK},
416 {"pn", "Lite-On 82c168/82c169 PNIC adapter", FLG_FIXED, CLS_NETWORK},
417 {"tl", "Texas Instruments ThunderLAN ethernet adapter", FLG_FIXED, CLS_NETWORK},
418 {"vr", "VIA Rhine/Rhine II ethernet adapter", FLG_FIXED, CLS_NETWORK},
419 {"wb", "Winbond W89C840F ethernet adapter", FLG_FIXED, CLS_NETWORK},
420 {"xl", "3COM 3C90x PCI ethernet adapter", FLG_FIXED, CLS_NETWORK},
421 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK},
423 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
424 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
425 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS},
426 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
427 {"cyy", "Cyclades Ye/PCI multiport async adapter",FLG_INVISIBLE,CLS_COMMS},
428 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS},
429 {"si", "Specialix SI/XIO async adapter", 0, CLS_COMMS},
430 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
431 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
432 {"lpt", "Parallel printer port", 0, CLS_COMMS},
433 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
434 {"ppi", "Generic Parallel Port I/O device", FLG_FIXED, CLS_COMMS},
435 {"lpt", "Line Printer driver", FLG_FIXED, CLS_COMMS},
436 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS},
437 {"uhci", "UHCI USB host controller driver", FLG_IMMUTABLE, CLS_COMMS},
438 {"ohci", "OHCI USB host controller driver", FLG_IMMUTABLE, CLS_COMMS},
440 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
441 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
443 {"pckbd", "Keyboard", FLG_FIXED, CLS_INPUT},
445 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT},
446 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
447 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
448 {"vt", "PCVT console driver", FLG_IMMUTABLE, CLS_INPUT},
449 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
451 {"bktr", "Brooktree BT848 based frame grabber/tuner card", 0,CLS_MMEDIA},
452 {"pcm", "New Luigi audio driver for all supported sound cards", 0,CLS_MMEDIA},
453 {"sb", "Soundblaster PCM (SB, SBPro, SB16, ProAudio Spectrum)",0,CLS_MMEDIA},
454 {"sbxvi", "Soundblaster 16", 0, CLS_MMEDIA},
455 {"sbmidi", "Soundblaster MIDI interface", 0, CLS_MMEDIA},
456 {"awe", "AWE32 MIDI", 0, CLS_MMEDIA},
457 {"pas", "ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
458 {"gus", "Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
459 {"gusxvi", "Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
460 {"gusmax", "Gravis Ultrasound MAX", 0, CLS_MMEDIA},
461 {"mss", "Microsoft Sound System", 0, CLS_MMEDIA},
462 {"nss", "PC-9801-86 Sound Board", 0, CLS_MMEDIA},
463 {"opl", "OPL-2/3 FM, Soundblaster, SBPro, SB16, ProAudio Spectrum",0,CLS_MMEDIA},
464 {"mpu", "Roland MPU401 MIDI", 0, CLS_MMEDIA},
465 {"sscape", "Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
466 {"sscape_mss", "Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
467 {"uart", "6850 MIDI UART", 0, CLS_MMEDIA},
468 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
469 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA},
470 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA},
471 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
472 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA},
473 {"asc", "AmiScan scanner", 0, CLS_MMEDIA},
474 {"qcam", "QuickCam parallel port camera", 0, CLS_MMEDIA},
476 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
477 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC},
478 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
479 {"lkm", "Loadable PCI driver support", FLG_INVISIBLE, CLS_MISC},
480 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
481 {"chip", "PCI chipset support", FLG_INVISIBLE, CLS_MISC},
482 {"piix", "Intel 82371 Bus-master IDE controller", FLG_INVISIBLE, CLS_MISC},
483 {"ide_pci", "PCI IDE controller", FLG_INVISIBLE, CLS_MISC},
487 typedef struct _devlist_struct
490 int attrib; /* flag values as per the FLG_* defines above */
491 int class; /* disk, etc as per the CLS_* defines above */
493 int iobase,irq,drq,maddr,msize,unit,flags,conflict_ok,id;
494 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
495 int conflicts; /* set/reset by findconflict, count of conflicts */
496 int changed; /* nonzero if the device has been edited */
497 struct isa_device *device;
498 struct _devlist_struct *prev,*next;
503 #define DEV_COMMENT 1
506 #define LIST_CURRENT (1<<0)
507 #define LIST_SELECTED (1<<1)
509 #define KEY_EXIT 0 /* return codes from dolist() and friends */
515 #define KEY_UP 5 /* these only returned from editval() */
519 #define KEY_NULL 9 /* this allows us to spin & redraw */
521 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
522 #define KEY_UNZOOM 11
524 #define KEY_HELP 12 /* duh? */
526 static void redraw(void);
527 static void insdev(DEV_LIST *dev, DEV_LIST *list);
528 static int devinfo(DEV_LIST *dev);
529 static int visuserconfig(void);
531 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
532 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
533 static DEV_LIST scratch; /* scratch record */
534 static int conflicts; /* total conflict count */
537 static char lines[] = "--------------------------------------------------------------------------------";
538 static char spaces[] = " ";
542 ** Device manipulation stuff : find, describe, configure.
548 ** Sets the device referenced by (*dev) to the parameters in the struct,
549 ** and the enable flag according to (enabled)
552 setdev(DEV_LIST *dev, int enabled)
554 if (dev->iobase == -2) /* PCI device */
556 dev->device->id_iobase = dev->iobase; /* copy happy */
557 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
558 dev->device->id_drq = (short)dev->drq;
559 dev->device->id_maddr = (caddr_t)dev->maddr;
560 dev->device->id_msize = dev->msize;
561 dev->device->id_flags = dev->flags;
562 dev->device->id_enabled = enabled;
569 ** Walk the kernel device tables and build the active and inactive lists
575 struct isa_device *ap;
577 ap = isa_devtab; /* pointer to array of devices */
578 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
580 scratch.unit = ap[i].id_unit; /* device parameters */
581 strcpy(scratch.dev,ap[i].id_driver->name);
582 scratch.iobase = ap[i].id_iobase;
583 scratch.irq = ffs(ap[i].id_irq)-1;
584 scratch.drq = ap[i].id_drq;
585 scratch.maddr = (int)ap[i].id_maddr;
586 scratch.msize = ap[i].id_msize;
587 scratch.flags = ap[i].id_flags;
588 scratch.conflict_ok = ap[i].id_conflicts;
590 scratch.comment = DEV_DEVICE; /* admin stuff */
591 scratch.conflicts = 0;
592 scratch.device = &ap[i]; /* save pointer for later reference */
594 if (!devinfo(&scratch)) /* get more info on the device */
595 insdev(&scratch,ap[i].id_enabled?active:inactive);
598 for (i = 0; i < pcidevice_set.ls_length; i++)
600 if (pcidevice_set.ls_items[i])
602 if (((const struct pci_device *)pcidevice_set.ls_items[i])->pd_name)
604 strcpy(scratch.dev,((const struct pci_device *)pcidevice_set.ls_items[i])->pd_name);
605 scratch.iobase = -2; /* mark as PCI for future reference */
611 scratch.conflict_ok = 0; /* shouldn't conflict */
612 scratch.comment = DEV_DEVICE; /* is a device */
613 scratch.unit = 0; /* arbitrary number of them */
614 scratch.conflicts = 0;
615 scratch.device = NULL;
618 if (!devinfo(&scratch)) /* look up name, set class and flags */
619 insdev(&scratch,active); /* always active */
623 #endif /* NPCI > 0 */
630 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
631 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
633 ** If the device is marked "invisible", return nonzero; the caller should
634 ** not insert any such device into either list.
636 ** PCI devices are always inserted into CLS_PCI, regardless of the class associated
637 ** with the driver type.
640 devinfo(DEV_LIST *dev)
644 for (i = 0; device_info[i].class; i++)
646 if (!strcmp(dev->dev,device_info[i].dev))
648 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
650 strcpy(dev->name,device_info[i].name); /* get the name */
651 if (dev->iobase == -2) { /* is this a PCI device? */
652 dev->attrib = FLG_IMMUTABLE; /* dark green ones up the back... */
653 dev->class = CLS_PCI;
655 dev->attrib = device_info[i].attrib; /* light green ones up the front */
656 dev->class = device_info[i].class;
661 strcpy(dev->name,"Unknown device");
663 dev->class = CLS_MISC;
669 ** List manipulation stuff : add, move, initialise, free, traverse
671 ** Note that there are assumptions throughout this code that
672 ** the first entry in a list will never move. (assumed to be
680 ** appends a copy of (dev) to the end of (*list)
683 addev(DEV_LIST *dev, DEV_LIST **list)
688 lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
689 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
691 if (*list) /* list exists */
695 ap = ap->next; /* scoot to end of list */
699 }else{ /* list does not yet exist */
701 lp->prev = lp->next = NULL; /* list now exists */
709 ** Finds the 'appropriate' place for (dev) in (list)
711 ** 'Appropriate' means in numeric order with other devices of the same type,
712 ** or in alphabetic order following a comment of the appropriate type.
713 ** or at the end of the list if an appropriate comment is not found. (this should
715 ** (Note that the appropriate point is never the top, but may be the bottom)
718 findspot(DEV_LIST *dev, DEV_LIST *list)
722 /* search for a previous instance of the same device */
723 if (dev->iobase != -2) /* avoid PCI devices grouping with non-PCI devices */
725 for (ap = list; ap; ap = ap->next)
727 if (ap->comment != DEV_DEVICE) /* ignore comments */
729 if (ap->iobase == -2) /* don't group with a PCI device */
731 if (!strcmp(dev->dev,ap->dev)) /* same base device */
733 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
734 || !ap->next) /* or end of list */
736 ap = ap->prev; /* back up one */
737 break; /* done here */
739 if (ap->next) /* if the next item exists */
741 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
743 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
750 if (!ap) /* not sure yet */
752 /* search for a class that the device might belong to */
753 for (ap = list; ap; ap = ap->next)
755 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
757 if (dev->class != ap->class) /* of same class too 8) */
759 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
761 ap = ap->prev; /* back up one */
762 break; /* done here */
764 if (ap->next) /* if the next item exists */
765 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
770 if (!ap) /* didn't find a match */
772 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
773 if ((ap->comment != DEV_DEVICE)
774 && (ap->class == dev->class)) /* appropriate place? */
776 } /* or just put up with last */
785 ** Inserts a copy of (dev) at the appropriate point in (list)
788 insdev(DEV_LIST *dev, DEV_LIST *list)
792 lp = (DEV_LIST *)malloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
793 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
795 ap = findspot(lp,list); /* find appropriate spot */
796 lp->next = ap->next; /* point to next */
798 ap->next->prev = lp; /* point next to new */
799 lp->prev = ap; /* point new to current */
800 ap->next = lp; /* and current to new */
807 ** Moves (dev) from its current list to an appropriate place in (list)
808 ** (dev) may not come from the top of a list, but it may from the bottom.
811 movedev(DEV_LIST *dev, DEV_LIST *list)
815 ap = findspot(dev,list);
816 dev->prev->next = dev->next; /* remove from old list */
818 dev->next->prev = dev->prev;
820 dev->next = ap->next; /* insert in new list */
822 ap->next->prev = dev; /* point next to new */
823 dev->prev = ap; /* point new to current */
824 ap->next = dev; /* and current to new */
831 ** Initialises (*list) with the basic headings
834 initlist(DEV_LIST **list)
838 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
840 strcpy(scratch.name,devclass_names[i].name);
841 scratch.comment = DEV_ZOOMED;
842 scratch.class = devclass_names[i].number;
843 scratch.attrib = FLG_MANDATORY; /* can't be moved */
844 addev(&scratch,list); /* add to the list */
852 ** Walks (list) and saves the settings of any entry marked as changed.
854 ** The device's active field is set according to (active).
856 ** Builds the isa_devlist used by kget to extract the changed device information.
857 ** The code for this was taken almost verbatim from the original module.
860 savelist(DEV_LIST *list, int active)
862 struct isa_device *id_p,*id_pn;
863 struct isa_driver *isa_drv;
868 if ((list->comment == DEV_DEVICE) && /* is a device */
869 (list->changed) && /* has been changed */
870 (list->iobase != -2) && /* is not a PCI device */
871 (list->device != NULL)) { /* has an isa_device structure */
873 setdev(list,active); /* set the device itself */
876 for (id_p=isa_devlist; id_p; id_p=id_p->id_next)
877 { /* look on the list for it */
878 if (id_p->id_id == list->device->id_id)
880 name = list->device->id_driver->name;
881 id_pn = id_p->id_next;
882 isa_drv = id_p->id_driver;
883 if (isa_drv && isa_drv->name)
884 free(isa_drv->name, M_DEVL);
886 free(isa_drv, M_DEVL);
887 bcopy(list->device,id_p,sizeof(struct isa_device));
888 save_resource(list->device);
889 isa_drv = malloc(sizeof(struct isa_driver),M_DEVL,M_WAITOK);
890 isa_drv->name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
891 strcpy(isa_drv->name, name);
892 id_p->id_driver = isa_drv;
893 id_pn->id_next = isa_devlist;
894 id_p->id_next = id_pn;
898 if (!id_pn) /* not already on the list */
900 name = list->device->id_driver->name;
901 id_pn = malloc(sizeof(struct isa_device),M_DEVL,M_WAITOK);
902 bcopy(list->device,id_pn,sizeof(struct isa_device));
903 save_resource(list->device);
904 isa_drv = malloc(sizeof(struct isa_driver),M_DEVL, M_WAITOK);
905 isa_drv->name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
906 strcpy(isa_drv->name, name);
907 id_pn->id_driver = isa_drv;
908 id_pn->id_next = isa_devlist;
909 isa_devlist = id_pn; /* park at top of list */
920 ** Frees all storage in use by a (list).
923 nukelist(DEV_LIST *list)
929 while(list->prev) /* walk to head of list */
944 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
945 ** if there is no previous entry. (Only possible if list->prev == NULL given the
946 ** premise that there is always a comment at the head of the list)
949 prevent(DEV_LIST *list)
955 dp = list->prev; /* start back one */
958 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
959 return(dp); /* so skip to comment */
960 if (dp->comment == DEV_COMMENT) /* not zoomed */
961 return(list->prev); /* one back as normal */
962 dp = dp->prev; /* backpedal */
964 return(dp); /* NULL, we can assume */
971 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
972 ** if there is no next entry. (Possible if the current entry is last, or
973 ** if the current entry is the last heading and it's collapsed)
976 nextent(DEV_LIST *list)
982 if (list->comment != DEV_ZOOMED) /* no reason to skip */
987 if (dp->comment != DEV_DEVICE) /* found another heading */
991 return(dp); /* back we go */
998 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
1001 ofsent(int ofs, DEV_LIST *list)
1003 while (ofs-- && list)
1004 list = nextent(list);
1012 ** Scans every element of (list) and sets the conflict tags appropriately
1013 ** Returns the number of conflicts found.
1016 findconflict(DEV_LIST *list)
1018 int count = 0; /* number of conflicts found */
1021 for (dp = list; dp; dp = dp->next) /* over the whole list */
1023 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
1025 if (dp->iobase == -2) /* it's a PCI device, not interested */
1028 dp->conflicts = 0; /* assume the best */
1029 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
1031 if (sp->comment != DEV_DEVICE) /* likewise */
1033 if (dp->iobase == -2) /* it's a PCI device, not interested */
1036 if (sp == dp) /* always conflict with itself */
1038 if (sp->conflict_ok && dp->conflict_ok)
1039 continue; /* both allowed to conflict */
1041 if ((dp->iobase > 0) && /* iobase conflict? */
1042 (dp->iobase == sp->iobase))
1044 if ((dp->irq > 0) && /* irq conflict? */
1045 (dp->irq == sp->irq))
1047 if ((dp->drq > 0) && /* drq conflict? */
1048 (dp->drq == sp->drq))
1050 if ((sp->maddr > 0) && /* maddr/msize conflict? */
1052 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
1053 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
1056 count += dp->conflicts; /* count conflicts */
1065 ** Unzooms all headings in (list)
1068 expandlist(DEV_LIST *list)
1072 if (list->comment == DEV_COMMENT)
1073 list->comment = DEV_ZOOMED;
1082 ** Zooms all headings in (list)
1085 collapselist(DEV_LIST *list)
1089 if (list->comment == DEV_ZOOMED)
1090 list->comment = DEV_COMMENT;
1097 ** Screen-manipulation stuff
1099 ** This is the basic screen layout :
1101 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1102 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1103 ** +--------------------------------------------------------------------------------+
1104 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
1105 ** 1 -| ........................ ....... .. 0x....|
1106 ** 2 -| ........................ ....... .. 0x....|
1107 ** 3 -| ........................ ....... .. 0x....|
1108 ** 4 -| ........................ ....... .. 0x....|
1109 ** 5 -| ........................ ....... .. 0x....|
1110 ** 6 -| ........................ ....... .. 0x....|
1111 ** 7 -| ........................ ....... .. 0x....|
1112 ** 8 -| ........................ ....... .. 0x....|
1113 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
1114 ** 10-| ........................ ....... |
1115 ** 11-| ........................ ....... |
1116 ** 12-| ........................ ....... |
1117 ** 13-| ........................ ....... |
1118 ** 14-| ........................ ....... |
1119 ** 15-| ........................ ....... |
1120 ** 16-| ........................ ....... |
1121 ** 17-|------------------------------------------------------UP-DOWN-------------------|
1122 ** 18-| Relevant parameters for the current device |
1125 ** 21-|--------------------------------------------------------------------------------|
1126 ** 22-| Help texts go here |
1128 ** +--------------------------------------------------------------------------------+
1132 ** On a collapsed comment :
1134 ** [Enter] Expand device list [z] Expand all lists
1135 ** [TAB] Change fields [Q] Save and Exit
1137 ** On an expanded comment :
1139 ** [Enter] Collapse device list [Z] Collapse all lists
1140 ** [TAB] Change fields [Q] Save and Exit
1142 ** On a comment with no followers
1145 ** [TAB] Change fields [Q] Save and Exit
1147 ** On a device in the active list
1149 ** [Enter] Edit device parameters [DEL] Disable device
1150 ** [TAB] Change fields [Q] Save and Exit [?] Help
1152 ** On a device in the inactive list
1154 ** [Enter] Enable device
1155 ** [TAB] Change fields [Q] Save and Exit [?] Help
1157 ** While editing parameters
1159 ** <parameter-specific help here>
1160 ** [TAB] Change fields [Q] Save device parameters
1167 ** The base-level screen primitives :
1169 ** bold() - enter bold mode \E[1m (md)
1170 ** inverse() - enter inverse mode \E[7m (so)
1171 ** normal() - clear bold/inverse mode \E[m (se)
1172 ** clear() - clear the screen \E[H\E[J (ce)
1173 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1198 printf("\033[H\033[J");
1204 printf("\033[%d;%dH",y+1,x+1);
1210 ** High-level screen primitives :
1212 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1213 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1214 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1215 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1216 ** putmsg(str) - put (str) in the message area
1217 ** puthelp(str) - put (str) in the upper helpline
1218 ** pad(str,len) - pad (str) to (len) with spaces
1219 ** drawline(row,detail,list,inverse,*dhelp)
1220 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1221 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1222 ** draw the line in inverse video, and display (*dhelp) on the
1224 ** drawlist(row,num,detail,list)
1225 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1226 ** through to drawline().
1227 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1228 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1229 ** redraw(); - Redraws the entire screen layout, including the
1230 ** - two list panels.
1235 ** writes (str) at x,y onscreen
1237 ** writes up to (len) of (str) at x,y onscreen.
1239 ** Supports embedded formatting :
1240 ** !i - inverse mode.
1242 ** !n - normal mode.
1245 putxyl(int x, int y, char *str, int len)
1250 while((*str) && (len--))
1252 if (*str == '!') /* format escape? */
1254 switch(*(str+1)) /* depending on the next character */
1258 str +=2; /* skip formatting */
1259 len++; /* doesn't count for length */
1264 str +=2; /* skip formatting */
1265 len++; /* doesn't count for length */
1270 str +=2; /* skip formatting */
1271 len++; /* doesn't count for length */
1275 putchar(*str++); /* not an escape */
1278 putchar(*str++); /* emit the character */
1283 #define putxy(x,y,str) putxyl(x,y,str,-1)
1289 ** Erases the region (x,y,w,h)
1292 erase(int x, int y, int w, int h)
1297 for (i = 0; i < h; i++)
1298 putxyl(x,y++,spaces,w);
1305 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1306 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1309 txtbox(int x, int y, int w, int h, char *str)
1314 while((str[i]) && h)
1316 if (str[i] == '\n') /* newline */
1318 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1319 y++; /* move down */
1320 h--; /* room for one less */
1321 str += (i+1); /* skip first newline */
1322 i = 0; /* zero offset */
1324 i++; /* next character */
1327 if (h) /* end of string, not region */
1335 ** writes (msg) in the helptext area
1340 erase(0,18,80,3); /* clear area */
1341 txtbox(0,18,80,3,msg);
1348 ** Writes (msg) in the helpline area
1361 ** Draws the help message at the bottom of the screen
1364 masterhelp(char *msg)
1374 ** space-pads a (str) to (len) characters
1377 pad(char *str, int len)
1381 for (i = 0; str[i]; i++) /* find the end of the string */
1383 if (i >= len) /* no padding needed */
1385 while(i < len) /* pad */
1394 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1395 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1397 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1398 ** help is shown for normal or zoomed comments
1401 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1403 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1405 if (list->comment == DEV_DEVICE)
1408 strncpy(nb+1,list->name,57);
1410 strncpy(nb,list->name,58);
1411 if ((list->comment == DEV_ZOOMED) && (list->next))
1412 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1413 strcat(nb," (Collapsed)");
1417 if (list->conflicts) /* device in conflict? */
1421 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1423 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1426 if (list->comment == DEV_DEVICE)
1428 sprintf(db,"%s%d",list->dev,list->unit);
1433 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1435 sprintf(ib," %d",list->irq);
1440 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1442 sprintf(pb,"0x%x",list->iobase);
1448 sprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1450 putxyl(0,row,lbuf,80);
1453 switch(list->comment)
1455 case DEV_DEVICE: /* ordinary device */
1461 if (list->next->comment == DEV_DEVICE)
1462 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1467 if (list->next->comment == DEV_DEVICE)
1468 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1471 puthelp(" WARNING: This list entry corrupted!");
1475 move(0,row); /* put the cursor somewhere relevant */
1482 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1483 ** port and IRQ fields as well if (detail) is nonzero
1485 ** printf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1488 drawlist(int row, int num, int detail, DEV_LIST *list)
1492 for(ofs = 0; ofs < num; ofs++)
1496 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1497 list = nextent(list); /* move down visible list */
1499 erase(0,row+ofs,80,1);
1508 ** Redraws the active list
1517 sprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1520 putxyl(45,0,lines,16);
1522 drawlist(1,8,1,alist); /* draw device lists */
1528 ** Redraws the inactive list
1531 redrawinactive(void)
1533 drawlist(10,7,0,ilist); /* draw device lists */
1540 ** Clear the screen and redraw the entire layout
1547 putxy(3,0,"!bActive!n-!bDrivers");
1548 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1550 putxy(3,9,"!bInactive!n-!bDrivers");
1551 putxy(63,9,"!bDev");
1554 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1564 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1565 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1568 yesnocancel(char *str)
1594 ** Show device parameters in the region below the lists
1596 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1597 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1598 ** +--------------------------------------------------------------------------------+
1599 ** 17-|--------------------------------------------------------------------------------|
1600 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1601 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1602 ** 20-| Flags : 0x0000 DRQ number : 00 |
1603 ** 21-|--------------------------------------------------------------------------------|
1606 showparams(DEV_LIST *dev)
1610 erase(0,18,80,3); /* clear area */
1613 if (dev->comment != DEV_DEVICE)
1617 if (dev->iobase > 0)
1619 sprintf(buf,"Port address : 0x%x",dev->iobase);
1622 if (dev->iobase == -2) /* a PCI device */
1623 putmsg(" PCI devices are displayed for informational purposes only, and\n"
1624 " cannot be disabled or configured here.");
1629 sprintf(buf,"IRQ number : %d",dev->irq);
1632 sprintf(buf,"Flags : 0x%x",dev->flags);
1636 sprintf(buf,"Memory address : 0x%x",dev->maddr);
1641 sprintf(buf,"Memory size : 0x%x",dev->msize);
1647 sprintf(buf,"DRQ number : %d",dev->drq);
1650 if (dev->conflict_ok)
1651 putxy(54,18,"Conflict allowed");
1656 ** Editing functions for device parameters
1658 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1659 ** onscreen. Refuse values outsise (min) and (max).
1660 ** editparams(dev) - Edit the parameters for (dev)
1664 #define VetRet(code) \
1666 if ((i >= min) && (i <= max)) /* legit? */ \
1669 sprintf(buf,hex?"0x%x":"%d",i); \
1670 putxy(hex?x-2:x,y,buf); \
1671 return(code); /* all done and exit */ \
1673 i = *val; /* restore original value */ \
1674 delta = 1; /* restore other stuff */ \
1681 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1682 ** in a field (width) wide. (Allow one space)
1683 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1685 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1688 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1690 int i = *val; /* work with copy of the value */
1691 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1692 int xp = 0; /* cursor offset into text copy */
1693 int delta = 1; /* force redraw first time in */
1695 int extended = 0; /* stage counter for extended key sequences */
1697 if (hex) /* we presume there's a leading 0x onscreen */
1698 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1702 if (delta) /* only update if necessary */
1704 sprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1705 sprintf(buf,"!i%s",tc); /* format for printing */
1706 erase(x,y,width,1); /* clear the area */
1707 putxy(x,y,buf); /* write */
1708 xp = strlen(tc); /* cursor always at end */
1709 move(x+xp,y); /* position the cursor */
1714 switch(extended) /* escape handling */
1717 if (c == 0x1b) /* esc? */
1719 extended = 1; /* flag and spin */
1723 break; /* nope, drop through */
1725 case 1: /* there was an escape prefix */
1726 if (c == '[' || c == 'O') /* second character in sequence */
1732 return(KEY_EXIT); /* double esc exits */
1734 break; /* nup, not a sequence. */
1738 switch(c) /* looks like the real McCoy */
1741 VetRet(KEY_UP); /* leave if OK */
1744 VetRet(KEY_DOWN); /* leave if OK */
1747 VetRet(KEY_RIGHT); /* leave if OK */
1750 VetRet(KEY_LEFT); /* leave if OK */
1760 case '\t': /* trying to tab off */
1761 VetRet(KEY_TAB); /* verify and maybe return */
1771 case '\177': /* BS or DEL */
1772 if (ro) /* readonly? */
1774 puthelp(" !iThis value cannot be edited (Press ESC)");
1775 while(getchar() != 0x1b); /* wait for key */
1776 return(KEY_NULL); /* spin */
1778 if (xp) /* still something left to delete */
1780 i = (hex ? i/0x10u : i/10); /* strip last digit */
1781 delta = 1; /* force update */
1804 if (ro) /* readonly? */
1806 puthelp(" !iThis value cannot be edited (Press ESC)");
1807 while(getchar() != 0x1b); /* wait for key */
1808 return(KEY_NULL); /* spin */
1810 if (xp >= width) /* no room for more characters anyway */
1814 if ((c >= '0') && (c <= '9'))
1816 i = i*0x10 + (c-'0'); /* update value */
1820 if ((c >= 'a') && (c <= 'f'))
1822 i = i*0x10 + (c-'a'+0xa);
1826 if ((c >= 'A') && (c <= 'F'))
1828 i = i*0x10 + (c-'A'+0xa);
1833 if ((c >= '0') && (c <= '9'))
1835 i = i*10 + (c-'0'); /* update value */
1836 delta = 1; /* force redraw */
1849 ** Edit the parameters for (dev)
1851 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1852 ** possible for this to spin in an endless loop...
1853 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1854 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1855 ** +--------------------------------------------------------------------------------+
1856 ** 17-|--------------------------------------------------------------------------------|
1857 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1858 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1859 ** 20-| Flags : 0x0000 DRQ number : 00 |
1860 ** 21-|--------------------------------------------------------------------------------|
1862 ** The "intelligence" in this function that hops around based on the directional
1863 ** returns from editval isn't very smart, and depends on the layout above.
1866 editparams(DEV_LIST *dev)
1869 char buf[16]; /* needs to fit the device name */
1871 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1872 sprintf(buf,"!b%s",dev->dev);
1879 if (dev->iobase > 0)
1881 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1882 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1902 puthelp(" Interrupt number (Decimal, 1-15)");
1903 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1915 if (dev->iobase > 0)
1926 puthelp(" Device-specific flag values.");
1927 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1941 if (dev->iobase > 0)
1961 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1962 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1969 if (dev->iobase > 0)
1991 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1992 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
2021 puthelp(" Device DMA request number (Decimal, 1-7)");
2022 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
2045 dev->changed = 1; /* mark as changed */
2048 static char *helptext[] =
2050 " Using the UserConfig kernel settings editor",
2051 " -------------------------------------------",
2057 "The screen displays a list of available drivers, divided into two",
2058 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
2059 "by default collapsed and can be expanded to show all the drivers",
2060 "available in each category. The parameters for the currently selected",
2061 "driver are shown at the bottom of the screen.",
2063 "- - Moving around -",
2065 "To move in the current list, use the UP and DOWN cursor keys to select",
2066 "an item (the selected item will be highlighted). If the item is a",
2067 "category name, you may alternatively expand or collapse the list of",
2068 "drivers for that category by pressing [!bENTER!n]. Once the category is",
2069 "expanded, you can select each driver in the same manner and either:",
2071 " - change its parameters using [!bENTER!n]",
2072 " - move it to the Inactive list using [!bDEL!n]",
2074 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
2075 "you need to move a driver from the Inactive list back to the Active",
2076 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
2077 "necessary, and press [!bENTER!n] -- the device will be moved back to",
2078 "its place in the Active list.",
2080 "- - Altering the list/parameters -",
2082 "Any drivers for devices not installed in your system should be moved",
2083 "to the Inactive list, until there are no remaining parameter conflicts",
2084 "between the drivers, as indicated at the top.",
2086 "Once the list of Active drivers only contains entries for the devices",
2087 "present in your system, you can set their parameters (Interrupt, DMA",
2088 "channel, I/O addresses). To do this, select the driver and press",
2089 "[!bENTER!n]: it is now possible to edit the settings the settings at the",
2090 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
2091 "finished, use [!bQ!n] to return to the list.",
2093 "- - Saving changes -",
2095 "When all settings seem correct, and you wish to proceed with the",
2096 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
2097 "confirm your choice.",
2106 ** Displays help text onscreen for people that are confused, using a simple
2112 int topline = 0; /* where we are in the text */
2116 for (;;) /* loop until user quits */
2120 /* display help text */
2123 clear(); /* remove everything else */
2124 for (line = topline;
2125 (line < (topline + 24)) && (helptext[line]);
2127 putxy(0,line-topline,helptext[line]);
2132 sprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
2135 c = getchar(); /* so what do they say? */
2142 case 'B': /* wired into 'more' users' fingers */
2143 if (topline > 0) /* room to go up? */
2146 if (topline < 0) /* don't go too far */
2154 case ' ': /* expected by most people */
2155 if (helptext[line]) /* maybe more below? */
2164 redraw(); /* restore the screen */
2172 ** High-level control functions
2179 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2180 ** (num) lines, starting at (*ofs) offset from row onscreen.
2181 ** Pass (detail) on to drawing routines.
2183 ** If the user hits a key other than a cursor key, maybe return a code.
2185 ** (*list) points to the device at the top line in the region, (*ofs) is the
2186 ** position of the highlight within the region. All routines below
2187 ** this take only a device and an absolute row : use ofsent() to find the
2188 ** device, and add (*ofs) to (row) to find the absolute row.
2191 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2202 showparams(ofsent(*ofs,*list)); /* show device parameters */
2203 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2207 c = getchar(); /* get a character */
2208 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2210 extended = 0; /* no longer */
2213 case 588: /* syscons' idea of 'up' */
2215 if (*ofs) /* just a move onscreen */
2217 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2218 (*ofs)--; /* move up */
2220 lp = prevent(*list); /* can we go up? */
2223 *list = lp; /* yes, move up list */
2224 drawlist(row,num,detail,*list);
2229 case 596: /* dooby-do */
2230 case 'B': /* down */
2231 lp = ofsent(*ofs,*list); /* get current item */
2233 break; /* nothing more to move to */
2234 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2235 if (*ofs < (num-1)) /* room to move onscreen? */
2239 *list = nextent(*list); /* scroll region down */
2240 drawlist(row,num,detail,*list);
2252 case '[': /* cheat : always preceeds cursor move */
2253 case 'O': /* ANSI application key mode */
2262 return(KEY_EXIT); /* user requests exit */
2266 return(KEY_DO); /* "do" something */
2271 return(KEY_DEL); /* "delete" response */
2275 return(KEY_UNZOOM); /* expand everything */
2279 return(KEY_ZOOM); /* collapse everything */
2282 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2283 return(KEY_TAB); /* "move" response */
2285 case '\014': /* ^L, redraw */
2288 case '?': /* helptext */
2300 ** Do the fullscreen config thang
2305 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2309 initlist(&inactive);
2315 conflicts = findconflict(active); /* find conflicts in the active list only */
2323 case 0: /* active devices */
2324 ret = dolist(1,8,1,&actofs,&alist,
2325 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2329 mode = 1; /* swap lists */
2346 collapselist(active);
2351 dp = ofsent(actofs,alist); /* get current device */
2352 if (dp) /* paranoia... */
2354 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2356 if (dp == alist) /* moving top item on list? */
2360 alist = dp->next; /* point list to non-moving item */
2362 alist = dp->prev; /* end of list, go back instead */
2365 if (!dp->next) /* moving last item on list? */
2368 dp->conflicts = 0; /* no conflicts on the inactive list */
2369 movedev(dp,inactive); /* shift to inactive list */
2370 conflicts = findconflict(active); /* update conflict tags */
2372 redrawactive(); /* redraw */
2377 case KEY_DO: /* edit device parameters */
2378 dp = ofsent(actofs,alist); /* get current device */
2379 if (dp) /* paranoia... */
2381 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2383 if (dp->iobase != -2) /* can't edit PCI devices */
2385 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2387 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2389 conflicts = findconflict(active); /* update conflict tags */
2391 }else{ /* DO on comment = zoom */
2392 switch(dp->comment) /* Depends on current state */
2394 case DEV_COMMENT: /* not currently zoomed */
2395 dp->comment = DEV_ZOOMED;
2399 dp->comment = DEV_COMMENT;
2409 case 1: /* inactive devices */
2410 ret = dolist(10,7,0,&inactofs,&ilist,
2411 " [!bEnter!n] Enable device ");
2425 expandlist(inactive);
2432 collapselist(inactive);
2437 dp = ofsent(inactofs,ilist); /* get current device */
2438 if (dp) /* paranoia... */
2440 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2442 if (dp == ilist) /* moving top of list? */
2446 ilist = dp->next; /* point list to non-moving item */
2448 ilist = dp->prev; /* can't go down, go up instead */
2451 if (!dp->next) /* last entry on list? */
2452 inactofs--; /* shift cursor up one */
2455 movedev(dp,active); /* shift to active list */
2456 conflicts = findconflict(active); /* update conflict tags */
2458 alist = dp; /* put at top and current */
2460 while(dp->comment == DEV_DEVICE)
2461 dp = dp->prev; /* forcibly unzoom section */
2462 dp ->comment = DEV_COMMENT;
2463 mode = 0; /* and swap modes to follow it */
2465 }else{ /* DO on comment = zoom */
2466 switch(dp->comment) /* Depends on current state */
2468 case DEV_COMMENT: /* not currently zoomed */
2469 dp->comment = DEV_ZOOMED;
2473 dp->comment = DEV_COMMENT;
2477 redrawactive(); /* redraw */
2482 default: /* nothing else relevant here */
2487 mode = 0; /* shouldn't happen... */
2490 /* handle returns that are the same for both modes */
2497 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2500 case 2: /* cancel */
2504 case 1: /* save and exit */
2506 savelist(inactive,0);
2509 nukelist(active); /* clean up after ourselves */
2519 #endif /* VISUAL_USERCONFIG */
2522 * Copyright (c) 1991 Regents of the University of California.
2523 * All rights reserved.
2524 * Copyright (c) 1994 Jordan K. Hubbard
2525 * All rights reserved.
2526 * Copyright (c) 1994 David Greenman
2527 * All rights reserved.
2529 * Many additional changes by Bruce Evans
2531 * This code is derived from software contributed by the
2532 * University of California Berkeley, Jordan K. Hubbard,
2533 * David Greenman and Bruce Evans.
2535 * Redistribution and use in source and binary forms, with or without
2536 * modification, are permitted provided that the following conditions
2538 * 1. Redistributions of source code must retain the above copyright
2539 * notice, this list of conditions and the following disclaimer.
2540 * 2. Redistributions in binary form must reproduce the above copyright
2541 * notice, this list of conditions and the following disclaimer in the
2542 * documentation and/or other materials provided with the distribution.
2543 * 3. All advertising materials mentioning features or use of this software
2544 * must display the following acknowledgement:
2545 * This product includes software developed by the University of
2546 * California, Berkeley and its contributors.
2547 * 4. Neither the name of the University nor the names of its contributors
2548 * may be used to endorse or promote products derived from this software
2549 * without specific prior written permission.
2551 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2552 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2553 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2554 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2555 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2556 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2557 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2558 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2559 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2560 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2563 * $Id: userconfig.c,v 1.85 1999/07/26 12:14:59 kato Exp $
2568 #define PARM_DEVSPEC 0x1
2569 #define PARM_INT 0x2
2570 #define PARM_ADDR 0x3
2571 #define PARM_STRING 0x4
2573 typedef struct _cmdparm {
2576 struct isa_device *dparm;
2585 typedef int (*CmdFunc)(CmdParm *);
2587 typedef struct _cmd {
2595 static void lsscsi(void);
2596 static int list_scsi(CmdParm *);
2599 static int lsdevtab(struct isa_device *);
2600 static struct isa_device *find_device(char *, int);
2601 static struct isa_device *search_devtable(struct isa_device *, char *, int);
2602 static void cngets(char *, int);
2603 static Cmd *parse_cmd(char *);
2604 static int parse_args(const char *, CmdParm *);
2605 static unsigned long strtoul(const char *, const char **, int);
2606 static int save_dev(struct isa_device *);
2608 static int list_devices(CmdParm *);
2609 static int set_device_ioaddr(CmdParm *);
2610 static int set_device_irq(CmdParm *);
2611 static int set_device_drq(CmdParm *);
2612 static int set_device_iosize(CmdParm *);
2613 static int set_device_mem(CmdParm *);
2614 static int set_device_flags(CmdParm *);
2615 static int set_device_enable(CmdParm *);
2616 static int set_device_disable(CmdParm *);
2617 static int quitfunc(CmdParm *);
2618 static int helpfunc(CmdParm *);
2619 #if defined(INTRO_USERCONFIG)
2620 static int introfunc(CmdParm *);
2624 static int lspnp(void);
2625 static int set_pnp_parms(CmdParm *);
2634 #include <i386/eisa/eisaconf.h>
2636 static int set_num_eisa_slots(CmdParm *);
2638 #endif /* NEISA > 0 */
2640 static CmdParm addr_parms[] = {
2641 { PARM_DEVSPEC, {} },
2646 static CmdParm int_parms[] = {
2647 { PARM_DEVSPEC, {} },
2652 static CmdParm dev_parms[] = {
2653 { PARM_DEVSPEC, {} },
2658 static CmdParm string_arg[] = {
2659 { PARM_STRING, {} },
2665 static CmdParm int_arg[] = {
2669 #endif /* NEISA > 0 */
2671 static Cmd CmdList[] = {
2672 { "?", helpfunc, NULL }, /* ? (help) */
2673 { "di", set_device_disable, dev_parms }, /* disable dev */
2674 { "dr", set_device_drq, int_parms }, /* drq dev # */
2676 { "ei", set_num_eisa_slots, int_arg }, /* # EISA slots */
2677 #endif /* NEISA > 0 */
2678 { "en", set_device_enable, dev_parms }, /* enable dev */
2679 { "ex", quitfunc, NULL }, /* exit (quit) */
2680 { "f", set_device_flags, int_parms }, /* flags dev mask */
2681 { "h", helpfunc, NULL }, /* help */
2682 #if defined(INTRO_USERCONFIG)
2683 { "intro", introfunc, NULL }, /* intro screen */
2685 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2686 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2687 { "ir", set_device_irq, int_parms }, /* irq dev # */
2688 { "l", list_devices, NULL }, /* ls, list */
2690 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2692 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2693 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2694 { "q", quitfunc, NULL }, /* quit */
2696 { "s", list_scsi, NULL }, /* scsi */
2698 #ifdef VISUAL_USERCONFIG
2699 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2701 { NULL, NULL, NULL },
2707 static char banner = 1;
2713 init_config_script();
2716 /* Only display signon banner if we are about to go interactive */
2717 if (!has_config_script()) {
2718 if (!(boothowto & RB_CONFIG))
2719 #ifdef INTRO_USERCONFIG
2726 printf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2727 " Type \"help\" for help"
2728 #ifdef VISUAL_USERCONFIG
2729 " or \"visual\" to go to the visual\n"
2730 " configuration interface (requires MGA/VGA display or\n"
2731 " serial terminal capable of displaying ANSI graphics)"
2739 if (input[0] == '\0')
2741 cmd = parse_cmd(input);
2743 printf("Invalid command or syntax. Type `?' for help.\n");
2746 rval = (*cmd->handler)(cmd->parms);
2755 parse_cmd(char *cmd)
2759 for (cp = CmdList; cp->name; cp++) {
2760 int len = strlen(cp->name);
2762 if (!strncmp(cp->name, cmd, len)) {
2763 while (*cmd && *cmd != ' ' && *cmd != '\t')
2765 if (parse_args(cmd, cp->parms))
2775 parse_args(const char *cmd, CmdParm *parms)
2780 if (*cmd == ' ' || *cmd == '\t') {
2784 if (parms == NULL || parms->type == -1) {
2787 printf("Extra arg(s): %s\n", cmd);
2790 if (parms->type == PARM_DEVSPEC) {
2795 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2796 (*cmd >= '0' && *cmd <= '9')))
2797 devname[i++] = *(cmd++);
2799 if (*cmd >= '0' && *cmd <= '9') {
2800 unit = strtoul(cmd, &ptr, 10);
2802 printf("Invalid device number\n");
2803 /* XXX should print invalid token here and elsewhere. */
2806 /* XXX else should require end of token. */
2809 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2810 printf("No such device: %s%d\n", devname, unit);
2816 if (parms->type == PARM_INT) {
2817 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2819 printf("Invalid numeric argument\n");
2826 if (parms->type == PARM_ADDR) {
2827 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2829 printf("Invalid address argument\n");
2836 if (parms->type == PARM_STRING) {
2837 parms->parm.u.sparm = cmd;
2845 list_devices(CmdParm *parms)
2848 if (lsdevtab(isa_devtab)) return 0;
2850 if (lspnp()) return 0;
2853 printf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots);
2854 #endif /* NEISA > 0 */
2859 set_device_ioaddr(CmdParm *parms)
2861 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2862 save_dev(parms[0].parm.dparm);
2867 set_device_irq(CmdParm *parms)
2871 irq = parms[1].parm.iparm;
2874 printf("Warning: Remapping IRQ 2 to IRQ 9 - see config(8)\n");
2877 else if (irq != -1 && irq > 15) {
2879 if (irq != -1 && irq > 15) {
2881 printf("An IRQ > 15 would be invalid.\n");
2884 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2885 save_dev(parms[0].parm.dparm);
2890 set_device_drq(CmdParm *parms)
2895 * The bounds checking is just to ensure that the value can be printed
2896 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2898 drq = parms[1].parm.iparm;
2899 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2900 save_dev(parms[0].parm.dparm);
2905 set_device_iosize(CmdParm *parms)
2907 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2908 save_dev(parms[0].parm.dparm);
2913 set_device_mem(CmdParm *parms)
2915 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2916 save_dev(parms[0].parm.dparm);
2921 set_device_flags(CmdParm *parms)
2923 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2924 save_dev(parms[0].parm.dparm);
2929 set_device_enable(CmdParm *parms)
2931 parms[0].parm.dparm->id_enabled = TRUE;
2932 save_dev(parms[0].parm.dparm);
2937 set_device_disable(CmdParm *parms)
2939 parms[0].parm.dparm->id_enabled = FALSE;
2940 save_dev(parms[0].parm.dparm);
2947 sysctl_machdep_uc_pnplist SYSCTL_HANDLER_ARGS
2953 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2956 * Output the pnp_ldn_overrides[] table.
2958 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2959 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2960 if(error) return(error);
2965 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2966 0, 0, sysctl_machdep_uc_pnplist, "A",
2967 "List of PnP overrides changed in UserConfig");
2970 * this function sets the kernel table to override bios PnP
2974 set_pnp_parms(CmdParm *parms)
2976 u_long idx, val, ldn, csn;
2979 const char *p = parms[0].parm.u.sparm;
2982 csn=strtoul(p,&q, 0);
2983 ldn=strtoul(q,&q, 0);
2984 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2985 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2986 printf("bad csn/ldn %ld:%ld\n", csn, ldn);
2989 for (i=0; i < MAX_PNP_LDN; i++) {
2990 if (pnp_ldn_overrides[i].csn == csn &&
2991 pnp_ldn_overrides[i].ldn == ldn)
2994 if (i==MAX_PNP_LDN) {
2995 for (i=0; i < MAX_PNP_LDN; i++) {
2996 if (pnp_ldn_overrides[i].csn <1 ||
2997 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
3001 if (i==MAX_PNP_LDN) {
3002 printf("sorry, no PnP entries available, try delete one\n");
3005 d = pnp_ldn_overrides[i] ;
3011 if (!strncmp(p,"irq",3)) {
3012 idx=strtoul(p+3,&q, 0);
3013 val=strtoul(q,&q, 0);
3014 if (idx >=0 && idx < 2) d.irq[idx] = val;
3015 } else if (!strncmp(p,"flags",5)) {
3016 idx=strtoul(p+5,&q, 0);
3018 } else if (!strncmp(p,"drq",3)) {
3019 idx=strtoul(p+3,&q, 0);
3020 val=strtoul(q,&q, 0);
3021 if (idx >=0 && idx < 2) d.drq[idx] = val;
3022 } else if (!strncmp(p,"port",4)) {
3023 idx=strtoul(p+4,&q, 0);
3024 val=strtoul(q,&q, 0);
3025 if (idx >=0 && idx < 8) d.port[idx] = val;
3026 } else if (!strncmp(p,"mem",3)) {
3027 idx=strtoul(p+3,&q, 0);
3028 val=strtoul(q,&q, 0);
3029 if (idx >=0 && idx < 4) d.mem[idx].base = val;
3030 } else if (!strncmp(p,"bios",4)) {
3033 } else if (!strncmp(p,"os",2)) {
3036 } else if (!strncmp(p,"disable",7)) {
3039 } else if (!strncmp(p,"enable",6)) {
3042 } else if (!strncmp(p,"delete",6)) {
3043 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
3044 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
3047 printf("unknown command <%s>\n", p);
3050 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
3052 pnp_ldn_overrides[i] = d ;
3059 set_num_eisa_slots(CmdParm *parms)
3063 num_slots = parms[0].parm.iparm;
3064 num_eisa_slots = (num_slots <= 16 ? num_slots : 10);
3067 #endif /* NEISA > 0 */
3070 quitfunc(CmdParm *parms)
3073 * If kernel config supplied, and we are parsing it, and -c also supplied,
3074 * ignore a quit command, This provides a safety mechanism to allow
3075 * recovery from a damaged/buggy kernel config.
3077 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
3083 helpfunc(CmdParm *parms)
3086 "Command\t\t\tDescription\n"
3087 "-------\t\t\t-----------\n"
3088 "ls\t\t\tList currently configured devices\n"
3089 "port <devname> <addr>\tSet device port (i/o address)\n"
3090 "irq <devname> <number>\tSet device irq\n"
3091 "drq <devname> <number>\tSet device drq\n"
3092 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
3093 "iosize <devname> <size>\tSet device memory size\n"
3094 "flags <devname> <mask>\tSet device flags\n"
3095 "enable <devname>\tEnable device\n"
3096 "disable <devname>\tDisable device (will not be probed)\n");
3099 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
3100 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
3101 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
3102 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
3103 "pnp <csn> <ldn> [irq <number>]\tset irq X (0..1) to number, 0=unused\n"
3104 "pnp <csn> <ldn> [drq <number>]\tset drq X (0..1) to number, 4=unused\n");
3107 printf("eisa <number>\t\tSet the number of EISA slots to probe\n");
3108 #endif /* NEISA > 0 */
3110 "quit\t\t\tExit this configuration utility\n"
3111 "reset\t\t\tReset CPU\n");
3112 #ifdef VISUAL_USERCONFIG
3113 printf("visual\t\t\tGo to fullscreen mode.\n");
3116 "help\t\t\tThis message\n\n"
3117 "Commands may be abbreviated to a unique prefix\n");
3121 #if defined(INTRO_USERCONFIG)
3123 #if defined (VISUAL_USERCONFIG)
3125 center(int y, char *str)
3127 putxy((80 - strlen(str)) / 2, y, str);
3132 introfunc(CmdParm *parms)
3134 #if defined (VISUAL_USERCONFIG)
3135 int curr_item, first_time, extended = 0;
3136 static char *choices[] = {
3137 " Skip kernel configuration and continue with installation ",
3138 " Start kernel configuration in full-screen visual mode ",
3139 " Start kernel configuration in CLI mode ",
3143 center(2, "!bKernel Configuration Menu!n");
3152 for (i = 0; i < 3; i++) {
3156 strcat(tmp, choices[i]);
3159 putxy(10, 5 + i, tmp);
3163 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3164 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3165 putxy(2, 12, "match your hardware configuration.");
3166 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3167 putxy(2, 15, "(press Down-Arrow then ENTER).");
3168 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3169 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3170 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3171 putxy(2, 21, "then simply press ENTER or Q now.");
3175 move(0, 0); /* move the cursor out of the way */
3178 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
3179 extended = 0; /* no longer */
3188 case 'B': /* down */
3200 case '[': /* cheat : always preceeds cursor move */
3201 case 'O': /* ANSI application key mode */
3212 return 1; /* user requests exit */
3214 case '1': /* select an item */
3238 case 'D': /* down */
3251 else if (curr_item == 1)
3252 return visuserconfig();
3254 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3255 /* enable quitfunc */
3256 userconfig_boot_parsing=0;
3258 boothowto |= RB_CONFIG; /* force -c */
3273 struct pnp_cinfo *c;
3277 for (i=0; i< MAX_PNP_LDN; i++) {
3278 c = &pnp_ldn_overrides[i];
3279 if (c->csn >0 && c->csn != 255) {
3281 static char pfmt[] =
3282 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3283 static char mfmt[] =
3284 "mem 0x%x 0x%x 0x%x 0x%x";
3287 if (!userconfig_boot_parsing) {
3289 if (getchar() == 'q') {
3297 if (lineno == 0 || first)
3298 printf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3300 printf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3302 c->override ? "OS ":"BIOS",
3303 c->enable ? "Y":"N",
3304 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3306 printf("flags 0x%08lx ",c->flags);
3307 for (pmax = 7; pmax >=0 ; pmax--)
3308 if (c->port[pmax]!=0) break;
3309 for (mmax = 3; mmax >=0 ; mmax--)
3310 if (c->mem[mmax].base!=0) break;
3313 buf[10 + 5*pmax]='\0';
3315 c->port[0], c->port[1], c->port[2], c->port[3],
3316 c->port[4], c->port[5], c->port[6], c->port[7]);
3320 buf[8 + 5*mmax]='\0';
3322 c->mem[0].base, c->mem[1].base,
3323 c->mem[2].base, c->mem[3].base);
3333 lsdevtab(struct isa_device *dt)
3335 for (; dt->id_id != 0; dt++) {
3340 if (!userconfig_boot_parsing) {
3341 if (getchar() == 'q') {
3351 "Device port irq drq iomem iosize unit flags enab confl\n"
3355 sprintf(dname, "%s%d", dt->id_driver->name, dt->id_unit);
3356 printf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s%-3s\n",
3357 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3358 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3359 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3360 /* dt->id_scsiid, dt->id_alive, dt->id_ri_flags, */
3361 /* dt->id_reconfig, */ dt->id_enabled ? "Yes" : "No",
3362 dt->id_conflicts ? "Yes" : "No");
3372 int count = resource_count();
3378 isa_devtab = malloc(sizeof(struct isa_device)*(count + 1),M_DEVL,M_WAITOK);
3379 isa_drvtab = malloc(sizeof(struct isa_driver)*(count + 1),M_DEVL,M_WAITOK);
3380 bzero(isa_devtab, sizeof(struct isa_device) * (count + 1));
3381 bzero(isa_drvtab, sizeof(struct isa_driver) * (count + 1));
3383 for (i = 0; i < count; i++) {
3384 name = resource_query_name(i);
3385 unit = resource_query_unit(i);
3387 continue; /* skip wildcards */
3388 isa_devtab[dt].id_id = id++;
3389 isa_devtab[dt].id_driver = &isa_drvtab[dt];
3390 resource_int_value(name, unit, "port", &isa_devtab[dt].id_iobase);
3392 resource_int_value(name, unit, "irq", &val);
3393 isa_devtab[dt].id_irq = (1 << val);
3394 resource_int_value(name, unit, "drq", &isa_devtab[dt].id_drq);
3395 resource_int_value(name, unit, "maddr",(int *)&isa_devtab[dt].id_maddr);
3396 resource_int_value(name, unit, "msize", &isa_devtab[dt].id_msize);
3397 isa_devtab[dt].id_unit = unit;
3398 resource_int_value(name, unit, "flags", &isa_devtab[dt].id_flags);
3400 resource_int_value(name, unit, "disabled", &val);
3401 isa_devtab[dt].id_enabled = !val;
3402 resource_int_value(name, unit, "conflicts",
3403 (int *)&isa_devtab[dt].id_conflicts);
3404 isa_drvtab[dt].name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3405 strcpy(isa_drvtab[dt].name, name);
3414 int count = resource_count();
3416 for (i = 0; i < count; i++)
3417 if (isa_drvtab[i].name)
3418 free(isa_drvtab[i].name, M_DEVL);
3419 free(isa_drvtab, M_DEVL);
3420 free(isa_devtab, M_DEVL);
3423 static struct isa_device *
3424 find_device(char *devname, int unit)
3426 struct isa_device *ret;
3428 if ((ret = search_devtable(isa_devtab, devname, unit)) != NULL)
3433 static struct isa_device *
3434 search_devtable(struct isa_device *dt, char *devname, int unit)
3438 for (i = 0; dt->id_id != 0; dt++)
3439 if (!strcmp(dt->id_driver->name, devname) && dt->id_unit == unit)
3445 cngets(char *input, int maxin)
3451 /* Treat ^H or ^? as backspace */
3452 if ((c == '\010' || c == '\177')) {
3454 printf("\010 \010");
3455 *--input = '\0', --nchars;
3459 /* Treat ^U or ^X as kill line */
3460 else if ((c == '\025' || c == '\030')) {
3462 printf("\010 \010");
3463 *--input = '\0', --nchars;
3468 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3472 *input++ = (u_char)c;
3478 * Kludges to get the library sources of strtoul.c to work in our
3479 * environment. isdigit() and isspace() could be used above too.
3481 #define isalpha(c) (((c) >= 'A' && (c) <= 'Z') \
3482 || ((c) >= 'a' && (c) <= 'z')) /* unsafe */
3483 #define isdigit(c) ((unsigned)((c) - '0') <= '9' - '0')
3484 #define isspace(c) ((c) == ' ' || (c) == '\t') /* unsafe */
3485 #define isupper(c) ((unsigned)((c) - 'A') <= 'Z' - 'A')
3490 * The following should be identical with the library sources for strtoul.c.
3494 * Convert a string to an unsigned long integer.
3496 * Ignores `locale' stuff. Assumes that the upper and lower case
3497 * alphabets and digits are each contiguous.
3499 static unsigned long
3500 strtoul(nptr, endptr, base)
3502 const char **endptr;
3505 register const char *s = nptr;
3506 register unsigned long acc;
3508 register unsigned long cutoff;
3509 register int neg = 0, any, cutlim;
3512 * See strtol for comments as to the logic used.
3516 } while (isspace(c));
3520 } else if (c == '+')
3522 if ((base == 0 || base == 16) &&
3523 c == '0' && (*s == 'x' || *s == 'X')) {
3529 base = c == '0' ? 8 : 10;
3530 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
3531 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
3532 for (acc = 0, any = 0;; c = *s++) {
3535 else if (isalpha(c))
3536 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
3541 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
3555 *endptr = (const char *)(any ? s - 1 : nptr);
3560 /* scsi: Support for displaying configured SCSI devices.
3561 * There is no way to edit them, and this is inconsistent
3562 * with the ISA method. This is here as a basis for further work.
3565 type_text(char *name) /* XXX: This is bogus */
3567 if (strcmp(name, "sd") == 0)
3570 if (strcmp(name, "st") == 0)
3576 id_put(char *desc, int id)
3578 if (id != SCCONF_UNSPEC)
3583 if (id == SCCONF_ANY)
3595 printf("scsi: (can't be edited):\n");
3597 for (i = 0; scsi_cinit[i].driver; i++)
3599 id_put("controller scbus", scsi_cinit[i].scbus);
3601 if (scsi_cinit[i].unit != -1)
3604 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3610 for (i = 0; scsi_dinit[i].name; i++)
3612 printf("%s ", type_text(scsi_dinit[i].name));
3614 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3615 id_put(" at scbus", scsi_dinit[i].cunit);
3616 id_put(" target ", scsi_dinit[i].target);
3617 id_put(" lun ", scsi_dinit[i].lun);
3619 if (scsi_dinit[i].flags)
3620 printf(" flags 0x%x\n", scsi_dinit[i].flags);
3627 list_scsi(CmdParm *parms)
3636 save_resource(struct isa_device *idev)
3641 name = idev->id_driver->name;
3642 unit = idev->id_unit;
3643 resource_set_int(name, unit, "port", idev->id_iobase);
3644 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3645 resource_set_int(name, unit, "drq", idev->id_drq);
3646 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3647 resource_set_int(name, unit, "msize", idev->id_msize);
3648 resource_set_int(name, unit, "flags", idev->id_flags);
3649 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3650 resource_set_int(name, unit, "conflicts", idev->id_conflicts);
3655 struct isa_device *idev;
3657 struct isa_device *id_p,*id_pn;
3658 struct isa_driver *isa_drv;
3659 char *name = idev->id_driver->name;
3661 for (id_p=isa_devlist;
3663 id_p=id_p->id_next) {
3664 if (id_p->id_id == idev->id_id) {
3665 id_pn = id_p->id_next;
3666 isa_drv = id_p->id_driver;
3667 if (isa_drv && isa_drv->name)
3668 free(isa_drv->name, M_DEVL);
3670 free(isa_drv, M_DEVL);
3671 bcopy(idev,id_p,sizeof(struct isa_device));
3672 save_resource(idev);
3673 isa_drv = malloc(sizeof(struct isa_driver),M_DEVL,
3675 isa_drv->name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3676 strcpy(isa_drv->name, name);
3677 id_p->id_driver = isa_drv;
3678 id_p->id_next = id_pn;
3682 id_pn = malloc(sizeof(struct isa_device),M_DEVL,M_WAITOK);
3683 bcopy(idev,id_pn,sizeof(struct isa_device));
3684 save_resource(idev);
3685 isa_drv = malloc(sizeof(struct isa_driver),M_DEVL, M_WAITOK);
3686 isa_drv->name = malloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3687 strcpy(isa_drv->name, name);
3688 id_pn->id_driver = isa_drv;
3689 id_pn->id_next = isa_devlist;
3690 isa_devlist = id_pn;