3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
5 ** This code contains a module marked :
7 * Copyright (c) 1991 Regents of the University of California.
9 * Copyright (c) 1994 Jordan K. Hubbard
10 * All rights reserved.
11 * Copyright (c) 1994 David Greenman
12 * All rights reserved.
14 * Many additional changes by Bruce Evans
16 * This code is derived from software contributed by the
17 * University of California Berkeley, Jordan K. Hubbard,
18 * David Greenman and Bruce Evans.
20 ** As such, it contains code subject to the above copyrights.
21 ** The module and its copyright can be found below.
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
26 ** 1. Redistributions of source code must retain the above copyright
27 ** notice, this list of conditions and the following disclaimer as
28 ** the first lines of this file unmodified.
29 ** 2. Redistributions in binary form must reproduce the above copyright
30 ** notice, this list of conditions and the following disclaimer in the
31 ** documentation and/or other materials provided with the distribution.
32 ** 3. All advertising materials mentioning features or use of this software
33 ** must display the following acknowledgment:
34 ** This product includes software developed by Michael Smith.
35 ** 4. The name of the author may not be used to endorse or promote products
36 ** derived from this software without specific prior written permission.
38 ** THIS SOFTWARE IS PROVIDED BY MICHAEL SMITH ``AS IS'' AND ANY EXPRESS OR
39 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 ** IN NO EVENT SHALL MICHAEL SMITH BE LIABLE FOR ANY DIRECT, INDIRECT,
42 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
55 ** Kernel boot-time configuration manipulation tool for FreeBSD.
57 ** Two modes of operation are supported : the default is the line-editor mode,
58 ** the command "visual" invokes the fullscreen mode.
60 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
61 ** fullscreen mode requires syscons or a minimal-ansi serial console.
65 ** USERCONFIG, visual mode.
69 ** Look for "EDIT THIS LIST" to add to the list of known devices
72 ** There are a number of assumptions made in this code.
74 ** - That the console supports a minimal set of ANSI escape sequences
75 ** (See the screen manipulation section for a summary)
76 ** and has at least 24 rows.
77 ** - That values less than or equal to zero for any of the device
78 ** parameters indicate that the driver does not use the parameter.
79 ** - That flags are _always_ editable.
81 ** Devices marked as disabled are imported as such.
83 ** For this tool to be useful, the list of devices below _MUST_ be updated
84 ** when a new driver is brought into the kernel. It is not possible to
85 ** extract this information from the drivers in the kernel.
89 ** - Display _what_ a device conflicts with.
90 ** - Implement page up/down (as what?)
91 ** - Wizard mode (no restrictions)
92 ** - Find out how to put syscons back into low-intensity mode so that the
93 ** !b escape is useful on the console. (It seems to be that it actually
94 ** gets low/high intensity backwards. That looks OK.)
96 ** - Only display headings with devices under them. (difficult)
99 #include "opt_userconfig.h"
100 #define COMPAT_OLDISA /* get the definitions */
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/kernel.h>
105 #include <sys/malloc.h>
106 #include <sys/reboot.h>
107 #include <sys/linker.h>
108 #include <sys/sysctl.h>
110 #include <sys/cons.h>
112 #include <machine/md_var.h>
113 #include <machine/limits.h>
115 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
121 #include <machine_base/isa/pnp.h>
124 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
126 #include <machine/uc_device.h>
127 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
128 static struct uc_device *uc_devtab; /* fake uc_device table */
130 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
132 static void load_devtab(void);
133 static void free_devtab(void);
134 static void save_resource(struct uc_device *);
137 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
139 struct uc_device *id;
147 error+=sizeof(struct uc_device)+8;
150 return(SYSCTL_OUT(req,0,error));
152 /* Output the data. The buffer is filled with consecutive
153 * struct uc_device and char buf[8], containing the name
154 * (not guaranteed to end with '\0').
158 error=sysctl_handle_opaque(oidp,id,
159 sizeof(struct uc_device),req);
160 if(error) return(error);
161 strncpy(name,id->id_name,8);
162 error=sysctl_handle_opaque(oidp,name,
164 if(error) return(error);
171 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
172 0, 0, sysctl_machdep_uc_devlist, "A",
173 "List of ISA devices changed in UserConfig");
176 ** Obtain command input.
178 ** Initially, input is read from a possibly-loaded script.
179 ** At the end of the script, or if no script is supplied,
180 ** behaviour is determined by the RB_CONFIG (-c) flag. If
181 ** the flag is set, user input is read from the console; if
182 ** unset, the 'quit' command is invoked and userconfig
185 ** Note that quit commands encountered in the script will be
186 ** ignored if the RB_CONFIG flag is supplied.
188 static const char *config_script;
189 static int config_script_size; /* use of int for -ve magic value */
191 #define has_config_script() (config_script_size > 0)
194 init_config_script(void)
196 caddr_t autoentry, autoattr;
198 /* Look for loaded userconfig script */
199 autoentry = preload_search_by_type("userconfig_script");
200 if (autoentry != NULL) {
201 /* We have one, get size and data */
202 config_script_size = 0;
203 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
204 config_script_size = (size_t)*(u_int32_t *)autoattr;
205 config_script = NULL;
206 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
207 config_script = *(const char **)autoattr;
209 if ((config_script_size == 0) || (config_script == NULL)) {
210 config_script_size = 0;
211 config_script = NULL;
214 return has_config_script();
221 #ifdef INTRO_USERCONFIG
222 static int intro = 0;
225 if (has_config_script())
227 /* Consume character from loaded userconfig script, display */
228 userconfig_boot_parsing = 1;
231 config_script_size--;
235 #ifdef INTRO_USERCONFIG
236 if (userconfig_boot_parsing) {
237 if (!(boothowto & RB_CONFIG)) {
238 /* userconfig_script, !RB_CONFIG -> quit */
241 config_script = "uit\n";
242 config_script_size = strlen(config_script);
243 /* userconfig_script will be 1 on the next pass */
246 /* userconfig_script, RB_CONFIG -> cngetc() */
249 if (!(boothowto & RB_CONFIG)) {
250 /* no userconfig_script, !RB_CONFIG -> show intro */
254 config_script = "ntro\n";
255 config_script_size = strlen(config_script);
256 /* userconfig_script will be 1 on the next pass */
259 /* no userconfig_script, RB_CONFIG -> cngetc() */
262 #else /* !INTRO_USERCONFIG */
263 /* assert(boothowto & RB_CONFIG) */
264 #endif /* INTRO_USERCONFIG */
265 userconfig_boot_parsing = 0;
274 #define TRUE (!FALSE)
277 #ifdef VISUAL_USERCONFIG
281 char dev[16]; /* device basename */
282 char name[60]; /* long name */
283 int attrib; /* things to do with the device */
284 int class; /* device classification */
287 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
288 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
289 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
290 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
291 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
292 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
293 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
294 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
295 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
297 #define CLS_STORAGE 1 /* storage devices */
298 #define CLS_NETWORK 2 /* network interfaces */
299 #define CLS_COMMS 3 /* serial, parallel ports */
300 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
301 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
302 #define CLS_MISC 255 /* none of the above */
311 static DEVCLASS_INFO devclass_names[] = {
312 { "Storage : ", CLS_STORAGE},
313 { "Network : ", CLS_NETWORK},
314 { "Communications : ", CLS_COMMS},
315 { "Input : ", CLS_INPUT},
316 { "Multimedia : ", CLS_MMEDIA},
317 { "Miscellaneous : ", CLS_MISC},
321 /********************* EDIT THIS LIST **********************/
325 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
326 ** - XXX The list below should be reviewed by the driver authors to verify
327 ** that the correct flags have been set for each driver, and that the
328 ** descriptions are accurate.
331 static DEV_INFO device_info[] = {
332 /*---Name----- ---Description---------------------------------------------- */
333 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
334 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE},
335 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE},
336 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
337 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
338 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
339 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
340 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
341 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
342 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
343 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
344 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
346 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
347 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
348 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
349 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
350 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
351 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
352 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
353 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
354 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
356 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
357 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
358 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
359 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
360 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS},
361 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS},
362 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
364 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
365 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
366 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
367 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
368 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
370 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
371 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
372 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
373 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
374 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
375 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
376 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
377 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
378 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
379 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
380 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
381 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
382 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
383 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
384 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
385 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
386 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
387 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
389 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
390 {"pcic", "PC-card controller", 0, CLS_MISC},
391 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
392 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
396 typedef struct _devlist_struct
399 int attrib; /* flag values as per the FLG_* defines above */
400 int class; /* disk, etc as per the CLS_* defines above */
402 int iobase,irq,drq,maddr,msize,unit,flags,id;
403 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
404 int conflicts; /* set/reset by findconflict, count of conflicts */
405 int changed; /* nonzero if the device has been edited */
406 struct uc_device *device;
407 struct _devlist_struct *prev,*next;
412 #define DEV_COMMENT 1
415 #define LIST_CURRENT (1<<0)
416 #define LIST_SELECTED (1<<1)
418 #define KEY_EXIT 0 /* return codes from dolist() and friends */
424 #define KEY_UP 5 /* these only returned from editval() */
428 #define KEY_NULL 9 /* this allows us to spin & redraw */
430 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
431 #define KEY_UNZOOM 11
433 #define KEY_HELP 12 /* duh? */
435 static void redraw(void);
436 static void insdev(DEV_LIST *dev, DEV_LIST *list);
437 static int devinfo(DEV_LIST *dev);
438 static int visuserconfig(void);
440 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
441 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
442 static DEV_LIST scratch; /* scratch record */
443 static int conflicts; /* total conflict count */
446 static char lines[] = "--------------------------------------------------------------------------------";
447 static char spaces[] = " ";
451 ** Device manipulation stuff : find, describe, configure.
457 ** Sets the device referenced by (*dev) to the parameters in the struct,
458 ** and the enable flag according to (enabled)
461 setdev(DEV_LIST *dev, int enabled)
463 dev->device->id_iobase = dev->iobase; /* copy happy */
464 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
465 dev->device->id_drq = (short)dev->drq;
466 dev->device->id_maddr = (caddr_t)dev->maddr;
467 dev->device->id_msize = dev->msize;
468 dev->device->id_flags = dev->flags;
469 dev->device->id_enabled = enabled;
476 ** Walk the kernel device tables and build the active and inactive lists
482 struct uc_device *ap;
484 ap = uc_devtab; /* pointer to array of devices */
485 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
487 scratch.unit = ap[i].id_unit; /* device parameters */
488 strcpy(scratch.dev,ap[i].id_name);
489 scratch.iobase = ap[i].id_iobase;
490 scratch.irq = ffs(ap[i].id_irq)-1;
491 scratch.drq = ap[i].id_drq;
492 scratch.maddr = (int)ap[i].id_maddr;
493 scratch.msize = ap[i].id_msize;
494 scratch.flags = ap[i].id_flags;
496 scratch.comment = DEV_DEVICE; /* admin stuff */
497 scratch.conflicts = 0;
498 scratch.device = &ap[i]; /* save pointer for later reference */
500 if (!devinfo(&scratch)) /* get more info on the device */
501 insdev(&scratch,ap[i].id_enabled?active:inactive);
509 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
510 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
512 ** If the device is marked "invisible", return nonzero; the caller should
513 ** not insert any such device into either list.
517 devinfo(DEV_LIST *dev)
521 for (i = 0; device_info[i].class; i++)
523 if (!strcmp(dev->dev,device_info[i].dev))
525 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
527 strcpy(dev->name,device_info[i].name); /* get the name */
528 dev->attrib = device_info[i].attrib;
529 dev->class = device_info[i].class;
533 strcpy(dev->name,"Unknown device");
535 dev->class = CLS_MISC;
541 ** List manipulation stuff : add, move, initialise, free, traverse
543 ** Note that there are assumptions throughout this code that
544 ** the first entry in a list will never move. (assumed to be
552 ** appends a copy of (dev) to the end of (*list)
555 addev(DEV_LIST *dev, DEV_LIST **list)
560 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
561 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
563 if (*list) /* list exists */
567 ap = ap->next; /* scoot to end of list */
571 }else{ /* list does not yet exist */
573 lp->prev = lp->next = NULL; /* list now exists */
581 ** Finds the 'appropriate' place for (dev) in (list)
583 ** 'Appropriate' means in numeric order with other devices of the same type,
584 ** or in alphabetic order following a comment of the appropriate type.
585 ** or at the end of the list if an appropriate comment is not found. (this should
587 ** (Note that the appropriate point is never the top, but may be the bottom)
590 findspot(DEV_LIST *dev, DEV_LIST *list)
594 /* search for a previous instance of the same device */
595 for (ap = list; ap; ap = ap->next)
597 if (ap->comment != DEV_DEVICE) /* ignore comments */
599 if (!strcmp(dev->dev,ap->dev)) /* same base device */
601 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
602 || !ap->next) /* or end of list */
604 ap = ap->prev; /* back up one */
605 break; /* done here */
607 if (ap->next) /* if the next item exists */
609 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
611 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
617 if (!ap) /* not sure yet */
619 /* search for a class that the device might belong to */
620 for (ap = list; ap; ap = ap->next)
622 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
624 if (dev->class != ap->class) /* of same class too 8) */
626 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
628 ap = ap->prev; /* back up one */
629 break; /* done here */
631 if (ap->next) /* if the next item exists */
632 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
637 if (!ap) /* didn't find a match */
639 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
640 if ((ap->comment != DEV_DEVICE)
641 && (ap->class == dev->class)) /* appropriate place? */
643 } /* or just put up with last */
652 ** Inserts a copy of (dev) at the appropriate point in (list)
655 insdev(DEV_LIST *dev, DEV_LIST *list)
659 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
660 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
662 ap = findspot(lp,list); /* find appropriate spot */
663 lp->next = ap->next; /* point to next */
665 ap->next->prev = lp; /* point next to new */
666 lp->prev = ap; /* point new to current */
667 ap->next = lp; /* and current to new */
674 ** Moves (dev) from its current list to an appropriate place in (list)
675 ** (dev) may not come from the top of a list, but it may from the bottom.
678 movedev(DEV_LIST *dev, DEV_LIST *list)
682 ap = findspot(dev,list);
683 dev->prev->next = dev->next; /* remove from old list */
685 dev->next->prev = dev->prev;
687 dev->next = ap->next; /* insert in new list */
689 ap->next->prev = dev; /* point next to new */
690 dev->prev = ap; /* point new to current */
691 ap->next = dev; /* and current to new */
698 ** Initialises (*list) with the basic headings
701 initlist(DEV_LIST **list)
705 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
707 strcpy(scratch.name,devclass_names[i].name);
708 scratch.comment = DEV_ZOOMED;
709 scratch.class = devclass_names[i].number;
710 scratch.attrib = FLG_MANDATORY; /* can't be moved */
711 addev(&scratch,list); /* add to the list */
719 ** Walks (list) and saves the settings of any entry marked as changed.
721 ** The device's active field is set according to (active).
723 ** Builds the uc_devlist used by kget to extract the changed device information.
724 ** The code for this was taken almost verbatim from the original module.
727 savelist(DEV_LIST *list, int active)
729 struct uc_device *id_p,*id_pn;
734 if ((list->comment == DEV_DEVICE) && /* is a device */
735 (list->changed) && /* has been changed */
736 (list->device != NULL)) { /* has an uc_device structure */
738 setdev(list,active); /* set the device itself */
741 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
742 { /* look on the list for it */
743 if (id_p->id_id == list->device->id_id)
745 name = list->device->id_name;
746 id_pn = id_p->id_next;
748 kfree(id_p->id_name, M_DEVL);
749 bcopy(list->device,id_p,sizeof(struct uc_device));
750 save_resource(list->device);
751 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
752 strcpy(id_p->id_name, name);
753 id_pn->id_next = uc_devlist;
754 id_p->id_next = id_pn;
758 if (!id_pn) /* not already on the list */
760 name = list->device->id_name;
761 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
762 bcopy(list->device,id_pn,sizeof(struct uc_device));
763 save_resource(list->device);
764 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
765 strcpy(id_pn->id_name, name);
766 id_pn->id_next = uc_devlist;
767 uc_devlist = id_pn; /* park at top of list */
778 ** Frees all storage in use by a (list).
781 nukelist(DEV_LIST *list)
787 while(list->prev) /* walk to head of list */
802 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
803 ** if there is no previous entry. (Only possible if list->prev == NULL given the
804 ** premise that there is always a comment at the head of the list)
807 prevent(DEV_LIST *list)
813 dp = list->prev; /* start back one */
816 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
817 return(dp); /* so skip to comment */
818 if (dp->comment == DEV_COMMENT) /* not zoomed */
819 return(list->prev); /* one back as normal */
820 dp = dp->prev; /* backpedal */
822 return(dp); /* NULL, we can assume */
829 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
830 ** if there is no next entry. (Possible if the current entry is last, or
831 ** if the current entry is the last heading and it's collapsed)
834 nextent(DEV_LIST *list)
840 if (list->comment != DEV_ZOOMED) /* no reason to skip */
845 if (dp->comment != DEV_DEVICE) /* found another heading */
849 return(dp); /* back we go */
856 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
859 ofsent(int ofs, DEV_LIST *list)
861 while (ofs-- && list)
862 list = nextent(list);
870 ** Scans every element of (list) and sets the conflict tags appropriately
871 ** Returns the number of conflicts found.
874 findconflict(DEV_LIST *list)
876 int count = 0; /* number of conflicts found */
879 for (dp = list; dp; dp = dp->next) /* over the whole list */
881 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
884 dp->conflicts = 0; /* assume the best */
885 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
887 if (sp->comment != DEV_DEVICE) /* likewise */
890 if (sp == dp) /* always conflict with itself */
893 if ((dp->iobase > 0) && /* iobase conflict? */
894 (dp->iobase == sp->iobase))
896 if ((dp->irq > 0) && /* irq conflict? */
897 (dp->irq == sp->irq))
899 if ((dp->drq > 0) && /* drq conflict? */
900 (dp->drq == sp->drq))
902 if ((sp->maddr > 0) && /* maddr/msize conflict? */
904 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
905 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
908 count += dp->conflicts; /* count conflicts */
917 ** Unzooms all headings in (list)
920 expandlist(DEV_LIST *list)
924 if (list->comment == DEV_COMMENT)
925 list->comment = DEV_ZOOMED;
934 ** Zooms all headings in (list)
937 collapselist(DEV_LIST *list)
941 if (list->comment == DEV_ZOOMED)
942 list->comment = DEV_COMMENT;
949 ** Screen-manipulation stuff
951 ** This is the basic screen layout :
953 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
954 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
955 ** +--------------------------------------------------------------------------------+
956 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
957 ** 1 -| ........................ ....... .. 0x....|
958 ** 2 -| ........................ ....... .. 0x....|
959 ** 3 -| ........................ ....... .. 0x....|
960 ** 4 -| ........................ ....... .. 0x....|
961 ** 5 -| ........................ ....... .. 0x....|
962 ** 6 -| ........................ ....... .. 0x....|
963 ** 7 -| ........................ ....... .. 0x....|
964 ** 8 -| ........................ ....... .. 0x....|
965 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
966 ** 10-| ........................ ....... |
967 ** 11-| ........................ ....... |
968 ** 12-| ........................ ....... |
969 ** 13-| ........................ ....... |
970 ** 14-| ........................ ....... |
971 ** 15-| ........................ ....... |
972 ** 16-| ........................ ....... |
973 ** 17-|------------------------------------------------------UP-DOWN-------------------|
974 ** 18-| Relevant parameters for the current device |
977 ** 21-|--------------------------------------------------------------------------------|
978 ** 22-| Help texts go here |
980 ** +--------------------------------------------------------------------------------+
984 ** On a collapsed comment :
986 ** [Enter] Expand device list [z] Expand all lists
987 ** [TAB] Change fields [Q] Save and Exit
989 ** On an expanded comment :
991 ** [Enter] Collapse device list [Z] Collapse all lists
992 ** [TAB] Change fields [Q] Save and Exit
994 ** On a comment with no followers
997 ** [TAB] Change fields [Q] Save and Exit
999 ** On a device in the active list
1001 ** [Enter] Edit device parameters [DEL] Disable device
1002 ** [TAB] Change fields [Q] Save and Exit [?] Help
1004 ** On a device in the inactive list
1006 ** [Enter] Enable device
1007 ** [TAB] Change fields [Q] Save and Exit [?] Help
1009 ** While editing parameters
1011 ** <parameter-specific help here>
1012 ** [TAB] Change fields [Q] Save device parameters
1019 ** The base-level screen primitives :
1021 ** bold() - enter bold mode \E[1m (md)
1022 ** inverse() - enter inverse mode \E[7m (so)
1023 ** normal() - clear bold/inverse mode \E[m (se)
1024 ** clear() - clear the screen \E[H\E[J (ce)
1025 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1050 kprintf("\033[H\033[J");
1056 kprintf("\033[%d;%dH",y+1,x+1);
1062 ** High-level screen primitives :
1064 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1065 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1066 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1067 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1068 ** putmsg(str) - put (str) in the message area
1069 ** puthelp(str) - put (str) in the upper helpline
1070 ** pad(str,len) - pad (str) to (len) with spaces
1071 ** drawline(row,detail,list,inverse,*dhelp)
1072 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1073 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1074 ** draw the line in inverse video, and display (*dhelp) on the
1076 ** drawlist(row,num,detail,list)
1077 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1078 ** through to drawline().
1079 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1080 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1081 ** redraw(); - Redraws the entire screen layout, including the
1082 ** - two list panels.
1087 ** writes (str) at x,y onscreen
1089 ** writes up to (len) of (str) at x,y onscreen.
1091 ** Supports embedded formatting :
1092 ** !i - inverse mode.
1094 ** !n - normal mode.
1097 putxyl(int x, int y, char *str, int len)
1102 while((*str) && (len--))
1104 if (*str == '!') /* format escape? */
1106 switch(*(str+1)) /* depending on the next character */
1110 str +=2; /* skip formatting */
1111 len++; /* doesn't count for length */
1116 str +=2; /* skip formatting */
1117 len++; /* doesn't count for length */
1122 str +=2; /* skip formatting */
1123 len++; /* doesn't count for length */
1127 kprintf("%c", *str++); /* not an escape */
1130 kprintf("%c", *str++); /* emit the character */
1135 #define putxy(x,y,str) putxyl(x,y,str,-1)
1141 ** Erases the region (x,y,w,h)
1144 erase(int x, int y, int w, int h)
1149 for (i = 0; i < h; i++)
1150 putxyl(x,y++,spaces,w);
1157 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1158 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1161 txtbox(int x, int y, int w, int h, char *str)
1166 while((str[i]) && h)
1168 if (str[i] == '\n') /* newline */
1170 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1171 y++; /* move down */
1172 h--; /* room for one less */
1173 str += (i+1); /* skip first newline */
1174 i = 0; /* zero offset */
1176 i++; /* next character */
1179 if (h) /* end of string, not region */
1187 ** writes (msg) in the helptext area
1192 erase(0,18,80,3); /* clear area */
1193 txtbox(0,18,80,3,msg);
1200 ** Writes (msg) in the helpline area
1213 ** Draws the help message at the bottom of the screen
1216 masterhelp(char *msg)
1226 ** space-pads a (str) to (len) characters
1229 pad(char *str, int len)
1233 for (i = 0; str[i]; i++) /* find the end of the string */
1235 if (i >= len) /* no padding needed */
1237 while(i < len) /* pad */
1246 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1247 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1249 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1250 ** help is shown for normal or zoomed comments
1253 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1255 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1257 if (list->comment == DEV_DEVICE)
1260 strncpy(nb+1,list->name,57);
1262 strncpy(nb,list->name,58);
1263 if ((list->comment == DEV_ZOOMED) && (list->next))
1264 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1265 strcat(nb," (Collapsed)");
1269 if (list->conflicts) /* device in conflict? */
1273 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1275 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1278 if (list->comment == DEV_DEVICE)
1280 ksprintf(db,"%s%d",list->dev,list->unit);
1285 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1287 ksprintf(ib," %d",list->irq);
1292 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1294 ksprintf(pb,"0x%x",list->iobase);
1300 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1302 putxyl(0,row,lbuf,80);
1305 switch(list->comment)
1307 case DEV_DEVICE: /* ordinary device */
1313 if (list->next->comment == DEV_DEVICE)
1314 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1319 if (list->next->comment == DEV_DEVICE)
1320 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1323 puthelp(" WARNING: This list entry corrupted!");
1327 move(0,row); /* put the cursor somewhere relevant */
1334 ** Displays (num) lines of the contents of (list) at (row), optionally
1335 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1338 drawlist(int row, int num, int detail, DEV_LIST *list)
1342 for(ofs = 0; ofs < num; ofs++)
1346 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1347 list = nextent(list); /* move down visible list */
1349 erase(0,row+ofs,80,1);
1358 ** Redraws the active list
1367 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1370 putxyl(45,0,lines,16);
1372 drawlist(1,8,1,alist); /* draw device lists */
1378 ** Redraws the inactive list
1381 redrawinactive(void)
1383 drawlist(10,7,0,ilist); /* draw device lists */
1390 ** Clear the screen and redraw the entire layout
1397 putxy(3,0,"!bActive!n-!bDrivers");
1398 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1400 putxy(3,9,"!bInactive!n-!bDrivers");
1401 putxy(63,9,"!bDev");
1404 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1414 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1415 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1418 yesnocancel(char *str)
1444 ** Show device parameters in the region below the lists
1446 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1447 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1448 ** +--------------------------------------------------------------------------------+
1449 ** 17-|--------------------------------------------------------------------------------|
1450 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1451 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1452 ** 20-| Flags : 0x0000 DRQ number : 00 |
1453 ** 21-|--------------------------------------------------------------------------------|
1456 showparams(DEV_LIST *dev)
1460 erase(0,18,80,3); /* clear area */
1463 if (dev->comment != DEV_DEVICE)
1467 if (dev->iobase > 0)
1469 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1475 ksprintf(buf,"IRQ number : %d",dev->irq);
1478 ksprintf(buf,"Flags : 0x%x",dev->flags);
1482 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1487 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1493 ksprintf(buf,"DRQ number : %d",dev->drq);
1500 ** Editing functions for device parameters
1502 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1503 ** onscreen. Refuse values outsise (min) and (max).
1504 ** editparams(dev) - Edit the parameters for (dev)
1508 #define VetRet(code) \
1510 if ((i >= min) && (i <= max)) /* legit? */ \
1513 ksprintf(buf,hex?"0x%x":"%d",i); \
1514 putxy(hex?x-2:x,y,buf); \
1515 return(code); /* all done and exit */ \
1517 i = *val; /* restore original value */ \
1518 delta = 1; /* restore other stuff */ \
1525 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1526 ** in a field (width) wide. (Allow one space)
1527 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1529 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1532 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1534 int i = *val; /* work with copy of the value */
1535 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1536 int xp = 0; /* cursor offset into text copy */
1537 int delta = 1; /* force redraw first time in */
1539 int extended = 0; /* stage counter for extended key sequences */
1541 if (hex) /* we presume there's a leading 0x onscreen */
1542 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1546 if (delta) /* only update if necessary */
1548 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1549 ksprintf(buf,"!i%s",tc); /* format for printing */
1550 erase(x,y,width,1); /* clear the area */
1551 putxy(x,y,buf); /* write */
1552 xp = strlen(tc); /* cursor always at end */
1553 move(x+xp,y); /* position the cursor */
1558 switch(extended) /* escape handling */
1561 if (c == 0x1b) /* esc? */
1563 extended = 1; /* flag and spin */
1567 break; /* nope, drop through */
1569 case 1: /* there was an escape prefix */
1570 if (c == '[' || c == 'O') /* second character in sequence */
1576 return(KEY_EXIT); /* double esc exits */
1578 break; /* nup, not a sequence. */
1582 switch(c) /* looks like the real McCoy */
1585 VetRet(KEY_UP); /* leave if OK */
1588 VetRet(KEY_DOWN); /* leave if OK */
1591 VetRet(KEY_RIGHT); /* leave if OK */
1594 VetRet(KEY_LEFT); /* leave if OK */
1604 case '\t': /* trying to tab off */
1605 VetRet(KEY_TAB); /* verify and maybe return */
1615 case '\177': /* BS or DEL */
1616 if (ro) /* readonly? */
1618 puthelp(" !iThis value cannot be edited (Press ESC)");
1619 while(kgetchar() != 0x1b); /* wait for key */
1620 return(KEY_NULL); /* spin */
1622 if (xp) /* still something left to delete */
1624 i = (hex ? i/0x10u : i/10); /* strip last digit */
1625 delta = 1; /* force update */
1648 if (ro) /* readonly? */
1650 puthelp(" !iThis value cannot be edited (Press ESC)");
1651 while(kgetchar() != 0x1b); /* wait for key */
1652 return(KEY_NULL); /* spin */
1654 if (xp >= width) /* no room for more characters anyway */
1658 if ((c >= '0') && (c <= '9'))
1660 i = i*0x10 + (c-'0'); /* update value */
1664 if ((c >= 'a') && (c <= 'f'))
1666 i = i*0x10 + (c-'a'+0xa);
1670 if ((c >= 'A') && (c <= 'F'))
1672 i = i*0x10 + (c-'A'+0xa);
1677 if ((c >= '0') && (c <= '9'))
1679 i = i*10 + (c-'0'); /* update value */
1680 delta = 1; /* force redraw */
1693 ** Edit the parameters for (dev)
1695 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1696 ** possible for this to spin in an endless loop...
1697 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1698 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1699 ** +--------------------------------------------------------------------------------+
1700 ** 17-|--------------------------------------------------------------------------------|
1701 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1702 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1703 ** 20-| Flags : 0x0000 DRQ number : 00 |
1704 ** 21-|--------------------------------------------------------------------------------|
1706 ** The "intelligence" in this function that hops around based on the directional
1707 ** returns from editval isn't very smart, and depends on the layout above.
1710 editparams(DEV_LIST *dev)
1713 char buf[16]; /* needs to fit the device name */
1715 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1716 ksprintf(buf,"!b%s",dev->dev);
1723 if (dev->iobase > 0)
1725 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1726 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1746 puthelp(" Interrupt number (Decimal, 1-15)");
1747 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1759 if (dev->iobase > 0)
1770 puthelp(" Device-specific flag values.");
1771 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1785 if (dev->iobase > 0)
1805 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1806 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1813 if (dev->iobase > 0)
1835 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1836 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1865 puthelp(" Device DMA request number (Decimal, 1-7)");
1866 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1889 dev->changed = 1; /* mark as changed */
1892 static char *helptext[] =
1894 " Using the UserConfig kernel settings editor",
1895 " -------------------------------------------",
1901 "The screen displays a list of available drivers, divided into two",
1902 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1903 "by default collapsed and can be expanded to show all the drivers",
1904 "available in each category. The parameters for the currently selected",
1905 "driver are shown at the bottom of the screen.",
1907 "- - Moving around -",
1909 "To move in the current list, use the UP and DOWN cursor keys to select",
1910 "an item (the selected item will be highlighted). If the item is a",
1911 "category name, you may alternatively expand or collapse the list of",
1912 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1913 "expanded, you can select each driver in the same manner and either:",
1915 " - change its parameters using [!bENTER!n]",
1916 " - move it to the Inactive list using [!bDEL!n]",
1918 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1919 "you need to move a driver from the Inactive list back to the Active",
1920 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1921 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1922 "its place in the Active list.",
1924 "- - Altering the list/parameters -",
1926 "Any drivers for devices not installed in your system should be moved",
1927 "to the Inactive list, until there are no remaining parameter conflicts",
1928 "between the drivers, as indicated at the top.",
1930 "Once the list of Active drivers only contains entries for the devices",
1931 "present in your system, you can set their parameters (Interrupt, DMA",
1932 "channel, I/O addresses). To do this, select the driver and press",
1933 "[!bENTER!n]: it is now possible to edit the settings at the",
1934 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1935 "finished, use [!bQ!n] to return to the list.",
1937 "- - Saving changes -",
1939 "When all settings seem correct, and you wish to proceed with the",
1940 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1941 "confirm your choice.",
1950 ** Displays help text onscreen for people that are confused, using a simple
1956 int topline = 0; /* where we are in the text */
1957 int line = 0; /* last line we displayed */
1961 for (;;) /* loop until user quits */
1963 /* display help text */
1966 clear(); /* remove everything else */
1967 for (line = topline;
1968 (line < (topline + 24)) && (helptext[line]);
1970 putxy(0,line-topline,helptext[line]);
1975 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1978 c = kgetchar(); /* so what do they say? */
1985 case 'B': /* wired into 'more' users' fingers */
1986 if (topline > 0) /* room to go up? */
1989 if (topline < 0) /* don't go too far */
1997 case ' ': /* expected by most people */
1998 if (helptext[line]) /* maybe more below? */
2007 redraw(); /* restore the screen */
2015 ** High-level control functions
2022 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2023 ** (num) lines, starting at (*ofs) offset from row onscreen.
2024 ** Pass (detail) on to drawing routines.
2026 ** If the user hits a key other than a cursor key, maybe return a code.
2028 ** (*list) points to the device at the top line in the region, (*ofs) is the
2029 ** position of the highlight within the region. All routines below
2030 ** this take only a device and an absolute row : use ofsent() to find the
2031 ** device, and add (*ofs) to (row) to find the absolute row.
2034 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2045 showparams(ofsent(*ofs,*list)); /* show device parameters */
2046 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2050 c = kgetchar(); /* get a character */
2051 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2053 extended = 0; /* no longer */
2056 case 588: /* syscons' idea of 'up' */
2058 if (*ofs) /* just a move onscreen */
2060 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2061 (*ofs)--; /* move up */
2063 lp = prevent(*list); /* can we go up? */
2066 *list = lp; /* yes, move up list */
2067 drawlist(row,num,detail,*list);
2072 case 596: /* dooby-do */
2073 case 'B': /* down */
2074 lp = ofsent(*ofs,*list); /* get current item */
2076 break; /* nothing more to move to */
2077 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2078 if (*ofs < (num-1)) /* room to move onscreen? */
2082 *list = nextent(*list); /* scroll region down */
2083 drawlist(row,num,detail,*list);
2095 case '[': /* cheat : always preceeds cursor move */
2096 case 'O': /* ANSI application key mode */
2105 return(KEY_EXIT); /* user requests exit */
2109 return(KEY_DO); /* "do" something */
2114 return(KEY_DEL); /* "delete" response */
2118 return(KEY_UNZOOM); /* expand everything */
2122 return(KEY_ZOOM); /* collapse everything */
2125 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2126 return(KEY_TAB); /* "move" response */
2128 case '\014': /* ^L, redraw */
2131 case '?': /* helptext */
2143 ** Do the fullscreen config thang
2148 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2152 initlist(&inactive);
2158 conflicts = findconflict(active); /* find conflicts in the active list only */
2166 case 0: /* active devices */
2167 ret = dolist(1,8,1,&actofs,&alist,
2168 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2172 mode = 1; /* swap lists */
2189 collapselist(active);
2194 dp = ofsent(actofs,alist); /* get current device */
2195 if (dp) /* paranoia... */
2197 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2199 if (dp == alist) /* moving top item on list? */
2203 alist = dp->next; /* point list to non-moving item */
2205 alist = dp->prev; /* end of list, go back instead */
2208 if (!dp->next) /* moving last item on list? */
2211 dp->conflicts = 0; /* no conflicts on the inactive list */
2212 movedev(dp,inactive); /* shift to inactive list */
2213 conflicts = findconflict(active); /* update conflict tags */
2215 redrawactive(); /* redraw */
2220 case KEY_DO: /* edit device parameters */
2221 dp = ofsent(actofs,alist); /* get current device */
2222 if (dp) /* paranoia... */
2224 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2226 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2228 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2230 conflicts = findconflict(active); /* update conflict tags */
2231 }else{ /* DO on comment = zoom */
2232 switch(dp->comment) /* Depends on current state */
2234 case DEV_COMMENT: /* not currently zoomed */
2235 dp->comment = DEV_ZOOMED;
2239 dp->comment = DEV_COMMENT;
2249 case 1: /* inactive devices */
2250 ret = dolist(10,7,0,&inactofs,&ilist,
2251 " [!bEnter!n] Enable device ");
2265 expandlist(inactive);
2272 collapselist(inactive);
2277 dp = ofsent(inactofs,ilist); /* get current device */
2278 if (dp) /* paranoia... */
2280 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2282 if (dp == ilist) /* moving top of list? */
2286 ilist = dp->next; /* point list to non-moving item */
2288 ilist = dp->prev; /* can't go down, go up instead */
2291 if (!dp->next) /* last entry on list? */
2292 inactofs--; /* shift cursor up one */
2295 movedev(dp,active); /* shift to active list */
2296 conflicts = findconflict(active); /* update conflict tags */
2298 alist = dp; /* put at top and current */
2300 while(dp->comment == DEV_DEVICE)
2301 dp = dp->prev; /* forcibly unzoom section */
2302 dp ->comment = DEV_COMMENT;
2303 mode = 0; /* and swap modes to follow it */
2305 }else{ /* DO on comment = zoom */
2306 switch(dp->comment) /* Depends on current state */
2308 case DEV_COMMENT: /* not currently zoomed */
2309 dp->comment = DEV_ZOOMED;
2313 dp->comment = DEV_COMMENT;
2317 redrawactive(); /* redraw */
2322 default: /* nothing else relevant here */
2327 mode = 0; /* shouldn't happen... */
2330 /* handle returns that are the same for both modes */
2337 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2340 case 2: /* cancel */
2344 case 1: /* save and exit */
2346 savelist(inactive,0);
2349 nukelist(active); /* clean up after ourselves */
2359 #endif /* VISUAL_USERCONFIG */
2362 * Copyright (c) 1991 Regents of the University of California.
2363 * All rights reserved.
2364 * Copyright (c) 1994 Jordan K. Hubbard
2365 * All rights reserved.
2366 * Copyright (c) 1994 David Greenman
2367 * All rights reserved.
2369 * Many additional changes by Bruce Evans
2371 * This code is derived from software contributed by the
2372 * University of California Berkeley, Jordan K. Hubbard,
2373 * David Greenman and Bruce Evans.
2375 * Redistribution and use in source and binary forms, with or without
2376 * modification, are permitted provided that the following conditions
2378 * 1. Redistributions of source code must retain the above copyright
2379 * notice, this list of conditions and the following disclaimer.
2380 * 2. Redistributions in binary form must reproduce the above copyright
2381 * notice, this list of conditions and the following disclaimer in the
2382 * documentation and/or other materials provided with the distribution.
2383 * 3. All advertising materials mentioning features or use of this software
2384 * must display the following acknowledgement:
2385 * This product includes software developed by the University of
2386 * California, Berkeley and its contributors.
2387 * 4. Neither the name of the University nor the names of its contributors
2388 * may be used to endorse or promote products derived from this software
2389 * without specific prior written permission.
2391 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2392 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2393 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2394 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2395 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2396 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2397 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2398 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2399 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2400 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2403 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2406 #define PARM_DEVSPEC 0x1
2407 #define PARM_INT 0x2
2408 #define PARM_ADDR 0x3
2409 #define PARM_STRING 0x4
2411 typedef struct _cmdparm {
2414 struct uc_device *dparm;
2423 typedef int (*CmdFunc)(CmdParm *);
2425 typedef struct _cmd {
2433 static void lsscsi(void);
2434 static int list_scsi(CmdParm *);
2437 static int lsdevtab(struct uc_device *);
2438 static struct uc_device *find_device(char *, int);
2439 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2440 static void cngets(char *, int);
2441 static Cmd *parse_cmd(char *);
2442 static int parse_args(const char *, CmdParm *);
2443 static int save_dev(struct uc_device *);
2445 static int list_devices(CmdParm *);
2446 static int set_device_ioaddr(CmdParm *);
2447 static int set_device_irq(CmdParm *);
2448 static int set_device_drq(CmdParm *);
2449 static int set_device_iosize(CmdParm *);
2450 static int set_device_mem(CmdParm *);
2451 static int set_device_flags(CmdParm *);
2452 static int set_device_enable(CmdParm *);
2453 static int set_device_disable(CmdParm *);
2454 static int quitfunc(CmdParm *);
2455 static int helpfunc(CmdParm *);
2456 static int introfunc(CmdParm *);
2459 static int lspnp(void);
2460 static int set_pnp_parms(CmdParm *);
2465 static CmdParm addr_parms[] = {
2466 { PARM_DEVSPEC, {} },
2471 static CmdParm int_parms[] = {
2472 { PARM_DEVSPEC, {} },
2477 static CmdParm dev_parms[] = {
2478 { PARM_DEVSPEC, {} },
2483 static CmdParm string_arg[] = {
2484 { PARM_STRING, {} },
2489 static Cmd CmdList[] = {
2490 { "?", helpfunc, NULL }, /* ? (help) */
2491 { "di", set_device_disable, dev_parms }, /* disable dev */
2492 { "dr", set_device_drq, int_parms }, /* drq dev # */
2493 { "en", set_device_enable, dev_parms }, /* enable dev */
2494 { "ex", quitfunc, NULL }, /* exit (quit) */
2495 { "f", set_device_flags, int_parms }, /* flags dev mask */
2496 { "h", helpfunc, NULL }, /* help */
2497 { "intro", introfunc, NULL }, /* intro screen */
2498 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2499 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2500 { "ir", set_device_irq, int_parms }, /* irq dev # */
2501 { "l", list_devices, NULL }, /* ls, list */
2503 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2505 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2506 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2507 { "q", quitfunc, NULL }, /* quit */
2509 { "s", list_scsi, NULL }, /* scsi */
2511 #ifdef VISUAL_USERCONFIG
2512 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2514 { NULL, NULL, NULL },
2520 static char banner = 1;
2526 init_config_script();
2529 /* Only display signon banner if we are about to go interactive */
2530 if (!has_config_script()) {
2531 if (!(boothowto & RB_CONFIG))
2532 #ifdef INTRO_USERCONFIG
2539 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2540 " Type \"help\" for help"
2541 #ifdef VISUAL_USERCONFIG
2542 " or \"visual\" to go to the visual\n"
2543 " configuration interface (requires MGA/VGA display or\n"
2544 " serial terminal capable of displaying ANSI graphics)"
2550 kprintf("config> ");
2552 if (input[0] == '\0')
2554 cmd = parse_cmd(input);
2556 kprintf("Invalid command or syntax. Type `?' for help.\n");
2559 rval = (*cmd->handler)(cmd->parms);
2568 parse_cmd(char *cmd)
2572 for (cp = CmdList; cp->name; cp++) {
2573 int len = strlen(cp->name);
2575 if (!strncmp(cp->name, cmd, len)) {
2576 while (*cmd && *cmd != ' ' && *cmd != '\t')
2578 if (parse_args(cmd, cp->parms))
2588 parse_args(const char *cmd, CmdParm *parms)
2593 if (*cmd == ' ' || *cmd == '\t') {
2597 if (parms == NULL || parms->type == -1) {
2600 kprintf("Extra arg(s): %s\n", cmd);
2603 if (parms->type == PARM_DEVSPEC) {
2608 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2609 (*cmd >= '0' && *cmd <= '9')))
2610 devname[i++] = *(cmd++);
2612 if (*cmd >= '0' && *cmd <= '9') {
2613 unit = strtoul(cmd, &ptr, 10);
2615 kprintf("Invalid device number\n");
2616 /* XXX should print invalid token here and elsewhere. */
2619 /* XXX else should require end of token. */
2622 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2623 kprintf("No such device: %s%d\n", devname, unit);
2629 if (parms->type == PARM_INT) {
2630 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2632 kprintf("Invalid numeric argument\n");
2639 if (parms->type == PARM_ADDR) {
2640 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2642 kprintf("Invalid address argument\n");
2649 if (parms->type == PARM_STRING) {
2650 parms->parm.u.sparm = cmd;
2658 list_devices(CmdParm *parms)
2661 if (lsdevtab(uc_devtab)) return 0;
2663 if (lspnp()) return 0;
2669 set_device_ioaddr(CmdParm *parms)
2671 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2672 save_dev(parms[0].parm.dparm);
2677 set_device_irq(CmdParm *parms)
2681 irq = parms[1].parm.iparm;
2683 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2686 else if (irq != -1 && irq > 15) {
2687 kprintf("An IRQ > 15 would be invalid.\n");
2690 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2691 save_dev(parms[0].parm.dparm);
2696 set_device_drq(CmdParm *parms)
2701 * The bounds checking is just to ensure that the value can be printed
2702 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2704 drq = parms[1].parm.iparm;
2705 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2706 save_dev(parms[0].parm.dparm);
2711 set_device_iosize(CmdParm *parms)
2713 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2714 save_dev(parms[0].parm.dparm);
2719 set_device_mem(CmdParm *parms)
2721 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2722 save_dev(parms[0].parm.dparm);
2727 set_device_flags(CmdParm *parms)
2729 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2730 save_dev(parms[0].parm.dparm);
2735 set_device_enable(CmdParm *parms)
2737 parms[0].parm.dparm->id_enabled = TRUE;
2738 save_dev(parms[0].parm.dparm);
2743 set_device_disable(CmdParm *parms)
2745 parms[0].parm.dparm->id_enabled = FALSE;
2746 save_dev(parms[0].parm.dparm);
2753 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2759 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2762 * Output the pnp_ldn_overrides[] table.
2764 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2765 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2766 if(error) return(error);
2771 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2772 0, 0, sysctl_machdep_uc_pnplist, "A",
2773 "List of PnP overrides changed in UserConfig");
2776 * this function sets the kernel table to override bios PnP
2780 set_pnp_parms(CmdParm *parms)
2782 u_long idx, val, ldn, csn;
2785 const char *p = parms[0].parm.u.sparm;
2788 csn=strtoul(p,&q, 0);
2789 ldn=strtoul(q,&q, 0);
2790 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2791 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2792 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2795 for (i=0; i < MAX_PNP_LDN; i++) {
2796 if (pnp_ldn_overrides[i].csn == csn &&
2797 pnp_ldn_overrides[i].ldn == ldn)
2800 if (i==MAX_PNP_LDN) {
2801 for (i=0; i < MAX_PNP_LDN; i++) {
2802 if (pnp_ldn_overrides[i].csn <1 ||
2803 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2807 if (i==MAX_PNP_LDN) {
2808 kprintf("sorry, no PnP entries available, try delete one\n");
2811 d = pnp_ldn_overrides[i] ;
2817 if (!strncmp(p,"irq",3)) {
2818 idx=strtoul(p+3,&q, 0);
2819 val=strtoul(q,&q, 0);
2820 if (idx >=0 && idx < 2) d.irq[idx] = val;
2821 } else if (!strncmp(p,"flags",5)) {
2822 idx=strtoul(p+5,&q, 0);
2824 } else if (!strncmp(p,"drq",3)) {
2825 idx=strtoul(p+3,&q, 0);
2826 val=strtoul(q,&q, 0);
2827 if (idx >=0 && idx < 2) d.drq[idx] = val;
2828 } else if (!strncmp(p,"port",4)) {
2829 idx=strtoul(p+4,&q, 0);
2830 val=strtoul(q,&q, 0);
2831 if (idx >=0 && idx < 8) d.port[idx] = val;
2832 } else if (!strncmp(p,"mem",3)) {
2833 idx=strtoul(p+3,&q, 0);
2834 val=strtoul(q,&q, 0);
2835 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2836 } else if (!strncmp(p,"bios",4)) {
2839 } else if (!strncmp(p,"os",2)) {
2842 } else if (!strncmp(p,"disable",7)) {
2845 } else if (!strncmp(p,"enable",6)) {
2848 } else if (!strncmp(p,"delete",6)) {
2849 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2850 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2853 kprintf("unknown command <%s>\n", p);
2856 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2858 pnp_ldn_overrides[i] = d ;
2864 quitfunc(CmdParm *parms)
2867 * If kernel config supplied, and we are parsing it, and -c also supplied,
2868 * ignore a quit command, This provides a safety mechanism to allow
2869 * recovery from a damaged/buggy kernel config.
2871 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2877 helpfunc(CmdParm *parms)
2880 "Command\t\t\tDescription\n"
2881 "-------\t\t\t-----------\n"
2882 "ls\t\t\tList currently configured devices\n"
2883 "port <devname> <addr>\tSet device port (i/o address)\n"
2884 "irq <devname> <number>\tSet device irq\n"
2885 "drq <devname> <number>\tSet device drq\n"
2886 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2887 "iosize <devname> <size>\tSet device memory size\n"
2888 "flags <devname> <mask>\tSet device flags\n"
2889 "enable <devname>\tEnable device\n"
2890 "disable <devname>\tDisable device (will not be probed)\n");
2893 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2894 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2895 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2896 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2897 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2898 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2901 "quit\t\t\tExit this configuration utility\n"
2902 "reset\t\t\tReset CPU\n");
2903 #ifdef VISUAL_USERCONFIG
2904 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2907 "help\t\t\tThis message\n\n"
2908 "Commands may be abbreviated to a unique prefix\n");
2912 #if defined (VISUAL_USERCONFIG)
2914 center(int y, char *str)
2916 putxy((80 - strlen(str)) / 2, y, str);
2921 introfunc(CmdParm *parms)
2923 #if defined (VISUAL_USERCONFIG)
2924 int curr_item, first_time, extended = 0;
2925 static char *choices[] = {
2926 " Skip kernel configuration and continue with installation ",
2927 " Start kernel configuration in full-screen visual mode ",
2928 " Start kernel configuration in CLI mode ",
2932 center(2, "!bKernel Configuration Menu!n");
2941 for (i = 0; i < 3; i++) {
2945 strcat(tmp, choices[i]);
2948 putxy(10, 5 + i, tmp);
2952 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2953 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2954 putxy(2, 12, "match your hardware configuration.");
2955 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2956 putxy(2, 15, "(press Down-Arrow then ENTER).");
2957 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2958 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2959 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2960 putxy(2, 21, "then simply press ENTER or Q now.");
2964 move(0, 0); /* move the cursor out of the way */
2967 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2968 extended = 0; /* no longer */
2977 case 'B': /* down */
2989 case '[': /* cheat : always preceeds cursor move */
2990 case 'O': /* ANSI application key mode */
3001 return 1; /* user requests exit */
3003 case '1': /* select an item */
3027 case 'D': /* down */
3040 else if (curr_item == 1)
3041 return visuserconfig();
3043 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3044 /* enable quitfunc */
3045 userconfig_boot_parsing=0;
3047 boothowto |= RB_CONFIG; /* force -c */
3061 struct pnp_cinfo *c;
3065 for (i=0; i< MAX_PNP_LDN; i++) {
3066 c = &pnp_ldn_overrides[i];
3067 if (c->csn >0 && c->csn != 255) {
3069 static char pfmt[] =
3070 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3071 static char mfmt[] =
3072 "mem 0x%x 0x%x 0x%x 0x%x";
3075 if (!userconfig_boot_parsing) {
3077 if (kgetchar() == 'q') {
3085 if (lineno == 0 || first)
3086 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3088 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3090 c->override ? "OS ":"BIOS",
3091 c->enable ? "Y":"N",
3092 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3094 kprintf("flags 0x%08lx ",c->flags);
3095 for (pmax = 7; pmax >=0 ; pmax--)
3096 if (c->port[pmax]!=0) break;
3097 for (mmax = 3; mmax >=0 ; mmax--)
3098 if (c->mem[mmax].base!=0) break;
3101 buf[10 + 5*pmax]='\0';
3103 c->port[0], c->port[1], c->port[2], c->port[3],
3104 c->port[4], c->port[5], c->port[6], c->port[7]);
3108 buf[8 + 5*mmax]='\0';
3110 c->mem[0].base, c->mem[1].base,
3111 c->mem[2].base, c->mem[3].base);
3121 lsdevtab(struct uc_device *dt)
3123 for (; dt->id_id != 0; dt++) {
3128 if (!userconfig_boot_parsing) {
3129 if (kgetchar() == 'q') {
3139 "Device port irq drq iomem iosize unit flags enab\n"
3143 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3144 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3145 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3146 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3147 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3148 dt->id_enabled ? "Yes" : "No");
3158 int count = resource_count();
3164 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3167 for (i = 0; i < count; i++) {
3168 name = resource_query_name(i);
3169 unit = resource_query_unit(i);
3171 continue; /* skip wildcards */
3172 uc_devtab[dt].id_id = id++;
3173 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3175 resource_int_value(name, unit, "irq", &val);
3176 uc_devtab[dt].id_irq = (1 << val);
3177 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3178 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3179 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3180 uc_devtab[dt].id_unit = unit;
3181 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3183 resource_int_value(name, unit, "disabled", &val);
3184 uc_devtab[dt].id_enabled = !val;
3185 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3186 strcpy(uc_devtab[dt].id_name, name);
3195 int count = resource_count();
3197 for (i = 0; i < count; i++)
3198 if (uc_devtab[i].id_name)
3199 kfree(uc_devtab[i].id_name, M_DEVL);
3200 kfree(uc_devtab, M_DEVL);
3203 static struct uc_device *
3204 find_device(char *devname, int unit)
3206 struct uc_device *ret;
3208 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3213 static struct uc_device *
3214 search_devtable(struct uc_device *dt, char *devname, int unit)
3216 for (; dt->id_id != 0; dt++)
3217 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3223 cngets(char *input, int maxin)
3229 /* Treat ^H or ^? as backspace */
3230 if ((c == '\010' || c == '\177')) {
3232 kprintf("\010 \010");
3233 *--input = '\0', --nchars;
3237 /* Treat ^U or ^X as kill line */
3238 else if ((c == '\025' || c == '\030')) {
3240 kprintf("\010 \010");
3241 *--input = '\0', --nchars;
3246 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3250 *input++ = (u_char)c;
3256 /* scsi: Support for displaying configured SCSI devices.
3257 * There is no way to edit them, and this is inconsistent
3258 * with the ISA method. This is here as a basis for further work.
3261 type_text(char *name) /* XXX: This is bogus */
3263 if (strcmp(name, "sd") == 0)
3266 if (strcmp(name, "st") == 0)
3272 id_put(char *desc, int id)
3274 if (id != SCCONF_UNSPEC)
3277 kprintf("%s", desc);
3279 if (id == SCCONF_ANY)
3291 kprintf("scsi: (can't be edited):\n");
3293 for (i = 0; scsi_cinit[i].driver; i++)
3295 id_put("controller scbus", scsi_cinit[i].scbus);
3297 if (scsi_cinit[i].unit != -1)
3300 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3306 for (i = 0; scsi_dinit[i].name; i++)
3308 kprintf("%s ", type_text(scsi_dinit[i].name));
3310 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3311 id_put(" at scbus", scsi_dinit[i].cunit);
3312 id_put(" target ", scsi_dinit[i].target);
3313 id_put(" lun ", scsi_dinit[i].lun);
3315 if (scsi_dinit[i].flags)
3316 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3323 list_scsi(CmdParm *parms)
3332 save_resource(struct uc_device *idev)
3337 name = idev->id_name;
3338 unit = idev->id_unit;
3339 resource_set_int(name, unit, "port", idev->id_iobase);
3340 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3341 resource_set_int(name, unit, "drq", idev->id_drq);
3342 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3343 resource_set_int(name, unit, "msize", idev->id_msize);
3344 resource_set_int(name, unit, "flags", idev->id_flags);
3345 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3349 save_dev(struct uc_device *idev)
3351 struct uc_device *id_p,*id_pn;
3352 char *name = idev->id_name;
3354 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3355 if (id_p->id_id == idev->id_id) {
3356 id_pn = id_p->id_next;
3358 kfree(id_p->id_name, M_DEVL);
3359 bcopy(idev,id_p,sizeof(struct uc_device));
3360 save_resource(idev);
3361 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3362 strcpy(id_p->id_name, name);
3363 id_p->id_next = id_pn;
3367 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3368 bcopy(idev,id_pn,sizeof(struct uc_device));
3369 save_resource(idev);
3370 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3371 strcpy(id_pn->id_name, name);
3372 id_pn->id_next = uc_devlist;