3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
5 ** This code contains a module marked :
7 * Copyright (c) 1991 Regents of the University of California.
9 * Copyright (c) 1994 Jordan K. Hubbard
10 * All rights reserved.
11 * Copyright (c) 1994 David Greenman
12 * All rights reserved.
14 * Many additional changes by Bruce Evans
16 * This code is derived from software contributed by the
17 * University of California Berkeley, Jordan K. Hubbard,
18 * David Greenman and Bruce Evans.
20 ** As such, it contains code subject to the above copyrights.
21 ** The module and its copyright can be found below.
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
26 ** 1. Redistributions of source code must retain the above copyright
27 ** notice, this list of conditions and the following disclaimer as
28 ** the first lines of this file unmodified.
29 ** 2. Redistributions in binary form must reproduce the above copyright
30 ** notice, this list of conditions and the following disclaimer in the
31 ** documentation and/or other materials provided with the distribution.
32 ** 3. All advertising materials mentioning features or use of this software
33 ** must display the following acknowledgment:
34 ** This product includes software developed by Michael Smith.
35 ** 4. The name of the author may not be used to endorse or promote products
36 ** derived from this software without specific prior written permission.
38 ** THIS SOFTWARE IS PROVIDED BY MICHAEL SMITH ``AS IS'' AND ANY EXPRESS OR
39 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 ** IN NO EVENT SHALL MICHAEL SMITH BE LIABLE FOR ANY DIRECT, INDIRECT,
42 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
55 ** Kernel boot-time configuration manipulation tool for FreeBSD.
57 ** Two modes of operation are supported : the default is the line-editor mode,
58 ** the command "visual" invokes the fullscreen mode.
60 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
61 ** fullscreen mode requires syscons or a minimal-ansi serial console.
65 ** USERCONFIG, visual mode.
69 ** Look for "EDIT THIS LIST" to add to the list of known devices
72 ** There are a number of assumptions made in this code.
74 ** - That the console supports a minimal set of ANSI escape sequences
75 ** (See the screen manipulation section for a summary)
76 ** and has at least 24 rows.
77 ** - That values less than or equal to zero for any of the device
78 ** parameters indicate that the driver does not use the parameter.
79 ** - That flags are _always_ editable.
81 ** Devices marked as disabled are imported as such.
83 ** For this tool to be useful, the list of devices below _MUST_ be updated
84 ** when a new driver is brought into the kernel. It is not possible to
85 ** extract this information from the drivers in the kernel.
89 ** - Display _what_ a device conflicts with.
90 ** - Implement page up/down (as what?)
91 ** - Wizard mode (no restrictions)
92 ** - Find out how to put syscons back into low-intensity mode so that the
93 ** !b escape is useful on the console. (It seems to be that it actually
94 ** gets low/high intensity backwards. That looks OK.)
96 ** - Only display headings with devices under them. (difficult)
99 #include "opt_userconfig.h"
100 #define COMPAT_OLDISA /* get the definitions */
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/kernel.h>
105 #include <sys/malloc.h>
106 #include <sys/reboot.h>
107 #include <sys/linker.h>
108 #include <sys/sysctl.h>
110 #include <sys/cons.h>
112 #include <machine/md_var.h>
113 #include <machine/limits.h>
115 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
121 #include <machine_base/isa/pnp.h>
124 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
126 #include <machine/uc_device.h>
127 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
128 static struct uc_device *uc_devtab; /* fake uc_device table */
130 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
132 static void load_devtab(void);
133 static void free_devtab(void);
134 static void save_resource(struct uc_device *);
137 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
139 struct uc_device *id;
147 error+=sizeof(struct uc_device)+8;
150 return(SYSCTL_OUT(req,0,error));
152 /* Output the data. The buffer is filled with consecutive
153 * struct uc_device and char buf[8], containing the name
154 * (not guaranteed to end with '\0').
158 error=sysctl_handle_opaque(oidp,id,
159 sizeof(struct uc_device),req);
160 if(error) return(error);
161 strncpy(name,id->id_name,8);
162 error=sysctl_handle_opaque(oidp,name,
164 if(error) return(error);
171 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
172 0, 0, sysctl_machdep_uc_devlist, "A",
173 "List of ISA devices changed in UserConfig");
176 ** Obtain command input.
178 ** Initially, input is read from a possibly-loaded script.
179 ** At the end of the script, or if no script is supplied,
180 ** behaviour is determined by the RB_CONFIG (-c) flag. If
181 ** the flag is set, user input is read from the console; if
182 ** unset, the 'quit' command is invoked and userconfig
185 ** Note that quit commands encountered in the script will be
186 ** ignored if the RB_CONFIG flag is supplied.
188 static const char *config_script;
189 static int config_script_size; /* use of int for -ve magic value */
191 #define has_config_script() (config_script_size > 0)
194 init_config_script(void)
196 caddr_t autoentry, autoattr;
198 /* Look for loaded userconfig script */
199 autoentry = preload_search_by_type("userconfig_script");
200 if (autoentry != NULL) {
201 /* We have one, get size and data */
202 config_script_size = 0;
203 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
204 config_script_size = (size_t)*(u_int32_t *)autoattr;
205 config_script = NULL;
206 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
207 config_script = *(const char **)autoattr;
209 if ((config_script_size == 0) || (config_script == NULL)) {
210 config_script_size = 0;
211 config_script = NULL;
214 return has_config_script();
221 #ifdef INTRO_USERCONFIG
222 static int intro = 0;
225 if (has_config_script())
227 /* Consume character from loaded userconfig script, display */
228 userconfig_boot_parsing = 1;
231 config_script_size--;
235 #ifdef INTRO_USERCONFIG
236 if (userconfig_boot_parsing) {
237 if (!(boothowto & RB_CONFIG)) {
238 /* userconfig_script, !RB_CONFIG -> quit */
241 config_script = "uit\n";
242 config_script_size = strlen(config_script);
243 /* userconfig_script will be 1 on the next pass */
246 /* userconfig_script, RB_CONFIG -> cngetc() */
249 if (!(boothowto & RB_CONFIG)) {
250 /* no userconfig_script, !RB_CONFIG -> show intro */
254 config_script = "ntro\n";
255 config_script_size = strlen(config_script);
256 /* userconfig_script will be 1 on the next pass */
259 /* no userconfig_script, RB_CONFIG -> cngetc() */
262 #else /* !INTRO_USERCONFIG */
263 /* assert(boothowto & RB_CONFIG) */
264 #endif /* INTRO_USERCONFIG */
265 userconfig_boot_parsing = 0;
274 #define TRUE (!FALSE)
277 #ifdef VISUAL_USERCONFIG
281 char dev[16]; /* device basename */
282 char name[60]; /* long name */
283 int attrib; /* things to do with the device */
284 int class; /* device classification */
287 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
288 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
289 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
290 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
291 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
292 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
293 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
294 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
295 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
297 #define CLS_STORAGE 1 /* storage devices */
298 #define CLS_NETWORK 2 /* network interfaces */
299 #define CLS_COMMS 3 /* serial, parallel ports */
300 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
301 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
302 #define CLS_MISC 255 /* none of the above */
311 static DEVCLASS_INFO devclass_names[] = {
312 { "Storage : ", CLS_STORAGE},
313 { "Network : ", CLS_NETWORK},
314 { "Communications : ", CLS_COMMS},
315 { "Input : ", CLS_INPUT},
316 { "Multimedia : ", CLS_MMEDIA},
317 { "Miscellaneous : ", CLS_MISC},
321 /********************* EDIT THIS LIST **********************/
325 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
326 ** - XXX The list below should be reviewed by the driver authors to verify
327 ** that the correct flags have been set for each driver, and that the
328 ** descriptions are accurate.
331 static DEV_INFO device_info[] = {
332 /*---Name----- ---Description---------------------------------------------- */
333 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
334 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE},
335 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE},
336 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
337 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE},
338 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
339 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
340 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
341 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
342 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
344 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
345 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
346 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
347 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
348 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
349 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
350 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
351 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
352 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
354 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
355 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS},
356 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
357 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
359 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
360 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
361 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
362 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
363 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
365 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
366 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
367 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
368 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
369 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
370 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
371 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
372 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
373 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
374 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
375 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
376 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
377 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
378 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
379 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
380 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
381 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
382 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
384 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
385 {"pcic", "PC-card controller", 0, CLS_MISC},
386 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
387 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
391 typedef struct _devlist_struct
394 int attrib; /* flag values as per the FLG_* defines above */
395 int class; /* disk, etc as per the CLS_* defines above */
397 int iobase,irq,drq,maddr,msize,unit,flags,id;
398 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
399 int conflicts; /* set/reset by findconflict, count of conflicts */
400 int changed; /* nonzero if the device has been edited */
401 struct uc_device *device;
402 struct _devlist_struct *prev,*next;
407 #define DEV_COMMENT 1
410 #define LIST_CURRENT (1<<0)
411 #define LIST_SELECTED (1<<1)
413 #define KEY_EXIT 0 /* return codes from dolist() and friends */
419 #define KEY_UP 5 /* these only returned from editval() */
423 #define KEY_NULL 9 /* this allows us to spin & redraw */
425 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
426 #define KEY_UNZOOM 11
428 #define KEY_HELP 12 /* duh? */
430 static void redraw(void);
431 static void insdev(DEV_LIST *dev, DEV_LIST *list);
432 static int devinfo(DEV_LIST *dev);
433 static int visuserconfig(void);
435 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
436 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
437 static DEV_LIST scratch; /* scratch record */
438 static int conflicts; /* total conflict count */
441 static char lines[] = "--------------------------------------------------------------------------------";
442 static char spaces[] = " ";
446 ** Device manipulation stuff : find, describe, configure.
452 ** Sets the device referenced by (*dev) to the parameters in the struct,
453 ** and the enable flag according to (enabled)
456 setdev(DEV_LIST *dev, int enabled)
458 dev->device->id_iobase = dev->iobase; /* copy happy */
459 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
460 dev->device->id_drq = (short)dev->drq;
461 dev->device->id_maddr = (caddr_t)dev->maddr;
462 dev->device->id_msize = dev->msize;
463 dev->device->id_flags = dev->flags;
464 dev->device->id_enabled = enabled;
471 ** Walk the kernel device tables and build the active and inactive lists
477 struct uc_device *ap;
479 ap = uc_devtab; /* pointer to array of devices */
480 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
482 scratch.unit = ap[i].id_unit; /* device parameters */
483 strcpy(scratch.dev,ap[i].id_name);
484 scratch.iobase = ap[i].id_iobase;
485 scratch.irq = ffs(ap[i].id_irq)-1;
486 scratch.drq = ap[i].id_drq;
487 scratch.maddr = (int)ap[i].id_maddr;
488 scratch.msize = ap[i].id_msize;
489 scratch.flags = ap[i].id_flags;
491 scratch.comment = DEV_DEVICE; /* admin stuff */
492 scratch.conflicts = 0;
493 scratch.device = &ap[i]; /* save pointer for later reference */
495 if (!devinfo(&scratch)) /* get more info on the device */
496 insdev(&scratch,ap[i].id_enabled?active:inactive);
504 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
505 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
507 ** If the device is marked "invisible", return nonzero; the caller should
508 ** not insert any such device into either list.
512 devinfo(DEV_LIST *dev)
516 for (i = 0; device_info[i].class; i++)
518 if (!strcmp(dev->dev,device_info[i].dev))
520 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
522 strcpy(dev->name,device_info[i].name); /* get the name */
523 dev->attrib = device_info[i].attrib;
524 dev->class = device_info[i].class;
528 strcpy(dev->name,"Unknown device");
530 dev->class = CLS_MISC;
536 ** List manipulation stuff : add, move, initialise, free, traverse
538 ** Note that there are assumptions throughout this code that
539 ** the first entry in a list will never move. (assumed to be
547 ** appends a copy of (dev) to the end of (*list)
550 addev(DEV_LIST *dev, DEV_LIST **list)
555 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
556 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
558 if (*list) /* list exists */
562 ap = ap->next; /* scoot to end of list */
566 }else{ /* list does not yet exist */
568 lp->prev = lp->next = NULL; /* list now exists */
576 ** Finds the 'appropriate' place for (dev) in (list)
578 ** 'Appropriate' means in numeric order with other devices of the same type,
579 ** or in alphabetic order following a comment of the appropriate type.
580 ** or at the end of the list if an appropriate comment is not found. (this should
582 ** (Note that the appropriate point is never the top, but may be the bottom)
585 findspot(DEV_LIST *dev, DEV_LIST *list)
589 /* search for a previous instance of the same device */
590 for (ap = list; ap; ap = ap->next)
592 if (ap->comment != DEV_DEVICE) /* ignore comments */
594 if (!strcmp(dev->dev,ap->dev)) /* same base device */
596 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
597 || !ap->next) /* or end of list */
599 ap = ap->prev; /* back up one */
600 break; /* done here */
602 if (ap->next) /* if the next item exists */
604 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
606 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
612 if (!ap) /* not sure yet */
614 /* search for a class that the device might belong to */
615 for (ap = list; ap; ap = ap->next)
617 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
619 if (dev->class != ap->class) /* of same class too 8) */
621 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
623 ap = ap->prev; /* back up one */
624 break; /* done here */
626 if (ap->next) /* if the next item exists */
627 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
632 if (!ap) /* didn't find a match */
634 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
635 if ((ap->comment != DEV_DEVICE)
636 && (ap->class == dev->class)) /* appropriate place? */
638 } /* or just put up with last */
647 ** Inserts a copy of (dev) at the appropriate point in (list)
650 insdev(DEV_LIST *dev, DEV_LIST *list)
654 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
655 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
657 ap = findspot(lp,list); /* find appropriate spot */
658 lp->next = ap->next; /* point to next */
660 ap->next->prev = lp; /* point next to new */
661 lp->prev = ap; /* point new to current */
662 ap->next = lp; /* and current to new */
669 ** Moves (dev) from its current list to an appropriate place in (list)
670 ** (dev) may not come from the top of a list, but it may from the bottom.
673 movedev(DEV_LIST *dev, DEV_LIST *list)
677 ap = findspot(dev,list);
678 dev->prev->next = dev->next; /* remove from old list */
680 dev->next->prev = dev->prev;
682 dev->next = ap->next; /* insert in new list */
684 ap->next->prev = dev; /* point next to new */
685 dev->prev = ap; /* point new to current */
686 ap->next = dev; /* and current to new */
693 ** Initialises (*list) with the basic headings
696 initlist(DEV_LIST **list)
700 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
702 strcpy(scratch.name,devclass_names[i].name);
703 scratch.comment = DEV_ZOOMED;
704 scratch.class = devclass_names[i].number;
705 scratch.attrib = FLG_MANDATORY; /* can't be moved */
706 addev(&scratch,list); /* add to the list */
714 ** Walks (list) and saves the settings of any entry marked as changed.
716 ** The device's active field is set according to (active).
718 ** Builds the uc_devlist used by kget to extract the changed device information.
719 ** The code for this was taken almost verbatim from the original module.
722 savelist(DEV_LIST *list, int active)
724 struct uc_device *id_p,*id_pn;
729 if ((list->comment == DEV_DEVICE) && /* is a device */
730 (list->changed) && /* has been changed */
731 (list->device != NULL)) { /* has an uc_device structure */
733 setdev(list,active); /* set the device itself */
736 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
737 { /* look on the list for it */
738 if (id_p->id_id == list->device->id_id)
740 name = list->device->id_name;
741 id_pn = id_p->id_next;
743 kfree(id_p->id_name, M_DEVL);
744 bcopy(list->device,id_p,sizeof(struct uc_device));
745 save_resource(list->device);
746 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
747 strcpy(id_p->id_name, name);
748 id_pn->id_next = uc_devlist;
749 id_p->id_next = id_pn;
753 if (!id_pn) /* not already on the list */
755 name = list->device->id_name;
756 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
757 bcopy(list->device,id_pn,sizeof(struct uc_device));
758 save_resource(list->device);
759 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
760 strcpy(id_pn->id_name, name);
761 id_pn->id_next = uc_devlist;
762 uc_devlist = id_pn; /* park at top of list */
773 ** Frees all storage in use by a (list).
776 nukelist(DEV_LIST *list)
782 while(list->prev) /* walk to head of list */
797 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
798 ** if there is no previous entry. (Only possible if list->prev == NULL given the
799 ** premise that there is always a comment at the head of the list)
802 prevent(DEV_LIST *list)
808 dp = list->prev; /* start back one */
811 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
812 return(dp); /* so skip to comment */
813 if (dp->comment == DEV_COMMENT) /* not zoomed */
814 return(list->prev); /* one back as normal */
815 dp = dp->prev; /* backpedal */
817 return(dp); /* NULL, we can assume */
824 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
825 ** if there is no next entry. (Possible if the current entry is last, or
826 ** if the current entry is the last heading and it's collapsed)
829 nextent(DEV_LIST *list)
835 if (list->comment != DEV_ZOOMED) /* no reason to skip */
840 if (dp->comment != DEV_DEVICE) /* found another heading */
844 return(dp); /* back we go */
851 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
854 ofsent(int ofs, DEV_LIST *list)
856 while (ofs-- && list)
857 list = nextent(list);
865 ** Scans every element of (list) and sets the conflict tags appropriately
866 ** Returns the number of conflicts found.
869 findconflict(DEV_LIST *list)
871 int count = 0; /* number of conflicts found */
874 for (dp = list; dp; dp = dp->next) /* over the whole list */
876 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
879 dp->conflicts = 0; /* assume the best */
880 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
882 if (sp->comment != DEV_DEVICE) /* likewise */
885 if (sp == dp) /* always conflict with itself */
888 if ((dp->iobase > 0) && /* iobase conflict? */
889 (dp->iobase == sp->iobase))
891 if ((dp->irq > 0) && /* irq conflict? */
892 (dp->irq == sp->irq))
894 if ((dp->drq > 0) && /* drq conflict? */
895 (dp->drq == sp->drq))
897 if ((sp->maddr > 0) && /* maddr/msize conflict? */
899 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
900 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
903 count += dp->conflicts; /* count conflicts */
912 ** Unzooms all headings in (list)
915 expandlist(DEV_LIST *list)
919 if (list->comment == DEV_COMMENT)
920 list->comment = DEV_ZOOMED;
929 ** Zooms all headings in (list)
932 collapselist(DEV_LIST *list)
936 if (list->comment == DEV_ZOOMED)
937 list->comment = DEV_COMMENT;
944 ** Screen-manipulation stuff
946 ** This is the basic screen layout :
948 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
949 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
950 ** +--------------------------------------------------------------------------------+
951 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
952 ** 1 -| ........................ ....... .. 0x....|
953 ** 2 -| ........................ ....... .. 0x....|
954 ** 3 -| ........................ ....... .. 0x....|
955 ** 4 -| ........................ ....... .. 0x....|
956 ** 5 -| ........................ ....... .. 0x....|
957 ** 6 -| ........................ ....... .. 0x....|
958 ** 7 -| ........................ ....... .. 0x....|
959 ** 8 -| ........................ ....... .. 0x....|
960 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
961 ** 10-| ........................ ....... |
962 ** 11-| ........................ ....... |
963 ** 12-| ........................ ....... |
964 ** 13-| ........................ ....... |
965 ** 14-| ........................ ....... |
966 ** 15-| ........................ ....... |
967 ** 16-| ........................ ....... |
968 ** 17-|------------------------------------------------------UP-DOWN-------------------|
969 ** 18-| Relevant parameters for the current device |
972 ** 21-|--------------------------------------------------------------------------------|
973 ** 22-| Help texts go here |
975 ** +--------------------------------------------------------------------------------+
979 ** On a collapsed comment :
981 ** [Enter] Expand device list [z] Expand all lists
982 ** [TAB] Change fields [Q] Save and Exit
984 ** On an expanded comment :
986 ** [Enter] Collapse device list [Z] Collapse all lists
987 ** [TAB] Change fields [Q] Save and Exit
989 ** On a comment with no followers
992 ** [TAB] Change fields [Q] Save and Exit
994 ** On a device in the active list
996 ** [Enter] Edit device parameters [DEL] Disable device
997 ** [TAB] Change fields [Q] Save and Exit [?] Help
999 ** On a device in the inactive list
1001 ** [Enter] Enable device
1002 ** [TAB] Change fields [Q] Save and Exit [?] Help
1004 ** While editing parameters
1006 ** <parameter-specific help here>
1007 ** [TAB] Change fields [Q] Save device parameters
1014 ** The base-level screen primitives :
1016 ** bold() - enter bold mode \E[1m (md)
1017 ** inverse() - enter inverse mode \E[7m (so)
1018 ** normal() - clear bold/inverse mode \E[m (se)
1019 ** clear() - clear the screen \E[H\E[J (ce)
1020 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1045 kprintf("\033[H\033[J");
1051 kprintf("\033[%d;%dH",y+1,x+1);
1057 ** High-level screen primitives :
1059 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1060 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1061 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1062 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1063 ** putmsg(str) - put (str) in the message area
1064 ** puthelp(str) - put (str) in the upper helpline
1065 ** pad(str,len) - pad (str) to (len) with spaces
1066 ** drawline(row,detail,list,inverse,*dhelp)
1067 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1068 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1069 ** draw the line in inverse video, and display (*dhelp) on the
1071 ** drawlist(row,num,detail,list)
1072 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1073 ** through to drawline().
1074 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1075 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1076 ** redraw(); - Redraws the entire screen layout, including the
1077 ** - two list panels.
1082 ** writes (str) at x,y onscreen
1084 ** writes up to (len) of (str) at x,y onscreen.
1086 ** Supports embedded formatting :
1087 ** !i - inverse mode.
1089 ** !n - normal mode.
1092 putxyl(int x, int y, char *str, int len)
1097 while((*str) && (len--))
1099 if (*str == '!') /* format escape? */
1101 switch(*(str+1)) /* depending on the next character */
1105 str +=2; /* skip formatting */
1106 len++; /* doesn't count for length */
1111 str +=2; /* skip formatting */
1112 len++; /* doesn't count for length */
1117 str +=2; /* skip formatting */
1118 len++; /* doesn't count for length */
1122 kprintf("%c", *str++); /* not an escape */
1125 kprintf("%c", *str++); /* emit the character */
1130 #define putxy(x,y,str) putxyl(x,y,str,-1)
1136 ** Erases the region (x,y,w,h)
1139 erase(int x, int y, int w, int h)
1144 for (i = 0; i < h; i++)
1145 putxyl(x,y++,spaces,w);
1152 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1153 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1156 txtbox(int x, int y, int w, int h, char *str)
1161 while((str[i]) && h)
1163 if (str[i] == '\n') /* newline */
1165 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1166 y++; /* move down */
1167 h--; /* room for one less */
1168 str += (i+1); /* skip first newline */
1169 i = 0; /* zero offset */
1171 i++; /* next character */
1174 if (h) /* end of string, not region */
1182 ** writes (msg) in the helptext area
1187 erase(0,18,80,3); /* clear area */
1188 txtbox(0,18,80,3,msg);
1195 ** Writes (msg) in the helpline area
1208 ** Draws the help message at the bottom of the screen
1211 masterhelp(char *msg)
1221 ** space-pads a (str) to (len) characters
1224 pad(char *str, int len)
1228 for (i = 0; str[i]; i++) /* find the end of the string */
1230 if (i >= len) /* no padding needed */
1232 while(i < len) /* pad */
1241 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1242 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1244 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1245 ** help is shown for normal or zoomed comments
1248 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1250 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1252 if (list->comment == DEV_DEVICE)
1255 strncpy(nb+1,list->name,57);
1257 strncpy(nb,list->name,58);
1258 if ((list->comment == DEV_ZOOMED) && (list->next))
1259 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1260 strcat(nb," (Collapsed)");
1264 if (list->conflicts) /* device in conflict? */
1268 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1270 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1273 if (list->comment == DEV_DEVICE)
1275 ksprintf(db,"%s%d",list->dev,list->unit);
1280 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1282 ksprintf(ib," %d",list->irq);
1287 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1289 ksprintf(pb,"0x%x",list->iobase);
1295 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1297 putxyl(0,row,lbuf,80);
1300 switch(list->comment)
1302 case DEV_DEVICE: /* ordinary device */
1308 if (list->next->comment == DEV_DEVICE)
1309 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1314 if (list->next->comment == DEV_DEVICE)
1315 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1318 puthelp(" WARNING: This list entry corrupted!");
1322 move(0,row); /* put the cursor somewhere relevant */
1329 ** Displays (num) lines of the contents of (list) at (row), optionally
1330 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1333 drawlist(int row, int num, int detail, DEV_LIST *list)
1337 for(ofs = 0; ofs < num; ofs++)
1341 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1342 list = nextent(list); /* move down visible list */
1344 erase(0,row+ofs,80,1);
1353 ** Redraws the active list
1362 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1365 putxyl(45,0,lines,16);
1367 drawlist(1,8,1,alist); /* draw device lists */
1373 ** Redraws the inactive list
1376 redrawinactive(void)
1378 drawlist(10,7,0,ilist); /* draw device lists */
1385 ** Clear the screen and redraw the entire layout
1392 putxy(3,0,"!bActive!n-!bDrivers");
1393 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1395 putxy(3,9,"!bInactive!n-!bDrivers");
1396 putxy(63,9,"!bDev");
1399 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1409 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1410 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1413 yesnocancel(char *str)
1439 ** Show device parameters in the region below the lists
1441 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1442 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1443 ** +--------------------------------------------------------------------------------+
1444 ** 17-|--------------------------------------------------------------------------------|
1445 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1446 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1447 ** 20-| Flags : 0x0000 DRQ number : 00 |
1448 ** 21-|--------------------------------------------------------------------------------|
1451 showparams(DEV_LIST *dev)
1455 erase(0,18,80,3); /* clear area */
1458 if (dev->comment != DEV_DEVICE)
1462 if (dev->iobase > 0)
1464 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1470 ksprintf(buf,"IRQ number : %d",dev->irq);
1473 ksprintf(buf,"Flags : 0x%x",dev->flags);
1477 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1482 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1488 ksprintf(buf,"DRQ number : %d",dev->drq);
1495 ** Editing functions for device parameters
1497 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1498 ** onscreen. Refuse values outsise (min) and (max).
1499 ** editparams(dev) - Edit the parameters for (dev)
1503 #define VetRet(code) \
1505 if ((i >= min) && (i <= max)) /* legit? */ \
1508 ksprintf(buf,hex?"0x%x":"%d",i); \
1509 putxy(hex?x-2:x,y,buf); \
1510 return(code); /* all done and exit */ \
1512 i = *val; /* restore original value */ \
1513 delta = 1; /* restore other stuff */ \
1520 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1521 ** in a field (width) wide. (Allow one space)
1522 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1524 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1527 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1529 int i = *val; /* work with copy of the value */
1530 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1531 int xp = 0; /* cursor offset into text copy */
1532 int delta = 1; /* force redraw first time in */
1534 int extended = 0; /* stage counter for extended key sequences */
1536 if (hex) /* we presume there's a leading 0x onscreen */
1537 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1541 if (delta) /* only update if necessary */
1543 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1544 ksprintf(buf,"!i%s",tc); /* format for printing */
1545 erase(x,y,width,1); /* clear the area */
1546 putxy(x,y,buf); /* write */
1547 xp = strlen(tc); /* cursor always at end */
1548 move(x+xp,y); /* position the cursor */
1553 switch(extended) /* escape handling */
1556 if (c == 0x1b) /* esc? */
1558 extended = 1; /* flag and spin */
1562 break; /* nope, drop through */
1564 case 1: /* there was an escape prefix */
1565 if (c == '[' || c == 'O') /* second character in sequence */
1571 return(KEY_EXIT); /* double esc exits */
1573 break; /* nup, not a sequence. */
1577 switch(c) /* looks like the real McCoy */
1580 VetRet(KEY_UP); /* leave if OK */
1583 VetRet(KEY_DOWN); /* leave if OK */
1586 VetRet(KEY_RIGHT); /* leave if OK */
1589 VetRet(KEY_LEFT); /* leave if OK */
1599 case '\t': /* trying to tab off */
1600 VetRet(KEY_TAB); /* verify and maybe return */
1610 case '\177': /* BS or DEL */
1611 if (ro) /* readonly? */
1613 puthelp(" !iThis value cannot be edited (Press ESC)");
1614 while(kgetchar() != 0x1b); /* wait for key */
1615 return(KEY_NULL); /* spin */
1617 if (xp) /* still something left to delete */
1619 i = (hex ? i/0x10u : i/10); /* strip last digit */
1620 delta = 1; /* force update */
1643 if (ro) /* readonly? */
1645 puthelp(" !iThis value cannot be edited (Press ESC)");
1646 while(kgetchar() != 0x1b); /* wait for key */
1647 return(KEY_NULL); /* spin */
1649 if (xp >= width) /* no room for more characters anyway */
1653 if ((c >= '0') && (c <= '9'))
1655 i = i*0x10 + (c-'0'); /* update value */
1659 if ((c >= 'a') && (c <= 'f'))
1661 i = i*0x10 + (c-'a'+0xa);
1665 if ((c >= 'A') && (c <= 'F'))
1667 i = i*0x10 + (c-'A'+0xa);
1672 if ((c >= '0') && (c <= '9'))
1674 i = i*10 + (c-'0'); /* update value */
1675 delta = 1; /* force redraw */
1688 ** Edit the parameters for (dev)
1690 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1691 ** possible for this to spin in an endless loop...
1692 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1693 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1694 ** +--------------------------------------------------------------------------------+
1695 ** 17-|--------------------------------------------------------------------------------|
1696 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1697 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1698 ** 20-| Flags : 0x0000 DRQ number : 00 |
1699 ** 21-|--------------------------------------------------------------------------------|
1701 ** The "intelligence" in this function that hops around based on the directional
1702 ** returns from editval isn't very smart, and depends on the layout above.
1705 editparams(DEV_LIST *dev)
1708 char buf[16]; /* needs to fit the device name */
1710 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1711 ksprintf(buf,"!b%s",dev->dev);
1718 if (dev->iobase > 0)
1720 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1721 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1741 puthelp(" Interrupt number (Decimal, 1-15)");
1742 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1754 if (dev->iobase > 0)
1765 puthelp(" Device-specific flag values.");
1766 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1780 if (dev->iobase > 0)
1800 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1801 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1808 if (dev->iobase > 0)
1830 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1831 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1860 puthelp(" Device DMA request number (Decimal, 1-7)");
1861 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1884 dev->changed = 1; /* mark as changed */
1887 static char *helptext[] =
1889 " Using the UserConfig kernel settings editor",
1890 " -------------------------------------------",
1896 "The screen displays a list of available drivers, divided into two",
1897 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1898 "by default collapsed and can be expanded to show all the drivers",
1899 "available in each category. The parameters for the currently selected",
1900 "driver are shown at the bottom of the screen.",
1902 "- - Moving around -",
1904 "To move in the current list, use the UP and DOWN cursor keys to select",
1905 "an item (the selected item will be highlighted). If the item is a",
1906 "category name, you may alternatively expand or collapse the list of",
1907 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1908 "expanded, you can select each driver in the same manner and either:",
1910 " - change its parameters using [!bENTER!n]",
1911 " - move it to the Inactive list using [!bDEL!n]",
1913 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1914 "you need to move a driver from the Inactive list back to the Active",
1915 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1916 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1917 "its place in the Active list.",
1919 "- - Altering the list/parameters -",
1921 "Any drivers for devices not installed in your system should be moved",
1922 "to the Inactive list, until there are no remaining parameter conflicts",
1923 "between the drivers, as indicated at the top.",
1925 "Once the list of Active drivers only contains entries for the devices",
1926 "present in your system, you can set their parameters (Interrupt, DMA",
1927 "channel, I/O addresses). To do this, select the driver and press",
1928 "[!bENTER!n]: it is now possible to edit the settings at the",
1929 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1930 "finished, use [!bQ!n] to return to the list.",
1932 "- - Saving changes -",
1934 "When all settings seem correct, and you wish to proceed with the",
1935 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1936 "confirm your choice.",
1945 ** Displays help text onscreen for people that are confused, using a simple
1951 int topline = 0; /* where we are in the text */
1952 int line = 0; /* last line we displayed */
1956 for (;;) /* loop until user quits */
1958 /* display help text */
1961 clear(); /* remove everything else */
1962 for (line = topline;
1963 (line < (topline + 24)) && (helptext[line]);
1965 putxy(0,line-topline,helptext[line]);
1970 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1973 c = kgetchar(); /* so what do they say? */
1980 case 'B': /* wired into 'more' users' fingers */
1981 if (topline > 0) /* room to go up? */
1984 if (topline < 0) /* don't go too far */
1992 case ' ': /* expected by most people */
1993 if (helptext[line]) /* maybe more below? */
2002 redraw(); /* restore the screen */
2010 ** High-level control functions
2017 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2018 ** (num) lines, starting at (*ofs) offset from row onscreen.
2019 ** Pass (detail) on to drawing routines.
2021 ** If the user hits a key other than a cursor key, maybe return a code.
2023 ** (*list) points to the device at the top line in the region, (*ofs) is the
2024 ** position of the highlight within the region. All routines below
2025 ** this take only a device and an absolute row : use ofsent() to find the
2026 ** device, and add (*ofs) to (row) to find the absolute row.
2029 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2040 showparams(ofsent(*ofs,*list)); /* show device parameters */
2041 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2045 c = kgetchar(); /* get a character */
2046 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2048 extended = 0; /* no longer */
2051 case 588: /* syscons' idea of 'up' */
2053 if (*ofs) /* just a move onscreen */
2055 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2056 (*ofs)--; /* move up */
2058 lp = prevent(*list); /* can we go up? */
2061 *list = lp; /* yes, move up list */
2062 drawlist(row,num,detail,*list);
2067 case 596: /* dooby-do */
2068 case 'B': /* down */
2069 lp = ofsent(*ofs,*list); /* get current item */
2071 break; /* nothing more to move to */
2072 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2073 if (*ofs < (num-1)) /* room to move onscreen? */
2077 *list = nextent(*list); /* scroll region down */
2078 drawlist(row,num,detail,*list);
2090 case '[': /* cheat : always preceeds cursor move */
2091 case 'O': /* ANSI application key mode */
2100 return(KEY_EXIT); /* user requests exit */
2104 return(KEY_DO); /* "do" something */
2109 return(KEY_DEL); /* "delete" response */
2113 return(KEY_UNZOOM); /* expand everything */
2117 return(KEY_ZOOM); /* collapse everything */
2120 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2121 return(KEY_TAB); /* "move" response */
2123 case '\014': /* ^L, redraw */
2126 case '?': /* helptext */
2138 ** Do the fullscreen config thang
2143 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2147 initlist(&inactive);
2153 conflicts = findconflict(active); /* find conflicts in the active list only */
2161 case 0: /* active devices */
2162 ret = dolist(1,8,1,&actofs,&alist,
2163 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2167 mode = 1; /* swap lists */
2184 collapselist(active);
2189 dp = ofsent(actofs,alist); /* get current device */
2190 if (dp) /* paranoia... */
2192 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2194 if (dp == alist) /* moving top item on list? */
2198 alist = dp->next; /* point list to non-moving item */
2200 alist = dp->prev; /* end of list, go back instead */
2203 if (!dp->next) /* moving last item on list? */
2206 dp->conflicts = 0; /* no conflicts on the inactive list */
2207 movedev(dp,inactive); /* shift to inactive list */
2208 conflicts = findconflict(active); /* update conflict tags */
2210 redrawactive(); /* redraw */
2215 case KEY_DO: /* edit device parameters */
2216 dp = ofsent(actofs,alist); /* get current device */
2217 if (dp) /* paranoia... */
2219 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2221 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2223 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2225 conflicts = findconflict(active); /* update conflict tags */
2226 }else{ /* DO on comment = zoom */
2227 switch(dp->comment) /* Depends on current state */
2229 case DEV_COMMENT: /* not currently zoomed */
2230 dp->comment = DEV_ZOOMED;
2234 dp->comment = DEV_COMMENT;
2244 case 1: /* inactive devices */
2245 ret = dolist(10,7,0,&inactofs,&ilist,
2246 " [!bEnter!n] Enable device ");
2260 expandlist(inactive);
2267 collapselist(inactive);
2272 dp = ofsent(inactofs,ilist); /* get current device */
2273 if (dp) /* paranoia... */
2275 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2277 if (dp == ilist) /* moving top of list? */
2281 ilist = dp->next; /* point list to non-moving item */
2283 ilist = dp->prev; /* can't go down, go up instead */
2286 if (!dp->next) /* last entry on list? */
2287 inactofs--; /* shift cursor up one */
2290 movedev(dp,active); /* shift to active list */
2291 conflicts = findconflict(active); /* update conflict tags */
2293 alist = dp; /* put at top and current */
2295 while(dp->comment == DEV_DEVICE)
2296 dp = dp->prev; /* forcibly unzoom section */
2297 dp ->comment = DEV_COMMENT;
2298 mode = 0; /* and swap modes to follow it */
2300 }else{ /* DO on comment = zoom */
2301 switch(dp->comment) /* Depends on current state */
2303 case DEV_COMMENT: /* not currently zoomed */
2304 dp->comment = DEV_ZOOMED;
2308 dp->comment = DEV_COMMENT;
2312 redrawactive(); /* redraw */
2317 default: /* nothing else relevant here */
2322 mode = 0; /* shouldn't happen... */
2325 /* handle returns that are the same for both modes */
2332 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2335 case 2: /* cancel */
2339 case 1: /* save and exit */
2341 savelist(inactive,0);
2344 nukelist(active); /* clean up after ourselves */
2354 #endif /* VISUAL_USERCONFIG */
2357 * Copyright (c) 1991 Regents of the University of California.
2358 * All rights reserved.
2359 * Copyright (c) 1994 Jordan K. Hubbard
2360 * All rights reserved.
2361 * Copyright (c) 1994 David Greenman
2362 * All rights reserved.
2364 * Many additional changes by Bruce Evans
2366 * This code is derived from software contributed by the
2367 * University of California Berkeley, Jordan K. Hubbard,
2368 * David Greenman and Bruce Evans.
2370 * Redistribution and use in source and binary forms, with or without
2371 * modification, are permitted provided that the following conditions
2373 * 1. Redistributions of source code must retain the above copyright
2374 * notice, this list of conditions and the following disclaimer.
2375 * 2. Redistributions in binary form must reproduce the above copyright
2376 * notice, this list of conditions and the following disclaimer in the
2377 * documentation and/or other materials provided with the distribution.
2378 * 3. All advertising materials mentioning features or use of this software
2379 * must display the following acknowledgement:
2380 * This product includes software developed by the University of
2381 * California, Berkeley and its contributors.
2382 * 4. Neither the name of the University nor the names of its contributors
2383 * may be used to endorse or promote products derived from this software
2384 * without specific prior written permission.
2386 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2387 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2388 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2389 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2390 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2391 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2392 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2393 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2394 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2395 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2398 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2401 #define PARM_DEVSPEC 0x1
2402 #define PARM_INT 0x2
2403 #define PARM_ADDR 0x3
2404 #define PARM_STRING 0x4
2406 typedef struct _cmdparm {
2409 struct uc_device *dparm;
2418 typedef int (*CmdFunc)(CmdParm *);
2420 typedef struct _cmd {
2428 static void lsscsi(void);
2429 static int list_scsi(CmdParm *);
2432 static int lsdevtab(struct uc_device *);
2433 static struct uc_device *find_device(char *, int);
2434 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2435 static void cngets(char *, int);
2436 static Cmd *parse_cmd(char *);
2437 static int parse_args(const char *, CmdParm *);
2438 static int save_dev(struct uc_device *);
2440 static int list_devices(CmdParm *);
2441 static int set_device_ioaddr(CmdParm *);
2442 static int set_device_irq(CmdParm *);
2443 static int set_device_drq(CmdParm *);
2444 static int set_device_iosize(CmdParm *);
2445 static int set_device_mem(CmdParm *);
2446 static int set_device_flags(CmdParm *);
2447 static int set_device_enable(CmdParm *);
2448 static int set_device_disable(CmdParm *);
2449 static int quitfunc(CmdParm *);
2450 static int helpfunc(CmdParm *);
2451 static int introfunc(CmdParm *);
2454 static int lspnp(void);
2455 static int set_pnp_parms(CmdParm *);
2460 static CmdParm addr_parms[] = {
2461 { PARM_DEVSPEC, {} },
2466 static CmdParm int_parms[] = {
2467 { PARM_DEVSPEC, {} },
2472 static CmdParm dev_parms[] = {
2473 { PARM_DEVSPEC, {} },
2478 static CmdParm string_arg[] = {
2479 { PARM_STRING, {} },
2484 static Cmd CmdList[] = {
2485 { "?", helpfunc, NULL }, /* ? (help) */
2486 { "di", set_device_disable, dev_parms }, /* disable dev */
2487 { "dr", set_device_drq, int_parms }, /* drq dev # */
2488 { "en", set_device_enable, dev_parms }, /* enable dev */
2489 { "ex", quitfunc, NULL }, /* exit (quit) */
2490 { "f", set_device_flags, int_parms }, /* flags dev mask */
2491 { "h", helpfunc, NULL }, /* help */
2492 { "intro", introfunc, NULL }, /* intro screen */
2493 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2494 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2495 { "ir", set_device_irq, int_parms }, /* irq dev # */
2496 { "l", list_devices, NULL }, /* ls, list */
2498 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2500 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2501 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2502 { "q", quitfunc, NULL }, /* quit */
2504 { "s", list_scsi, NULL }, /* scsi */
2506 #ifdef VISUAL_USERCONFIG
2507 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2509 { NULL, NULL, NULL },
2515 static char banner = 1;
2521 init_config_script();
2524 /* Only display signon banner if we are about to go interactive */
2525 if (!has_config_script()) {
2526 if (!(boothowto & RB_CONFIG))
2527 #ifdef INTRO_USERCONFIG
2534 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2535 " Type \"help\" for help"
2536 #ifdef VISUAL_USERCONFIG
2537 " or \"visual\" to go to the visual\n"
2538 " configuration interface (requires MGA/VGA display or\n"
2539 " serial terminal capable of displaying ANSI graphics)"
2545 kprintf("config> ");
2547 if (input[0] == '\0')
2549 cmd = parse_cmd(input);
2551 kprintf("Invalid command or syntax. Type `?' for help.\n");
2554 rval = (*cmd->handler)(cmd->parms);
2563 parse_cmd(char *cmd)
2567 for (cp = CmdList; cp->name; cp++) {
2568 int len = strlen(cp->name);
2570 if (!strncmp(cp->name, cmd, len)) {
2571 while (*cmd && *cmd != ' ' && *cmd != '\t')
2573 if (parse_args(cmd, cp->parms))
2583 parse_args(const char *cmd, CmdParm *parms)
2588 if (*cmd == ' ' || *cmd == '\t') {
2592 if (parms == NULL || parms->type == -1) {
2595 kprintf("Extra arg(s): %s\n", cmd);
2598 if (parms->type == PARM_DEVSPEC) {
2603 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2604 (*cmd >= '0' && *cmd <= '9')))
2605 devname[i++] = *(cmd++);
2607 if (*cmd >= '0' && *cmd <= '9') {
2608 unit = strtoul(cmd, &ptr, 10);
2610 kprintf("Invalid device number\n");
2611 /* XXX should print invalid token here and elsewhere. */
2614 /* XXX else should require end of token. */
2617 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2618 kprintf("No such device: %s%d\n", devname, unit);
2624 if (parms->type == PARM_INT) {
2625 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2627 kprintf("Invalid numeric argument\n");
2634 if (parms->type == PARM_ADDR) {
2635 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2637 kprintf("Invalid address argument\n");
2644 if (parms->type == PARM_STRING) {
2645 parms->parm.u.sparm = cmd;
2653 list_devices(CmdParm *parms)
2656 if (lsdevtab(uc_devtab)) return 0;
2658 if (lspnp()) return 0;
2664 set_device_ioaddr(CmdParm *parms)
2666 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2667 save_dev(parms[0].parm.dparm);
2672 set_device_irq(CmdParm *parms)
2676 irq = parms[1].parm.iparm;
2678 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2681 else if (irq != -1 && irq > 15) {
2682 kprintf("An IRQ > 15 would be invalid.\n");
2685 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2686 save_dev(parms[0].parm.dparm);
2691 set_device_drq(CmdParm *parms)
2696 * The bounds checking is just to ensure that the value can be printed
2697 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2699 drq = parms[1].parm.iparm;
2700 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2701 save_dev(parms[0].parm.dparm);
2706 set_device_iosize(CmdParm *parms)
2708 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2709 save_dev(parms[0].parm.dparm);
2714 set_device_mem(CmdParm *parms)
2716 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2717 save_dev(parms[0].parm.dparm);
2722 set_device_flags(CmdParm *parms)
2724 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2725 save_dev(parms[0].parm.dparm);
2730 set_device_enable(CmdParm *parms)
2732 parms[0].parm.dparm->id_enabled = TRUE;
2733 save_dev(parms[0].parm.dparm);
2738 set_device_disable(CmdParm *parms)
2740 parms[0].parm.dparm->id_enabled = FALSE;
2741 save_dev(parms[0].parm.dparm);
2748 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2754 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2757 * Output the pnp_ldn_overrides[] table.
2759 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2760 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2761 if(error) return(error);
2766 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2767 0, 0, sysctl_machdep_uc_pnplist, "A",
2768 "List of PnP overrides changed in UserConfig");
2771 * this function sets the kernel table to override bios PnP
2775 set_pnp_parms(CmdParm *parms)
2777 u_long idx, val, ldn, csn;
2780 const char *p = parms[0].parm.u.sparm;
2783 csn=strtoul(p,&q, 0);
2784 ldn=strtoul(q,&q, 0);
2785 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2786 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2787 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2790 for (i=0; i < MAX_PNP_LDN; i++) {
2791 if (pnp_ldn_overrides[i].csn == csn &&
2792 pnp_ldn_overrides[i].ldn == ldn)
2795 if (i==MAX_PNP_LDN) {
2796 for (i=0; i < MAX_PNP_LDN; i++) {
2797 if (pnp_ldn_overrides[i].csn <1 ||
2798 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2802 if (i==MAX_PNP_LDN) {
2803 kprintf("sorry, no PnP entries available, try delete one\n");
2806 d = pnp_ldn_overrides[i] ;
2812 if (!strncmp(p,"irq",3)) {
2813 idx=strtoul(p+3,&q, 0);
2814 val=strtoul(q,&q, 0);
2815 if (idx >=0 && idx < 2) d.irq[idx] = val;
2816 } else if (!strncmp(p,"flags",5)) {
2817 idx=strtoul(p+5,&q, 0);
2819 } else if (!strncmp(p,"drq",3)) {
2820 idx=strtoul(p+3,&q, 0);
2821 val=strtoul(q,&q, 0);
2822 if (idx >=0 && idx < 2) d.drq[idx] = val;
2823 } else if (!strncmp(p,"port",4)) {
2824 idx=strtoul(p+4,&q, 0);
2825 val=strtoul(q,&q, 0);
2826 if (idx >=0 && idx < 8) d.port[idx] = val;
2827 } else if (!strncmp(p,"mem",3)) {
2828 idx=strtoul(p+3,&q, 0);
2829 val=strtoul(q,&q, 0);
2830 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2831 } else if (!strncmp(p,"bios",4)) {
2834 } else if (!strncmp(p,"os",2)) {
2837 } else if (!strncmp(p,"disable",7)) {
2840 } else if (!strncmp(p,"enable",6)) {
2843 } else if (!strncmp(p,"delete",6)) {
2844 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2845 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2848 kprintf("unknown command <%s>\n", p);
2851 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2853 pnp_ldn_overrides[i] = d ;
2859 quitfunc(CmdParm *parms)
2862 * If kernel config supplied, and we are parsing it, and -c also supplied,
2863 * ignore a quit command, This provides a safety mechanism to allow
2864 * recovery from a damaged/buggy kernel config.
2866 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2872 helpfunc(CmdParm *parms)
2875 "Command\t\t\tDescription\n"
2876 "-------\t\t\t-----------\n"
2877 "ls\t\t\tList currently configured devices\n"
2878 "port <devname> <addr>\tSet device port (i/o address)\n"
2879 "irq <devname> <number>\tSet device irq\n"
2880 "drq <devname> <number>\tSet device drq\n"
2881 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2882 "iosize <devname> <size>\tSet device memory size\n"
2883 "flags <devname> <mask>\tSet device flags\n"
2884 "enable <devname>\tEnable device\n"
2885 "disable <devname>\tDisable device (will not be probed)\n");
2888 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2889 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2890 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2891 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2892 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2893 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2896 "quit\t\t\tExit this configuration utility\n"
2897 "reset\t\t\tReset CPU\n");
2898 #ifdef VISUAL_USERCONFIG
2899 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2902 "help\t\t\tThis message\n\n"
2903 "Commands may be abbreviated to a unique prefix\n");
2907 #if defined (VISUAL_USERCONFIG)
2909 center(int y, char *str)
2911 putxy((80 - strlen(str)) / 2, y, str);
2916 introfunc(CmdParm *parms)
2918 #if defined (VISUAL_USERCONFIG)
2919 int curr_item, first_time, extended = 0;
2920 static char *choices[] = {
2921 " Skip kernel configuration and continue with installation ",
2922 " Start kernel configuration in full-screen visual mode ",
2923 " Start kernel configuration in CLI mode ",
2927 center(2, "!bKernel Configuration Menu!n");
2936 for (i = 0; i < 3; i++) {
2940 strcat(tmp, choices[i]);
2943 putxy(10, 5 + i, tmp);
2947 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2948 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2949 putxy(2, 12, "match your hardware configuration.");
2950 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2951 putxy(2, 15, "(press Down-Arrow then ENTER).");
2952 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2953 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2954 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2955 putxy(2, 21, "then simply press ENTER or Q now.");
2959 move(0, 0); /* move the cursor out of the way */
2962 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2963 extended = 0; /* no longer */
2972 case 'B': /* down */
2984 case '[': /* cheat : always preceeds cursor move */
2985 case 'O': /* ANSI application key mode */
2996 return 1; /* user requests exit */
2998 case '1': /* select an item */
3022 case 'D': /* down */
3035 else if (curr_item == 1)
3036 return visuserconfig();
3038 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3039 /* enable quitfunc */
3040 userconfig_boot_parsing=0;
3042 boothowto |= RB_CONFIG; /* force -c */
3049 #else /* !VISUAL_USERCONFIG */
3051 #endif /* VISUAL_USERCONFIG */
3058 struct pnp_cinfo *c;
3062 for (i=0; i< MAX_PNP_LDN; i++) {
3063 c = &pnp_ldn_overrides[i];
3064 if (c->csn >0 && c->csn != 255) {
3066 static char pfmt[] =
3067 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3068 static char mfmt[] =
3069 "mem 0x%x 0x%x 0x%x 0x%x";
3072 if (!userconfig_boot_parsing) {
3074 if (kgetchar() == 'q') {
3082 if (lineno == 0 || first)
3083 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3085 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3087 c->override ? "OS ":"BIOS",
3088 c->enable ? "Y":"N",
3089 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3091 kprintf("flags 0x%08lx ",c->flags);
3092 for (pmax = 7; pmax >=0 ; pmax--)
3093 if (c->port[pmax]!=0) break;
3094 for (mmax = 3; mmax >=0 ; mmax--)
3095 if (c->mem[mmax].base!=0) break;
3098 buf[10 + 5*pmax]='\0';
3100 c->port[0], c->port[1], c->port[2], c->port[3],
3101 c->port[4], c->port[5], c->port[6], c->port[7]);
3105 buf[8 + 5*mmax]='\0';
3107 c->mem[0].base, c->mem[1].base,
3108 c->mem[2].base, c->mem[3].base);
3118 lsdevtab(struct uc_device *dt)
3120 for (; dt->id_id != 0; dt++) {
3125 if (!userconfig_boot_parsing) {
3126 if (kgetchar() == 'q') {
3136 "Device port irq drq iomem iosize unit flags enab\n"
3140 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3141 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3142 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3143 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3144 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3145 dt->id_enabled ? "Yes" : "No");
3155 int count = resource_count();
3161 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3164 for (i = 0; i < count; i++) {
3165 name = resource_query_name(i);
3166 unit = resource_query_unit(i);
3168 continue; /* skip wildcards */
3169 uc_devtab[dt].id_id = id++;
3170 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3172 resource_int_value(name, unit, "irq", &val);
3173 uc_devtab[dt].id_irq = (1 << val);
3174 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3175 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3176 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3177 uc_devtab[dt].id_unit = unit;
3178 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3180 resource_int_value(name, unit, "disabled", &val);
3181 uc_devtab[dt].id_enabled = !val;
3182 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3183 strcpy(uc_devtab[dt].id_name, name);
3192 int count = resource_count();
3194 for (i = 0; i < count; i++)
3195 if (uc_devtab[i].id_name)
3196 kfree(uc_devtab[i].id_name, M_DEVL);
3197 kfree(uc_devtab, M_DEVL);
3200 static struct uc_device *
3201 find_device(char *devname, int unit)
3203 struct uc_device *ret;
3205 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3210 static struct uc_device *
3211 search_devtable(struct uc_device *dt, char *devname, int unit)
3213 for (; dt->id_id != 0; dt++)
3214 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3220 cngets(char *input, int maxin)
3226 /* Treat ^H or ^? as backspace */
3227 if ((c == '\010' || c == '\177')) {
3229 kprintf("\010 \010");
3230 *--input = '\0', --nchars;
3234 /* Treat ^U or ^X as kill line */
3235 else if ((c == '\025' || c == '\030')) {
3237 kprintf("\010 \010");
3238 *--input = '\0', --nchars;
3243 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3247 *input++ = (u_char)c;
3253 /* scsi: Support for displaying configured SCSI devices.
3254 * There is no way to edit them, and this is inconsistent
3255 * with the ISA method. This is here as a basis for further work.
3258 type_text(char *name) /* XXX: This is bogus */
3260 if (strcmp(name, "sd") == 0)
3263 if (strcmp(name, "st") == 0)
3269 id_put(char *desc, int id)
3271 if (id != SCCONF_UNSPEC)
3274 kprintf("%s", desc);
3276 if (id == SCCONF_ANY)
3288 kprintf("scsi: (can't be edited):\n");
3290 for (i = 0; scsi_cinit[i].driver; i++)
3292 id_put("controller scbus", scsi_cinit[i].scbus);
3294 if (scsi_cinit[i].unit != -1)
3297 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3303 for (i = 0; scsi_dinit[i].name; i++)
3305 kprintf("%s ", type_text(scsi_dinit[i].name));
3307 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3308 id_put(" at scbus", scsi_dinit[i].cunit);
3309 id_put(" target ", scsi_dinit[i].target);
3310 id_put(" lun ", scsi_dinit[i].lun);
3312 if (scsi_dinit[i].flags)
3313 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3320 list_scsi(CmdParm *parms)
3329 save_resource(struct uc_device *idev)
3334 name = idev->id_name;
3335 unit = idev->id_unit;
3336 resource_set_int(name, unit, "port", idev->id_iobase);
3337 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3338 resource_set_int(name, unit, "drq", idev->id_drq);
3339 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3340 resource_set_int(name, unit, "msize", idev->id_msize);
3341 resource_set_int(name, unit, "flags", idev->id_flags);
3342 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3346 save_dev(struct uc_device *idev)
3348 struct uc_device *id_p,*id_pn;
3349 char *name = idev->id_name;
3351 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3352 if (id_p->id_id == idev->id_id) {
3353 id_pn = id_p->id_next;
3355 kfree(id_p->id_name, M_DEVL);
3356 bcopy(idev,id_p,sizeof(struct uc_device));
3357 save_resource(idev);
3358 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3359 strcpy(id_p->id_name, name);
3360 id_p->id_next = id_pn;
3364 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3365 bcopy(idev,id_pn,sizeof(struct uc_device));
3366 save_resource(idev);
3367 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3368 strcpy(id_pn->id_name, name);
3369 id_pn->id_next = uc_devlist;