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 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS},
357 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
358 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
360 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
361 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
362 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
363 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
364 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
366 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA},
367 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA},
368 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA},
369 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA},
370 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA},
371 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA},
372 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA},
373 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA},
374 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA},
375 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA},
376 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA},
377 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA},
378 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA},
379 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA},
380 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA},
381 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA},
382 {"pca", "PC speaker PCM audio driver", FLG_FIXED, CLS_MMEDIA},
383 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA},
385 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
386 {"pcic", "PC-card controller", 0, CLS_MISC},
387 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
388 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
392 typedef struct _devlist_struct
395 int attrib; /* flag values as per the FLG_* defines above */
396 int class; /* disk, etc as per the CLS_* defines above */
398 int iobase,irq,drq,maddr,msize,unit,flags,id;
399 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
400 int conflicts; /* set/reset by findconflict, count of conflicts */
401 int changed; /* nonzero if the device has been edited */
402 struct uc_device *device;
403 struct _devlist_struct *prev,*next;
408 #define DEV_COMMENT 1
411 #define LIST_CURRENT (1<<0)
412 #define LIST_SELECTED (1<<1)
414 #define KEY_EXIT 0 /* return codes from dolist() and friends */
420 #define KEY_UP 5 /* these only returned from editval() */
424 #define KEY_NULL 9 /* this allows us to spin & redraw */
426 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
427 #define KEY_UNZOOM 11
429 #define KEY_HELP 12 /* duh? */
431 static void redraw(void);
432 static void insdev(DEV_LIST *dev, DEV_LIST *list);
433 static int devinfo(DEV_LIST *dev);
434 static int visuserconfig(void);
436 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
437 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
438 static DEV_LIST scratch; /* scratch record */
439 static int conflicts; /* total conflict count */
442 static char lines[] = "--------------------------------------------------------------------------------";
443 static char spaces[] = " ";
447 ** Device manipulation stuff : find, describe, configure.
453 ** Sets the device referenced by (*dev) to the parameters in the struct,
454 ** and the enable flag according to (enabled)
457 setdev(DEV_LIST *dev, int enabled)
459 dev->device->id_iobase = dev->iobase; /* copy happy */
460 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
461 dev->device->id_drq = (short)dev->drq;
462 dev->device->id_maddr = (caddr_t)dev->maddr;
463 dev->device->id_msize = dev->msize;
464 dev->device->id_flags = dev->flags;
465 dev->device->id_enabled = enabled;
472 ** Walk the kernel device tables and build the active and inactive lists
478 struct uc_device *ap;
480 ap = uc_devtab; /* pointer to array of devices */
481 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
483 scratch.unit = ap[i].id_unit; /* device parameters */
484 strcpy(scratch.dev,ap[i].id_name);
485 scratch.iobase = ap[i].id_iobase;
486 scratch.irq = ffs(ap[i].id_irq)-1;
487 scratch.drq = ap[i].id_drq;
488 scratch.maddr = (int)ap[i].id_maddr;
489 scratch.msize = ap[i].id_msize;
490 scratch.flags = ap[i].id_flags;
492 scratch.comment = DEV_DEVICE; /* admin stuff */
493 scratch.conflicts = 0;
494 scratch.device = &ap[i]; /* save pointer for later reference */
496 if (!devinfo(&scratch)) /* get more info on the device */
497 insdev(&scratch,ap[i].id_enabled?active:inactive);
505 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
506 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
508 ** If the device is marked "invisible", return nonzero; the caller should
509 ** not insert any such device into either list.
513 devinfo(DEV_LIST *dev)
517 for (i = 0; device_info[i].class; i++)
519 if (!strcmp(dev->dev,device_info[i].dev))
521 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
523 strcpy(dev->name,device_info[i].name); /* get the name */
524 dev->attrib = device_info[i].attrib;
525 dev->class = device_info[i].class;
529 strcpy(dev->name,"Unknown device");
531 dev->class = CLS_MISC;
537 ** List manipulation stuff : add, move, initialise, free, traverse
539 ** Note that there are assumptions throughout this code that
540 ** the first entry in a list will never move. (assumed to be
548 ** appends a copy of (dev) to the end of (*list)
551 addev(DEV_LIST *dev, DEV_LIST **list)
556 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
557 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
559 if (*list) /* list exists */
563 ap = ap->next; /* scoot to end of list */
567 }else{ /* list does not yet exist */
569 lp->prev = lp->next = NULL; /* list now exists */
577 ** Finds the 'appropriate' place for (dev) in (list)
579 ** 'Appropriate' means in numeric order with other devices of the same type,
580 ** or in alphabetic order following a comment of the appropriate type.
581 ** or at the end of the list if an appropriate comment is not found. (this should
583 ** (Note that the appropriate point is never the top, but may be the bottom)
586 findspot(DEV_LIST *dev, DEV_LIST *list)
590 /* search for a previous instance of the same device */
591 for (ap = list; ap; ap = ap->next)
593 if (ap->comment != DEV_DEVICE) /* ignore comments */
595 if (!strcmp(dev->dev,ap->dev)) /* same base device */
597 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
598 || !ap->next) /* or end of list */
600 ap = ap->prev; /* back up one */
601 break; /* done here */
603 if (ap->next) /* if the next item exists */
605 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
607 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
613 if (!ap) /* not sure yet */
615 /* search for a class that the device might belong to */
616 for (ap = list; ap; ap = ap->next)
618 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
620 if (dev->class != ap->class) /* of same class too 8) */
622 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
624 ap = ap->prev; /* back up one */
625 break; /* done here */
627 if (ap->next) /* if the next item exists */
628 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
633 if (!ap) /* didn't find a match */
635 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
636 if ((ap->comment != DEV_DEVICE)
637 && (ap->class == dev->class)) /* appropriate place? */
639 } /* or just put up with last */
648 ** Inserts a copy of (dev) at the appropriate point in (list)
651 insdev(DEV_LIST *dev, DEV_LIST *list)
655 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
656 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
658 ap = findspot(lp,list); /* find appropriate spot */
659 lp->next = ap->next; /* point to next */
661 ap->next->prev = lp; /* point next to new */
662 lp->prev = ap; /* point new to current */
663 ap->next = lp; /* and current to new */
670 ** Moves (dev) from its current list to an appropriate place in (list)
671 ** (dev) may not come from the top of a list, but it may from the bottom.
674 movedev(DEV_LIST *dev, DEV_LIST *list)
678 ap = findspot(dev,list);
679 dev->prev->next = dev->next; /* remove from old list */
681 dev->next->prev = dev->prev;
683 dev->next = ap->next; /* insert in new list */
685 ap->next->prev = dev; /* point next to new */
686 dev->prev = ap; /* point new to current */
687 ap->next = dev; /* and current to new */
694 ** Initialises (*list) with the basic headings
697 initlist(DEV_LIST **list)
701 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
703 strcpy(scratch.name,devclass_names[i].name);
704 scratch.comment = DEV_ZOOMED;
705 scratch.class = devclass_names[i].number;
706 scratch.attrib = FLG_MANDATORY; /* can't be moved */
707 addev(&scratch,list); /* add to the list */
715 ** Walks (list) and saves the settings of any entry marked as changed.
717 ** The device's active field is set according to (active).
719 ** Builds the uc_devlist used by kget to extract the changed device information.
720 ** The code for this was taken almost verbatim from the original module.
723 savelist(DEV_LIST *list, int active)
725 struct uc_device *id_p,*id_pn;
730 if ((list->comment == DEV_DEVICE) && /* is a device */
731 (list->changed) && /* has been changed */
732 (list->device != NULL)) { /* has an uc_device structure */
734 setdev(list,active); /* set the device itself */
737 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
738 { /* look on the list for it */
739 if (id_p->id_id == list->device->id_id)
741 name = list->device->id_name;
742 id_pn = id_p->id_next;
744 kfree(id_p->id_name, M_DEVL);
745 bcopy(list->device,id_p,sizeof(struct uc_device));
746 save_resource(list->device);
747 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
748 strcpy(id_p->id_name, name);
749 id_pn->id_next = uc_devlist;
750 id_p->id_next = id_pn;
754 if (!id_pn) /* not already on the list */
756 name = list->device->id_name;
757 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
758 bcopy(list->device,id_pn,sizeof(struct uc_device));
759 save_resource(list->device);
760 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
761 strcpy(id_pn->id_name, name);
762 id_pn->id_next = uc_devlist;
763 uc_devlist = id_pn; /* park at top of list */
774 ** Frees all storage in use by a (list).
777 nukelist(DEV_LIST *list)
783 while(list->prev) /* walk to head of list */
798 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
799 ** if there is no previous entry. (Only possible if list->prev == NULL given the
800 ** premise that there is always a comment at the head of the list)
803 prevent(DEV_LIST *list)
809 dp = list->prev; /* start back one */
812 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
813 return(dp); /* so skip to comment */
814 if (dp->comment == DEV_COMMENT) /* not zoomed */
815 return(list->prev); /* one back as normal */
816 dp = dp->prev; /* backpedal */
818 return(dp); /* NULL, we can assume */
825 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
826 ** if there is no next entry. (Possible if the current entry is last, or
827 ** if the current entry is the last heading and it's collapsed)
830 nextent(DEV_LIST *list)
836 if (list->comment != DEV_ZOOMED) /* no reason to skip */
841 if (dp->comment != DEV_DEVICE) /* found another heading */
845 return(dp); /* back we go */
852 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
855 ofsent(int ofs, DEV_LIST *list)
857 while (ofs-- && list)
858 list = nextent(list);
866 ** Scans every element of (list) and sets the conflict tags appropriately
867 ** Returns the number of conflicts found.
870 findconflict(DEV_LIST *list)
872 int count = 0; /* number of conflicts found */
875 for (dp = list; dp; dp = dp->next) /* over the whole list */
877 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
880 dp->conflicts = 0; /* assume the best */
881 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
883 if (sp->comment != DEV_DEVICE) /* likewise */
886 if (sp == dp) /* always conflict with itself */
889 if ((dp->iobase > 0) && /* iobase conflict? */
890 (dp->iobase == sp->iobase))
892 if ((dp->irq > 0) && /* irq conflict? */
893 (dp->irq == sp->irq))
895 if ((dp->drq > 0) && /* drq conflict? */
896 (dp->drq == sp->drq))
898 if ((sp->maddr > 0) && /* maddr/msize conflict? */
900 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
901 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
904 count += dp->conflicts; /* count conflicts */
913 ** Unzooms all headings in (list)
916 expandlist(DEV_LIST *list)
920 if (list->comment == DEV_COMMENT)
921 list->comment = DEV_ZOOMED;
930 ** Zooms all headings in (list)
933 collapselist(DEV_LIST *list)
937 if (list->comment == DEV_ZOOMED)
938 list->comment = DEV_COMMENT;
945 ** Screen-manipulation stuff
947 ** This is the basic screen layout :
949 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
950 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
951 ** +--------------------------------------------------------------------------------+
952 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
953 ** 1 -| ........................ ....... .. 0x....|
954 ** 2 -| ........................ ....... .. 0x....|
955 ** 3 -| ........................ ....... .. 0x....|
956 ** 4 -| ........................ ....... .. 0x....|
957 ** 5 -| ........................ ....... .. 0x....|
958 ** 6 -| ........................ ....... .. 0x....|
959 ** 7 -| ........................ ....... .. 0x....|
960 ** 8 -| ........................ ....... .. 0x....|
961 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
962 ** 10-| ........................ ....... |
963 ** 11-| ........................ ....... |
964 ** 12-| ........................ ....... |
965 ** 13-| ........................ ....... |
966 ** 14-| ........................ ....... |
967 ** 15-| ........................ ....... |
968 ** 16-| ........................ ....... |
969 ** 17-|------------------------------------------------------UP-DOWN-------------------|
970 ** 18-| Relevant parameters for the current device |
973 ** 21-|--------------------------------------------------------------------------------|
974 ** 22-| Help texts go here |
976 ** +--------------------------------------------------------------------------------+
980 ** On a collapsed comment :
982 ** [Enter] Expand device list [z] Expand all lists
983 ** [TAB] Change fields [Q] Save and Exit
985 ** On an expanded comment :
987 ** [Enter] Collapse device list [Z] Collapse all lists
988 ** [TAB] Change fields [Q] Save and Exit
990 ** On a comment with no followers
993 ** [TAB] Change fields [Q] Save and Exit
995 ** On a device in the active list
997 ** [Enter] Edit device parameters [DEL] Disable device
998 ** [TAB] Change fields [Q] Save and Exit [?] Help
1000 ** On a device in the inactive list
1002 ** [Enter] Enable device
1003 ** [TAB] Change fields [Q] Save and Exit [?] Help
1005 ** While editing parameters
1007 ** <parameter-specific help here>
1008 ** [TAB] Change fields [Q] Save device parameters
1015 ** The base-level screen primitives :
1017 ** bold() - enter bold mode \E[1m (md)
1018 ** inverse() - enter inverse mode \E[7m (so)
1019 ** normal() - clear bold/inverse mode \E[m (se)
1020 ** clear() - clear the screen \E[H\E[J (ce)
1021 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1046 kprintf("\033[H\033[J");
1052 kprintf("\033[%d;%dH",y+1,x+1);
1058 ** High-level screen primitives :
1060 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1061 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1062 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1063 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1064 ** putmsg(str) - put (str) in the message area
1065 ** puthelp(str) - put (str) in the upper helpline
1066 ** pad(str,len) - pad (str) to (len) with spaces
1067 ** drawline(row,detail,list,inverse,*dhelp)
1068 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1069 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1070 ** draw the line in inverse video, and display (*dhelp) on the
1072 ** drawlist(row,num,detail,list)
1073 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1074 ** through to drawline().
1075 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1076 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1077 ** redraw(); - Redraws the entire screen layout, including the
1078 ** - two list panels.
1083 ** writes (str) at x,y onscreen
1085 ** writes up to (len) of (str) at x,y onscreen.
1087 ** Supports embedded formatting :
1088 ** !i - inverse mode.
1090 ** !n - normal mode.
1093 putxyl(int x, int y, char *str, int len)
1098 while((*str) && (len--))
1100 if (*str == '!') /* format escape? */
1102 switch(*(str+1)) /* depending on the next character */
1106 str +=2; /* skip formatting */
1107 len++; /* doesn't count for length */
1112 str +=2; /* skip formatting */
1113 len++; /* doesn't count for length */
1118 str +=2; /* skip formatting */
1119 len++; /* doesn't count for length */
1123 kprintf("%c", *str++); /* not an escape */
1126 kprintf("%c", *str++); /* emit the character */
1131 #define putxy(x,y,str) putxyl(x,y,str,-1)
1137 ** Erases the region (x,y,w,h)
1140 erase(int x, int y, int w, int h)
1145 for (i = 0; i < h; i++)
1146 putxyl(x,y++,spaces,w);
1153 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1154 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1157 txtbox(int x, int y, int w, int h, char *str)
1162 while((str[i]) && h)
1164 if (str[i] == '\n') /* newline */
1166 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1167 y++; /* move down */
1168 h--; /* room for one less */
1169 str += (i+1); /* skip first newline */
1170 i = 0; /* zero offset */
1172 i++; /* next character */
1175 if (h) /* end of string, not region */
1183 ** writes (msg) in the helptext area
1188 erase(0,18,80,3); /* clear area */
1189 txtbox(0,18,80,3,msg);
1196 ** Writes (msg) in the helpline area
1209 ** Draws the help message at the bottom of the screen
1212 masterhelp(char *msg)
1222 ** space-pads a (str) to (len) characters
1225 pad(char *str, int len)
1229 for (i = 0; str[i]; i++) /* find the end of the string */
1231 if (i >= len) /* no padding needed */
1233 while(i < len) /* pad */
1242 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1243 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1245 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1246 ** help is shown for normal or zoomed comments
1249 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1251 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1253 if (list->comment == DEV_DEVICE)
1256 strncpy(nb+1,list->name,57);
1258 strncpy(nb,list->name,58);
1259 if ((list->comment == DEV_ZOOMED) && (list->next))
1260 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1261 strcat(nb," (Collapsed)");
1265 if (list->conflicts) /* device in conflict? */
1269 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1271 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1274 if (list->comment == DEV_DEVICE)
1276 ksprintf(db,"%s%d",list->dev,list->unit);
1281 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1283 ksprintf(ib," %d",list->irq);
1288 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1290 ksprintf(pb,"0x%x",list->iobase);
1296 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1298 putxyl(0,row,lbuf,80);
1301 switch(list->comment)
1303 case DEV_DEVICE: /* ordinary device */
1309 if (list->next->comment == DEV_DEVICE)
1310 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1315 if (list->next->comment == DEV_DEVICE)
1316 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1319 puthelp(" WARNING: This list entry corrupted!");
1323 move(0,row); /* put the cursor somewhere relevant */
1330 ** Displays (num) lines of the contents of (list) at (row), optionally
1331 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1334 drawlist(int row, int num, int detail, DEV_LIST *list)
1338 for(ofs = 0; ofs < num; ofs++)
1342 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1343 list = nextent(list); /* move down visible list */
1345 erase(0,row+ofs,80,1);
1354 ** Redraws the active list
1363 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1366 putxyl(45,0,lines,16);
1368 drawlist(1,8,1,alist); /* draw device lists */
1374 ** Redraws the inactive list
1377 redrawinactive(void)
1379 drawlist(10,7,0,ilist); /* draw device lists */
1386 ** Clear the screen and redraw the entire layout
1393 putxy(3,0,"!bActive!n-!bDrivers");
1394 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1396 putxy(3,9,"!bInactive!n-!bDrivers");
1397 putxy(63,9,"!bDev");
1400 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1410 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1411 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1414 yesnocancel(char *str)
1440 ** Show device parameters in the region below the lists
1442 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1443 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1444 ** +--------------------------------------------------------------------------------+
1445 ** 17-|--------------------------------------------------------------------------------|
1446 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1447 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1448 ** 20-| Flags : 0x0000 DRQ number : 00 |
1449 ** 21-|--------------------------------------------------------------------------------|
1452 showparams(DEV_LIST *dev)
1456 erase(0,18,80,3); /* clear area */
1459 if (dev->comment != DEV_DEVICE)
1463 if (dev->iobase > 0)
1465 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1471 ksprintf(buf,"IRQ number : %d",dev->irq);
1474 ksprintf(buf,"Flags : 0x%x",dev->flags);
1478 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1483 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1489 ksprintf(buf,"DRQ number : %d",dev->drq);
1496 ** Editing functions for device parameters
1498 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1499 ** onscreen. Refuse values outsise (min) and (max).
1500 ** editparams(dev) - Edit the parameters for (dev)
1504 #define VetRet(code) \
1506 if ((i >= min) && (i <= max)) /* legit? */ \
1509 ksprintf(buf,hex?"0x%x":"%d",i); \
1510 putxy(hex?x-2:x,y,buf); \
1511 return(code); /* all done and exit */ \
1513 i = *val; /* restore original value */ \
1514 delta = 1; /* restore other stuff */ \
1521 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1522 ** in a field (width) wide. (Allow one space)
1523 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1525 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1528 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1530 int i = *val; /* work with copy of the value */
1531 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1532 int xp = 0; /* cursor offset into text copy */
1533 int delta = 1; /* force redraw first time in */
1535 int extended = 0; /* stage counter for extended key sequences */
1537 if (hex) /* we presume there's a leading 0x onscreen */
1538 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1542 if (delta) /* only update if necessary */
1544 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1545 ksprintf(buf,"!i%s",tc); /* format for printing */
1546 erase(x,y,width,1); /* clear the area */
1547 putxy(x,y,buf); /* write */
1548 xp = strlen(tc); /* cursor always at end */
1549 move(x+xp,y); /* position the cursor */
1554 switch(extended) /* escape handling */
1557 if (c == 0x1b) /* esc? */
1559 extended = 1; /* flag and spin */
1563 break; /* nope, drop through */
1565 case 1: /* there was an escape prefix */
1566 if (c == '[' || c == 'O') /* second character in sequence */
1572 return(KEY_EXIT); /* double esc exits */
1574 break; /* nup, not a sequence. */
1578 switch(c) /* looks like the real McCoy */
1581 VetRet(KEY_UP); /* leave if OK */
1584 VetRet(KEY_DOWN); /* leave if OK */
1587 VetRet(KEY_RIGHT); /* leave if OK */
1590 VetRet(KEY_LEFT); /* leave if OK */
1600 case '\t': /* trying to tab off */
1601 VetRet(KEY_TAB); /* verify and maybe return */
1611 case '\177': /* BS or DEL */
1612 if (ro) /* readonly? */
1614 puthelp(" !iThis value cannot be edited (Press ESC)");
1615 while(kgetchar() != 0x1b); /* wait for key */
1616 return(KEY_NULL); /* spin */
1618 if (xp) /* still something left to delete */
1620 i = (hex ? i/0x10u : i/10); /* strip last digit */
1621 delta = 1; /* force update */
1644 if (ro) /* readonly? */
1646 puthelp(" !iThis value cannot be edited (Press ESC)");
1647 while(kgetchar() != 0x1b); /* wait for key */
1648 return(KEY_NULL); /* spin */
1650 if (xp >= width) /* no room for more characters anyway */
1654 if ((c >= '0') && (c <= '9'))
1656 i = i*0x10 + (c-'0'); /* update value */
1660 if ((c >= 'a') && (c <= 'f'))
1662 i = i*0x10 + (c-'a'+0xa);
1666 if ((c >= 'A') && (c <= 'F'))
1668 i = i*0x10 + (c-'A'+0xa);
1673 if ((c >= '0') && (c <= '9'))
1675 i = i*10 + (c-'0'); /* update value */
1676 delta = 1; /* force redraw */
1689 ** Edit the parameters for (dev)
1691 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1692 ** possible for this to spin in an endless loop...
1693 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1694 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1695 ** +--------------------------------------------------------------------------------+
1696 ** 17-|--------------------------------------------------------------------------------|
1697 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1698 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1699 ** 20-| Flags : 0x0000 DRQ number : 00 |
1700 ** 21-|--------------------------------------------------------------------------------|
1702 ** The "intelligence" in this function that hops around based on the directional
1703 ** returns from editval isn't very smart, and depends on the layout above.
1706 editparams(DEV_LIST *dev)
1709 char buf[16]; /* needs to fit the device name */
1711 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1712 ksprintf(buf,"!b%s",dev->dev);
1719 if (dev->iobase > 0)
1721 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1722 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1742 puthelp(" Interrupt number (Decimal, 1-15)");
1743 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1755 if (dev->iobase > 0)
1766 puthelp(" Device-specific flag values.");
1767 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1781 if (dev->iobase > 0)
1801 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1802 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1809 if (dev->iobase > 0)
1831 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1832 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1861 puthelp(" Device DMA request number (Decimal, 1-7)");
1862 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1885 dev->changed = 1; /* mark as changed */
1888 static char *helptext[] =
1890 " Using the UserConfig kernel settings editor",
1891 " -------------------------------------------",
1897 "The screen displays a list of available drivers, divided into two",
1898 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1899 "by default collapsed and can be expanded to show all the drivers",
1900 "available in each category. The parameters for the currently selected",
1901 "driver are shown at the bottom of the screen.",
1903 "- - Moving around -",
1905 "To move in the current list, use the UP and DOWN cursor keys to select",
1906 "an item (the selected item will be highlighted). If the item is a",
1907 "category name, you may alternatively expand or collapse the list of",
1908 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1909 "expanded, you can select each driver in the same manner and either:",
1911 " - change its parameters using [!bENTER!n]",
1912 " - move it to the Inactive list using [!bDEL!n]",
1914 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1915 "you need to move a driver from the Inactive list back to the Active",
1916 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1917 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1918 "its place in the Active list.",
1920 "- - Altering the list/parameters -",
1922 "Any drivers for devices not installed in your system should be moved",
1923 "to the Inactive list, until there are no remaining parameter conflicts",
1924 "between the drivers, as indicated at the top.",
1926 "Once the list of Active drivers only contains entries for the devices",
1927 "present in your system, you can set their parameters (Interrupt, DMA",
1928 "channel, I/O addresses). To do this, select the driver and press",
1929 "[!bENTER!n]: it is now possible to edit the settings at the",
1930 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1931 "finished, use [!bQ!n] to return to the list.",
1933 "- - Saving changes -",
1935 "When all settings seem correct, and you wish to proceed with the",
1936 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1937 "confirm your choice.",
1946 ** Displays help text onscreen for people that are confused, using a simple
1952 int topline = 0; /* where we are in the text */
1953 int line = 0; /* last line we displayed */
1957 for (;;) /* loop until user quits */
1959 /* display help text */
1962 clear(); /* remove everything else */
1963 for (line = topline;
1964 (line < (topline + 24)) && (helptext[line]);
1966 putxy(0,line-topline,helptext[line]);
1971 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1974 c = kgetchar(); /* so what do they say? */
1981 case 'B': /* wired into 'more' users' fingers */
1982 if (topline > 0) /* room to go up? */
1985 if (topline < 0) /* don't go too far */
1993 case ' ': /* expected by most people */
1994 if (helptext[line]) /* maybe more below? */
2003 redraw(); /* restore the screen */
2011 ** High-level control functions
2018 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2019 ** (num) lines, starting at (*ofs) offset from row onscreen.
2020 ** Pass (detail) on to drawing routines.
2022 ** If the user hits a key other than a cursor key, maybe return a code.
2024 ** (*list) points to the device at the top line in the region, (*ofs) is the
2025 ** position of the highlight within the region. All routines below
2026 ** this take only a device and an absolute row : use ofsent() to find the
2027 ** device, and add (*ofs) to (row) to find the absolute row.
2030 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2041 showparams(ofsent(*ofs,*list)); /* show device parameters */
2042 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2046 c = kgetchar(); /* get a character */
2047 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2049 extended = 0; /* no longer */
2052 case 588: /* syscons' idea of 'up' */
2054 if (*ofs) /* just a move onscreen */
2056 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2057 (*ofs)--; /* move up */
2059 lp = prevent(*list); /* can we go up? */
2062 *list = lp; /* yes, move up list */
2063 drawlist(row,num,detail,*list);
2068 case 596: /* dooby-do */
2069 case 'B': /* down */
2070 lp = ofsent(*ofs,*list); /* get current item */
2072 break; /* nothing more to move to */
2073 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2074 if (*ofs < (num-1)) /* room to move onscreen? */
2078 *list = nextent(*list); /* scroll region down */
2079 drawlist(row,num,detail,*list);
2091 case '[': /* cheat : always preceeds cursor move */
2092 case 'O': /* ANSI application key mode */
2101 return(KEY_EXIT); /* user requests exit */
2105 return(KEY_DO); /* "do" something */
2110 return(KEY_DEL); /* "delete" response */
2114 return(KEY_UNZOOM); /* expand everything */
2118 return(KEY_ZOOM); /* collapse everything */
2121 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2122 return(KEY_TAB); /* "move" response */
2124 case '\014': /* ^L, redraw */
2127 case '?': /* helptext */
2139 ** Do the fullscreen config thang
2144 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2148 initlist(&inactive);
2154 conflicts = findconflict(active); /* find conflicts in the active list only */
2162 case 0: /* active devices */
2163 ret = dolist(1,8,1,&actofs,&alist,
2164 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2168 mode = 1; /* swap lists */
2185 collapselist(active);
2190 dp = ofsent(actofs,alist); /* get current device */
2191 if (dp) /* paranoia... */
2193 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2195 if (dp == alist) /* moving top item on list? */
2199 alist = dp->next; /* point list to non-moving item */
2201 alist = dp->prev; /* end of list, go back instead */
2204 if (!dp->next) /* moving last item on list? */
2207 dp->conflicts = 0; /* no conflicts on the inactive list */
2208 movedev(dp,inactive); /* shift to inactive list */
2209 conflicts = findconflict(active); /* update conflict tags */
2211 redrawactive(); /* redraw */
2216 case KEY_DO: /* edit device parameters */
2217 dp = ofsent(actofs,alist); /* get current device */
2218 if (dp) /* paranoia... */
2220 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2222 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2224 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2226 conflicts = findconflict(active); /* update conflict tags */
2227 }else{ /* DO on comment = zoom */
2228 switch(dp->comment) /* Depends on current state */
2230 case DEV_COMMENT: /* not currently zoomed */
2231 dp->comment = DEV_ZOOMED;
2235 dp->comment = DEV_COMMENT;
2245 case 1: /* inactive devices */
2246 ret = dolist(10,7,0,&inactofs,&ilist,
2247 " [!bEnter!n] Enable device ");
2261 expandlist(inactive);
2268 collapselist(inactive);
2273 dp = ofsent(inactofs,ilist); /* get current device */
2274 if (dp) /* paranoia... */
2276 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2278 if (dp == ilist) /* moving top of list? */
2282 ilist = dp->next; /* point list to non-moving item */
2284 ilist = dp->prev; /* can't go down, go up instead */
2287 if (!dp->next) /* last entry on list? */
2288 inactofs--; /* shift cursor up one */
2291 movedev(dp,active); /* shift to active list */
2292 conflicts = findconflict(active); /* update conflict tags */
2294 alist = dp; /* put at top and current */
2296 while(dp->comment == DEV_DEVICE)
2297 dp = dp->prev; /* forcibly unzoom section */
2298 dp ->comment = DEV_COMMENT;
2299 mode = 0; /* and swap modes to follow it */
2301 }else{ /* DO on comment = zoom */
2302 switch(dp->comment) /* Depends on current state */
2304 case DEV_COMMENT: /* not currently zoomed */
2305 dp->comment = DEV_ZOOMED;
2309 dp->comment = DEV_COMMENT;
2313 redrawactive(); /* redraw */
2318 default: /* nothing else relevant here */
2323 mode = 0; /* shouldn't happen... */
2326 /* handle returns that are the same for both modes */
2333 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2336 case 2: /* cancel */
2340 case 1: /* save and exit */
2342 savelist(inactive,0);
2345 nukelist(active); /* clean up after ourselves */
2355 #endif /* VISUAL_USERCONFIG */
2358 * Copyright (c) 1991 Regents of the University of California.
2359 * All rights reserved.
2360 * Copyright (c) 1994 Jordan K. Hubbard
2361 * All rights reserved.
2362 * Copyright (c) 1994 David Greenman
2363 * All rights reserved.
2365 * Many additional changes by Bruce Evans
2367 * This code is derived from software contributed by the
2368 * University of California Berkeley, Jordan K. Hubbard,
2369 * David Greenman and Bruce Evans.
2371 * Redistribution and use in source and binary forms, with or without
2372 * modification, are permitted provided that the following conditions
2374 * 1. Redistributions of source code must retain the above copyright
2375 * notice, this list of conditions and the following disclaimer.
2376 * 2. Redistributions in binary form must reproduce the above copyright
2377 * notice, this list of conditions and the following disclaimer in the
2378 * documentation and/or other materials provided with the distribution.
2379 * 3. All advertising materials mentioning features or use of this software
2380 * must display the following acknowledgement:
2381 * This product includes software developed by the University of
2382 * California, Berkeley and its contributors.
2383 * 4. Neither the name of the University nor the names of its contributors
2384 * may be used to endorse or promote products derived from this software
2385 * without specific prior written permission.
2387 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2388 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2389 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2390 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2391 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2392 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2393 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2394 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2395 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2396 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2399 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2402 #define PARM_DEVSPEC 0x1
2403 #define PARM_INT 0x2
2404 #define PARM_ADDR 0x3
2405 #define PARM_STRING 0x4
2407 typedef struct _cmdparm {
2410 struct uc_device *dparm;
2419 typedef int (*CmdFunc)(CmdParm *);
2421 typedef struct _cmd {
2429 static void lsscsi(void);
2430 static int list_scsi(CmdParm *);
2433 static int lsdevtab(struct uc_device *);
2434 static struct uc_device *find_device(char *, int);
2435 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2436 static void cngets(char *, int);
2437 static Cmd *parse_cmd(char *);
2438 static int parse_args(const char *, CmdParm *);
2439 static int save_dev(struct uc_device *);
2441 static int list_devices(CmdParm *);
2442 static int set_device_ioaddr(CmdParm *);
2443 static int set_device_irq(CmdParm *);
2444 static int set_device_drq(CmdParm *);
2445 static int set_device_iosize(CmdParm *);
2446 static int set_device_mem(CmdParm *);
2447 static int set_device_flags(CmdParm *);
2448 static int set_device_enable(CmdParm *);
2449 static int set_device_disable(CmdParm *);
2450 static int quitfunc(CmdParm *);
2451 static int helpfunc(CmdParm *);
2452 static int introfunc(CmdParm *);
2455 static int lspnp(void);
2456 static int set_pnp_parms(CmdParm *);
2461 static CmdParm addr_parms[] = {
2462 { PARM_DEVSPEC, {} },
2467 static CmdParm int_parms[] = {
2468 { PARM_DEVSPEC, {} },
2473 static CmdParm dev_parms[] = {
2474 { PARM_DEVSPEC, {} },
2479 static CmdParm string_arg[] = {
2480 { PARM_STRING, {} },
2485 static Cmd CmdList[] = {
2486 { "?", helpfunc, NULL }, /* ? (help) */
2487 { "di", set_device_disable, dev_parms }, /* disable dev */
2488 { "dr", set_device_drq, int_parms }, /* drq dev # */
2489 { "en", set_device_enable, dev_parms }, /* enable dev */
2490 { "ex", quitfunc, NULL }, /* exit (quit) */
2491 { "f", set_device_flags, int_parms }, /* flags dev mask */
2492 { "h", helpfunc, NULL }, /* help */
2493 { "intro", introfunc, NULL }, /* intro screen */
2494 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2495 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2496 { "ir", set_device_irq, int_parms }, /* irq dev # */
2497 { "l", list_devices, NULL }, /* ls, list */
2499 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2501 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2502 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2503 { "q", quitfunc, NULL }, /* quit */
2505 { "s", list_scsi, NULL }, /* scsi */
2507 #ifdef VISUAL_USERCONFIG
2508 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2510 { NULL, NULL, NULL },
2516 static char banner = 1;
2522 init_config_script();
2525 /* Only display signon banner if we are about to go interactive */
2526 if (!has_config_script()) {
2527 if (!(boothowto & RB_CONFIG))
2528 #ifdef INTRO_USERCONFIG
2535 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2536 " Type \"help\" for help"
2537 #ifdef VISUAL_USERCONFIG
2538 " or \"visual\" to go to the visual\n"
2539 " configuration interface (requires MGA/VGA display or\n"
2540 " serial terminal capable of displaying ANSI graphics)"
2546 kprintf("config> ");
2548 if (input[0] == '\0')
2550 cmd = parse_cmd(input);
2552 kprintf("Invalid command or syntax. Type `?' for help.\n");
2555 rval = (*cmd->handler)(cmd->parms);
2564 parse_cmd(char *cmd)
2568 for (cp = CmdList; cp->name; cp++) {
2569 int len = strlen(cp->name);
2571 if (!strncmp(cp->name, cmd, len)) {
2572 while (*cmd && *cmd != ' ' && *cmd != '\t')
2574 if (parse_args(cmd, cp->parms))
2584 parse_args(const char *cmd, CmdParm *parms)
2589 if (*cmd == ' ' || *cmd == '\t') {
2593 if (parms == NULL || parms->type == -1) {
2596 kprintf("Extra arg(s): %s\n", cmd);
2599 if (parms->type == PARM_DEVSPEC) {
2604 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2605 (*cmd >= '0' && *cmd <= '9')))
2606 devname[i++] = *(cmd++);
2608 if (*cmd >= '0' && *cmd <= '9') {
2609 unit = strtoul(cmd, &ptr, 10);
2611 kprintf("Invalid device number\n");
2612 /* XXX should print invalid token here and elsewhere. */
2615 /* XXX else should require end of token. */
2618 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2619 kprintf("No such device: %s%d\n", devname, unit);
2625 if (parms->type == PARM_INT) {
2626 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2628 kprintf("Invalid numeric argument\n");
2635 if (parms->type == PARM_ADDR) {
2636 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2638 kprintf("Invalid address argument\n");
2645 if (parms->type == PARM_STRING) {
2646 parms->parm.u.sparm = cmd;
2654 list_devices(CmdParm *parms)
2657 if (lsdevtab(uc_devtab)) return 0;
2659 if (lspnp()) return 0;
2665 set_device_ioaddr(CmdParm *parms)
2667 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2668 save_dev(parms[0].parm.dparm);
2673 set_device_irq(CmdParm *parms)
2677 irq = parms[1].parm.iparm;
2679 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2682 else if (irq != -1 && irq > 15) {
2683 kprintf("An IRQ > 15 would be invalid.\n");
2686 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2687 save_dev(parms[0].parm.dparm);
2692 set_device_drq(CmdParm *parms)
2697 * The bounds checking is just to ensure that the value can be printed
2698 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2700 drq = parms[1].parm.iparm;
2701 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2702 save_dev(parms[0].parm.dparm);
2707 set_device_iosize(CmdParm *parms)
2709 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2710 save_dev(parms[0].parm.dparm);
2715 set_device_mem(CmdParm *parms)
2717 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2718 save_dev(parms[0].parm.dparm);
2723 set_device_flags(CmdParm *parms)
2725 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2726 save_dev(parms[0].parm.dparm);
2731 set_device_enable(CmdParm *parms)
2733 parms[0].parm.dparm->id_enabled = TRUE;
2734 save_dev(parms[0].parm.dparm);
2739 set_device_disable(CmdParm *parms)
2741 parms[0].parm.dparm->id_enabled = FALSE;
2742 save_dev(parms[0].parm.dparm);
2749 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2755 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2758 * Output the pnp_ldn_overrides[] table.
2760 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2761 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2762 if(error) return(error);
2767 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2768 0, 0, sysctl_machdep_uc_pnplist, "A",
2769 "List of PnP overrides changed in UserConfig");
2772 * this function sets the kernel table to override bios PnP
2776 set_pnp_parms(CmdParm *parms)
2778 u_long idx, val, ldn, csn;
2781 const char *p = parms[0].parm.u.sparm;
2784 csn=strtoul(p,&q, 0);
2785 ldn=strtoul(q,&q, 0);
2786 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2787 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2788 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2791 for (i=0; i < MAX_PNP_LDN; i++) {
2792 if (pnp_ldn_overrides[i].csn == csn &&
2793 pnp_ldn_overrides[i].ldn == ldn)
2796 if (i==MAX_PNP_LDN) {
2797 for (i=0; i < MAX_PNP_LDN; i++) {
2798 if (pnp_ldn_overrides[i].csn <1 ||
2799 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2803 if (i==MAX_PNP_LDN) {
2804 kprintf("sorry, no PnP entries available, try delete one\n");
2807 d = pnp_ldn_overrides[i] ;
2813 if (!strncmp(p,"irq",3)) {
2814 idx=strtoul(p+3,&q, 0);
2815 val=strtoul(q,&q, 0);
2816 if (idx >=0 && idx < 2) d.irq[idx] = val;
2817 } else if (!strncmp(p,"flags",5)) {
2818 idx=strtoul(p+5,&q, 0);
2820 } else if (!strncmp(p,"drq",3)) {
2821 idx=strtoul(p+3,&q, 0);
2822 val=strtoul(q,&q, 0);
2823 if (idx >=0 && idx < 2) d.drq[idx] = val;
2824 } else if (!strncmp(p,"port",4)) {
2825 idx=strtoul(p+4,&q, 0);
2826 val=strtoul(q,&q, 0);
2827 if (idx >=0 && idx < 8) d.port[idx] = val;
2828 } else if (!strncmp(p,"mem",3)) {
2829 idx=strtoul(p+3,&q, 0);
2830 val=strtoul(q,&q, 0);
2831 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2832 } else if (!strncmp(p,"bios",4)) {
2835 } else if (!strncmp(p,"os",2)) {
2838 } else if (!strncmp(p,"disable",7)) {
2841 } else if (!strncmp(p,"enable",6)) {
2844 } else if (!strncmp(p,"delete",6)) {
2845 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2846 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2849 kprintf("unknown command <%s>\n", p);
2852 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2854 pnp_ldn_overrides[i] = d ;
2860 quitfunc(CmdParm *parms)
2863 * If kernel config supplied, and we are parsing it, and -c also supplied,
2864 * ignore a quit command, This provides a safety mechanism to allow
2865 * recovery from a damaged/buggy kernel config.
2867 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2873 helpfunc(CmdParm *parms)
2876 "Command\t\t\tDescription\n"
2877 "-------\t\t\t-----------\n"
2878 "ls\t\t\tList currently configured devices\n"
2879 "port <devname> <addr>\tSet device port (i/o address)\n"
2880 "irq <devname> <number>\tSet device irq\n"
2881 "drq <devname> <number>\tSet device drq\n"
2882 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2883 "iosize <devname> <size>\tSet device memory size\n"
2884 "flags <devname> <mask>\tSet device flags\n"
2885 "enable <devname>\tEnable device\n"
2886 "disable <devname>\tDisable device (will not be probed)\n");
2889 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2890 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2891 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2892 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2893 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2894 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2897 "quit\t\t\tExit this configuration utility\n"
2898 "reset\t\t\tReset CPU\n");
2899 #ifdef VISUAL_USERCONFIG
2900 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2903 "help\t\t\tThis message\n\n"
2904 "Commands may be abbreviated to a unique prefix\n");
2908 #if defined (VISUAL_USERCONFIG)
2910 center(int y, char *str)
2912 putxy((80 - strlen(str)) / 2, y, str);
2917 introfunc(CmdParm *parms)
2919 #if defined (VISUAL_USERCONFIG)
2920 int curr_item, first_time, extended = 0;
2921 static char *choices[] = {
2922 " Skip kernel configuration and continue with installation ",
2923 " Start kernel configuration in full-screen visual mode ",
2924 " Start kernel configuration in CLI mode ",
2928 center(2, "!bKernel Configuration Menu!n");
2937 for (i = 0; i < 3; i++) {
2941 strcat(tmp, choices[i]);
2944 putxy(10, 5 + i, tmp);
2948 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2949 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2950 putxy(2, 12, "match your hardware configuration.");
2951 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2952 putxy(2, 15, "(press Down-Arrow then ENTER).");
2953 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2954 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2955 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2956 putxy(2, 21, "then simply press ENTER or Q now.");
2960 move(0, 0); /* move the cursor out of the way */
2963 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2964 extended = 0; /* no longer */
2973 case 'B': /* down */
2985 case '[': /* cheat : always preceeds cursor move */
2986 case 'O': /* ANSI application key mode */
2997 return 1; /* user requests exit */
2999 case '1': /* select an item */
3023 case 'D': /* down */
3036 else if (curr_item == 1)
3037 return visuserconfig();
3039 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3040 /* enable quitfunc */
3041 userconfig_boot_parsing=0;
3043 boothowto |= RB_CONFIG; /* force -c */
3050 #else /* !VISUAL_USERCONFIG */
3052 #endif /* VISUAL_USERCONFIG */
3059 struct pnp_cinfo *c;
3063 for (i=0; i< MAX_PNP_LDN; i++) {
3064 c = &pnp_ldn_overrides[i];
3065 if (c->csn >0 && c->csn != 255) {
3067 static char pfmt[] =
3068 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3069 static char mfmt[] =
3070 "mem 0x%x 0x%x 0x%x 0x%x";
3073 if (!userconfig_boot_parsing) {
3075 if (kgetchar() == 'q') {
3083 if (lineno == 0 || first)
3084 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3086 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3088 c->override ? "OS ":"BIOS",
3089 c->enable ? "Y":"N",
3090 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3092 kprintf("flags 0x%08lx ",c->flags);
3093 for (pmax = 7; pmax >=0 ; pmax--)
3094 if (c->port[pmax]!=0) break;
3095 for (mmax = 3; mmax >=0 ; mmax--)
3096 if (c->mem[mmax].base!=0) break;
3099 buf[10 + 5*pmax]='\0';
3101 c->port[0], c->port[1], c->port[2], c->port[3],
3102 c->port[4], c->port[5], c->port[6], c->port[7]);
3106 buf[8 + 5*mmax]='\0';
3108 c->mem[0].base, c->mem[1].base,
3109 c->mem[2].base, c->mem[3].base);
3119 lsdevtab(struct uc_device *dt)
3121 for (; dt->id_id != 0; dt++) {
3126 if (!userconfig_boot_parsing) {
3127 if (kgetchar() == 'q') {
3137 "Device port irq drq iomem iosize unit flags enab\n"
3141 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3142 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3143 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3144 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3145 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3146 dt->id_enabled ? "Yes" : "No");
3156 int count = resource_count();
3162 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3165 for (i = 0; i < count; i++) {
3166 name = resource_query_name(i);
3167 unit = resource_query_unit(i);
3169 continue; /* skip wildcards */
3170 uc_devtab[dt].id_id = id++;
3171 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3173 resource_int_value(name, unit, "irq", &val);
3174 uc_devtab[dt].id_irq = (1 << val);
3175 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3176 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3177 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3178 uc_devtab[dt].id_unit = unit;
3179 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3181 resource_int_value(name, unit, "disabled", &val);
3182 uc_devtab[dt].id_enabled = !val;
3183 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3184 strcpy(uc_devtab[dt].id_name, name);
3193 int count = resource_count();
3195 for (i = 0; i < count; i++)
3196 if (uc_devtab[i].id_name)
3197 kfree(uc_devtab[i].id_name, M_DEVL);
3198 kfree(uc_devtab, M_DEVL);
3201 static struct uc_device *
3202 find_device(char *devname, int unit)
3204 struct uc_device *ret;
3206 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3211 static struct uc_device *
3212 search_devtable(struct uc_device *dt, char *devname, int unit)
3214 for (; dt->id_id != 0; dt++)
3215 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3221 cngets(char *input, int maxin)
3227 /* Treat ^H or ^? as backspace */
3228 if ((c == '\010' || c == '\177')) {
3230 kprintf("\010 \010");
3231 *--input = '\0', --nchars;
3235 /* Treat ^U or ^X as kill line */
3236 else if ((c == '\025' || c == '\030')) {
3238 kprintf("\010 \010");
3239 *--input = '\0', --nchars;
3244 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3248 *input++ = (u_char)c;
3254 /* scsi: Support for displaying configured SCSI devices.
3255 * There is no way to edit them, and this is inconsistent
3256 * with the ISA method. This is here as a basis for further work.
3259 type_text(char *name) /* XXX: This is bogus */
3261 if (strcmp(name, "sd") == 0)
3264 if (strcmp(name, "st") == 0)
3270 id_put(char *desc, int id)
3272 if (id != SCCONF_UNSPEC)
3275 kprintf("%s", desc);
3277 if (id == SCCONF_ANY)
3289 kprintf("scsi: (can't be edited):\n");
3291 for (i = 0; scsi_cinit[i].driver; i++)
3293 id_put("controller scbus", scsi_cinit[i].scbus);
3295 if (scsi_cinit[i].unit != -1)
3298 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3304 for (i = 0; scsi_dinit[i].name; i++)
3306 kprintf("%s ", type_text(scsi_dinit[i].name));
3308 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3309 id_put(" at scbus", scsi_dinit[i].cunit);
3310 id_put(" target ", scsi_dinit[i].target);
3311 id_put(" lun ", scsi_dinit[i].lun);
3313 if (scsi_dinit[i].flags)
3314 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3321 list_scsi(CmdParm *parms)
3330 save_resource(struct uc_device *idev)
3335 name = idev->id_name;
3336 unit = idev->id_unit;
3337 resource_set_int(name, unit, "port", idev->id_iobase);
3338 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3339 resource_set_int(name, unit, "drq", idev->id_drq);
3340 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3341 resource_set_int(name, unit, "msize", idev->id_msize);
3342 resource_set_int(name, unit, "flags", idev->id_flags);
3343 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3347 save_dev(struct uc_device *idev)
3349 struct uc_device *id_p,*id_pn;
3350 char *name = idev->id_name;
3352 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3353 if (id_p->id_id == idev->id_id) {
3354 id_pn = id_p->id_next;
3356 kfree(id_p->id_name, M_DEVL);
3357 bcopy(idev,id_p,sizeof(struct uc_device));
3358 save_resource(idev);
3359 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3360 strcpy(id_p->id_name, name);
3361 id_p->id_next = id_pn;
3365 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3366 bcopy(idev,id_pn,sizeof(struct uc_device));
3367 save_resource(idev);
3368 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3369 strcpy(id_pn->id_name, name);
3370 id_pn->id_next = uc_devlist;