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 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
365 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
366 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
367 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
368 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
369 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
370 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
371 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
372 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
373 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
374 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
375 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
376 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
377 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
378 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
379 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
380 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
381 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
383 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
384 {"pcic", "PC-card controller", 0, CLS_MISC},
385 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
386 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
390 typedef struct _devlist_struct
393 int attrib; /* flag values as per the FLG_* defines above */
394 int class; /* disk, etc as per the CLS_* defines above */
396 int iobase,irq,drq,maddr,msize,unit,flags,id;
397 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
398 int conflicts; /* set/reset by findconflict, count of conflicts */
399 int changed; /* nonzero if the device has been edited */
400 struct uc_device *device;
401 struct _devlist_struct *prev,*next;
406 #define DEV_COMMENT 1
409 #define LIST_CURRENT (1<<0)
410 #define LIST_SELECTED (1<<1)
412 #define KEY_EXIT 0 /* return codes from dolist() and friends */
418 #define KEY_UP 5 /* these only returned from editval() */
422 #define KEY_NULL 9 /* this allows us to spin & redraw */
424 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
425 #define KEY_UNZOOM 11
427 #define KEY_HELP 12 /* duh? */
429 static void redraw(void);
430 static void insdev(DEV_LIST *dev, DEV_LIST *list);
431 static int devinfo(DEV_LIST *dev);
432 static int visuserconfig(void);
434 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
435 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
436 static DEV_LIST scratch; /* scratch record */
437 static int conflicts; /* total conflict count */
440 static char lines[] = "--------------------------------------------------------------------------------";
441 static char spaces[] = " ";
445 ** Device manipulation stuff : find, describe, configure.
451 ** Sets the device referenced by (*dev) to the parameters in the struct,
452 ** and the enable flag according to (enabled)
455 setdev(DEV_LIST *dev, int enabled)
457 dev->device->id_iobase = dev->iobase; /* copy happy */
458 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
459 dev->device->id_drq = (short)dev->drq;
460 dev->device->id_maddr = (caddr_t)dev->maddr;
461 dev->device->id_msize = dev->msize;
462 dev->device->id_flags = dev->flags;
463 dev->device->id_enabled = enabled;
470 ** Walk the kernel device tables and build the active and inactive lists
476 struct uc_device *ap;
478 ap = uc_devtab; /* pointer to array of devices */
479 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
481 scratch.unit = ap[i].id_unit; /* device parameters */
482 strcpy(scratch.dev,ap[i].id_name);
483 scratch.iobase = ap[i].id_iobase;
484 scratch.irq = ffs(ap[i].id_irq)-1;
485 scratch.drq = ap[i].id_drq;
486 scratch.maddr = (int)ap[i].id_maddr;
487 scratch.msize = ap[i].id_msize;
488 scratch.flags = ap[i].id_flags;
490 scratch.comment = DEV_DEVICE; /* admin stuff */
491 scratch.conflicts = 0;
492 scratch.device = &ap[i]; /* save pointer for later reference */
494 if (!devinfo(&scratch)) /* get more info on the device */
495 insdev(&scratch,ap[i].id_enabled?active:inactive);
503 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
504 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
506 ** If the device is marked "invisible", return nonzero; the caller should
507 ** not insert any such device into either list.
511 devinfo(DEV_LIST *dev)
515 for (i = 0; device_info[i].class; i++)
517 if (!strcmp(dev->dev,device_info[i].dev))
519 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
521 strcpy(dev->name,device_info[i].name); /* get the name */
522 dev->attrib = device_info[i].attrib;
523 dev->class = device_info[i].class;
527 strcpy(dev->name,"Unknown device");
529 dev->class = CLS_MISC;
535 ** List manipulation stuff : add, move, initialise, free, traverse
537 ** Note that there are assumptions throughout this code that
538 ** the first entry in a list will never move. (assumed to be
546 ** appends a copy of (dev) to the end of (*list)
549 addev(DEV_LIST *dev, DEV_LIST **list)
554 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
555 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
557 if (*list) /* list exists */
561 ap = ap->next; /* scoot to end of list */
565 }else{ /* list does not yet exist */
567 lp->prev = lp->next = NULL; /* list now exists */
575 ** Finds the 'appropriate' place for (dev) in (list)
577 ** 'Appropriate' means in numeric order with other devices of the same type,
578 ** or in alphabetic order following a comment of the appropriate type.
579 ** or at the end of the list if an appropriate comment is not found. (this should
581 ** (Note that the appropriate point is never the top, but may be the bottom)
584 findspot(DEV_LIST *dev, DEV_LIST *list)
588 /* search for a previous instance of the same device */
589 for (ap = list; ap; ap = ap->next)
591 if (ap->comment != DEV_DEVICE) /* ignore comments */
593 if (!strcmp(dev->dev,ap->dev)) /* same base device */
595 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
596 || !ap->next) /* or end of list */
598 ap = ap->prev; /* back up one */
599 break; /* done here */
601 if (ap->next) /* if the next item exists */
603 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
605 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
611 if (!ap) /* not sure yet */
613 /* search for a class that the device might belong to */
614 for (ap = list; ap; ap = ap->next)
616 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
618 if (dev->class != ap->class) /* of same class too 8) */
620 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
622 ap = ap->prev; /* back up one */
623 break; /* done here */
625 if (ap->next) /* if the next item exists */
626 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
631 if (!ap) /* didn't find a match */
633 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
634 if ((ap->comment != DEV_DEVICE)
635 && (ap->class == dev->class)) /* appropriate place? */
637 } /* or just put up with last */
646 ** Inserts a copy of (dev) at the appropriate point in (list)
649 insdev(DEV_LIST *dev, DEV_LIST *list)
653 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
654 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
656 ap = findspot(lp,list); /* find appropriate spot */
657 lp->next = ap->next; /* point to next */
659 ap->next->prev = lp; /* point next to new */
660 lp->prev = ap; /* point new to current */
661 ap->next = lp; /* and current to new */
668 ** Moves (dev) from its current list to an appropriate place in (list)
669 ** (dev) may not come from the top of a list, but it may from the bottom.
672 movedev(DEV_LIST *dev, DEV_LIST *list)
676 ap = findspot(dev,list);
677 dev->prev->next = dev->next; /* remove from old list */
679 dev->next->prev = dev->prev;
681 dev->next = ap->next; /* insert in new list */
683 ap->next->prev = dev; /* point next to new */
684 dev->prev = ap; /* point new to current */
685 ap->next = dev; /* and current to new */
692 ** Initialises (*list) with the basic headings
695 initlist(DEV_LIST **list)
699 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
701 strcpy(scratch.name,devclass_names[i].name);
702 scratch.comment = DEV_ZOOMED;
703 scratch.class = devclass_names[i].number;
704 scratch.attrib = FLG_MANDATORY; /* can't be moved */
705 addev(&scratch,list); /* add to the list */
713 ** Walks (list) and saves the settings of any entry marked as changed.
715 ** The device's active field is set according to (active).
717 ** Builds the uc_devlist used by kget to extract the changed device information.
718 ** The code for this was taken almost verbatim from the original module.
721 savelist(DEV_LIST *list, int active)
723 struct uc_device *id_p,*id_pn;
728 if ((list->comment == DEV_DEVICE) && /* is a device */
729 (list->changed) && /* has been changed */
730 (list->device != NULL)) { /* has an uc_device structure */
732 setdev(list,active); /* set the device itself */
735 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
736 { /* look on the list for it */
737 if (id_p->id_id == list->device->id_id)
739 name = list->device->id_name;
740 id_pn = id_p->id_next;
742 kfree(id_p->id_name, M_DEVL);
743 bcopy(list->device,id_p,sizeof(struct uc_device));
744 save_resource(list->device);
745 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
746 strcpy(id_p->id_name, name);
747 id_pn->id_next = uc_devlist;
748 id_p->id_next = id_pn;
752 if (!id_pn) /* not already on the list */
754 name = list->device->id_name;
755 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
756 bcopy(list->device,id_pn,sizeof(struct uc_device));
757 save_resource(list->device);
758 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
759 strcpy(id_pn->id_name, name);
760 id_pn->id_next = uc_devlist;
761 uc_devlist = id_pn; /* park at top of list */
772 ** Frees all storage in use by a (list).
775 nukelist(DEV_LIST *list)
781 while(list->prev) /* walk to head of list */
796 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
797 ** if there is no previous entry. (Only possible if list->prev == NULL given the
798 ** premise that there is always a comment at the head of the list)
801 prevent(DEV_LIST *list)
807 dp = list->prev; /* start back one */
810 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
811 return(dp); /* so skip to comment */
812 if (dp->comment == DEV_COMMENT) /* not zoomed */
813 return(list->prev); /* one back as normal */
814 dp = dp->prev; /* backpedal */
816 return(dp); /* NULL, we can assume */
823 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
824 ** if there is no next entry. (Possible if the current entry is last, or
825 ** if the current entry is the last heading and it's collapsed)
828 nextent(DEV_LIST *list)
834 if (list->comment != DEV_ZOOMED) /* no reason to skip */
839 if (dp->comment != DEV_DEVICE) /* found another heading */
843 return(dp); /* back we go */
850 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
853 ofsent(int ofs, DEV_LIST *list)
855 while (ofs-- && list)
856 list = nextent(list);
864 ** Scans every element of (list) and sets the conflict tags appropriately
865 ** Returns the number of conflicts found.
868 findconflict(DEV_LIST *list)
870 int count = 0; /* number of conflicts found */
873 for (dp = list; dp; dp = dp->next) /* over the whole list */
875 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
878 dp->conflicts = 0; /* assume the best */
879 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
881 if (sp->comment != DEV_DEVICE) /* likewise */
884 if (sp == dp) /* always conflict with itself */
887 if ((dp->iobase > 0) && /* iobase conflict? */
888 (dp->iobase == sp->iobase))
890 if ((dp->irq > 0) && /* irq conflict? */
891 (dp->irq == sp->irq))
893 if ((dp->drq > 0) && /* drq conflict? */
894 (dp->drq == sp->drq))
896 if ((sp->maddr > 0) && /* maddr/msize conflict? */
898 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
899 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
902 count += dp->conflicts; /* count conflicts */
911 ** Unzooms all headings in (list)
914 expandlist(DEV_LIST *list)
918 if (list->comment == DEV_COMMENT)
919 list->comment = DEV_ZOOMED;
928 ** Zooms all headings in (list)
931 collapselist(DEV_LIST *list)
935 if (list->comment == DEV_ZOOMED)
936 list->comment = DEV_COMMENT;
943 ** Screen-manipulation stuff
945 ** This is the basic screen layout :
947 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
948 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
949 ** +--------------------------------------------------------------------------------+
950 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
951 ** 1 -| ........................ ....... .. 0x....|
952 ** 2 -| ........................ ....... .. 0x....|
953 ** 3 -| ........................ ....... .. 0x....|
954 ** 4 -| ........................ ....... .. 0x....|
955 ** 5 -| ........................ ....... .. 0x....|
956 ** 6 -| ........................ ....... .. 0x....|
957 ** 7 -| ........................ ....... .. 0x....|
958 ** 8 -| ........................ ....... .. 0x....|
959 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
960 ** 10-| ........................ ....... |
961 ** 11-| ........................ ....... |
962 ** 12-| ........................ ....... |
963 ** 13-| ........................ ....... |
964 ** 14-| ........................ ....... |
965 ** 15-| ........................ ....... |
966 ** 16-| ........................ ....... |
967 ** 17-|------------------------------------------------------UP-DOWN-------------------|
968 ** 18-| Relevant parameters for the current device |
971 ** 21-|--------------------------------------------------------------------------------|
972 ** 22-| Help texts go here |
974 ** +--------------------------------------------------------------------------------+
978 ** On a collapsed comment :
980 ** [Enter] Expand device list [z] Expand all lists
981 ** [TAB] Change fields [Q] Save and Exit
983 ** On an expanded comment :
985 ** [Enter] Collapse device list [Z] Collapse all lists
986 ** [TAB] Change fields [Q] Save and Exit
988 ** On a comment with no followers
991 ** [TAB] Change fields [Q] Save and Exit
993 ** On a device in the active list
995 ** [Enter] Edit device parameters [DEL] Disable device
996 ** [TAB] Change fields [Q] Save and Exit [?] Help
998 ** On a device in the inactive list
1000 ** [Enter] Enable device
1001 ** [TAB] Change fields [Q] Save and Exit [?] Help
1003 ** While editing parameters
1005 ** <parameter-specific help here>
1006 ** [TAB] Change fields [Q] Save device parameters
1013 ** The base-level screen primitives :
1015 ** bold() - enter bold mode \E[1m (md)
1016 ** inverse() - enter inverse mode \E[7m (so)
1017 ** normal() - clear bold/inverse mode \E[m (se)
1018 ** clear() - clear the screen \E[H\E[J (ce)
1019 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1044 kprintf("\033[H\033[J");
1050 kprintf("\033[%d;%dH",y+1,x+1);
1056 ** High-level screen primitives :
1058 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1059 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1060 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1061 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1062 ** putmsg(str) - put (str) in the message area
1063 ** puthelp(str) - put (str) in the upper helpline
1064 ** pad(str,len) - pad (str) to (len) with spaces
1065 ** drawline(row,detail,list,inverse,*dhelp)
1066 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1067 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1068 ** draw the line in inverse video, and display (*dhelp) on the
1070 ** drawlist(row,num,detail,list)
1071 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1072 ** through to drawline().
1073 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1074 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1075 ** redraw(); - Redraws the entire screen layout, including the
1076 ** - two list panels.
1081 ** writes (str) at x,y onscreen
1083 ** writes up to (len) of (str) at x,y onscreen.
1085 ** Supports embedded formatting :
1086 ** !i - inverse mode.
1088 ** !n - normal mode.
1091 putxyl(int x, int y, char *str, int len)
1096 while((*str) && (len--))
1098 if (*str == '!') /* format escape? */
1100 switch(*(str+1)) /* depending on the next character */
1104 str +=2; /* skip formatting */
1105 len++; /* doesn't count for length */
1110 str +=2; /* skip formatting */
1111 len++; /* doesn't count for length */
1116 str +=2; /* skip formatting */
1117 len++; /* doesn't count for length */
1121 kprintf("%c", *str++); /* not an escape */
1124 kprintf("%c", *str++); /* emit the character */
1129 #define putxy(x,y,str) putxyl(x,y,str,-1)
1135 ** Erases the region (x,y,w,h)
1138 erase(int x, int y, int w, int h)
1143 for (i = 0; i < h; i++)
1144 putxyl(x,y++,spaces,w);
1151 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1152 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1155 txtbox(int x, int y, int w, int h, char *str)
1160 while((str[i]) && h)
1162 if (str[i] == '\n') /* newline */
1164 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1165 y++; /* move down */
1166 h--; /* room for one less */
1167 str += (i+1); /* skip first newline */
1168 i = 0; /* zero offset */
1170 i++; /* next character */
1173 if (h) /* end of string, not region */
1181 ** writes (msg) in the helptext area
1186 erase(0,18,80,3); /* clear area */
1187 txtbox(0,18,80,3,msg);
1194 ** Writes (msg) in the helpline area
1207 ** Draws the help message at the bottom of the screen
1210 masterhelp(char *msg)
1220 ** space-pads a (str) to (len) characters
1223 pad(char *str, int len)
1227 for (i = 0; str[i]; i++) /* find the end of the string */
1229 if (i >= len) /* no padding needed */
1231 while(i < len) /* pad */
1240 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1241 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1243 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1244 ** help is shown for normal or zoomed comments
1247 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1249 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1251 if (list->comment == DEV_DEVICE)
1254 strncpy(nb+1,list->name,57);
1256 strncpy(nb,list->name,58);
1257 if ((list->comment == DEV_ZOOMED) && (list->next))
1258 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1259 strcat(nb," (Collapsed)");
1263 if (list->conflicts) /* device in conflict? */
1267 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1269 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1272 if (list->comment == DEV_DEVICE)
1274 ksprintf(db,"%s%d",list->dev,list->unit);
1279 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1281 ksprintf(ib," %d",list->irq);
1286 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1288 ksprintf(pb,"0x%x",list->iobase);
1294 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1296 putxyl(0,row,lbuf,80);
1299 switch(list->comment)
1301 case DEV_DEVICE: /* ordinary device */
1307 if (list->next->comment == DEV_DEVICE)
1308 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1313 if (list->next->comment == DEV_DEVICE)
1314 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1317 puthelp(" WARNING: This list entry corrupted!");
1321 move(0,row); /* put the cursor somewhere relevant */
1328 ** Displays (num) lines of the contents of (list) at (row), optionally
1329 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1332 drawlist(int row, int num, int detail, DEV_LIST *list)
1336 for(ofs = 0; ofs < num; ofs++)
1340 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1341 list = nextent(list); /* move down visible list */
1343 erase(0,row+ofs,80,1);
1352 ** Redraws the active list
1361 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1364 putxyl(45,0,lines,16);
1366 drawlist(1,8,1,alist); /* draw device lists */
1372 ** Redraws the inactive list
1375 redrawinactive(void)
1377 drawlist(10,7,0,ilist); /* draw device lists */
1384 ** Clear the screen and redraw the entire layout
1391 putxy(3,0,"!bActive!n-!bDrivers");
1392 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1394 putxy(3,9,"!bInactive!n-!bDrivers");
1395 putxy(63,9,"!bDev");
1398 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1408 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1409 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1412 yesnocancel(char *str)
1438 ** Show device parameters in the region below the lists
1440 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1441 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1442 ** +--------------------------------------------------------------------------------+
1443 ** 17-|--------------------------------------------------------------------------------|
1444 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1445 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1446 ** 20-| Flags : 0x0000 DRQ number : 00 |
1447 ** 21-|--------------------------------------------------------------------------------|
1450 showparams(DEV_LIST *dev)
1454 erase(0,18,80,3); /* clear area */
1457 if (dev->comment != DEV_DEVICE)
1461 if (dev->iobase > 0)
1463 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1469 ksprintf(buf,"IRQ number : %d",dev->irq);
1472 ksprintf(buf,"Flags : 0x%x",dev->flags);
1476 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1481 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1487 ksprintf(buf,"DRQ number : %d",dev->drq);
1494 ** Editing functions for device parameters
1496 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1497 ** onscreen. Refuse values outsise (min) and (max).
1498 ** editparams(dev) - Edit the parameters for (dev)
1502 #define VetRet(code) \
1504 if ((i >= min) && (i <= max)) /* legit? */ \
1507 ksprintf(buf,hex?"0x%x":"%d",i); \
1508 putxy(hex?x-2:x,y,buf); \
1509 return(code); /* all done and exit */ \
1511 i = *val; /* restore original value */ \
1512 delta = 1; /* restore other stuff */ \
1519 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1520 ** in a field (width) wide. (Allow one space)
1521 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1523 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1526 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1528 int i = *val; /* work with copy of the value */
1529 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1530 int xp = 0; /* cursor offset into text copy */
1531 int delta = 1; /* force redraw first time in */
1533 int extended = 0; /* stage counter for extended key sequences */
1535 if (hex) /* we presume there's a leading 0x onscreen */
1536 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1540 if (delta) /* only update if necessary */
1542 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1543 ksprintf(buf,"!i%s",tc); /* format for printing */
1544 erase(x,y,width,1); /* clear the area */
1545 putxy(x,y,buf); /* write */
1546 xp = strlen(tc); /* cursor always at end */
1547 move(x+xp,y); /* position the cursor */
1552 switch(extended) /* escape handling */
1555 if (c == 0x1b) /* esc? */
1557 extended = 1; /* flag and spin */
1561 break; /* nope, drop through */
1563 case 1: /* there was an escape prefix */
1564 if (c == '[' || c == 'O') /* second character in sequence */
1570 return(KEY_EXIT); /* double esc exits */
1572 break; /* nup, not a sequence. */
1576 switch(c) /* looks like the real McCoy */
1579 VetRet(KEY_UP); /* leave if OK */
1582 VetRet(KEY_DOWN); /* leave if OK */
1585 VetRet(KEY_RIGHT); /* leave if OK */
1588 VetRet(KEY_LEFT); /* leave if OK */
1598 case '\t': /* trying to tab off */
1599 VetRet(KEY_TAB); /* verify and maybe return */
1609 case '\177': /* BS or DEL */
1610 if (ro) /* readonly? */
1612 puthelp(" !iThis value cannot be edited (Press ESC)");
1613 while(kgetchar() != 0x1b); /* wait for key */
1614 return(KEY_NULL); /* spin */
1616 if (xp) /* still something left to delete */
1618 i = (hex ? i/0x10u : i/10); /* strip last digit */
1619 delta = 1; /* force update */
1642 if (ro) /* readonly? */
1644 puthelp(" !iThis value cannot be edited (Press ESC)");
1645 while(kgetchar() != 0x1b); /* wait for key */
1646 return(KEY_NULL); /* spin */
1648 if (xp >= width) /* no room for more characters anyway */
1652 if ((c >= '0') && (c <= '9'))
1654 i = i*0x10 + (c-'0'); /* update value */
1658 if ((c >= 'a') && (c <= 'f'))
1660 i = i*0x10 + (c-'a'+0xa);
1664 if ((c >= 'A') && (c <= 'F'))
1666 i = i*0x10 + (c-'A'+0xa);
1671 if ((c >= '0') && (c <= '9'))
1673 i = i*10 + (c-'0'); /* update value */
1674 delta = 1; /* force redraw */
1687 ** Edit the parameters for (dev)
1689 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1690 ** possible for this to spin in an endless loop...
1691 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1692 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1693 ** +--------------------------------------------------------------------------------+
1694 ** 17-|--------------------------------------------------------------------------------|
1695 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1696 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1697 ** 20-| Flags : 0x0000 DRQ number : 00 |
1698 ** 21-|--------------------------------------------------------------------------------|
1700 ** The "intelligence" in this function that hops around based on the directional
1701 ** returns from editval isn't very smart, and depends on the layout above.
1704 editparams(DEV_LIST *dev)
1707 char buf[16]; /* needs to fit the device name */
1709 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1710 ksprintf(buf,"!b%s",dev->dev);
1717 if (dev->iobase > 0)
1719 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1720 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1740 puthelp(" Interrupt number (Decimal, 1-15)");
1741 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1753 if (dev->iobase > 0)
1764 puthelp(" Device-specific flag values.");
1765 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1779 if (dev->iobase > 0)
1799 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1800 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1807 if (dev->iobase > 0)
1829 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1830 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1859 puthelp(" Device DMA request number (Decimal, 1-7)");
1860 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1883 dev->changed = 1; /* mark as changed */
1886 static char *helptext[] =
1888 " Using the UserConfig kernel settings editor",
1889 " -------------------------------------------",
1895 "The screen displays a list of available drivers, divided into two",
1896 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1897 "by default collapsed and can be expanded to show all the drivers",
1898 "available in each category. The parameters for the currently selected",
1899 "driver are shown at the bottom of the screen.",
1901 "- - Moving around -",
1903 "To move in the current list, use the UP and DOWN cursor keys to select",
1904 "an item (the selected item will be highlighted). If the item is a",
1905 "category name, you may alternatively expand or collapse the list of",
1906 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1907 "expanded, you can select each driver in the same manner and either:",
1909 " - change its parameters using [!bENTER!n]",
1910 " - move it to the Inactive list using [!bDEL!n]",
1912 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1913 "you need to move a driver from the Inactive list back to the Active",
1914 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1915 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1916 "its place in the Active list.",
1918 "- - Altering the list/parameters -",
1920 "Any drivers for devices not installed in your system should be moved",
1921 "to the Inactive list, until there are no remaining parameter conflicts",
1922 "between the drivers, as indicated at the top.",
1924 "Once the list of Active drivers only contains entries for the devices",
1925 "present in your system, you can set their parameters (Interrupt, DMA",
1926 "channel, I/O addresses). To do this, select the driver and press",
1927 "[!bENTER!n]: it is now possible to edit the settings at the",
1928 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1929 "finished, use [!bQ!n] to return to the list.",
1931 "- - Saving changes -",
1933 "When all settings seem correct, and you wish to proceed with the",
1934 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1935 "confirm your choice.",
1944 ** Displays help text onscreen for people that are confused, using a simple
1950 int topline = 0; /* where we are in the text */
1951 int line = 0; /* last line we displayed */
1955 for (;;) /* loop until user quits */
1957 /* display help text */
1960 clear(); /* remove everything else */
1961 for (line = topline;
1962 (line < (topline + 24)) && (helptext[line]);
1964 putxy(0,line-topline,helptext[line]);
1969 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1972 c = kgetchar(); /* so what do they say? */
1979 case 'B': /* wired into 'more' users' fingers */
1980 if (topline > 0) /* room to go up? */
1983 if (topline < 0) /* don't go too far */
1991 case ' ': /* expected by most people */
1992 if (helptext[line]) /* maybe more below? */
2001 redraw(); /* restore the screen */
2009 ** High-level control functions
2016 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2017 ** (num) lines, starting at (*ofs) offset from row onscreen.
2018 ** Pass (detail) on to drawing routines.
2020 ** If the user hits a key other than a cursor key, maybe return a code.
2022 ** (*list) points to the device at the top line in the region, (*ofs) is the
2023 ** position of the highlight within the region. All routines below
2024 ** this take only a device and an absolute row : use ofsent() to find the
2025 ** device, and add (*ofs) to (row) to find the absolute row.
2028 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2039 showparams(ofsent(*ofs,*list)); /* show device parameters */
2040 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2044 c = kgetchar(); /* get a character */
2045 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2047 extended = 0; /* no longer */
2050 case 588: /* syscons' idea of 'up' */
2052 if (*ofs) /* just a move onscreen */
2054 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2055 (*ofs)--; /* move up */
2057 lp = prevent(*list); /* can we go up? */
2060 *list = lp; /* yes, move up list */
2061 drawlist(row,num,detail,*list);
2066 case 596: /* dooby-do */
2067 case 'B': /* down */
2068 lp = ofsent(*ofs,*list); /* get current item */
2070 break; /* nothing more to move to */
2071 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2072 if (*ofs < (num-1)) /* room to move onscreen? */
2076 *list = nextent(*list); /* scroll region down */
2077 drawlist(row,num,detail,*list);
2089 case '[': /* cheat : always preceeds cursor move */
2090 case 'O': /* ANSI application key mode */
2099 return(KEY_EXIT); /* user requests exit */
2103 return(KEY_DO); /* "do" something */
2108 return(KEY_DEL); /* "delete" response */
2112 return(KEY_UNZOOM); /* expand everything */
2116 return(KEY_ZOOM); /* collapse everything */
2119 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2120 return(KEY_TAB); /* "move" response */
2122 case '\014': /* ^L, redraw */
2125 case '?': /* helptext */
2137 ** Do the fullscreen config thang
2142 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2146 initlist(&inactive);
2152 conflicts = findconflict(active); /* find conflicts in the active list only */
2160 case 0: /* active devices */
2161 ret = dolist(1,8,1,&actofs,&alist,
2162 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2166 mode = 1; /* swap lists */
2183 collapselist(active);
2188 dp = ofsent(actofs,alist); /* get current device */
2189 if (dp) /* paranoia... */
2191 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2193 if (dp == alist) /* moving top item on list? */
2197 alist = dp->next; /* point list to non-moving item */
2199 alist = dp->prev; /* end of list, go back instead */
2202 if (!dp->next) /* moving last item on list? */
2205 dp->conflicts = 0; /* no conflicts on the inactive list */
2206 movedev(dp,inactive); /* shift to inactive list */
2207 conflicts = findconflict(active); /* update conflict tags */
2209 redrawactive(); /* redraw */
2214 case KEY_DO: /* edit device parameters */
2215 dp = ofsent(actofs,alist); /* get current device */
2216 if (dp) /* paranoia... */
2218 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2220 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2222 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2224 conflicts = findconflict(active); /* update conflict tags */
2225 }else{ /* DO on comment = zoom */
2226 switch(dp->comment) /* Depends on current state */
2228 case DEV_COMMENT: /* not currently zoomed */
2229 dp->comment = DEV_ZOOMED;
2233 dp->comment = DEV_COMMENT;
2243 case 1: /* inactive devices */
2244 ret = dolist(10,7,0,&inactofs,&ilist,
2245 " [!bEnter!n] Enable device ");
2259 expandlist(inactive);
2266 collapselist(inactive);
2271 dp = ofsent(inactofs,ilist); /* get current device */
2272 if (dp) /* paranoia... */
2274 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2276 if (dp == ilist) /* moving top of list? */
2280 ilist = dp->next; /* point list to non-moving item */
2282 ilist = dp->prev; /* can't go down, go up instead */
2285 if (!dp->next) /* last entry on list? */
2286 inactofs--; /* shift cursor up one */
2289 movedev(dp,active); /* shift to active list */
2290 conflicts = findconflict(active); /* update conflict tags */
2292 alist = dp; /* put at top and current */
2294 while(dp->comment == DEV_DEVICE)
2295 dp = dp->prev; /* forcibly unzoom section */
2296 dp ->comment = DEV_COMMENT;
2297 mode = 0; /* and swap modes to follow it */
2299 }else{ /* DO on comment = zoom */
2300 switch(dp->comment) /* Depends on current state */
2302 case DEV_COMMENT: /* not currently zoomed */
2303 dp->comment = DEV_ZOOMED;
2307 dp->comment = DEV_COMMENT;
2311 redrawactive(); /* redraw */
2316 default: /* nothing else relevant here */
2321 mode = 0; /* shouldn't happen... */
2324 /* handle returns that are the same for both modes */
2331 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2334 case 2: /* cancel */
2338 case 1: /* save and exit */
2340 savelist(inactive,0);
2343 nukelist(active); /* clean up after ourselves */
2353 #endif /* VISUAL_USERCONFIG */
2356 * Copyright (c) 1991 Regents of the University of California.
2357 * All rights reserved.
2358 * Copyright (c) 1994 Jordan K. Hubbard
2359 * All rights reserved.
2360 * Copyright (c) 1994 David Greenman
2361 * All rights reserved.
2363 * Many additional changes by Bruce Evans
2365 * This code is derived from software contributed by the
2366 * University of California Berkeley, Jordan K. Hubbard,
2367 * David Greenman and Bruce Evans.
2369 * Redistribution and use in source and binary forms, with or without
2370 * modification, are permitted provided that the following conditions
2372 * 1. Redistributions of source code must retain the above copyright
2373 * notice, this list of conditions and the following disclaimer.
2374 * 2. Redistributions in binary form must reproduce the above copyright
2375 * notice, this list of conditions and the following disclaimer in the
2376 * documentation and/or other materials provided with the distribution.
2377 * 3. All advertising materials mentioning features or use of this software
2378 * must display the following acknowledgement:
2379 * This product includes software developed by the University of
2380 * California, Berkeley and its contributors.
2381 * 4. Neither the name of the University nor the names of its contributors
2382 * may be used to endorse or promote products derived from this software
2383 * without specific prior written permission.
2385 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2386 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2387 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2388 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2389 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2390 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2391 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2392 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2393 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2394 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2397 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2400 #define PARM_DEVSPEC 0x1
2401 #define PARM_INT 0x2
2402 #define PARM_ADDR 0x3
2403 #define PARM_STRING 0x4
2405 typedef struct _cmdparm {
2408 struct uc_device *dparm;
2417 typedef int (*CmdFunc)(CmdParm *);
2419 typedef struct _cmd {
2427 static void lsscsi(void);
2428 static int list_scsi(CmdParm *);
2431 static int lsdevtab(struct uc_device *);
2432 static struct uc_device *find_device(char *, int);
2433 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2434 static void cngets(char *, int);
2435 static Cmd *parse_cmd(char *);
2436 static int parse_args(const char *, CmdParm *);
2437 static int save_dev(struct uc_device *);
2439 static int list_devices(CmdParm *);
2440 static int set_device_ioaddr(CmdParm *);
2441 static int set_device_irq(CmdParm *);
2442 static int set_device_drq(CmdParm *);
2443 static int set_device_iosize(CmdParm *);
2444 static int set_device_mem(CmdParm *);
2445 static int set_device_flags(CmdParm *);
2446 static int set_device_enable(CmdParm *);
2447 static int set_device_disable(CmdParm *);
2448 static int quitfunc(CmdParm *);
2449 static int helpfunc(CmdParm *);
2450 static int introfunc(CmdParm *);
2453 static int lspnp(void);
2454 static int set_pnp_parms(CmdParm *);
2459 static CmdParm addr_parms[] = {
2460 { PARM_DEVSPEC, {} },
2465 static CmdParm int_parms[] = {
2466 { PARM_DEVSPEC, {} },
2471 static CmdParm dev_parms[] = {
2472 { PARM_DEVSPEC, {} },
2477 static CmdParm string_arg[] = {
2478 { PARM_STRING, {} },
2483 static Cmd CmdList[] = {
2484 { "?", helpfunc, NULL }, /* ? (help) */
2485 { "di", set_device_disable, dev_parms }, /* disable dev */
2486 { "dr", set_device_drq, int_parms }, /* drq dev # */
2487 { "en", set_device_enable, dev_parms }, /* enable dev */
2488 { "ex", quitfunc, NULL }, /* exit (quit) */
2489 { "f", set_device_flags, int_parms }, /* flags dev mask */
2490 { "h", helpfunc, NULL }, /* help */
2491 { "intro", introfunc, NULL }, /* intro screen */
2492 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2493 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2494 { "ir", set_device_irq, int_parms }, /* irq dev # */
2495 { "l", list_devices, NULL }, /* ls, list */
2497 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2499 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2500 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2501 { "q", quitfunc, NULL }, /* quit */
2503 { "s", list_scsi, NULL }, /* scsi */
2505 #ifdef VISUAL_USERCONFIG
2506 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2508 { NULL, NULL, NULL },
2514 static char banner = 1;
2520 init_config_script();
2523 /* Only display signon banner if we are about to go interactive */
2524 if (!has_config_script()) {
2525 if (!(boothowto & RB_CONFIG))
2526 #ifdef INTRO_USERCONFIG
2533 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2534 " Type \"help\" for help"
2535 #ifdef VISUAL_USERCONFIG
2536 " or \"visual\" to go to the visual\n"
2537 " configuration interface (requires MGA/VGA display or\n"
2538 " serial terminal capable of displaying ANSI graphics)"
2544 kprintf("config> ");
2546 if (input[0] == '\0')
2548 cmd = parse_cmd(input);
2550 kprintf("Invalid command or syntax. Type `?' for help.\n");
2553 rval = (*cmd->handler)(cmd->parms);
2562 parse_cmd(char *cmd)
2566 for (cp = CmdList; cp->name; cp++) {
2567 int len = strlen(cp->name);
2569 if (!strncmp(cp->name, cmd, len)) {
2570 while (*cmd && *cmd != ' ' && *cmd != '\t')
2572 if (parse_args(cmd, cp->parms))
2582 parse_args(const char *cmd, CmdParm *parms)
2587 if (*cmd == ' ' || *cmd == '\t') {
2591 if (parms == NULL || parms->type == -1) {
2594 kprintf("Extra arg(s): %s\n", cmd);
2597 if (parms->type == PARM_DEVSPEC) {
2602 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2603 (*cmd >= '0' && *cmd <= '9')))
2604 devname[i++] = *(cmd++);
2606 if (*cmd >= '0' && *cmd <= '9') {
2607 unit = strtoul(cmd, &ptr, 10);
2609 kprintf("Invalid device number\n");
2610 /* XXX should print invalid token here and elsewhere. */
2613 /* XXX else should require end of token. */
2616 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2617 kprintf("No such device: %s%d\n", devname, unit);
2623 if (parms->type == PARM_INT) {
2624 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2626 kprintf("Invalid numeric argument\n");
2633 if (parms->type == PARM_ADDR) {
2634 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2636 kprintf("Invalid address argument\n");
2643 if (parms->type == PARM_STRING) {
2644 parms->parm.u.sparm = cmd;
2652 list_devices(CmdParm *parms)
2655 if (lsdevtab(uc_devtab)) return 0;
2657 if (lspnp()) return 0;
2663 set_device_ioaddr(CmdParm *parms)
2665 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2666 save_dev(parms[0].parm.dparm);
2671 set_device_irq(CmdParm *parms)
2675 irq = parms[1].parm.iparm;
2677 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2680 else if (irq != -1 && irq > 15) {
2681 kprintf("An IRQ > 15 would be invalid.\n");
2684 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2685 save_dev(parms[0].parm.dparm);
2690 set_device_drq(CmdParm *parms)
2695 * The bounds checking is just to ensure that the value can be printed
2696 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2698 drq = parms[1].parm.iparm;
2699 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2700 save_dev(parms[0].parm.dparm);
2705 set_device_iosize(CmdParm *parms)
2707 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2708 save_dev(parms[0].parm.dparm);
2713 set_device_mem(CmdParm *parms)
2715 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2716 save_dev(parms[0].parm.dparm);
2721 set_device_flags(CmdParm *parms)
2723 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2724 save_dev(parms[0].parm.dparm);
2729 set_device_enable(CmdParm *parms)
2731 parms[0].parm.dparm->id_enabled = TRUE;
2732 save_dev(parms[0].parm.dparm);
2737 set_device_disable(CmdParm *parms)
2739 parms[0].parm.dparm->id_enabled = FALSE;
2740 save_dev(parms[0].parm.dparm);
2747 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2753 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2756 * Output the pnp_ldn_overrides[] table.
2758 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2759 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2760 if(error) return(error);
2765 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2766 0, 0, sysctl_machdep_uc_pnplist, "A",
2767 "List of PnP overrides changed in UserConfig");
2770 * this function sets the kernel table to override bios PnP
2774 set_pnp_parms(CmdParm *parms)
2776 u_long idx, val, ldn, csn;
2779 const char *p = parms[0].parm.u.sparm;
2782 csn=strtoul(p,&q, 0);
2783 ldn=strtoul(q,&q, 0);
2784 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2785 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2786 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2789 for (i=0; i < MAX_PNP_LDN; i++) {
2790 if (pnp_ldn_overrides[i].csn == csn &&
2791 pnp_ldn_overrides[i].ldn == ldn)
2794 if (i==MAX_PNP_LDN) {
2795 for (i=0; i < MAX_PNP_LDN; i++) {
2796 if (pnp_ldn_overrides[i].csn <1 ||
2797 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2801 if (i==MAX_PNP_LDN) {
2802 kprintf("sorry, no PnP entries available, try delete one\n");
2805 d = pnp_ldn_overrides[i] ;
2811 if (!strncmp(p,"irq",3)) {
2812 idx=strtoul(p+3,&q, 0);
2813 val=strtoul(q,&q, 0);
2814 if (idx >=0 && idx < 2) d.irq[idx] = val;
2815 } else if (!strncmp(p,"flags",5)) {
2816 idx=strtoul(p+5,&q, 0);
2818 } else if (!strncmp(p,"drq",3)) {
2819 idx=strtoul(p+3,&q, 0);
2820 val=strtoul(q,&q, 0);
2821 if (idx >=0 && idx < 2) d.drq[idx] = val;
2822 } else if (!strncmp(p,"port",4)) {
2823 idx=strtoul(p+4,&q, 0);
2824 val=strtoul(q,&q, 0);
2825 if (idx >=0 && idx < 8) d.port[idx] = val;
2826 } else if (!strncmp(p,"mem",3)) {
2827 idx=strtoul(p+3,&q, 0);
2828 val=strtoul(q,&q, 0);
2829 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2830 } else if (!strncmp(p,"bios",4)) {
2833 } else if (!strncmp(p,"os",2)) {
2836 } else if (!strncmp(p,"disable",7)) {
2839 } else if (!strncmp(p,"enable",6)) {
2842 } else if (!strncmp(p,"delete",6)) {
2843 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2844 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2847 kprintf("unknown command <%s>\n", p);
2850 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2852 pnp_ldn_overrides[i] = d ;
2858 quitfunc(CmdParm *parms)
2861 * If kernel config supplied, and we are parsing it, and -c also supplied,
2862 * ignore a quit command, This provides a safety mechanism to allow
2863 * recovery from a damaged/buggy kernel config.
2865 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2871 helpfunc(CmdParm *parms)
2874 "Command\t\t\tDescription\n"
2875 "-------\t\t\t-----------\n"
2876 "ls\t\t\tList currently configured devices\n"
2877 "port <devname> <addr>\tSet device port (i/o address)\n"
2878 "irq <devname> <number>\tSet device irq\n"
2879 "drq <devname> <number>\tSet device drq\n"
2880 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2881 "iosize <devname> <size>\tSet device memory size\n"
2882 "flags <devname> <mask>\tSet device flags\n"
2883 "enable <devname>\tEnable device\n"
2884 "disable <devname>\tDisable device (will not be probed)\n");
2887 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2888 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2889 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2890 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2891 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2892 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2895 "quit\t\t\tExit this configuration utility\n"
2896 "reset\t\t\tReset CPU\n");
2897 #ifdef VISUAL_USERCONFIG
2898 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2901 "help\t\t\tThis message\n\n"
2902 "Commands may be abbreviated to a unique prefix\n");
2906 #if defined (VISUAL_USERCONFIG)
2908 center(int y, char *str)
2910 putxy((80 - strlen(str)) / 2, y, str);
2915 introfunc(CmdParm *parms)
2917 #if defined (VISUAL_USERCONFIG)
2918 int curr_item, first_time, extended = 0;
2919 static char *choices[] = {
2920 " Skip kernel configuration and continue with installation ",
2921 " Start kernel configuration in full-screen visual mode ",
2922 " Start kernel configuration in CLI mode ",
2926 center(2, "!bKernel Configuration Menu!n");
2935 for (i = 0; i < 3; i++) {
2939 strcat(tmp, choices[i]);
2942 putxy(10, 5 + i, tmp);
2946 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2947 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2948 putxy(2, 12, "match your hardware configuration.");
2949 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2950 putxy(2, 15, "(press Down-Arrow then ENTER).");
2951 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2952 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2953 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2954 putxy(2, 21, "then simply press ENTER or Q now.");
2958 move(0, 0); /* move the cursor out of the way */
2961 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2962 extended = 0; /* no longer */
2971 case 'B': /* down */
2983 case '[': /* cheat : always preceeds cursor move */
2984 case 'O': /* ANSI application key mode */
2995 return 1; /* user requests exit */
2997 case '1': /* select an item */
3021 case 'D': /* down */
3034 else if (curr_item == 1)
3035 return visuserconfig();
3037 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3038 /* enable quitfunc */
3039 userconfig_boot_parsing=0;
3041 boothowto |= RB_CONFIG; /* force -c */
3048 #else /* !VISUAL_USERCONFIG */
3050 #endif /* VISUAL_USERCONFIG */
3057 struct pnp_cinfo *c;
3061 for (i=0; i< MAX_PNP_LDN; i++) {
3062 c = &pnp_ldn_overrides[i];
3063 if (c->csn >0 && c->csn != 255) {
3065 static char pfmt[] =
3066 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3067 static char mfmt[] =
3068 "mem 0x%x 0x%x 0x%x 0x%x";
3071 if (!userconfig_boot_parsing) {
3073 if (kgetchar() == 'q') {
3081 if (lineno == 0 || first)
3082 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3084 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3086 c->override ? "OS ":"BIOS",
3087 c->enable ? "Y":"N",
3088 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3090 kprintf("flags 0x%08lx ",c->flags);
3091 for (pmax = 7; pmax >=0 ; pmax--)
3092 if (c->port[pmax]!=0) break;
3093 for (mmax = 3; mmax >=0 ; mmax--)
3094 if (c->mem[mmax].base!=0) break;
3097 buf[10 + 5*pmax]='\0';
3099 c->port[0], c->port[1], c->port[2], c->port[3],
3100 c->port[4], c->port[5], c->port[6], c->port[7]);
3104 buf[8 + 5*mmax]='\0';
3106 c->mem[0].base, c->mem[1].base,
3107 c->mem[2].base, c->mem[3].base);
3117 lsdevtab(struct uc_device *dt)
3119 for (; dt->id_id != 0; dt++) {
3124 if (!userconfig_boot_parsing) {
3125 if (kgetchar() == 'q') {
3135 "Device port irq drq iomem iosize unit flags enab\n"
3139 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3140 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3141 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3142 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3143 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3144 dt->id_enabled ? "Yes" : "No");
3154 int count = resource_count();
3160 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3163 for (i = 0; i < count; i++) {
3164 name = resource_query_name(i);
3165 unit = resource_query_unit(i);
3167 continue; /* skip wildcards */
3168 uc_devtab[dt].id_id = id++;
3169 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3171 resource_int_value(name, unit, "irq", &val);
3172 uc_devtab[dt].id_irq = (1 << val);
3173 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3174 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3175 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3176 uc_devtab[dt].id_unit = unit;
3177 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3179 resource_int_value(name, unit, "disabled", &val);
3180 uc_devtab[dt].id_enabled = !val;
3181 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3182 strcpy(uc_devtab[dt].id_name, name);
3191 int count = resource_count();
3193 for (i = 0; i < count; i++)
3194 if (uc_devtab[i].id_name)
3195 kfree(uc_devtab[i].id_name, M_DEVL);
3196 kfree(uc_devtab, M_DEVL);
3199 static struct uc_device *
3200 find_device(char *devname, int unit)
3202 struct uc_device *ret;
3204 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3209 static struct uc_device *
3210 search_devtable(struct uc_device *dt, char *devname, int unit)
3212 for (; dt->id_id != 0; dt++)
3213 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3219 cngets(char *input, int maxin)
3225 /* Treat ^H or ^? as backspace */
3226 if ((c == '\010' || c == '\177')) {
3228 kprintf("\010 \010");
3229 *--input = '\0', --nchars;
3233 /* Treat ^U or ^X as kill line */
3234 else if ((c == '\025' || c == '\030')) {
3236 kprintf("\010 \010");
3237 *--input = '\0', --nchars;
3242 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3246 *input++ = (u_char)c;
3252 /* scsi: Support for displaying configured SCSI devices.
3253 * There is no way to edit them, and this is inconsistent
3254 * with the ISA method. This is here as a basis for further work.
3257 type_text(char *name) /* XXX: This is bogus */
3259 if (strcmp(name, "sd") == 0)
3262 if (strcmp(name, "st") == 0)
3268 id_put(char *desc, int id)
3270 if (id != SCCONF_UNSPEC)
3273 kprintf("%s", desc);
3275 if (id == SCCONF_ANY)
3287 kprintf("scsi: (can't be edited):\n");
3289 for (i = 0; scsi_cinit[i].driver; i++)
3291 id_put("controller scbus", scsi_cinit[i].scbus);
3293 if (scsi_cinit[i].unit != -1)
3296 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3302 for (i = 0; scsi_dinit[i].name; i++)
3304 kprintf("%s ", type_text(scsi_dinit[i].name));
3306 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3307 id_put(" at scbus", scsi_dinit[i].cunit);
3308 id_put(" target ", scsi_dinit[i].target);
3309 id_put(" lun ", scsi_dinit[i].lun);
3311 if (scsi_dinit[i].flags)
3312 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3319 list_scsi(CmdParm *parms)
3328 save_resource(struct uc_device *idev)
3333 name = idev->id_name;
3334 unit = idev->id_unit;
3335 resource_set_int(name, unit, "port", idev->id_iobase);
3336 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3337 resource_set_int(name, unit, "drq", idev->id_drq);
3338 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3339 resource_set_int(name, unit, "msize", idev->id_msize);
3340 resource_set_int(name, unit, "flags", idev->id_flags);
3341 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3345 save_dev(struct uc_device *idev)
3347 struct uc_device *id_p,*id_pn;
3348 char *name = idev->id_name;
3350 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3351 if (id_p->id_id == idev->id_id) {
3352 id_pn = id_p->id_next;
3354 kfree(id_p->id_name, M_DEVL);
3355 bcopy(idev,id_p,sizeof(struct uc_device));
3356 save_resource(idev);
3357 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3358 strcpy(id_p->id_name, name);
3359 id_p->id_next = id_pn;
3363 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3364 bcopy(idev,id_pn,sizeof(struct uc_device));
3365 save_resource(idev);
3366 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3367 strcpy(id_pn->id_name, name);
3368 id_pn->id_next = uc_devlist;