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"
101 #include <sys/param.h>
102 #include <sys/systm.h>
103 #include <sys/kernel.h>
104 #include <sys/malloc.h>
105 #include <sys/reboot.h>
106 #include <sys/linker.h>
107 #include <sys/sysctl.h>
109 #include <sys/cons.h>
111 #include <machine/md_var.h>
112 #include <machine/limits.h>
114 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
120 #include <machine_base/isa/pnp.h>
123 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
125 #include <machine/uc_device.h>
126 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
127 static struct uc_device *uc_devtab; /* fake uc_device table */
129 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
131 static void load_devtab(void);
132 static void free_devtab(void);
133 static void save_resource(struct uc_device *);
136 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
138 struct uc_device *id;
146 error+=sizeof(struct uc_device)+8;
149 return(SYSCTL_OUT(req,0,error));
151 /* Output the data. The buffer is filled with consecutive
152 * struct uc_device and char buf[8], containing the name
153 * (not guaranteed to end with '\0').
157 error=sysctl_handle_opaque(oidp,id,
158 sizeof(struct uc_device),req);
159 if(error) return(error);
160 strncpy(name,id->id_name,8);
161 error=sysctl_handle_opaque(oidp,name,
163 if(error) return(error);
170 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
171 0, 0, sysctl_machdep_uc_devlist, "A",
172 "List of ISA devices changed in UserConfig");
175 ** Obtain command input.
177 ** Initially, input is read from a possibly-loaded script.
178 ** At the end of the script, or if no script is supplied,
179 ** behaviour is determined by the RB_CONFIG (-c) flag. If
180 ** the flag is set, user input is read from the console; if
181 ** unset, the 'quit' command is invoked and userconfig
184 ** Note that quit commands encountered in the script will be
185 ** ignored if the RB_CONFIG flag is supplied.
187 static const char *config_script;
188 static int config_script_size; /* use of int for -ve magic value */
190 #define has_config_script() (config_script_size > 0)
193 init_config_script(void)
195 caddr_t autoentry, autoattr;
197 /* Look for loaded userconfig script */
198 autoentry = preload_search_by_type("userconfig_script");
199 if (autoentry != NULL) {
200 /* We have one, get size and data */
201 config_script_size = 0;
202 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
203 config_script_size = (size_t)*(u_int32_t *)autoattr;
204 config_script = NULL;
205 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
206 config_script = *(const char **)autoattr;
208 if ((config_script_size == 0) || (config_script == NULL)) {
209 config_script_size = 0;
210 config_script = NULL;
213 return has_config_script();
220 #ifdef INTRO_USERCONFIG
221 static int intro = 0;
224 if (has_config_script())
226 /* Consume character from loaded userconfig script, display */
227 userconfig_boot_parsing = 1;
230 config_script_size--;
234 #ifdef INTRO_USERCONFIG
235 if (userconfig_boot_parsing) {
236 if (!(boothowto & RB_CONFIG)) {
237 /* userconfig_script, !RB_CONFIG -> quit */
240 config_script = "uit\n";
241 config_script_size = strlen(config_script);
242 /* userconfig_script will be 1 on the next pass */
245 /* userconfig_script, RB_CONFIG -> cngetc() */
248 if (!(boothowto & RB_CONFIG)) {
249 /* no userconfig_script, !RB_CONFIG -> show intro */
253 config_script = "ntro\n";
254 config_script_size = strlen(config_script);
255 /* userconfig_script will be 1 on the next pass */
258 /* no userconfig_script, RB_CONFIG -> cngetc() */
261 #else /* !INTRO_USERCONFIG */
262 /* assert(boothowto & RB_CONFIG) */
263 #endif /* INTRO_USERCONFIG */
264 userconfig_boot_parsing = 0;
273 #define TRUE (!FALSE)
276 #ifdef VISUAL_USERCONFIG
280 char dev[16]; /* device basename */
281 char name[60]; /* long name */
282 int attrib; /* things to do with the device */
283 int class; /* device classification */
286 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
287 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
288 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
289 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
290 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
291 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
292 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
293 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
294 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
296 #define CLS_STORAGE 1 /* storage devices */
297 #define CLS_NETWORK 2 /* network interfaces */
298 #define CLS_COMMS 3 /* serial, parallel ports */
299 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
300 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
301 #define CLS_MISC 255 /* none of the above */
310 static DEVCLASS_INFO devclass_names[] = {
311 { "Storage : ", CLS_STORAGE},
312 { "Network : ", CLS_NETWORK},
313 { "Communications : ", CLS_COMMS},
314 { "Input : ", CLS_INPUT},
315 { "Multimedia : ", CLS_MMEDIA},
316 { "Miscellaneous : ", CLS_MISC},
320 /********************* EDIT THIS LIST **********************/
324 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
325 ** - XXX The list below should be reviewed by the driver authors to verify
326 ** that the correct flags have been set for each driver, and that the
327 ** descriptions are accurate.
330 static DEV_INFO device_info[] = {
331 /*---Name----- ---Description---------------------------------------------- */
332 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
333 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
334 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
335 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
336 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
337 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
338 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
339 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
340 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
341 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
343 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
344 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
345 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
346 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
347 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
348 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
349 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
350 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
351 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
353 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
354 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
355 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
356 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
358 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
359 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
360 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
361 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
362 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
364 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
365 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
366 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
367 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
368 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
369 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
370 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
371 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
372 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
373 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
374 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
375 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
376 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
377 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
378 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
380 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
381 {"pcic", "PC-card controller", 0, CLS_MISC},
382 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
383 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
387 typedef struct _devlist_struct
390 int attrib; /* flag values as per the FLG_* defines above */
391 int class; /* disk, etc as per the CLS_* defines above */
393 int iobase,irq,drq,maddr,msize,unit,flags,id;
394 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
395 int conflicts; /* set/reset by findconflict, count of conflicts */
396 int changed; /* nonzero if the device has been edited */
397 struct uc_device *device;
398 struct _devlist_struct *prev,*next;
403 #define DEV_COMMENT 1
406 #define LIST_CURRENT (1<<0)
407 #define LIST_SELECTED (1<<1)
409 #define KEY_EXIT 0 /* return codes from dolist() and friends */
415 #define KEY_UP 5 /* these only returned from editval() */
419 #define KEY_NULL 9 /* this allows us to spin & redraw */
421 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
422 #define KEY_UNZOOM 11
424 #define KEY_HELP 12 /* duh? */
426 static void redraw(void);
427 static void insdev(DEV_LIST *dev, DEV_LIST *list);
428 static int devinfo(DEV_LIST *dev);
429 static int visuserconfig(void);
431 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
432 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
433 static DEV_LIST scratch; /* scratch record */
434 static int conflicts; /* total conflict count */
437 static char lines[] = "--------------------------------------------------------------------------------";
438 static char spaces[] = " ";
442 ** Device manipulation stuff : find, describe, configure.
448 ** Sets the device referenced by (*dev) to the parameters in the struct,
449 ** and the enable flag according to (enabled)
452 setdev(DEV_LIST *dev, int enabled)
454 dev->device->id_iobase = dev->iobase; /* copy happy */
455 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
456 dev->device->id_drq = (short)dev->drq;
457 dev->device->id_maddr = (caddr_t)dev->maddr;
458 dev->device->id_msize = dev->msize;
459 dev->device->id_flags = dev->flags;
460 dev->device->id_enabled = enabled;
467 ** Walk the kernel device tables and build the active and inactive lists
473 struct uc_device *ap;
475 ap = uc_devtab; /* pointer to array of devices */
476 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
478 scratch.unit = ap[i].id_unit; /* device parameters */
479 strcpy(scratch.dev,ap[i].id_name);
480 scratch.iobase = ap[i].id_iobase;
481 scratch.irq = ffs(ap[i].id_irq)-1;
482 scratch.drq = ap[i].id_drq;
483 scratch.maddr = (int)ap[i].id_maddr;
484 scratch.msize = ap[i].id_msize;
485 scratch.flags = ap[i].id_flags;
487 scratch.comment = DEV_DEVICE; /* admin stuff */
488 scratch.conflicts = 0;
489 scratch.device = &ap[i]; /* save pointer for later reference */
491 if (!devinfo(&scratch)) /* get more info on the device */
492 insdev(&scratch,ap[i].id_enabled?active:inactive);
500 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
501 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
503 ** If the device is marked "invisible", return nonzero; the caller should
504 ** not insert any such device into either list.
508 devinfo(DEV_LIST *dev)
512 for (i = 0; device_info[i].class; i++)
514 if (!strcmp(dev->dev,device_info[i].dev))
516 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
518 strcpy(dev->name,device_info[i].name); /* get the name */
519 dev->attrib = device_info[i].attrib;
520 dev->class = device_info[i].class;
524 strcpy(dev->name,"Unknown device");
526 dev->class = CLS_MISC;
532 ** List manipulation stuff : add, move, initialise, free, traverse
534 ** Note that there are assumptions throughout this code that
535 ** the first entry in a list will never move. (assumed to be
543 ** appends a copy of (dev) to the end of (*list)
546 addev(DEV_LIST *dev, DEV_LIST **list)
551 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
552 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
554 if (*list) /* list exists */
558 ap = ap->next; /* scoot to end of list */
562 }else{ /* list does not yet exist */
564 lp->prev = lp->next = NULL; /* list now exists */
572 ** Finds the 'appropriate' place for (dev) in (list)
574 ** 'Appropriate' means in numeric order with other devices of the same type,
575 ** or in alphabetic order following a comment of the appropriate type.
576 ** or at the end of the list if an appropriate comment is not found. (this should
578 ** (Note that the appropriate point is never the top, but may be the bottom)
581 findspot(DEV_LIST *dev, DEV_LIST *list)
585 /* search for a previous instance of the same device */
586 for (ap = list; ap; ap = ap->next)
588 if (ap->comment != DEV_DEVICE) /* ignore comments */
590 if (!strcmp(dev->dev,ap->dev)) /* same base device */
592 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
593 || !ap->next) /* or end of list */
595 ap = ap->prev; /* back up one */
596 break; /* done here */
598 if (ap->next) /* if the next item exists */
600 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
602 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
608 if (!ap) /* not sure yet */
610 /* search for a class that the device might belong to */
611 for (ap = list; ap; ap = ap->next)
613 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
615 if (dev->class != ap->class) /* of same class too 8) */
617 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
619 ap = ap->prev; /* back up one */
620 break; /* done here */
622 if (ap->next) /* if the next item exists */
623 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
628 if (!ap) /* didn't find a match */
630 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
631 if ((ap->comment != DEV_DEVICE)
632 && (ap->class == dev->class)) /* appropriate place? */
634 } /* or just put up with last */
643 ** Inserts a copy of (dev) at the appropriate point in (list)
646 insdev(DEV_LIST *dev, DEV_LIST *list)
650 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
651 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
653 ap = findspot(lp,list); /* find appropriate spot */
654 lp->next = ap->next; /* point to next */
656 ap->next->prev = lp; /* point next to new */
657 lp->prev = ap; /* point new to current */
658 ap->next = lp; /* and current to new */
665 ** Moves (dev) from its current list to an appropriate place in (list)
666 ** (dev) may not come from the top of a list, but it may from the bottom.
669 movedev(DEV_LIST *dev, DEV_LIST *list)
673 ap = findspot(dev,list);
674 dev->prev->next = dev->next; /* remove from old list */
676 dev->next->prev = dev->prev;
678 dev->next = ap->next; /* insert in new list */
680 ap->next->prev = dev; /* point next to new */
681 dev->prev = ap; /* point new to current */
682 ap->next = dev; /* and current to new */
689 ** Initialises (*list) with the basic headings
692 initlist(DEV_LIST **list)
696 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
698 strcpy(scratch.name,devclass_names[i].name);
699 scratch.comment = DEV_ZOOMED;
700 scratch.class = devclass_names[i].number;
701 scratch.attrib = FLG_MANDATORY; /* can't be moved */
702 addev(&scratch,list); /* add to the list */
710 ** Walks (list) and saves the settings of any entry marked as changed.
712 ** The device's active field is set according to (active).
714 ** Builds the uc_devlist used by kget to extract the changed device information.
715 ** The code for this was taken almost verbatim from the original module.
718 savelist(DEV_LIST *list, int active)
720 struct uc_device *id_p,*id_pn;
725 if ((list->comment == DEV_DEVICE) && /* is a device */
726 (list->changed) && /* has been changed */
727 (list->device != NULL)) { /* has an uc_device structure */
729 setdev(list,active); /* set the device itself */
732 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
733 { /* look on the list for it */
734 if (id_p->id_id == list->device->id_id)
736 name = list->device->id_name;
737 id_pn = id_p->id_next;
739 kfree(id_p->id_name, M_DEVL);
740 bcopy(list->device,id_p,sizeof(struct uc_device));
741 save_resource(list->device);
742 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
743 strcpy(id_p->id_name, name);
744 id_pn->id_next = uc_devlist;
745 id_p->id_next = id_pn;
749 if (!id_pn) /* not already on the list */
751 name = list->device->id_name;
752 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
753 bcopy(list->device,id_pn,sizeof(struct uc_device));
754 save_resource(list->device);
755 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
756 strcpy(id_pn->id_name, name);
757 id_pn->id_next = uc_devlist;
758 uc_devlist = id_pn; /* park at top of list */
769 ** Frees all storage in use by a (list).
772 nukelist(DEV_LIST *list)
778 while(list->prev) /* walk to head of list */
793 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
794 ** if there is no previous entry. (Only possible if list->prev == NULL given the
795 ** premise that there is always a comment at the head of the list)
798 prevent(DEV_LIST *list)
804 dp = list->prev; /* start back one */
807 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
808 return(dp); /* so skip to comment */
809 if (dp->comment == DEV_COMMENT) /* not zoomed */
810 return(list->prev); /* one back as normal */
811 dp = dp->prev; /* backpedal */
813 return(dp); /* NULL, we can assume */
820 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
821 ** if there is no next entry. (Possible if the current entry is last, or
822 ** if the current entry is the last heading and it's collapsed)
825 nextent(DEV_LIST *list)
831 if (list->comment != DEV_ZOOMED) /* no reason to skip */
836 if (dp->comment != DEV_DEVICE) /* found another heading */
840 return(dp); /* back we go */
847 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
850 ofsent(int ofs, DEV_LIST *list)
852 while (ofs-- && list)
853 list = nextent(list);
861 ** Scans every element of (list) and sets the conflict tags appropriately
862 ** Returns the number of conflicts found.
865 findconflict(DEV_LIST *list)
867 int count = 0; /* number of conflicts found */
870 for (dp = list; dp; dp = dp->next) /* over the whole list */
872 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
875 dp->conflicts = 0; /* assume the best */
876 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
878 if (sp->comment != DEV_DEVICE) /* likewise */
881 if (sp == dp) /* always conflict with itself */
884 if ((dp->iobase > 0) && /* iobase conflict? */
885 (dp->iobase == sp->iobase))
887 if ((dp->irq > 0) && /* irq conflict? */
888 (dp->irq == sp->irq))
890 if ((dp->drq > 0) && /* drq conflict? */
891 (dp->drq == sp->drq))
893 if ((sp->maddr > 0) && /* maddr/msize conflict? */
895 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
896 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
899 count += dp->conflicts; /* count conflicts */
908 ** Unzooms all headings in (list)
911 expandlist(DEV_LIST *list)
915 if (list->comment == DEV_COMMENT)
916 list->comment = DEV_ZOOMED;
925 ** Zooms all headings in (list)
928 collapselist(DEV_LIST *list)
932 if (list->comment == DEV_ZOOMED)
933 list->comment = DEV_COMMENT;
940 ** Screen-manipulation stuff
942 ** This is the basic screen layout :
944 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
945 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
946 ** +--------------------------------------------------------------------------------+
947 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
948 ** 1 -| ........................ ....... .. 0x....|
949 ** 2 -| ........................ ....... .. 0x....|
950 ** 3 -| ........................ ....... .. 0x....|
951 ** 4 -| ........................ ....... .. 0x....|
952 ** 5 -| ........................ ....... .. 0x....|
953 ** 6 -| ........................ ....... .. 0x....|
954 ** 7 -| ........................ ....... .. 0x....|
955 ** 8 -| ........................ ....... .. 0x....|
956 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
957 ** 10-| ........................ ....... |
958 ** 11-| ........................ ....... |
959 ** 12-| ........................ ....... |
960 ** 13-| ........................ ....... |
961 ** 14-| ........................ ....... |
962 ** 15-| ........................ ....... |
963 ** 16-| ........................ ....... |
964 ** 17-|------------------------------------------------------UP-DOWN-------------------|
965 ** 18-| Relevant parameters for the current device |
968 ** 21-|--------------------------------------------------------------------------------|
969 ** 22-| Help texts go here |
971 ** +--------------------------------------------------------------------------------+
975 ** On a collapsed comment :
977 ** [Enter] Expand device list [z] Expand all lists
978 ** [TAB] Change fields [Q] Save and Exit
980 ** On an expanded comment :
982 ** [Enter] Collapse device list [Z] Collapse all lists
983 ** [TAB] Change fields [Q] Save and Exit
985 ** On a comment with no followers
988 ** [TAB] Change fields [Q] Save and Exit
990 ** On a device in the active list
992 ** [Enter] Edit device parameters [DEL] Disable device
993 ** [TAB] Change fields [Q] Save and Exit [?] Help
995 ** On a device in the inactive list
997 ** [Enter] Enable device
998 ** [TAB] Change fields [Q] Save and Exit [?] Help
1000 ** While editing parameters
1002 ** <parameter-specific help here>
1003 ** [TAB] Change fields [Q] Save device parameters
1010 ** The base-level screen primitives :
1012 ** bold() - enter bold mode \E[1m (md)
1013 ** inverse() - enter inverse mode \E[7m (so)
1014 ** normal() - clear bold/inverse mode \E[m (se)
1015 ** clear() - clear the screen \E[H\E[J (ce)
1016 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1041 kprintf("\033[H\033[J");
1047 kprintf("\033[%d;%dH",y+1,x+1);
1053 ** High-level screen primitives :
1055 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1056 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1057 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1058 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1059 ** putmsg(str) - put (str) in the message area
1060 ** puthelp(str) - put (str) in the upper helpline
1061 ** pad(str,len) - pad (str) to (len) with spaces
1062 ** drawline(row,detail,list,inverse,*dhelp)
1063 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1064 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1065 ** draw the line in inverse video, and display (*dhelp) on the
1067 ** drawlist(row,num,detail,list)
1068 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1069 ** through to drawline().
1070 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1071 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1072 ** redraw(); - Redraws the entire screen layout, including the
1073 ** - two list panels.
1078 ** writes (str) at x,y onscreen
1080 ** writes up to (len) of (str) at x,y onscreen.
1082 ** Supports embedded formatting :
1083 ** !i - inverse mode.
1085 ** !n - normal mode.
1088 putxyl(int x, int y, char *str, int len)
1093 while((*str) && (len--))
1095 if (*str == '!') /* format escape? */
1097 switch(*(str+1)) /* depending on the next character */
1101 str +=2; /* skip formatting */
1102 len++; /* doesn't count for length */
1107 str +=2; /* skip formatting */
1108 len++; /* doesn't count for length */
1113 str +=2; /* skip formatting */
1114 len++; /* doesn't count for length */
1118 kprintf("%c", *str++); /* not an escape */
1121 kprintf("%c", *str++); /* emit the character */
1126 #define putxy(x,y,str) putxyl(x,y,str,-1)
1132 ** Erases the region (x,y,w,h)
1135 erase(int x, int y, int w, int h)
1140 for (i = 0; i < h; i++)
1141 putxyl(x,y++,spaces,w);
1148 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1149 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1152 txtbox(int x, int y, int w, int h, char *str)
1157 while((str[i]) && h)
1159 if (str[i] == '\n') /* newline */
1161 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1162 y++; /* move down */
1163 h--; /* room for one less */
1164 str += (i+1); /* skip first newline */
1165 i = 0; /* zero offset */
1167 i++; /* next character */
1170 if (h) /* end of string, not region */
1178 ** writes (msg) in the helptext area
1183 erase(0,18,80,3); /* clear area */
1184 txtbox(0,18,80,3,msg);
1191 ** Writes (msg) in the helpline area
1204 ** Draws the help message at the bottom of the screen
1207 masterhelp(char *msg)
1217 ** space-pads a (str) to (len) characters
1220 pad(char *str, int len)
1224 for (i = 0; str[i]; i++) /* find the end of the string */
1226 if (i >= len) /* no padding needed */
1228 while(i < len) /* pad */
1237 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1238 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1240 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1241 ** help is shown for normal or zoomed comments
1244 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1246 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1248 if (list->comment == DEV_DEVICE)
1251 strncpy(nb+1,list->name,57);
1253 strncpy(nb,list->name,58);
1254 if ((list->comment == DEV_ZOOMED) && (list->next))
1255 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1256 strcat(nb," (Collapsed)");
1260 if (list->conflicts) /* device in conflict? */
1264 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1266 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1269 if (list->comment == DEV_DEVICE)
1271 ksprintf(db,"%s%d",list->dev,list->unit);
1276 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1278 ksprintf(ib," %d",list->irq);
1283 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1285 ksprintf(pb,"0x%x",list->iobase);
1291 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1293 putxyl(0,row,lbuf,80);
1296 switch(list->comment)
1298 case DEV_DEVICE: /* ordinary device */
1304 if (list->next->comment == DEV_DEVICE)
1305 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1310 if (list->next->comment == DEV_DEVICE)
1311 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1314 puthelp(" WARNING: This list entry corrupted!");
1318 move(0,row); /* put the cursor somewhere relevant */
1325 ** Displays (num) lines of the contents of (list) at (row), optionally
1326 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1329 drawlist(int row, int num, int detail, DEV_LIST *list)
1333 for(ofs = 0; ofs < num; ofs++)
1337 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1338 list = nextent(list); /* move down visible list */
1340 erase(0,row+ofs,80,1);
1349 ** Redraws the active list
1358 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1361 putxyl(45,0,lines,16);
1363 drawlist(1,8,1,alist); /* draw device lists */
1369 ** Redraws the inactive list
1372 redrawinactive(void)
1374 drawlist(10,7,0,ilist); /* draw device lists */
1381 ** Clear the screen and redraw the entire layout
1388 putxy(3,0,"!bActive!n-!bDrivers");
1389 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1391 putxy(3,9,"!bInactive!n-!bDrivers");
1392 putxy(63,9,"!bDev");
1395 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1405 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1406 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1409 yesnocancel(char *str)
1435 ** Show device parameters in the region below the lists
1437 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1438 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1439 ** +--------------------------------------------------------------------------------+
1440 ** 17-|--------------------------------------------------------------------------------|
1441 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1442 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1443 ** 20-| Flags : 0x0000 DRQ number : 00 |
1444 ** 21-|--------------------------------------------------------------------------------|
1447 showparams(DEV_LIST *dev)
1451 erase(0,18,80,3); /* clear area */
1454 if (dev->comment != DEV_DEVICE)
1458 if (dev->iobase > 0)
1460 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1466 ksprintf(buf,"IRQ number : %d",dev->irq);
1469 ksprintf(buf,"Flags : 0x%x",dev->flags);
1473 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1478 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1484 ksprintf(buf,"DRQ number : %d",dev->drq);
1491 ** Editing functions for device parameters
1493 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1494 ** onscreen. Refuse values outsise (min) and (max).
1495 ** editparams(dev) - Edit the parameters for (dev)
1499 #define VetRet(code) \
1501 if ((i >= min) && (i <= max)) /* legit? */ \
1504 ksprintf(buf,hex?"0x%x":"%d",i); \
1505 putxy(hex?x-2:x,y,buf); \
1506 return(code); /* all done and exit */ \
1508 i = *val; /* restore original value */ \
1509 delta = 1; /* restore other stuff */ \
1516 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1517 ** in a field (width) wide. (Allow one space)
1518 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1520 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1523 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1525 int i = *val; /* work with copy of the value */
1526 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1527 int xp = 0; /* cursor offset into text copy */
1528 int delta = 1; /* force redraw first time in */
1530 int extended = 0; /* stage counter for extended key sequences */
1532 if (hex) /* we presume there's a leading 0x onscreen */
1533 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1537 if (delta) /* only update if necessary */
1539 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1540 ksprintf(buf,"!i%s",tc); /* format for printing */
1541 erase(x,y,width,1); /* clear the area */
1542 putxy(x,y,buf); /* write */
1543 xp = strlen(tc); /* cursor always at end */
1544 move(x+xp,y); /* position the cursor */
1549 switch(extended) /* escape handling */
1552 if (c == 0x1b) /* esc? */
1554 extended = 1; /* flag and spin */
1558 break; /* nope, drop through */
1560 case 1: /* there was an escape prefix */
1561 if (c == '[' || c == 'O') /* second character in sequence */
1567 return(KEY_EXIT); /* double esc exits */
1569 break; /* nup, not a sequence. */
1573 switch(c) /* looks like the real McCoy */
1576 VetRet(KEY_UP); /* leave if OK */
1579 VetRet(KEY_DOWN); /* leave if OK */
1582 VetRet(KEY_RIGHT); /* leave if OK */
1585 VetRet(KEY_LEFT); /* leave if OK */
1595 case '\t': /* trying to tab off */
1596 VetRet(KEY_TAB); /* verify and maybe return */
1606 case '\177': /* BS or DEL */
1607 if (ro) /* readonly? */
1609 puthelp(" !iThis value cannot be edited (Press ESC)");
1610 while(kgetchar() != 0x1b); /* wait for key */
1611 return(KEY_NULL); /* spin */
1613 if (xp) /* still something left to delete */
1615 i = (hex ? i/0x10u : i/10); /* strip last digit */
1616 delta = 1; /* force update */
1639 if (ro) /* readonly? */
1641 puthelp(" !iThis value cannot be edited (Press ESC)");
1642 while(kgetchar() != 0x1b); /* wait for key */
1643 return(KEY_NULL); /* spin */
1645 if (xp >= width) /* no room for more characters anyway */
1649 if ((c >= '0') && (c <= '9'))
1651 i = i*0x10 + (c-'0'); /* update value */
1655 if ((c >= 'a') && (c <= 'f'))
1657 i = i*0x10 + (c-'a'+0xa);
1661 if ((c >= 'A') && (c <= 'F'))
1663 i = i*0x10 + (c-'A'+0xa);
1668 if ((c >= '0') && (c <= '9'))
1670 i = i*10 + (c-'0'); /* update value */
1671 delta = 1; /* force redraw */
1684 ** Edit the parameters for (dev)
1686 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1687 ** possible for this to spin in an endless loop...
1688 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1689 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1690 ** +--------------------------------------------------------------------------------+
1691 ** 17-|--------------------------------------------------------------------------------|
1692 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1693 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1694 ** 20-| Flags : 0x0000 DRQ number : 00 |
1695 ** 21-|--------------------------------------------------------------------------------|
1697 ** The "intelligence" in this function that hops around based on the directional
1698 ** returns from editval isn't very smart, and depends on the layout above.
1701 editparams(DEV_LIST *dev)
1704 char buf[16]; /* needs to fit the device name */
1706 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1707 ksprintf(buf,"!b%s",dev->dev);
1714 if (dev->iobase > 0)
1716 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1717 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1737 puthelp(" Interrupt number (Decimal, 1-15)");
1738 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1750 if (dev->iobase > 0)
1761 puthelp(" Device-specific flag values.");
1762 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1776 if (dev->iobase > 0)
1796 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1797 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1804 if (dev->iobase > 0)
1826 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1827 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1856 puthelp(" Device DMA request number (Decimal, 1-7)");
1857 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1880 dev->changed = 1; /* mark as changed */
1883 static char *helptext[] =
1885 " Using the UserConfig kernel settings editor",
1886 " -------------------------------------------",
1892 "The screen displays a list of available drivers, divided into two",
1893 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1894 "by default collapsed and can be expanded to show all the drivers",
1895 "available in each category. The parameters for the currently selected",
1896 "driver are shown at the bottom of the screen.",
1898 "- - Moving around -",
1900 "To move in the current list, use the UP and DOWN cursor keys to select",
1901 "an item (the selected item will be highlighted). If the item is a",
1902 "category name, you may alternatively expand or collapse the list of",
1903 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1904 "expanded, you can select each driver in the same manner and either:",
1906 " - change its parameters using [!bENTER!n]",
1907 " - move it to the Inactive list using [!bDEL!n]",
1909 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1910 "you need to move a driver from the Inactive list back to the Active",
1911 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1912 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1913 "its place in the Active list.",
1915 "- - Altering the list/parameters -",
1917 "Any drivers for devices not installed in your system should be moved",
1918 "to the Inactive list, until there are no remaining parameter conflicts",
1919 "between the drivers, as indicated at the top.",
1921 "Once the list of Active drivers only contains entries for the devices",
1922 "present in your system, you can set their parameters (Interrupt, DMA",
1923 "channel, I/O addresses). To do this, select the driver and press",
1924 "[!bENTER!n]: it is now possible to edit the settings at the",
1925 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1926 "finished, use [!bQ!n] to return to the list.",
1928 "- - Saving changes -",
1930 "When all settings seem correct, and you wish to proceed with the",
1931 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1932 "confirm your choice.",
1941 ** Displays help text onscreen for people that are confused, using a simple
1947 int topline = 0; /* where we are in the text */
1948 int line = 0; /* last line we displayed */
1952 for (;;) /* loop until user quits */
1954 /* display help text */
1957 clear(); /* remove everything else */
1958 for (line = topline;
1959 (line < (topline + 24)) && (helptext[line]);
1961 putxy(0,line-topline,helptext[line]);
1966 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1969 c = kgetchar(); /* so what do they say? */
1976 case 'B': /* wired into 'more' users' fingers */
1977 if (topline > 0) /* room to go up? */
1980 if (topline < 0) /* don't go too far */
1988 case ' ': /* expected by most people */
1989 if (helptext[line]) /* maybe more below? */
1998 redraw(); /* restore the screen */
2006 ** High-level control functions
2013 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2014 ** (num) lines, starting at (*ofs) offset from row onscreen.
2015 ** Pass (detail) on to drawing routines.
2017 ** If the user hits a key other than a cursor key, maybe return a code.
2019 ** (*list) points to the device at the top line in the region, (*ofs) is the
2020 ** position of the highlight within the region. All routines below
2021 ** this take only a device and an absolute row : use ofsent() to find the
2022 ** device, and add (*ofs) to (row) to find the absolute row.
2025 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2036 showparams(ofsent(*ofs,*list)); /* show device parameters */
2037 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2041 c = kgetchar(); /* get a character */
2042 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2044 extended = 0; /* no longer */
2047 case 588: /* syscons' idea of 'up' */
2049 if (*ofs) /* just a move onscreen */
2051 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2052 (*ofs)--; /* move up */
2054 lp = prevent(*list); /* can we go up? */
2057 *list = lp; /* yes, move up list */
2058 drawlist(row,num,detail,*list);
2063 case 596: /* dooby-do */
2064 case 'B': /* down */
2065 lp = ofsent(*ofs,*list); /* get current item */
2067 break; /* nothing more to move to */
2068 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2069 if (*ofs < (num-1)) /* room to move onscreen? */
2073 *list = nextent(*list); /* scroll region down */
2074 drawlist(row,num,detail,*list);
2086 case '[': /* cheat : always preceeds cursor move */
2087 case 'O': /* ANSI application key mode */
2096 return(KEY_EXIT); /* user requests exit */
2100 return(KEY_DO); /* "do" something */
2105 return(KEY_DEL); /* "delete" response */
2109 return(KEY_UNZOOM); /* expand everything */
2113 return(KEY_ZOOM); /* collapse everything */
2116 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2117 return(KEY_TAB); /* "move" response */
2119 case '\014': /* ^L, redraw */
2122 case '?': /* helptext */
2134 ** Do the fullscreen config thang
2139 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2143 initlist(&inactive);
2149 conflicts = findconflict(active); /* find conflicts in the active list only */
2157 case 0: /* active devices */
2158 ret = dolist(1,8,1,&actofs,&alist,
2159 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2163 mode = 1; /* swap lists */
2180 collapselist(active);
2185 dp = ofsent(actofs,alist); /* get current device */
2186 if (dp) /* paranoia... */
2188 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2190 if (dp == alist) /* moving top item on list? */
2194 alist = dp->next; /* point list to non-moving item */
2196 alist = dp->prev; /* end of list, go back instead */
2199 if (!dp->next) /* moving last item on list? */
2202 dp->conflicts = 0; /* no conflicts on the inactive list */
2203 movedev(dp,inactive); /* shift to inactive list */
2204 conflicts = findconflict(active); /* update conflict tags */
2206 redrawactive(); /* redraw */
2211 case KEY_DO: /* edit device parameters */
2212 dp = ofsent(actofs,alist); /* get current device */
2213 if (dp) /* paranoia... */
2215 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2217 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2219 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2221 conflicts = findconflict(active); /* update conflict tags */
2222 }else{ /* DO on comment = zoom */
2223 switch(dp->comment) /* Depends on current state */
2225 case DEV_COMMENT: /* not currently zoomed */
2226 dp->comment = DEV_ZOOMED;
2230 dp->comment = DEV_COMMENT;
2240 case 1: /* inactive devices */
2241 ret = dolist(10,7,0,&inactofs,&ilist,
2242 " [!bEnter!n] Enable device ");
2256 expandlist(inactive);
2263 collapselist(inactive);
2268 dp = ofsent(inactofs,ilist); /* get current device */
2269 if (dp) /* paranoia... */
2271 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2273 if (dp == ilist) /* moving top of list? */
2277 ilist = dp->next; /* point list to non-moving item */
2279 ilist = dp->prev; /* can't go down, go up instead */
2282 if (!dp->next) /* last entry on list? */
2283 inactofs--; /* shift cursor up one */
2286 movedev(dp,active); /* shift to active list */
2287 conflicts = findconflict(active); /* update conflict tags */
2289 alist = dp; /* put at top and current */
2291 while(dp->comment == DEV_DEVICE)
2292 dp = dp->prev; /* forcibly unzoom section */
2293 dp ->comment = DEV_COMMENT;
2294 mode = 0; /* and swap modes to follow it */
2296 }else{ /* DO on comment = zoom */
2297 switch(dp->comment) /* Depends on current state */
2299 case DEV_COMMENT: /* not currently zoomed */
2300 dp->comment = DEV_ZOOMED;
2304 dp->comment = DEV_COMMENT;
2308 redrawactive(); /* redraw */
2313 default: /* nothing else relevant here */
2318 mode = 0; /* shouldn't happen... */
2321 /* handle returns that are the same for both modes */
2328 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2331 case 2: /* cancel */
2335 case 1: /* save and exit */
2337 savelist(inactive,0);
2340 nukelist(active); /* clean up after ourselves */
2350 #endif /* VISUAL_USERCONFIG */
2353 * Copyright (c) 1991 Regents of the University of California.
2354 * All rights reserved.
2355 * Copyright (c) 1994 Jordan K. Hubbard
2356 * All rights reserved.
2357 * Copyright (c) 1994 David Greenman
2358 * All rights reserved.
2360 * Many additional changes by Bruce Evans
2362 * This code is derived from software contributed by the
2363 * University of California Berkeley, Jordan K. Hubbard,
2364 * David Greenman and Bruce Evans.
2366 * Redistribution and use in source and binary forms, with or without
2367 * modification, are permitted provided that the following conditions
2369 * 1. Redistributions of source code must retain the above copyright
2370 * notice, this list of conditions and the following disclaimer.
2371 * 2. Redistributions in binary form must reproduce the above copyright
2372 * notice, this list of conditions and the following disclaimer in the
2373 * documentation and/or other materials provided with the distribution.
2374 * 3. All advertising materials mentioning features or use of this software
2375 * must display the following acknowledgement:
2376 * This product includes software developed by the University of
2377 * California, Berkeley and its contributors.
2378 * 4. Neither the name of the University nor the names of its contributors
2379 * may be used to endorse or promote products derived from this software
2380 * without specific prior written permission.
2382 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2383 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2384 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2385 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2386 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2387 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2388 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2389 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2390 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2391 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2394 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2397 #define PARM_DEVSPEC 0x1
2398 #define PARM_INT 0x2
2399 #define PARM_ADDR 0x3
2400 #define PARM_STRING 0x4
2402 typedef struct _cmdparm {
2405 struct uc_device *dparm;
2414 typedef int (*CmdFunc)(CmdParm *);
2416 typedef struct _cmd {
2424 static void lsscsi(void);
2425 static int list_scsi(CmdParm *);
2428 static int lsdevtab(struct uc_device *);
2429 static struct uc_device *find_device(char *, int);
2430 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2431 static void cngets(char *, int);
2432 static Cmd *parse_cmd(char *);
2433 static int parse_args(const char *, CmdParm *);
2434 static int save_dev(struct uc_device *);
2436 static int list_devices(CmdParm *);
2437 static int set_device_ioaddr(CmdParm *);
2438 static int set_device_irq(CmdParm *);
2439 static int set_device_drq(CmdParm *);
2440 static int set_device_iosize(CmdParm *);
2441 static int set_device_mem(CmdParm *);
2442 static int set_device_flags(CmdParm *);
2443 static int set_device_enable(CmdParm *);
2444 static int set_device_disable(CmdParm *);
2445 static int quitfunc(CmdParm *);
2446 static int helpfunc(CmdParm *);
2447 static int introfunc(CmdParm *);
2450 static int lspnp(void);
2451 static int set_pnp_parms(CmdParm *);
2456 static CmdParm addr_parms[] = {
2457 { PARM_DEVSPEC, {} },
2462 static CmdParm int_parms[] = {
2463 { PARM_DEVSPEC, {} },
2468 static CmdParm dev_parms[] = {
2469 { PARM_DEVSPEC, {} },
2474 static CmdParm string_arg[] = {
2475 { PARM_STRING, {} },
2480 static Cmd CmdList[] = {
2481 { "?", helpfunc, NULL }, /* ? (help) */
2482 { "di", set_device_disable, dev_parms }, /* disable dev */
2483 { "dr", set_device_drq, int_parms }, /* drq dev # */
2484 { "en", set_device_enable, dev_parms }, /* enable dev */
2485 { "ex", quitfunc, NULL }, /* exit (quit) */
2486 { "f", set_device_flags, int_parms }, /* flags dev mask */
2487 { "h", helpfunc, NULL }, /* help */
2488 { "intro", introfunc, NULL }, /* intro screen */
2489 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2490 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2491 { "ir", set_device_irq, int_parms }, /* irq dev # */
2492 { "l", list_devices, NULL }, /* ls, list */
2494 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2496 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2497 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2498 { "q", quitfunc, NULL }, /* quit */
2500 { "s", list_scsi, NULL }, /* scsi */
2502 #ifdef VISUAL_USERCONFIG
2503 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2505 { NULL, NULL, NULL },
2511 static char banner = 1;
2517 init_config_script();
2520 /* Only display signon banner if we are about to go interactive */
2521 if (!has_config_script()) {
2522 if (!(boothowto & RB_CONFIG))
2523 #ifdef INTRO_USERCONFIG
2530 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2531 " Type \"help\" for help"
2532 #ifdef VISUAL_USERCONFIG
2533 " or \"visual\" to go to the visual\n"
2534 " configuration interface (requires MGA/VGA display or\n"
2535 " serial terminal capable of displaying ANSI graphics)"
2541 kprintf("config> ");
2543 if (input[0] == '\0')
2545 cmd = parse_cmd(input);
2547 kprintf("Invalid command or syntax. Type `?' for help.\n");
2550 rval = (*cmd->handler)(cmd->parms);
2559 parse_cmd(char *cmd)
2563 for (cp = CmdList; cp->name; cp++) {
2564 int len = strlen(cp->name);
2566 if (!strncmp(cp->name, cmd, len)) {
2567 while (*cmd && *cmd != ' ' && *cmd != '\t')
2569 if (parse_args(cmd, cp->parms))
2579 parse_args(const char *cmd, CmdParm *parms)
2584 if (*cmd == ' ' || *cmd == '\t') {
2588 if (parms == NULL || parms->type == -1) {
2591 kprintf("Extra arg(s): %s\n", cmd);
2594 if (parms->type == PARM_DEVSPEC) {
2599 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2600 (*cmd >= '0' && *cmd <= '9')))
2601 devname[i++] = *(cmd++);
2603 if (*cmd >= '0' && *cmd <= '9') {
2604 unit = strtoul(cmd, &ptr, 10);
2606 kprintf("Invalid device number\n");
2607 /* XXX should print invalid token here and elsewhere. */
2610 /* XXX else should require end of token. */
2613 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2614 kprintf("No such device: %s%d\n", devname, unit);
2620 if (parms->type == PARM_INT) {
2621 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2623 kprintf("Invalid numeric argument\n");
2630 if (parms->type == PARM_ADDR) {
2631 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2633 kprintf("Invalid address argument\n");
2640 if (parms->type == PARM_STRING) {
2641 parms->parm.u.sparm = cmd;
2649 list_devices(CmdParm *parms)
2652 if (lsdevtab(uc_devtab)) return 0;
2654 if (lspnp()) return 0;
2660 set_device_ioaddr(CmdParm *parms)
2662 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2663 save_dev(parms[0].parm.dparm);
2668 set_device_irq(CmdParm *parms)
2672 irq = parms[1].parm.iparm;
2674 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2677 else if (irq != -1 && irq > 15) {
2678 kprintf("An IRQ > 15 would be invalid.\n");
2681 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2682 save_dev(parms[0].parm.dparm);
2687 set_device_drq(CmdParm *parms)
2692 * The bounds checking is just to ensure that the value can be printed
2693 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2695 drq = parms[1].parm.iparm;
2696 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2697 save_dev(parms[0].parm.dparm);
2702 set_device_iosize(CmdParm *parms)
2704 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2705 save_dev(parms[0].parm.dparm);
2710 set_device_mem(CmdParm *parms)
2712 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2713 save_dev(parms[0].parm.dparm);
2718 set_device_flags(CmdParm *parms)
2720 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2721 save_dev(parms[0].parm.dparm);
2726 set_device_enable(CmdParm *parms)
2728 parms[0].parm.dparm->id_enabled = TRUE;
2729 save_dev(parms[0].parm.dparm);
2734 set_device_disable(CmdParm *parms)
2736 parms[0].parm.dparm->id_enabled = FALSE;
2737 save_dev(parms[0].parm.dparm);
2744 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2750 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2753 * Output the pnp_ldn_overrides[] table.
2755 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2756 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2757 if(error) return(error);
2762 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2763 0, 0, sysctl_machdep_uc_pnplist, "A",
2764 "List of PnP overrides changed in UserConfig");
2767 * this function sets the kernel table to override bios PnP
2771 set_pnp_parms(CmdParm *parms)
2773 u_long idx, val, ldn, csn;
2776 const char *p = parms[0].parm.u.sparm;
2779 csn=strtoul(p,&q, 0);
2780 ldn=strtoul(q,&q, 0);
2781 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2782 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2783 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2786 for (i=0; i < MAX_PNP_LDN; i++) {
2787 if (pnp_ldn_overrides[i].csn == csn &&
2788 pnp_ldn_overrides[i].ldn == ldn)
2791 if (i==MAX_PNP_LDN) {
2792 for (i=0; i < MAX_PNP_LDN; i++) {
2793 if (pnp_ldn_overrides[i].csn <1 ||
2794 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2798 if (i==MAX_PNP_LDN) {
2799 kprintf("sorry, no PnP entries available, try delete one\n");
2802 d = pnp_ldn_overrides[i] ;
2808 if (!strncmp(p,"irq",3)) {
2809 idx=strtoul(p+3,&q, 0);
2810 val=strtoul(q,&q, 0);
2811 if (idx >=0 && idx < 2) d.irq[idx] = val;
2812 } else if (!strncmp(p,"flags",5)) {
2813 idx=strtoul(p+5,&q, 0);
2815 } else if (!strncmp(p,"drq",3)) {
2816 idx=strtoul(p+3,&q, 0);
2817 val=strtoul(q,&q, 0);
2818 if (idx >=0 && idx < 2) d.drq[idx] = val;
2819 } else if (!strncmp(p,"port",4)) {
2820 idx=strtoul(p+4,&q, 0);
2821 val=strtoul(q,&q, 0);
2822 if (idx >=0 && idx < 8) d.port[idx] = val;
2823 } else if (!strncmp(p,"mem",3)) {
2824 idx=strtoul(p+3,&q, 0);
2825 val=strtoul(q,&q, 0);
2826 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2827 } else if (!strncmp(p,"bios",4)) {
2830 } else if (!strncmp(p,"os",2)) {
2833 } else if (!strncmp(p,"disable",7)) {
2836 } else if (!strncmp(p,"enable",6)) {
2839 } else if (!strncmp(p,"delete",6)) {
2840 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2841 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2844 kprintf("unknown command <%s>\n", p);
2847 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2849 pnp_ldn_overrides[i] = d ;
2855 quitfunc(CmdParm *parms)
2858 * If kernel config supplied, and we are parsing it, and -c also supplied,
2859 * ignore a quit command, This provides a safety mechanism to allow
2860 * recovery from a damaged/buggy kernel config.
2862 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2868 helpfunc(CmdParm *parms)
2871 "Command\t\t\tDescription\n"
2872 "-------\t\t\t-----------\n"
2873 "ls\t\t\tList currently configured devices\n"
2874 "port <devname> <addr>\tSet device port (i/o address)\n"
2875 "irq <devname> <number>\tSet device irq\n"
2876 "drq <devname> <number>\tSet device drq\n"
2877 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2878 "iosize <devname> <size>\tSet device memory size\n"
2879 "flags <devname> <mask>\tSet device flags\n"
2880 "enable <devname>\tEnable device\n"
2881 "disable <devname>\tDisable device (will not be probed)\n");
2884 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2885 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2886 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2887 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2888 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2889 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2892 "quit\t\t\tExit this configuration utility\n"
2893 "reset\t\t\tReset CPU\n");
2894 #ifdef VISUAL_USERCONFIG
2895 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2898 "help\t\t\tThis message\n\n"
2899 "Commands may be abbreviated to a unique prefix\n");
2903 #if defined (VISUAL_USERCONFIG)
2905 center(int y, char *str)
2907 putxy((80 - strlen(str)) / 2, y, str);
2912 introfunc(CmdParm *parms)
2914 #if defined (VISUAL_USERCONFIG)
2915 int curr_item, first_time, extended = 0;
2916 static char *choices[] = {
2917 " Skip kernel configuration and continue with installation ",
2918 " Start kernel configuration in full-screen visual mode ",
2919 " Start kernel configuration in CLI mode ",
2923 center(2, "!bKernel Configuration Menu!n");
2932 for (i = 0; i < 3; i++) {
2936 strcat(tmp, choices[i]);
2939 putxy(10, 5 + i, tmp);
2943 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2944 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2945 putxy(2, 12, "match your hardware configuration.");
2946 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2947 putxy(2, 15, "(press Down-Arrow then ENTER).");
2948 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2949 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2950 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2951 putxy(2, 21, "then simply press ENTER or Q now.");
2955 move(0, 0); /* move the cursor out of the way */
2958 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2959 extended = 0; /* no longer */
2968 case 'B': /* down */
2980 case '[': /* cheat : always preceeds cursor move */
2981 case 'O': /* ANSI application key mode */
2992 return 1; /* user requests exit */
2994 case '1': /* select an item */
3018 case 'D': /* down */
3031 else if (curr_item == 1)
3032 return visuserconfig();
3034 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3035 /* enable quitfunc */
3036 userconfig_boot_parsing=0;
3038 boothowto |= RB_CONFIG; /* force -c */
3045 #else /* !VISUAL_USERCONFIG */
3047 #endif /* VISUAL_USERCONFIG */
3054 struct pnp_cinfo *c;
3058 for (i=0; i< MAX_PNP_LDN; i++) {
3059 c = &pnp_ldn_overrides[i];
3060 if (c->csn >0 && c->csn != 255) {
3062 static char pfmt[] =
3063 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3064 static char mfmt[] =
3065 "mem 0x%x 0x%x 0x%x 0x%x";
3068 if (!userconfig_boot_parsing) {
3070 if (kgetchar() == 'q') {
3078 if (lineno == 0 || first)
3079 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3081 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3083 c->override ? "OS ":"BIOS",
3084 c->enable ? "Y":"N",
3085 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3087 kprintf("flags 0x%08lx ",c->flags);
3088 for (pmax = 7; pmax >=0 ; pmax--)
3089 if (c->port[pmax]!=0) break;
3090 for (mmax = 3; mmax >=0 ; mmax--)
3091 if (c->mem[mmax].base!=0) break;
3094 buf[10 + 5*pmax]='\0';
3096 c->port[0], c->port[1], c->port[2], c->port[3],
3097 c->port[4], c->port[5], c->port[6], c->port[7]);
3101 buf[8 + 5*mmax]='\0';
3103 c->mem[0].base, c->mem[1].base,
3104 c->mem[2].base, c->mem[3].base);
3114 lsdevtab(struct uc_device *dt)
3116 for (; dt->id_id != 0; dt++) {
3121 if (!userconfig_boot_parsing) {
3122 if (kgetchar() == 'q') {
3132 "Device port irq drq iomem iosize unit flags enab\n"
3136 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3137 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3138 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3139 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3140 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3141 dt->id_enabled ? "Yes" : "No");
3151 int count = resource_count();
3157 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3160 for (i = 0; i < count; i++) {
3161 name = resource_query_name(i);
3162 unit = resource_query_unit(i);
3164 continue; /* skip wildcards */
3165 uc_devtab[dt].id_id = id++;
3166 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3168 resource_int_value(name, unit, "irq", &val);
3169 uc_devtab[dt].id_irq = (1 << val);
3170 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3171 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3172 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3173 uc_devtab[dt].id_unit = unit;
3174 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3176 resource_int_value(name, unit, "disabled", &val);
3177 uc_devtab[dt].id_enabled = !val;
3178 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3179 strcpy(uc_devtab[dt].id_name, name);
3188 int count = resource_count();
3190 for (i = 0; i < count; i++)
3191 if (uc_devtab[i].id_name)
3192 kfree(uc_devtab[i].id_name, M_DEVL);
3193 kfree(uc_devtab, M_DEVL);
3196 static struct uc_device *
3197 find_device(char *devname, int unit)
3199 struct uc_device *ret;
3201 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3206 static struct uc_device *
3207 search_devtable(struct uc_device *dt, char *devname, int unit)
3209 for (; dt->id_id != 0; dt++)
3210 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3216 cngets(char *input, int maxin)
3222 /* Treat ^H or ^? as backspace */
3223 if ((c == '\010' || c == '\177')) {
3225 kprintf("\010 \010");
3226 *--input = '\0', --nchars;
3230 /* Treat ^U or ^X as kill line */
3231 else if ((c == '\025' || c == '\030')) {
3233 kprintf("\010 \010");
3234 *--input = '\0', --nchars;
3239 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3243 *input++ = (u_char)c;
3249 /* scsi: Support for displaying configured SCSI devices.
3250 * There is no way to edit them, and this is inconsistent
3251 * with the ISA method. This is here as a basis for further work.
3254 type_text(char *name) /* XXX: This is bogus */
3256 if (strcmp(name, "sd") == 0)
3259 if (strcmp(name, "st") == 0)
3265 id_put(char *desc, int id)
3267 if (id != SCCONF_UNSPEC)
3270 kprintf("%s", desc);
3272 if (id == SCCONF_ANY)
3284 kprintf("scsi: (can't be edited):\n");
3286 for (i = 0; scsi_cinit[i].driver; i++)
3288 id_put("controller scbus", scsi_cinit[i].scbus);
3290 if (scsi_cinit[i].unit != -1)
3293 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3299 for (i = 0; scsi_dinit[i].name; i++)
3301 kprintf("%s ", type_text(scsi_dinit[i].name));
3303 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3304 id_put(" at scbus", scsi_dinit[i].cunit);
3305 id_put(" target ", scsi_dinit[i].target);
3306 id_put(" lun ", scsi_dinit[i].lun);
3308 if (scsi_dinit[i].flags)
3309 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3316 list_scsi(CmdParm *parms)
3325 save_resource(struct uc_device *idev)
3330 name = idev->id_name;
3331 unit = idev->id_unit;
3332 resource_set_int(name, unit, "port", idev->id_iobase);
3333 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3334 resource_set_int(name, unit, "drq", idev->id_drq);
3335 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3336 resource_set_int(name, unit, "msize", idev->id_msize);
3337 resource_set_int(name, unit, "flags", idev->id_flags);
3338 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3342 save_dev(struct uc_device *idev)
3344 struct uc_device *id_p,*id_pn;
3345 char *name = idev->id_name;
3347 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3348 if (id_p->id_id == idev->id_id) {
3349 id_pn = id_p->id_next;
3351 kfree(id_p->id_name, M_DEVL);
3352 bcopy(idev,id_p,sizeof(struct uc_device));
3353 save_resource(idev);
3354 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3355 strcpy(id_p->id_name, name);
3356 id_p->id_next = id_pn;
3360 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3361 bcopy(idev,id_pn,sizeof(struct uc_device));
3362 save_resource(idev);
3363 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3364 strcpy(id_pn->id_name, name);
3365 id_pn->id_next = uc_devlist;