3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
5 ** This code contains a module marked :
7 * Copyright (c) 1991 Regents of the University of California.
9 * Copyright (c) 1994 Jordan K. Hubbard
10 * All rights reserved.
11 * Copyright (c) 1994 David Greenman
12 * All rights reserved.
14 * Many additional changes by Bruce Evans
16 * This code is derived from software contributed by the
17 * University of California Berkeley, Jordan K. Hubbard,
18 * David Greenman and Bruce Evans.
20 ** As such, it contains code subject to the above copyrights.
21 ** The module and its copyright can be found below.
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
26 ** 1. Redistributions of source code must retain the above copyright
27 ** notice, this list of conditions and the following disclaimer as
28 ** the first lines of this file unmodified.
29 ** 2. Redistributions in binary form must reproduce the above copyright
30 ** notice, this list of conditions and the following disclaimer in the
31 ** documentation and/or other materials provided with the distribution.
32 ** 3. All advertising materials mentioning features or use of this software
33 ** must display the following acknowledgment:
34 ** This product includes software developed by Michael Smith.
35 ** 4. The name of the author may not be used to endorse or promote products
36 ** derived from this software without specific prior written permission.
38 ** THIS SOFTWARE IS PROVIDED BY MICHAEL SMITH ``AS IS'' AND ANY EXPRESS OR
39 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 ** IN NO EVENT SHALL MICHAEL SMITH BE LIABLE FOR ANY DIRECT, INDIRECT,
42 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
55 ** Kernel boot-time configuration manipulation tool for FreeBSD.
57 ** Two modes of operation are supported : the default is the line-editor mode,
58 ** the command "visual" invokes the fullscreen mode.
60 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
61 ** fullscreen mode requires syscons or a minimal-ansi serial console.
65 ** USERCONFIG, visual mode.
69 ** Look for "EDIT THIS LIST" to add to the list of known devices
72 ** There are a number of assumptions made in this code.
74 ** - That the console supports a minimal set of ANSI escape sequences
75 ** (See the screen manipulation section for a summary)
76 ** and has at least 24 rows.
77 ** - That values less than or equal to zero for any of the device
78 ** parameters indicate that the driver does not use the parameter.
79 ** - That flags are _always_ editable.
81 ** Devices marked as disabled are imported as such.
83 ** For this tool to be useful, the list of devices below _MUST_ be updated
84 ** when a new driver is brought into the kernel. It is not possible to
85 ** extract this information from the drivers in the kernel.
89 ** - Display _what_ a device conflicts with.
90 ** - Implement page up/down (as what?)
91 ** - Wizard mode (no restrictions)
92 ** - Find out how to put syscons back into low-intensity mode so that the
93 ** !b escape is useful on the console. (It seems to be that it actually
94 ** gets low/high intensity backwards. That looks OK.)
96 ** - Only display headings with devices under them. (difficult)
99 #include "opt_userconfig.h"
101 #include <sys/param.h>
102 #include <sys/systm.h>
103 #include <sys/kernel.h>
104 #include <sys/malloc.h>
105 #include <sys/reboot.h>
106 #include <sys/linker.h>
107 #include <sys/sysctl.h>
109 #include <sys/cons.h>
111 #include <machine/md_var.h>
112 #include <machine/limits.h>
114 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
120 #include <machine_base/isa/pnp.h>
123 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
125 #include <machine/uc_device.h>
126 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
127 static struct uc_device *uc_devtab; /* fake uc_device table */
129 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
131 static void load_devtab(void);
132 static void free_devtab(void);
133 static void save_resource(struct uc_device *);
136 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
138 struct uc_device *id;
146 error+=sizeof(struct uc_device)+8;
149 return(SYSCTL_OUT(req,0,error));
151 /* Output the data. The buffer is filled with consecutive
152 * struct uc_device and char buf[8], containing the name
153 * (not guaranteed to end with '\0').
157 error=sysctl_handle_opaque(oidp,id,
158 sizeof(struct uc_device),req);
159 if(error) return(error);
160 strncpy(name,id->id_name,8);
161 error=sysctl_handle_opaque(oidp,name,
163 if(error) return(error);
170 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
171 0, 0, sysctl_machdep_uc_devlist, "A",
172 "List of ISA devices changed in UserConfig");
175 ** Obtain command input.
177 ** Initially, input is read from a possibly-loaded script.
178 ** At the end of the script, or if no script is supplied,
179 ** behaviour is determined by the RB_CONFIG (-c) flag. If
180 ** the flag is set, user input is read from the console; if
181 ** unset, the 'quit' command is invoked and userconfig
184 ** Note that quit commands encountered in the script will be
185 ** ignored if the RB_CONFIG flag is supplied.
187 static const char *config_script;
188 static int config_script_size; /* use of int for -ve magic value */
190 #define has_config_script() (config_script_size > 0)
193 init_config_script(void)
195 caddr_t autoentry, autoattr;
197 /* Look for loaded userconfig script */
198 autoentry = preload_search_by_type("userconfig_script");
199 if (autoentry != NULL) {
200 /* We have one, get size and data */
201 config_script_size = 0;
202 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
203 config_script_size = (size_t)*(u_int32_t *)autoattr;
204 config_script = NULL;
205 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
206 config_script = *(const char **)autoattr;
208 if ((config_script_size == 0) || (config_script == NULL)) {
209 config_script_size = 0;
210 config_script = NULL;
213 return has_config_script();
220 #ifdef INTRO_USERCONFIG
221 static int intro = 0;
224 if (has_config_script())
226 /* Consume character from loaded userconfig script, display */
227 userconfig_boot_parsing = 1;
230 config_script_size--;
234 #ifdef INTRO_USERCONFIG
235 if (userconfig_boot_parsing) {
236 if (!(boothowto & RB_CONFIG)) {
237 /* userconfig_script, !RB_CONFIG -> quit */
240 config_script = "uit\n";
241 config_script_size = strlen(config_script);
242 /* userconfig_script will be 1 on the next pass */
245 /* userconfig_script, RB_CONFIG -> cngetc() */
248 if (!(boothowto & RB_CONFIG)) {
249 /* no userconfig_script, !RB_CONFIG -> show intro */
253 config_script = "ntro\n";
254 config_script_size = strlen(config_script);
255 /* userconfig_script will be 1 on the next pass */
258 /* no userconfig_script, RB_CONFIG -> cngetc() */
261 #else /* !INTRO_USERCONFIG */
262 /* assert(boothowto & RB_CONFIG) */
263 #endif /* INTRO_USERCONFIG */
264 userconfig_boot_parsing = 0;
273 #define TRUE (!FALSE)
276 #ifdef VISUAL_USERCONFIG
280 char dev[16]; /* device basename */
281 char name[60]; /* long name */
282 int attrib; /* things to do with the device */
283 int class; /* device classification */
286 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
287 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
288 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
289 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
290 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
291 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
292 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
293 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
294 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
296 #define CLS_STORAGE 1 /* storage devices */
297 #define CLS_NETWORK 2 /* network interfaces */
298 #define CLS_COMMS 3 /* serial, parallel ports */
299 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
300 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
301 #define CLS_MISC 255 /* none of the above */
310 static DEVCLASS_INFO devclass_names[] = {
311 { "Storage : ", CLS_STORAGE},
312 { "Communications : ", CLS_COMMS},
313 { "Input : ", CLS_INPUT},
314 { "Miscellaneous : ", CLS_MISC},
318 /********************* EDIT THIS LIST **********************/
322 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
323 ** - XXX The list below should be reviewed by the driver authors to verify
324 ** that the correct flags have been set for each driver, and that the
325 ** descriptions are accurate.
328 static DEV_INFO device_info[] = {
329 /*---Name----- ---Description---------------------------------------------- */
330 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
331 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
332 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
333 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
335 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
336 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
338 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
339 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
340 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
341 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
342 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
344 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
345 {"pcic", "PC-card controller", 0, CLS_MISC},
346 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
347 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
351 typedef struct _devlist_struct
354 int attrib; /* flag values as per the FLG_* defines above */
355 int class; /* disk, etc as per the CLS_* defines above */
357 int iobase,irq,drq,maddr,msize,unit,flags,id;
358 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
359 int conflicts; /* set/reset by findconflict, count of conflicts */
360 int changed; /* nonzero if the device has been edited */
361 struct uc_device *device;
362 struct _devlist_struct *prev,*next;
367 #define DEV_COMMENT 1
370 #define LIST_CURRENT (1<<0)
371 #define LIST_SELECTED (1<<1)
373 #define KEY_EXIT 0 /* return codes from dolist() and friends */
379 #define KEY_UP 5 /* these only returned from editval() */
383 #define KEY_NULL 9 /* this allows us to spin & redraw */
385 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
386 #define KEY_UNZOOM 11
388 #define KEY_HELP 12 /* duh? */
390 static void redraw(void);
391 static void insdev(DEV_LIST *dev, DEV_LIST *list);
392 static int devinfo(DEV_LIST *dev);
393 static int visuserconfig(void);
395 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
396 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
397 static DEV_LIST scratch; /* scratch record */
398 static int conflicts; /* total conflict count */
401 static char lines[] = "--------------------------------------------------------------------------------";
402 static char spaces[] = " ";
406 ** Device manipulation stuff : find, describe, configure.
412 ** Sets the device referenced by (*dev) to the parameters in the struct,
413 ** and the enable flag according to (enabled)
416 setdev(DEV_LIST *dev, int enabled)
418 dev->device->id_iobase = dev->iobase; /* copy happy */
419 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
420 dev->device->id_drq = (short)dev->drq;
421 dev->device->id_maddr = (caddr_t)dev->maddr;
422 dev->device->id_msize = dev->msize;
423 dev->device->id_flags = dev->flags;
424 dev->device->id_enabled = enabled;
431 ** Walk the kernel device tables and build the active and inactive lists
437 struct uc_device *ap;
439 ap = uc_devtab; /* pointer to array of devices */
440 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
442 scratch.unit = ap[i].id_unit; /* device parameters */
443 strcpy(scratch.dev,ap[i].id_name);
444 scratch.iobase = ap[i].id_iobase;
445 scratch.irq = ffs(ap[i].id_irq)-1;
446 scratch.drq = ap[i].id_drq;
447 scratch.maddr = (int)ap[i].id_maddr;
448 scratch.msize = ap[i].id_msize;
449 scratch.flags = ap[i].id_flags;
451 scratch.comment = DEV_DEVICE; /* admin stuff */
452 scratch.conflicts = 0;
453 scratch.device = &ap[i]; /* save pointer for later reference */
455 if (!devinfo(&scratch)) /* get more info on the device */
456 insdev(&scratch,ap[i].id_enabled?active:inactive);
464 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
465 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
467 ** If the device is marked "invisible", return nonzero; the caller should
468 ** not insert any such device into either list.
472 devinfo(DEV_LIST *dev)
476 for (i = 0; device_info[i].class; i++)
478 if (!strcmp(dev->dev,device_info[i].dev))
480 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
482 strcpy(dev->name,device_info[i].name); /* get the name */
483 dev->attrib = device_info[i].attrib;
484 dev->class = device_info[i].class;
488 strcpy(dev->name,"Unknown device");
490 dev->class = CLS_MISC;
496 ** List manipulation stuff : add, move, initialise, free, traverse
498 ** Note that there are assumptions throughout this code that
499 ** the first entry in a list will never move. (assumed to be
507 ** appends a copy of (dev) to the end of (*list)
510 addev(DEV_LIST *dev, DEV_LIST **list)
515 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
516 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
518 if (*list) /* list exists */
522 ap = ap->next; /* scoot to end of list */
526 }else{ /* list does not yet exist */
528 lp->prev = lp->next = NULL; /* list now exists */
536 ** Finds the 'appropriate' place for (dev) in (list)
538 ** 'Appropriate' means in numeric order with other devices of the same type,
539 ** or in alphabetic order following a comment of the appropriate type.
540 ** or at the end of the list if an appropriate comment is not found. (this should
542 ** (Note that the appropriate point is never the top, but may be the bottom)
545 findspot(DEV_LIST *dev, DEV_LIST *list)
549 /* search for a previous instance of the same device */
550 for (ap = list; ap; ap = ap->next)
552 if (ap->comment != DEV_DEVICE) /* ignore comments */
554 if (!strcmp(dev->dev,ap->dev)) /* same base device */
556 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
557 || !ap->next) /* or end of list */
559 ap = ap->prev; /* back up one */
560 break; /* done here */
562 if (ap->next) /* if the next item exists */
564 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
566 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
572 if (!ap) /* not sure yet */
574 /* search for a class that the device might belong to */
575 for (ap = list; ap; ap = ap->next)
577 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
579 if (dev->class != ap->class) /* of same class too 8) */
581 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
583 ap = ap->prev; /* back up one */
584 break; /* done here */
586 if (ap->next) /* if the next item exists */
587 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
592 if (!ap) /* didn't find a match */
594 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
595 if ((ap->comment != DEV_DEVICE)
596 && (ap->class == dev->class)) /* appropriate place? */
598 } /* or just put up with last */
607 ** Inserts a copy of (dev) at the appropriate point in (list)
610 insdev(DEV_LIST *dev, DEV_LIST *list)
614 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
615 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
617 ap = findspot(lp,list); /* find appropriate spot */
618 lp->next = ap->next; /* point to next */
620 ap->next->prev = lp; /* point next to new */
621 lp->prev = ap; /* point new to current */
622 ap->next = lp; /* and current to new */
629 ** Moves (dev) from its current list to an appropriate place in (list)
630 ** (dev) may not come from the top of a list, but it may from the bottom.
633 movedev(DEV_LIST *dev, DEV_LIST *list)
637 ap = findspot(dev,list);
638 dev->prev->next = dev->next; /* remove from old list */
640 dev->next->prev = dev->prev;
642 dev->next = ap->next; /* insert in new list */
644 ap->next->prev = dev; /* point next to new */
645 dev->prev = ap; /* point new to current */
646 ap->next = dev; /* and current to new */
653 ** Initialises (*list) with the basic headings
656 initlist(DEV_LIST **list)
660 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
662 strcpy(scratch.name,devclass_names[i].name);
663 scratch.comment = DEV_ZOOMED;
664 scratch.class = devclass_names[i].number;
665 scratch.attrib = FLG_MANDATORY; /* can't be moved */
666 addev(&scratch,list); /* add to the list */
674 ** Walks (list) and saves the settings of any entry marked as changed.
676 ** The device's active field is set according to (active).
678 ** Builds the uc_devlist used by kget to extract the changed device information.
679 ** The code for this was taken almost verbatim from the original module.
682 savelist(DEV_LIST *list, int active)
684 struct uc_device *id_p,*id_pn;
689 if ((list->comment == DEV_DEVICE) && /* is a device */
690 (list->changed) && /* has been changed */
691 (list->device != NULL)) { /* has an uc_device structure */
693 setdev(list,active); /* set the device itself */
696 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
697 { /* look on the list for it */
698 if (id_p->id_id == list->device->id_id)
700 name = list->device->id_name;
701 id_pn = id_p->id_next;
703 kfree(id_p->id_name, M_DEVL);
704 bcopy(list->device,id_p,sizeof(struct uc_device));
705 save_resource(list->device);
706 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
707 strcpy(id_p->id_name, name);
708 id_pn->id_next = uc_devlist;
709 id_p->id_next = id_pn;
713 if (!id_pn) /* not already on the list */
715 name = list->device->id_name;
716 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
717 bcopy(list->device,id_pn,sizeof(struct uc_device));
718 save_resource(list->device);
719 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
720 strcpy(id_pn->id_name, name);
721 id_pn->id_next = uc_devlist;
722 uc_devlist = id_pn; /* park at top of list */
733 ** Frees all storage in use by a (list).
736 nukelist(DEV_LIST *list)
742 while(list->prev) /* walk to head of list */
757 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
758 ** if there is no previous entry. (Only possible if list->prev == NULL given the
759 ** premise that there is always a comment at the head of the list)
762 prevent(DEV_LIST *list)
768 dp = list->prev; /* start back one */
771 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
772 return(dp); /* so skip to comment */
773 if (dp->comment == DEV_COMMENT) /* not zoomed */
774 return(list->prev); /* one back as normal */
775 dp = dp->prev; /* backpedal */
777 return(dp); /* NULL, we can assume */
784 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
785 ** if there is no next entry. (Possible if the current entry is last, or
786 ** if the current entry is the last heading and it's collapsed)
789 nextent(DEV_LIST *list)
795 if (list->comment != DEV_ZOOMED) /* no reason to skip */
800 if (dp->comment != DEV_DEVICE) /* found another heading */
804 return(dp); /* back we go */
811 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
814 ofsent(int ofs, DEV_LIST *list)
816 while (ofs-- && list)
817 list = nextent(list);
825 ** Scans every element of (list) and sets the conflict tags appropriately
826 ** Returns the number of conflicts found.
829 findconflict(DEV_LIST *list)
831 int count = 0; /* number of conflicts found */
834 for (dp = list; dp; dp = dp->next) /* over the whole list */
836 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
839 dp->conflicts = 0; /* assume the best */
840 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
842 if (sp->comment != DEV_DEVICE) /* likewise */
845 if (sp == dp) /* always conflict with itself */
848 if ((dp->iobase > 0) && /* iobase conflict? */
849 (dp->iobase == sp->iobase))
851 if ((dp->irq > 0) && /* irq conflict? */
852 (dp->irq == sp->irq))
854 if ((dp->drq > 0) && /* drq conflict? */
855 (dp->drq == sp->drq))
857 if ((sp->maddr > 0) && /* maddr/msize conflict? */
859 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
860 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
863 count += dp->conflicts; /* count conflicts */
872 ** Unzooms all headings in (list)
875 expandlist(DEV_LIST *list)
879 if (list->comment == DEV_COMMENT)
880 list->comment = DEV_ZOOMED;
889 ** Zooms all headings in (list)
892 collapselist(DEV_LIST *list)
896 if (list->comment == DEV_ZOOMED)
897 list->comment = DEV_COMMENT;
904 ** Screen-manipulation stuff
906 ** This is the basic screen layout :
908 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
909 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
910 ** +--------------------------------------------------------------------------------+
911 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
912 ** 1 -| ........................ ....... .. 0x....|
913 ** 2 -| ........................ ....... .. 0x....|
914 ** 3 -| ........................ ....... .. 0x....|
915 ** 4 -| ........................ ....... .. 0x....|
916 ** 5 -| ........................ ....... .. 0x....|
917 ** 6 -| ........................ ....... .. 0x....|
918 ** 7 -| ........................ ....... .. 0x....|
919 ** 8 -| ........................ ....... .. 0x....|
920 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
921 ** 10-| ........................ ....... |
922 ** 11-| ........................ ....... |
923 ** 12-| ........................ ....... |
924 ** 13-| ........................ ....... |
925 ** 14-| ........................ ....... |
926 ** 15-| ........................ ....... |
927 ** 16-| ........................ ....... |
928 ** 17-|------------------------------------------------------UP-DOWN-------------------|
929 ** 18-| Relevant parameters for the current device |
932 ** 21-|--------------------------------------------------------------------------------|
933 ** 22-| Help texts go here |
935 ** +--------------------------------------------------------------------------------+
939 ** On a collapsed comment :
941 ** [Enter] Expand device list [z] Expand all lists
942 ** [TAB] Change fields [Q] Save and Exit
944 ** On an expanded comment :
946 ** [Enter] Collapse device list [Z] Collapse all lists
947 ** [TAB] Change fields [Q] Save and Exit
949 ** On a comment with no followers
952 ** [TAB] Change fields [Q] Save and Exit
954 ** On a device in the active list
956 ** [Enter] Edit device parameters [DEL] Disable device
957 ** [TAB] Change fields [Q] Save and Exit [?] Help
959 ** On a device in the inactive list
961 ** [Enter] Enable device
962 ** [TAB] Change fields [Q] Save and Exit [?] Help
964 ** While editing parameters
966 ** <parameter-specific help here>
967 ** [TAB] Change fields [Q] Save device parameters
974 ** The base-level screen primitives :
976 ** bold() - enter bold mode \E[1m (md)
977 ** inverse() - enter inverse mode \E[7m (so)
978 ** normal() - clear bold/inverse mode \E[m (se)
979 ** clear() - clear the screen \E[H\E[J (ce)
980 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1005 kprintf("\033[H\033[J");
1011 kprintf("\033[%d;%dH",y+1,x+1);
1017 ** High-level screen primitives :
1019 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1020 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1021 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1022 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1023 ** putmsg(str) - put (str) in the message area
1024 ** puthelp(str) - put (str) in the upper helpline
1025 ** pad(str,len) - pad (str) to (len) with spaces
1026 ** drawline(row,detail,list,inverse,*dhelp)
1027 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1028 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1029 ** draw the line in inverse video, and display (*dhelp) on the
1031 ** drawlist(row,num,detail,list)
1032 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1033 ** through to drawline().
1034 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1035 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1036 ** redraw(); - Redraws the entire screen layout, including the
1037 ** - two list panels.
1042 ** writes (str) at x,y onscreen
1044 ** writes up to (len) of (str) at x,y onscreen.
1046 ** Supports embedded formatting :
1047 ** !i - inverse mode.
1049 ** !n - normal mode.
1052 putxyl(int x, int y, char *str, int len)
1057 while((*str) && (len--))
1059 if (*str == '!') /* format escape? */
1061 switch(*(str+1)) /* depending on the next character */
1065 str +=2; /* skip formatting */
1066 len++; /* doesn't count for length */
1071 str +=2; /* skip formatting */
1072 len++; /* doesn't count for length */
1077 str +=2; /* skip formatting */
1078 len++; /* doesn't count for length */
1082 kprintf("%c", *str++); /* not an escape */
1085 kprintf("%c", *str++); /* emit the character */
1090 #define putxy(x,y,str) putxyl(x,y,str,-1)
1096 ** Erases the region (x,y,w,h)
1099 erase(int x, int y, int w, int h)
1104 for (i = 0; i < h; i++)
1105 putxyl(x,y++,spaces,w);
1112 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1113 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1116 txtbox(int x, int y, int w, int h, char *str)
1121 while((str[i]) && h)
1123 if (str[i] == '\n') /* newline */
1125 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1126 y++; /* move down */
1127 h--; /* room for one less */
1128 str += (i+1); /* skip first newline */
1129 i = 0; /* zero offset */
1131 i++; /* next character */
1134 if (h) /* end of string, not region */
1142 ** writes (msg) in the helptext area
1147 erase(0,18,80,3); /* clear area */
1148 txtbox(0,18,80,3,msg);
1155 ** Writes (msg) in the helpline area
1168 ** Draws the help message at the bottom of the screen
1171 masterhelp(char *msg)
1181 ** space-pads a (str) to (len) characters
1184 pad(char *str, int len)
1188 for (i = 0; str[i]; i++) /* find the end of the string */
1190 if (i >= len) /* no padding needed */
1192 while(i < len) /* pad */
1201 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1202 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1204 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1205 ** help is shown for normal or zoomed comments
1208 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1210 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1212 if (list->comment == DEV_DEVICE)
1215 strncpy(nb+1,list->name,57);
1217 strncpy(nb,list->name,58);
1218 if ((list->comment == DEV_ZOOMED) && (list->next))
1219 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1220 strcat(nb," (Collapsed)");
1224 if (list->conflicts) /* device in conflict? */
1228 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1230 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1233 if (list->comment == DEV_DEVICE)
1235 ksprintf(db,"%s%d",list->dev,list->unit);
1240 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1242 ksprintf(ib," %d",list->irq);
1247 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1249 ksprintf(pb,"0x%x",list->iobase);
1255 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1257 putxyl(0,row,lbuf,80);
1260 switch(list->comment)
1262 case DEV_DEVICE: /* ordinary device */
1268 if (list->next->comment == DEV_DEVICE)
1269 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1274 if (list->next->comment == DEV_DEVICE)
1275 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1278 puthelp(" WARNING: This list entry corrupted!");
1282 move(0,row); /* put the cursor somewhere relevant */
1289 ** Displays (num) lines of the contents of (list) at (row), optionally
1290 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1293 drawlist(int row, int num, int detail, DEV_LIST *list)
1297 for(ofs = 0; ofs < num; ofs++)
1301 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1302 list = nextent(list); /* move down visible list */
1304 erase(0,row+ofs,80,1);
1313 ** Redraws the active list
1322 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1325 putxyl(45,0,lines,16);
1327 drawlist(1,8,1,alist); /* draw device lists */
1333 ** Redraws the inactive list
1336 redrawinactive(void)
1338 drawlist(10,7,0,ilist); /* draw device lists */
1345 ** Clear the screen and redraw the entire layout
1352 putxy(3,0,"!bActive!n-!bDrivers");
1353 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1355 putxy(3,9,"!bInactive!n-!bDrivers");
1356 putxy(63,9,"!bDev");
1359 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1369 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1370 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1373 yesnocancel(char *str)
1399 ** Show device parameters in the region below the lists
1401 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1402 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1403 ** +--------------------------------------------------------------------------------+
1404 ** 17-|--------------------------------------------------------------------------------|
1405 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1406 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1407 ** 20-| Flags : 0x0000 DRQ number : 00 |
1408 ** 21-|--------------------------------------------------------------------------------|
1411 showparams(DEV_LIST *dev)
1415 erase(0,18,80,3); /* clear area */
1418 if (dev->comment != DEV_DEVICE)
1422 if (dev->iobase > 0)
1424 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1430 ksprintf(buf,"IRQ number : %d",dev->irq);
1433 ksprintf(buf,"Flags : 0x%x",dev->flags);
1437 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1442 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1448 ksprintf(buf,"DRQ number : %d",dev->drq);
1455 ** Editing functions for device parameters
1457 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1458 ** onscreen. Refuse values outsise (min) and (max).
1459 ** editparams(dev) - Edit the parameters for (dev)
1463 #define VetRet(code) \
1465 if ((i >= min) && (i <= max)) /* legit? */ \
1468 ksprintf(buf,hex?"0x%x":"%d",i); \
1469 putxy(hex?x-2:x,y,buf); \
1470 return(code); /* all done and exit */ \
1472 i = *val; /* restore original value */ \
1473 delta = 1; /* restore other stuff */ \
1480 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1481 ** in a field (width) wide. (Allow one space)
1482 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1484 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1487 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1489 int i = *val; /* work with copy of the value */
1490 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1491 int xp = 0; /* cursor offset into text copy */
1492 int delta = 1; /* force redraw first time in */
1494 int extended = 0; /* stage counter for extended key sequences */
1496 if (hex) /* we presume there's a leading 0x onscreen */
1497 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1501 if (delta) /* only update if necessary */
1503 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1504 ksprintf(buf,"!i%s",tc); /* format for printing */
1505 erase(x,y,width,1); /* clear the area */
1506 putxy(x,y,buf); /* write */
1507 xp = strlen(tc); /* cursor always at end */
1508 move(x+xp,y); /* position the cursor */
1513 switch(extended) /* escape handling */
1516 if (c == 0x1b) /* esc? */
1518 extended = 1; /* flag and spin */
1522 break; /* nope, drop through */
1524 case 1: /* there was an escape prefix */
1525 if (c == '[' || c == 'O') /* second character in sequence */
1531 return(KEY_EXIT); /* double esc exits */
1533 break; /* nup, not a sequence. */
1537 switch(c) /* looks like the real McCoy */
1540 VetRet(KEY_UP); /* leave if OK */
1543 VetRet(KEY_DOWN); /* leave if OK */
1546 VetRet(KEY_RIGHT); /* leave if OK */
1549 VetRet(KEY_LEFT); /* leave if OK */
1559 case '\t': /* trying to tab off */
1560 VetRet(KEY_TAB); /* verify and maybe return */
1570 case '\177': /* BS or DEL */
1571 if (ro) /* readonly? */
1573 puthelp(" !iThis value cannot be edited (Press ESC)");
1574 while(kgetchar() != 0x1b); /* wait for key */
1575 return(KEY_NULL); /* spin */
1577 if (xp) /* still something left to delete */
1579 i = (hex ? i/0x10u : i/10); /* strip last digit */
1580 delta = 1; /* force update */
1603 if (ro) /* readonly? */
1605 puthelp(" !iThis value cannot be edited (Press ESC)");
1606 while(kgetchar() != 0x1b); /* wait for key */
1607 return(KEY_NULL); /* spin */
1609 if (xp >= width) /* no room for more characters anyway */
1613 if ((c >= '0') && (c <= '9'))
1615 i = i*0x10 + (c-'0'); /* update value */
1619 if ((c >= 'a') && (c <= 'f'))
1621 i = i*0x10 + (c-'a'+0xa);
1625 if ((c >= 'A') && (c <= 'F'))
1627 i = i*0x10 + (c-'A'+0xa);
1632 if ((c >= '0') && (c <= '9'))
1634 i = i*10 + (c-'0'); /* update value */
1635 delta = 1; /* force redraw */
1648 ** Edit the parameters for (dev)
1650 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1651 ** possible for this to spin in an endless loop...
1652 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1653 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1654 ** +--------------------------------------------------------------------------------+
1655 ** 17-|--------------------------------------------------------------------------------|
1656 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1657 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1658 ** 20-| Flags : 0x0000 DRQ number : 00 |
1659 ** 21-|--------------------------------------------------------------------------------|
1661 ** The "intelligence" in this function that hops around based on the directional
1662 ** returns from editval isn't very smart, and depends on the layout above.
1665 editparams(DEV_LIST *dev)
1668 char buf[16]; /* needs to fit the device name */
1670 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1671 ksprintf(buf,"!b%s",dev->dev);
1678 if (dev->iobase > 0)
1680 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1681 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1701 puthelp(" Interrupt number (Decimal, 1-15)");
1702 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1714 if (dev->iobase > 0)
1725 puthelp(" Device-specific flag values.");
1726 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1740 if (dev->iobase > 0)
1760 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1761 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1768 if (dev->iobase > 0)
1790 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1791 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1820 puthelp(" Device DMA request number (Decimal, 1-7)");
1821 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1844 dev->changed = 1; /* mark as changed */
1847 static char *helptext[] =
1849 " Using the UserConfig kernel settings editor",
1850 " -------------------------------------------",
1856 "The screen displays a list of available drivers, divided into two",
1857 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1858 "by default collapsed and can be expanded to show all the drivers",
1859 "available in each category. The parameters for the currently selected",
1860 "driver are shown at the bottom of the screen.",
1862 "- - Moving around -",
1864 "To move in the current list, use the UP and DOWN cursor keys to select",
1865 "an item (the selected item will be highlighted). If the item is a",
1866 "category name, you may alternatively expand or collapse the list of",
1867 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1868 "expanded, you can select each driver in the same manner and either:",
1870 " - change its parameters using [!bENTER!n]",
1871 " - move it to the Inactive list using [!bDEL!n]",
1873 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1874 "you need to move a driver from the Inactive list back to the Active",
1875 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1876 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1877 "its place in the Active list.",
1879 "- - Altering the list/parameters -",
1881 "Any drivers for devices not installed in your system should be moved",
1882 "to the Inactive list, until there are no remaining parameter conflicts",
1883 "between the drivers, as indicated at the top.",
1885 "Once the list of Active drivers only contains entries for the devices",
1886 "present in your system, you can set their parameters (Interrupt, DMA",
1887 "channel, I/O addresses). To do this, select the driver and press",
1888 "[!bENTER!n]: it is now possible to edit the settings at the",
1889 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1890 "finished, use [!bQ!n] to return to the list.",
1892 "- - Saving changes -",
1894 "When all settings seem correct, and you wish to proceed with the",
1895 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1896 "confirm your choice.",
1905 ** Displays help text onscreen for people that are confused, using a simple
1911 int topline = 0; /* where we are in the text */
1912 int line = 0; /* last line we displayed */
1916 for (;;) /* loop until user quits */
1918 /* display help text */
1921 clear(); /* remove everything else */
1922 for (line = topline;
1923 (line < (topline + 24)) && (helptext[line]);
1925 putxy(0,line-topline,helptext[line]);
1930 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1933 c = kgetchar(); /* so what do they say? */
1940 case 'B': /* wired into 'more' users' fingers */
1941 if (topline > 0) /* room to go up? */
1944 if (topline < 0) /* don't go too far */
1952 case ' ': /* expected by most people */
1953 if (helptext[line]) /* maybe more below? */
1962 redraw(); /* restore the screen */
1970 ** High-level control functions
1977 ** Handle user movement within (*list) in the region starting at (row) onscreen with
1978 ** (num) lines, starting at (*ofs) offset from row onscreen.
1979 ** Pass (detail) on to drawing routines.
1981 ** If the user hits a key other than a cursor key, maybe return a code.
1983 ** (*list) points to the device at the top line in the region, (*ofs) is the
1984 ** position of the highlight within the region. All routines below
1985 ** this take only a device and an absolute row : use ofsent() to find the
1986 ** device, and add (*ofs) to (row) to find the absolute row.
1989 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2000 showparams(ofsent(*ofs,*list)); /* show device parameters */
2001 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2005 c = kgetchar(); /* get a character */
2006 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2008 extended = 0; /* no longer */
2011 case 588: /* syscons' idea of 'up' */
2013 if (*ofs) /* just a move onscreen */
2015 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2016 (*ofs)--; /* move up */
2018 lp = prevent(*list); /* can we go up? */
2021 *list = lp; /* yes, move up list */
2022 drawlist(row,num,detail,*list);
2027 case 596: /* dooby-do */
2028 case 'B': /* down */
2029 lp = ofsent(*ofs,*list); /* get current item */
2031 break; /* nothing more to move to */
2032 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2033 if (*ofs < (num-1)) /* room to move onscreen? */
2037 *list = nextent(*list); /* scroll region down */
2038 drawlist(row,num,detail,*list);
2050 case '[': /* cheat : always preceeds cursor move */
2051 case 'O': /* ANSI application key mode */
2060 return(KEY_EXIT); /* user requests exit */
2064 return(KEY_DO); /* "do" something */
2069 return(KEY_DEL); /* "delete" response */
2073 return(KEY_UNZOOM); /* expand everything */
2077 return(KEY_ZOOM); /* collapse everything */
2080 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2081 return(KEY_TAB); /* "move" response */
2083 case '\014': /* ^L, redraw */
2086 case '?': /* helptext */
2098 ** Do the fullscreen config thang
2103 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2107 initlist(&inactive);
2113 conflicts = findconflict(active); /* find conflicts in the active list only */
2121 case 0: /* active devices */
2122 ret = dolist(1,8,1,&actofs,&alist,
2123 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2127 mode = 1; /* swap lists */
2144 collapselist(active);
2149 dp = ofsent(actofs,alist); /* get current device */
2150 if (dp) /* paranoia... */
2152 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2154 if (dp == alist) /* moving top item on list? */
2158 alist = dp->next; /* point list to non-moving item */
2160 alist = dp->prev; /* end of list, go back instead */
2163 if (!dp->next) /* moving last item on list? */
2166 dp->conflicts = 0; /* no conflicts on the inactive list */
2167 movedev(dp,inactive); /* shift to inactive list */
2168 conflicts = findconflict(active); /* update conflict tags */
2170 redrawactive(); /* redraw */
2175 case KEY_DO: /* edit device parameters */
2176 dp = ofsent(actofs,alist); /* get current device */
2177 if (dp) /* paranoia... */
2179 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2181 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2183 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2185 conflicts = findconflict(active); /* update conflict tags */
2186 }else{ /* DO on comment = zoom */
2187 switch(dp->comment) /* Depends on current state */
2189 case DEV_COMMENT: /* not currently zoomed */
2190 dp->comment = DEV_ZOOMED;
2194 dp->comment = DEV_COMMENT;
2204 case 1: /* inactive devices */
2205 ret = dolist(10,7,0,&inactofs,&ilist,
2206 " [!bEnter!n] Enable device ");
2220 expandlist(inactive);
2227 collapselist(inactive);
2232 dp = ofsent(inactofs,ilist); /* get current device */
2233 if (dp) /* paranoia... */
2235 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2237 if (dp == ilist) /* moving top of list? */
2241 ilist = dp->next; /* point list to non-moving item */
2243 ilist = dp->prev; /* can't go down, go up instead */
2246 if (!dp->next) /* last entry on list? */
2247 inactofs--; /* shift cursor up one */
2250 movedev(dp,active); /* shift to active list */
2251 conflicts = findconflict(active); /* update conflict tags */
2253 alist = dp; /* put at top and current */
2255 while(dp->comment == DEV_DEVICE)
2256 dp = dp->prev; /* forcibly unzoom section */
2257 dp ->comment = DEV_COMMENT;
2258 mode = 0; /* and swap modes to follow it */
2260 }else{ /* DO on comment = zoom */
2261 switch(dp->comment) /* Depends on current state */
2263 case DEV_COMMENT: /* not currently zoomed */
2264 dp->comment = DEV_ZOOMED;
2268 dp->comment = DEV_COMMENT;
2272 redrawactive(); /* redraw */
2277 default: /* nothing else relevant here */
2282 mode = 0; /* shouldn't happen... */
2285 /* handle returns that are the same for both modes */
2292 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2295 case 2: /* cancel */
2299 case 1: /* save and exit */
2301 savelist(inactive,0);
2304 nukelist(active); /* clean up after ourselves */
2314 #endif /* VISUAL_USERCONFIG */
2317 * Copyright (c) 1991 Regents of the University of California.
2318 * All rights reserved.
2319 * Copyright (c) 1994 Jordan K. Hubbard
2320 * All rights reserved.
2321 * Copyright (c) 1994 David Greenman
2322 * All rights reserved.
2324 * Many additional changes by Bruce Evans
2326 * This code is derived from software contributed by the
2327 * University of California Berkeley, Jordan K. Hubbard,
2328 * David Greenman and Bruce Evans.
2330 * Redistribution and use in source and binary forms, with or without
2331 * modification, are permitted provided that the following conditions
2333 * 1. Redistributions of source code must retain the above copyright
2334 * notice, this list of conditions and the following disclaimer.
2335 * 2. Redistributions in binary form must reproduce the above copyright
2336 * notice, this list of conditions and the following disclaimer in the
2337 * documentation and/or other materials provided with the distribution.
2338 * 3. All advertising materials mentioning features or use of this software
2339 * must display the following acknowledgement:
2340 * This product includes software developed by the University of
2341 * California, Berkeley and its contributors.
2342 * 4. Neither the name of the University nor the names of its contributors
2343 * may be used to endorse or promote products derived from this software
2344 * without specific prior written permission.
2346 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2347 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2348 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2350 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2351 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2352 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2353 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2354 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2355 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2358 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2361 #define PARM_DEVSPEC 0x1
2362 #define PARM_INT 0x2
2363 #define PARM_ADDR 0x3
2364 #define PARM_STRING 0x4
2366 typedef struct _cmdparm {
2369 struct uc_device *dparm;
2378 typedef int (*CmdFunc)(CmdParm *);
2380 typedef struct _cmd {
2388 static void lsscsi(void);
2389 static int list_scsi(CmdParm *);
2392 static int lsdevtab(struct uc_device *);
2393 static struct uc_device *find_device(char *, int);
2394 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2395 static void cngets(char *, int);
2396 static Cmd *parse_cmd(char *);
2397 static int parse_args(const char *, CmdParm *);
2398 static int save_dev(struct uc_device *);
2400 static int list_devices(CmdParm *);
2401 static int set_device_ioaddr(CmdParm *);
2402 static int set_device_irq(CmdParm *);
2403 static int set_device_drq(CmdParm *);
2404 static int set_device_iosize(CmdParm *);
2405 static int set_device_mem(CmdParm *);
2406 static int set_device_flags(CmdParm *);
2407 static int set_device_enable(CmdParm *);
2408 static int set_device_disable(CmdParm *);
2409 static int quitfunc(CmdParm *);
2410 static int helpfunc(CmdParm *);
2411 static int introfunc(CmdParm *);
2414 static int lspnp(void);
2415 static int set_pnp_parms(CmdParm *);
2420 static CmdParm addr_parms[] = {
2421 { PARM_DEVSPEC, {} },
2426 static CmdParm int_parms[] = {
2427 { PARM_DEVSPEC, {} },
2432 static CmdParm dev_parms[] = {
2433 { PARM_DEVSPEC, {} },
2438 static CmdParm string_arg[] = {
2439 { PARM_STRING, {} },
2444 static Cmd CmdList[] = {
2445 { "?", helpfunc, NULL }, /* ? (help) */
2446 { "di", set_device_disable, dev_parms }, /* disable dev */
2447 { "dr", set_device_drq, int_parms }, /* drq dev # */
2448 { "en", set_device_enable, dev_parms }, /* enable dev */
2449 { "ex", quitfunc, NULL }, /* exit (quit) */
2450 { "f", set_device_flags, int_parms }, /* flags dev mask */
2451 { "h", helpfunc, NULL }, /* help */
2452 { "intro", introfunc, NULL }, /* intro screen */
2453 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2454 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2455 { "ir", set_device_irq, int_parms }, /* irq dev # */
2456 { "l", list_devices, NULL }, /* ls, list */
2458 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2460 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2461 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2462 { "q", quitfunc, NULL }, /* quit */
2464 { "s", list_scsi, NULL }, /* scsi */
2466 #ifdef VISUAL_USERCONFIG
2467 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2469 { NULL, NULL, NULL },
2475 static char banner = 1;
2481 init_config_script();
2484 /* Only display signon banner if we are about to go interactive */
2485 if (!has_config_script()) {
2486 if (!(boothowto & RB_CONFIG))
2487 #ifdef INTRO_USERCONFIG
2494 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2495 " Type \"help\" for help"
2496 #ifdef VISUAL_USERCONFIG
2497 " or \"visual\" to go to the visual\n"
2498 " configuration interface (requires MGA/VGA display or\n"
2499 " serial terminal capable of displaying ANSI graphics)"
2505 kprintf("config> ");
2507 if (input[0] == '\0')
2509 cmd = parse_cmd(input);
2511 kprintf("Invalid command or syntax. Type `?' for help.\n");
2514 rval = (*cmd->handler)(cmd->parms);
2523 parse_cmd(char *cmd)
2527 for (cp = CmdList; cp->name; cp++) {
2528 int len = strlen(cp->name);
2530 if (!strncmp(cp->name, cmd, len)) {
2531 while (*cmd && *cmd != ' ' && *cmd != '\t')
2533 if (parse_args(cmd, cp->parms))
2543 parse_args(const char *cmd, CmdParm *parms)
2548 if (*cmd == ' ' || *cmd == '\t') {
2552 if (parms == NULL || parms->type == -1) {
2555 kprintf("Extra arg(s): %s\n", cmd);
2558 if (parms->type == PARM_DEVSPEC) {
2563 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2564 (*cmd >= '0' && *cmd <= '9')))
2565 devname[i++] = *(cmd++);
2567 if (*cmd >= '0' && *cmd <= '9') {
2568 unit = strtoul(cmd, &ptr, 10);
2570 kprintf("Invalid device number\n");
2571 /* XXX should print invalid token here and elsewhere. */
2574 /* XXX else should require end of token. */
2577 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2578 kprintf("No such device: %s%d\n", devname, unit);
2584 if (parms->type == PARM_INT) {
2585 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2587 kprintf("Invalid numeric argument\n");
2594 if (parms->type == PARM_ADDR) {
2595 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2597 kprintf("Invalid address argument\n");
2604 if (parms->type == PARM_STRING) {
2605 parms->parm.u.sparm = cmd;
2613 list_devices(CmdParm *parms)
2616 if (lsdevtab(uc_devtab)) return 0;
2618 if (lspnp()) return 0;
2624 set_device_ioaddr(CmdParm *parms)
2626 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2627 save_dev(parms[0].parm.dparm);
2632 set_device_irq(CmdParm *parms)
2636 irq = parms[1].parm.iparm;
2638 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2641 else if (irq != -1 && irq > 15) {
2642 kprintf("An IRQ > 15 would be invalid.\n");
2645 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2646 save_dev(parms[0].parm.dparm);
2651 set_device_drq(CmdParm *parms)
2656 * The bounds checking is just to ensure that the value can be printed
2657 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2659 drq = parms[1].parm.iparm;
2660 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2661 save_dev(parms[0].parm.dparm);
2666 set_device_iosize(CmdParm *parms)
2668 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2669 save_dev(parms[0].parm.dparm);
2674 set_device_mem(CmdParm *parms)
2676 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2677 save_dev(parms[0].parm.dparm);
2682 set_device_flags(CmdParm *parms)
2684 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2685 save_dev(parms[0].parm.dparm);
2690 set_device_enable(CmdParm *parms)
2692 parms[0].parm.dparm->id_enabled = TRUE;
2693 save_dev(parms[0].parm.dparm);
2698 set_device_disable(CmdParm *parms)
2700 parms[0].parm.dparm->id_enabled = FALSE;
2701 save_dev(parms[0].parm.dparm);
2708 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2714 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2717 * Output the pnp_ldn_overrides[] table.
2719 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2720 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2721 if(error) return(error);
2726 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2727 0, 0, sysctl_machdep_uc_pnplist, "A",
2728 "List of PnP overrides changed in UserConfig");
2731 * this function sets the kernel table to override bios PnP
2735 set_pnp_parms(CmdParm *parms)
2737 u_long idx, val, ldn, csn;
2740 const char *p = parms[0].parm.u.sparm;
2743 csn=strtoul(p,&q, 0);
2744 ldn=strtoul(q,&q, 0);
2745 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2746 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2747 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2750 for (i=0; i < MAX_PNP_LDN; i++) {
2751 if (pnp_ldn_overrides[i].csn == csn &&
2752 pnp_ldn_overrides[i].ldn == ldn)
2755 if (i==MAX_PNP_LDN) {
2756 for (i=0; i < MAX_PNP_LDN; i++) {
2757 if (pnp_ldn_overrides[i].csn <1 ||
2758 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2762 if (i==MAX_PNP_LDN) {
2763 kprintf("sorry, no PnP entries available, try delete one\n");
2766 d = pnp_ldn_overrides[i] ;
2772 if (!strncmp(p,"irq",3)) {
2773 idx=strtoul(p+3,&q, 0);
2774 val=strtoul(q,&q, 0);
2775 if (idx >=0 && idx < 2) d.irq[idx] = val;
2776 } else if (!strncmp(p,"flags",5)) {
2777 idx=strtoul(p+5,&q, 0);
2779 } else if (!strncmp(p,"drq",3)) {
2780 idx=strtoul(p+3,&q, 0);
2781 val=strtoul(q,&q, 0);
2782 if (idx >=0 && idx < 2) d.drq[idx] = val;
2783 } else if (!strncmp(p,"port",4)) {
2784 idx=strtoul(p+4,&q, 0);
2785 val=strtoul(q,&q, 0);
2786 if (idx >=0 && idx < 8) d.port[idx] = val;
2787 } else if (!strncmp(p,"mem",3)) {
2788 idx=strtoul(p+3,&q, 0);
2789 val=strtoul(q,&q, 0);
2790 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2791 } else if (!strncmp(p,"bios",4)) {
2794 } else if (!strncmp(p,"os",2)) {
2797 } else if (!strncmp(p,"disable",7)) {
2800 } else if (!strncmp(p,"enable",6)) {
2803 } else if (!strncmp(p,"delete",6)) {
2804 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2805 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2808 kprintf("unknown command <%s>\n", p);
2811 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2813 pnp_ldn_overrides[i] = d ;
2819 quitfunc(CmdParm *parms)
2822 * If kernel config supplied, and we are parsing it, and -c also supplied,
2823 * ignore a quit command, This provides a safety mechanism to allow
2824 * recovery from a damaged/buggy kernel config.
2826 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2832 helpfunc(CmdParm *parms)
2835 "Command\t\t\tDescription\n"
2836 "-------\t\t\t-----------\n"
2837 "ls\t\t\tList currently configured devices\n"
2838 "port <devname> <addr>\tSet device port (i/o address)\n"
2839 "irq <devname> <number>\tSet device irq\n"
2840 "drq <devname> <number>\tSet device drq\n"
2841 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2842 "iosize <devname> <size>\tSet device memory size\n"
2843 "flags <devname> <mask>\tSet device flags\n"
2844 "enable <devname>\tEnable device\n"
2845 "disable <devname>\tDisable device (will not be probed)\n");
2848 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2849 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2850 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2851 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2852 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2853 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2856 "quit\t\t\tExit this configuration utility\n"
2857 "reset\t\t\tReset CPU\n");
2858 #ifdef VISUAL_USERCONFIG
2859 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2862 "help\t\t\tThis message\n\n"
2863 "Commands may be abbreviated to a unique prefix\n");
2867 #if defined (VISUAL_USERCONFIG)
2869 center(int y, char *str)
2871 putxy((80 - strlen(str)) / 2, y, str);
2876 introfunc(CmdParm *parms)
2878 #if defined (VISUAL_USERCONFIG)
2879 int curr_item, first_time, extended = 0;
2880 static char *choices[] = {
2881 " Skip kernel configuration and continue with installation ",
2882 " Start kernel configuration in full-screen visual mode ",
2883 " Start kernel configuration in CLI mode ",
2887 center(2, "!bKernel Configuration Menu!n");
2896 for (i = 0; i < 3; i++) {
2900 strcat(tmp, choices[i]);
2903 putxy(10, 5 + i, tmp);
2907 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2908 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2909 putxy(2, 12, "match your hardware configuration.");
2910 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2911 putxy(2, 15, "(press Down-Arrow then ENTER).");
2912 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2913 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2914 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2915 putxy(2, 21, "then simply press ENTER or Q now.");
2919 move(0, 0); /* move the cursor out of the way */
2922 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2923 extended = 0; /* no longer */
2932 case 'B': /* down */
2944 case '[': /* cheat : always preceeds cursor move */
2945 case 'O': /* ANSI application key mode */
2956 return 1; /* user requests exit */
2958 case '1': /* select an item */
2982 case 'D': /* down */
2995 else if (curr_item == 1)
2996 return visuserconfig();
2998 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
2999 /* enable quitfunc */
3000 userconfig_boot_parsing=0;
3002 boothowto |= RB_CONFIG; /* force -c */
3009 #else /* !VISUAL_USERCONFIG */
3011 #endif /* VISUAL_USERCONFIG */
3018 struct pnp_cinfo *c;
3022 for (i=0; i< MAX_PNP_LDN; i++) {
3023 c = &pnp_ldn_overrides[i];
3024 if (c->csn >0 && c->csn != 255) {
3026 static char pfmt[] =
3027 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3028 static char mfmt[] =
3029 "mem 0x%x 0x%x 0x%x 0x%x";
3032 if (!userconfig_boot_parsing) {
3034 if (kgetchar() == 'q') {
3042 if (lineno == 0 || first)
3043 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3045 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3047 c->override ? "OS ":"BIOS",
3048 c->enable ? "Y":"N",
3049 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3051 kprintf("flags 0x%08lx ",c->flags);
3052 for (pmax = 7; pmax >=0 ; pmax--)
3053 if (c->port[pmax]!=0) break;
3054 for (mmax = 3; mmax >=0 ; mmax--)
3055 if (c->mem[mmax].base!=0) break;
3058 buf[10 + 5*pmax]='\0';
3060 c->port[0], c->port[1], c->port[2], c->port[3],
3061 c->port[4], c->port[5], c->port[6], c->port[7]);
3065 buf[8 + 5*mmax]='\0';
3067 c->mem[0].base, c->mem[1].base,
3068 c->mem[2].base, c->mem[3].base);
3078 lsdevtab(struct uc_device *dt)
3080 for (; dt->id_id != 0; dt++) {
3085 if (!userconfig_boot_parsing) {
3086 if (kgetchar() == 'q') {
3096 "Device port irq drq iomem iosize unit flags enab\n"
3100 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3101 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3102 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3103 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3104 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3105 dt->id_enabled ? "Yes" : "No");
3115 int count = resource_count();
3121 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3124 for (i = 0; i < count; i++) {
3125 name = resource_query_name(i);
3126 unit = resource_query_unit(i);
3128 continue; /* skip wildcards */
3129 uc_devtab[dt].id_id = id++;
3130 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3132 resource_int_value(name, unit, "irq", &val);
3133 uc_devtab[dt].id_irq = (1 << val);
3134 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3135 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3136 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3137 uc_devtab[dt].id_unit = unit;
3138 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3140 resource_int_value(name, unit, "disabled", &val);
3141 uc_devtab[dt].id_enabled = !val;
3142 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3143 strcpy(uc_devtab[dt].id_name, name);
3152 int count = resource_count();
3154 for (i = 0; i < count; i++)
3155 if (uc_devtab[i].id_name)
3156 kfree(uc_devtab[i].id_name, M_DEVL);
3157 kfree(uc_devtab, M_DEVL);
3160 static struct uc_device *
3161 find_device(char *devname, int unit)
3163 struct uc_device *ret;
3165 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3170 static struct uc_device *
3171 search_devtable(struct uc_device *dt, char *devname, int unit)
3173 for (; dt->id_id != 0; dt++)
3174 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3180 cngets(char *input, int maxin)
3186 /* Treat ^H or ^? as backspace */
3187 if ((c == '\010' || c == '\177')) {
3189 kprintf("\010 \010");
3190 *--input = '\0', --nchars;
3194 /* Treat ^U or ^X as kill line */
3195 else if ((c == '\025' || c == '\030')) {
3197 kprintf("\010 \010");
3198 *--input = '\0', --nchars;
3203 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3207 *input++ = (u_char)c;
3213 /* scsi: Support for displaying configured SCSI devices.
3214 * There is no way to edit them, and this is inconsistent
3215 * with the ISA method. This is here as a basis for further work.
3218 type_text(char *name) /* XXX: This is bogus */
3220 if (strcmp(name, "sd") == 0)
3223 if (strcmp(name, "st") == 0)
3229 id_put(char *desc, int id)
3231 if (id != SCCONF_UNSPEC)
3234 kprintf("%s", desc);
3236 if (id == SCCONF_ANY)
3248 kprintf("scsi: (can't be edited):\n");
3250 for (i = 0; scsi_cinit[i].driver; i++)
3252 id_put("controller scbus", scsi_cinit[i].scbus);
3254 if (scsi_cinit[i].unit != -1)
3257 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3263 for (i = 0; scsi_dinit[i].name; i++)
3265 kprintf("%s ", type_text(scsi_dinit[i].name));
3267 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3268 id_put(" at scbus", scsi_dinit[i].cunit);
3269 id_put(" target ", scsi_dinit[i].target);
3270 id_put(" lun ", scsi_dinit[i].lun);
3272 if (scsi_dinit[i].flags)
3273 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3280 list_scsi(CmdParm *parms)
3289 save_resource(struct uc_device *idev)
3294 name = idev->id_name;
3295 unit = idev->id_unit;
3296 resource_set_int(name, unit, "port", idev->id_iobase);
3297 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3298 resource_set_int(name, unit, "drq", idev->id_drq);
3299 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3300 resource_set_int(name, unit, "msize", idev->id_msize);
3301 resource_set_int(name, unit, "flags", idev->id_flags);
3302 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3306 save_dev(struct uc_device *idev)
3308 struct uc_device *id_p,*id_pn;
3309 char *name = idev->id_name;
3311 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3312 if (id_p->id_id == idev->id_id) {
3313 id_pn = id_p->id_next;
3315 kfree(id_p->id_name, M_DEVL);
3316 bcopy(idev,id_p,sizeof(struct uc_device));
3317 save_resource(idev);
3318 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3319 strcpy(id_p->id_name, name);
3320 id_p->id_next = id_pn;
3324 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3325 bcopy(idev,id_pn,sizeof(struct uc_device));
3326 save_resource(idev);
3327 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3328 strcpy(id_pn->id_name, name);
3329 id_pn->id_next = uc_devlist;