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 {"pcic", "PC-card controller", 0, CLS_MISC},
345 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
346 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
350 typedef struct _devlist_struct
353 int attrib; /* flag values as per the FLG_* defines above */
354 int class; /* disk, etc as per the CLS_* defines above */
356 int iobase,irq,drq,maddr,msize,unit,flags,id;
357 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
358 int conflicts; /* set/reset by findconflict, count of conflicts */
359 int changed; /* nonzero if the device has been edited */
360 struct uc_device *device;
361 struct _devlist_struct *prev,*next;
366 #define DEV_COMMENT 1
369 #define LIST_CURRENT (1<<0)
370 #define LIST_SELECTED (1<<1)
372 #define KEY_EXIT 0 /* return codes from dolist() and friends */
378 #define KEY_UP 5 /* these only returned from editval() */
382 #define KEY_NULL 9 /* this allows us to spin & redraw */
384 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
385 #define KEY_UNZOOM 11
387 #define KEY_HELP 12 /* duh? */
389 static void redraw(void);
390 static void insdev(DEV_LIST *dev, DEV_LIST *list);
391 static int devinfo(DEV_LIST *dev);
392 static int visuserconfig(void);
394 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
395 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
396 static DEV_LIST scratch; /* scratch record */
397 static int conflicts; /* total conflict count */
400 static char lines[] = "--------------------------------------------------------------------------------";
401 static char spaces[] = " ";
405 ** Device manipulation stuff : find, describe, configure.
411 ** Sets the device referenced by (*dev) to the parameters in the struct,
412 ** and the enable flag according to (enabled)
415 setdev(DEV_LIST *dev, int enabled)
417 dev->device->id_iobase = dev->iobase; /* copy happy */
418 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
419 dev->device->id_drq = (short)dev->drq;
420 dev->device->id_maddr = (caddr_t)dev->maddr;
421 dev->device->id_msize = dev->msize;
422 dev->device->id_flags = dev->flags;
423 dev->device->id_enabled = enabled;
430 ** Walk the kernel device tables and build the active and inactive lists
436 struct uc_device *ap;
438 ap = uc_devtab; /* pointer to array of devices */
439 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
441 scratch.unit = ap[i].id_unit; /* device parameters */
442 strcpy(scratch.dev,ap[i].id_name);
443 scratch.iobase = ap[i].id_iobase;
444 scratch.irq = ffs(ap[i].id_irq)-1;
445 scratch.drq = ap[i].id_drq;
446 scratch.maddr = (int)ap[i].id_maddr;
447 scratch.msize = ap[i].id_msize;
448 scratch.flags = ap[i].id_flags;
450 scratch.comment = DEV_DEVICE; /* admin stuff */
451 scratch.conflicts = 0;
452 scratch.device = &ap[i]; /* save pointer for later reference */
454 if (!devinfo(&scratch)) /* get more info on the device */
455 insdev(&scratch,ap[i].id_enabled?active:inactive);
463 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
464 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
466 ** If the device is marked "invisible", return nonzero; the caller should
467 ** not insert any such device into either list.
471 devinfo(DEV_LIST *dev)
475 for (i = 0; device_info[i].class; i++)
477 if (!strcmp(dev->dev,device_info[i].dev))
479 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
481 strcpy(dev->name,device_info[i].name); /* get the name */
482 dev->attrib = device_info[i].attrib;
483 dev->class = device_info[i].class;
487 strcpy(dev->name,"Unknown device");
489 dev->class = CLS_MISC;
495 ** List manipulation stuff : add, move, initialise, free, traverse
497 ** Note that there are assumptions throughout this code that
498 ** the first entry in a list will never move. (assumed to be
506 ** appends a copy of (dev) to the end of (*list)
509 addev(DEV_LIST *dev, DEV_LIST **list)
514 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
515 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
517 if (*list) /* list exists */
521 ap = ap->next; /* scoot to end of list */
525 }else{ /* list does not yet exist */
527 lp->prev = lp->next = NULL; /* list now exists */
535 ** Finds the 'appropriate' place for (dev) in (list)
537 ** 'Appropriate' means in numeric order with other devices of the same type,
538 ** or in alphabetic order following a comment of the appropriate type.
539 ** or at the end of the list if an appropriate comment is not found. (this should
541 ** (Note that the appropriate point is never the top, but may be the bottom)
544 findspot(DEV_LIST *dev, DEV_LIST *list)
548 /* search for a previous instance of the same device */
549 for (ap = list; ap; ap = ap->next)
551 if (ap->comment != DEV_DEVICE) /* ignore comments */
553 if (!strcmp(dev->dev,ap->dev)) /* same base device */
555 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
556 || !ap->next) /* or end of list */
558 ap = ap->prev; /* back up one */
559 break; /* done here */
561 if (ap->next) /* if the next item exists */
563 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
565 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
571 if (!ap) /* not sure yet */
573 /* search for a class that the device might belong to */
574 for (ap = list; ap; ap = ap->next)
576 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
578 if (dev->class != ap->class) /* of same class too 8) */
580 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
582 ap = ap->prev; /* back up one */
583 break; /* done here */
585 if (ap->next) /* if the next item exists */
586 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
591 if (!ap) /* didn't find a match */
593 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
594 if ((ap->comment != DEV_DEVICE)
595 && (ap->class == dev->class)) /* appropriate place? */
597 } /* or just put up with last */
606 ** Inserts a copy of (dev) at the appropriate point in (list)
609 insdev(DEV_LIST *dev, DEV_LIST *list)
613 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
614 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
616 ap = findspot(lp,list); /* find appropriate spot */
617 lp->next = ap->next; /* point to next */
619 ap->next->prev = lp; /* point next to new */
620 lp->prev = ap; /* point new to current */
621 ap->next = lp; /* and current to new */
628 ** Moves (dev) from its current list to an appropriate place in (list)
629 ** (dev) may not come from the top of a list, but it may from the bottom.
632 movedev(DEV_LIST *dev, DEV_LIST *list)
636 ap = findspot(dev,list);
637 dev->prev->next = dev->next; /* remove from old list */
639 dev->next->prev = dev->prev;
641 dev->next = ap->next; /* insert in new list */
643 ap->next->prev = dev; /* point next to new */
644 dev->prev = ap; /* point new to current */
645 ap->next = dev; /* and current to new */
652 ** Initialises (*list) with the basic headings
655 initlist(DEV_LIST **list)
659 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
661 strcpy(scratch.name,devclass_names[i].name);
662 scratch.comment = DEV_ZOOMED;
663 scratch.class = devclass_names[i].number;
664 scratch.attrib = FLG_MANDATORY; /* can't be moved */
665 addev(&scratch,list); /* add to the list */
673 ** Walks (list) and saves the settings of any entry marked as changed.
675 ** The device's active field is set according to (active).
677 ** Builds the uc_devlist used by kget to extract the changed device information.
678 ** The code for this was taken almost verbatim from the original module.
681 savelist(DEV_LIST *list, int active)
683 struct uc_device *id_p,*id_pn;
688 if ((list->comment == DEV_DEVICE) && /* is a device */
689 (list->changed) && /* has been changed */
690 (list->device != NULL)) { /* has an uc_device structure */
692 setdev(list,active); /* set the device itself */
695 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
696 { /* look on the list for it */
697 if (id_p->id_id == list->device->id_id)
699 name = list->device->id_name;
700 id_pn = id_p->id_next;
702 kfree(id_p->id_name, M_DEVL);
703 bcopy(list->device,id_p,sizeof(struct uc_device));
704 save_resource(list->device);
705 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
706 strcpy(id_p->id_name, name);
707 id_pn->id_next = uc_devlist;
708 id_p->id_next = id_pn;
712 if (!id_pn) /* not already on the list */
714 name = list->device->id_name;
715 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
716 bcopy(list->device,id_pn,sizeof(struct uc_device));
717 save_resource(list->device);
718 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
719 strcpy(id_pn->id_name, name);
720 id_pn->id_next = uc_devlist;
721 uc_devlist = id_pn; /* park at top of list */
732 ** Frees all storage in use by a (list).
735 nukelist(DEV_LIST *list)
741 while(list->prev) /* walk to head of list */
756 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
757 ** if there is no previous entry. (Only possible if list->prev == NULL given the
758 ** premise that there is always a comment at the head of the list)
761 prevent(DEV_LIST *list)
767 dp = list->prev; /* start back one */
770 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
771 return(dp); /* so skip to comment */
772 if (dp->comment == DEV_COMMENT) /* not zoomed */
773 return(list->prev); /* one back as normal */
774 dp = dp->prev; /* backpedal */
776 return(dp); /* NULL, we can assume */
783 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
784 ** if there is no next entry. (Possible if the current entry is last, or
785 ** if the current entry is the last heading and it's collapsed)
788 nextent(DEV_LIST *list)
794 if (list->comment != DEV_ZOOMED) /* no reason to skip */
799 if (dp->comment != DEV_DEVICE) /* found another heading */
803 return(dp); /* back we go */
810 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
813 ofsent(int ofs, DEV_LIST *list)
815 while (ofs-- && list)
816 list = nextent(list);
824 ** Scans every element of (list) and sets the conflict tags appropriately
825 ** Returns the number of conflicts found.
828 findconflict(DEV_LIST *list)
830 int count = 0; /* number of conflicts found */
833 for (dp = list; dp; dp = dp->next) /* over the whole list */
835 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
838 dp->conflicts = 0; /* assume the best */
839 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
841 if (sp->comment != DEV_DEVICE) /* likewise */
844 if (sp == dp) /* always conflict with itself */
847 if ((dp->iobase > 0) && /* iobase conflict? */
848 (dp->iobase == sp->iobase))
850 if ((dp->irq > 0) && /* irq conflict? */
851 (dp->irq == sp->irq))
853 if ((dp->drq > 0) && /* drq conflict? */
854 (dp->drq == sp->drq))
856 if ((sp->maddr > 0) && /* maddr/msize conflict? */
858 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
859 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
862 count += dp->conflicts; /* count conflicts */
871 ** Unzooms all headings in (list)
874 expandlist(DEV_LIST *list)
878 if (list->comment == DEV_COMMENT)
879 list->comment = DEV_ZOOMED;
888 ** Zooms all headings in (list)
891 collapselist(DEV_LIST *list)
895 if (list->comment == DEV_ZOOMED)
896 list->comment = DEV_COMMENT;
903 ** Screen-manipulation stuff
905 ** This is the basic screen layout :
907 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
908 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
909 ** +--------------------------------------------------------------------------------+
910 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
911 ** 1 -| ........................ ....... .. 0x....|
912 ** 2 -| ........................ ....... .. 0x....|
913 ** 3 -| ........................ ....... .. 0x....|
914 ** 4 -| ........................ ....... .. 0x....|
915 ** 5 -| ........................ ....... .. 0x....|
916 ** 6 -| ........................ ....... .. 0x....|
917 ** 7 -| ........................ ....... .. 0x....|
918 ** 8 -| ........................ ....... .. 0x....|
919 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
920 ** 10-| ........................ ....... |
921 ** 11-| ........................ ....... |
922 ** 12-| ........................ ....... |
923 ** 13-| ........................ ....... |
924 ** 14-| ........................ ....... |
925 ** 15-| ........................ ....... |
926 ** 16-| ........................ ....... |
927 ** 17-|------------------------------------------------------UP-DOWN-------------------|
928 ** 18-| Relevant parameters for the current device |
931 ** 21-|--------------------------------------------------------------------------------|
932 ** 22-| Help texts go here |
934 ** +--------------------------------------------------------------------------------+
938 ** On a collapsed comment :
940 ** [Enter] Expand device list [z] Expand all lists
941 ** [TAB] Change fields [Q] Save and Exit
943 ** On an expanded comment :
945 ** [Enter] Collapse device list [Z] Collapse all lists
946 ** [TAB] Change fields [Q] Save and Exit
948 ** On a comment with no followers
951 ** [TAB] Change fields [Q] Save and Exit
953 ** On a device in the active list
955 ** [Enter] Edit device parameters [DEL] Disable device
956 ** [TAB] Change fields [Q] Save and Exit [?] Help
958 ** On a device in the inactive list
960 ** [Enter] Enable device
961 ** [TAB] Change fields [Q] Save and Exit [?] Help
963 ** While editing parameters
965 ** <parameter-specific help here>
966 ** [TAB] Change fields [Q] Save device parameters
973 ** The base-level screen primitives :
975 ** bold() - enter bold mode \E[1m (md)
976 ** inverse() - enter inverse mode \E[7m (so)
977 ** normal() - clear bold/inverse mode \E[m (se)
978 ** clear() - clear the screen \E[H\E[J (ce)
979 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1004 kprintf("\033[H\033[J");
1010 kprintf("\033[%d;%dH",y+1,x+1);
1016 ** High-level screen primitives :
1018 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1019 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1020 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1021 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1022 ** putmsg(str) - put (str) in the message area
1023 ** puthelp(str) - put (str) in the upper helpline
1024 ** pad(str,len) - pad (str) to (len) with spaces
1025 ** drawline(row,detail,list,inverse,*dhelp)
1026 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1027 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1028 ** draw the line in inverse video, and display (*dhelp) on the
1030 ** drawlist(row,num,detail,list)
1031 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1032 ** through to drawline().
1033 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1034 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1035 ** redraw(); - Redraws the entire screen layout, including the
1036 ** - two list panels.
1041 ** writes (str) at x,y onscreen
1043 ** writes up to (len) of (str) at x,y onscreen.
1045 ** Supports embedded formatting :
1046 ** !i - inverse mode.
1048 ** !n - normal mode.
1051 putxyl(int x, int y, char *str, int len)
1056 while((*str) && (len--))
1058 if (*str == '!') /* format escape? */
1060 switch(*(str+1)) /* depending on the next character */
1064 str +=2; /* skip formatting */
1065 len++; /* doesn't count for length */
1070 str +=2; /* skip formatting */
1071 len++; /* doesn't count for length */
1076 str +=2; /* skip formatting */
1077 len++; /* doesn't count for length */
1081 kprintf("%c", *str++); /* not an escape */
1084 kprintf("%c", *str++); /* emit the character */
1089 #define putxy(x,y,str) putxyl(x,y,str,-1)
1095 ** Erases the region (x,y,w,h)
1098 erase(int x, int y, int w, int h)
1103 for (i = 0; i < h; i++)
1104 putxyl(x,y++,spaces,w);
1111 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1112 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1115 txtbox(int x, int y, int w, int h, char *str)
1120 while((str[i]) && h)
1122 if (str[i] == '\n') /* newline */
1124 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1125 y++; /* move down */
1126 h--; /* room for one less */
1127 str += (i+1); /* skip first newline */
1128 i = 0; /* zero offset */
1130 i++; /* next character */
1133 if (h) /* end of string, not region */
1141 ** writes (msg) in the helptext area
1146 erase(0,18,80,3); /* clear area */
1147 txtbox(0,18,80,3,msg);
1154 ** Writes (msg) in the helpline area
1167 ** Draws the help message at the bottom of the screen
1170 masterhelp(char *msg)
1180 ** space-pads a (str) to (len) characters
1183 pad(char *str, int len)
1187 for (i = 0; str[i]; i++) /* find the end of the string */
1189 if (i >= len) /* no padding needed */
1191 while(i < len) /* pad */
1200 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1201 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1203 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1204 ** help is shown for normal or zoomed comments
1207 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1209 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1211 if (list->comment == DEV_DEVICE)
1214 strncpy(nb+1,list->name,57);
1216 strncpy(nb,list->name,58);
1217 if ((list->comment == DEV_ZOOMED) && (list->next))
1218 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1219 strcat(nb," (Collapsed)");
1223 if (list->conflicts) /* device in conflict? */
1227 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1229 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1232 if (list->comment == DEV_DEVICE)
1234 ksprintf(db,"%s%d",list->dev,list->unit);
1239 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1241 ksprintf(ib," %d",list->irq);
1246 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1248 ksprintf(pb,"0x%x",list->iobase);
1254 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1256 putxyl(0,row,lbuf,80);
1259 switch(list->comment)
1261 case DEV_DEVICE: /* ordinary device */
1267 if (list->next->comment == DEV_DEVICE)
1268 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1273 if (list->next->comment == DEV_DEVICE)
1274 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1277 puthelp(" WARNING: This list entry corrupted!");
1281 move(0,row); /* put the cursor somewhere relevant */
1288 ** Displays (num) lines of the contents of (list) at (row), optionally
1289 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1292 drawlist(int row, int num, int detail, DEV_LIST *list)
1296 for(ofs = 0; ofs < num; ofs++)
1300 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1301 list = nextent(list); /* move down visible list */
1303 erase(0,row+ofs,80,1);
1312 ** Redraws the active list
1321 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1324 putxyl(45,0,lines,16);
1326 drawlist(1,8,1,alist); /* draw device lists */
1332 ** Redraws the inactive list
1335 redrawinactive(void)
1337 drawlist(10,7,0,ilist); /* draw device lists */
1344 ** Clear the screen and redraw the entire layout
1351 putxy(3,0,"!bActive!n-!bDrivers");
1352 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1354 putxy(3,9,"!bInactive!n-!bDrivers");
1355 putxy(63,9,"!bDev");
1358 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1368 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1369 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1372 yesnocancel(char *str)
1398 ** Show device parameters in the region below the lists
1400 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1401 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1402 ** +--------------------------------------------------------------------------------+
1403 ** 17-|--------------------------------------------------------------------------------|
1404 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1405 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1406 ** 20-| Flags : 0x0000 DRQ number : 00 |
1407 ** 21-|--------------------------------------------------------------------------------|
1410 showparams(DEV_LIST *dev)
1414 erase(0,18,80,3); /* clear area */
1417 if (dev->comment != DEV_DEVICE)
1421 if (dev->iobase > 0)
1423 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1429 ksprintf(buf,"IRQ number : %d",dev->irq);
1432 ksprintf(buf,"Flags : 0x%x",dev->flags);
1436 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1441 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1447 ksprintf(buf,"DRQ number : %d",dev->drq);
1454 ** Editing functions for device parameters
1456 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1457 ** onscreen. Refuse values outsise (min) and (max).
1458 ** editparams(dev) - Edit the parameters for (dev)
1462 #define VetRet(code) \
1464 if ((i >= min) && (i <= max)) /* legit? */ \
1467 ksprintf(buf,hex?"0x%x":"%d",i); \
1468 putxy(hex?x-2:x,y,buf); \
1469 return(code); /* all done and exit */ \
1471 i = *val; /* restore original value */ \
1472 delta = 1; /* restore other stuff */ \
1479 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1480 ** in a field (width) wide. (Allow one space)
1481 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1483 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1486 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1488 int i = *val; /* work with copy of the value */
1489 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1490 int xp = 0; /* cursor offset into text copy */
1491 int delta = 1; /* force redraw first time in */
1493 int extended = 0; /* stage counter for extended key sequences */
1495 if (hex) /* we presume there's a leading 0x onscreen */
1496 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1500 if (delta) /* only update if necessary */
1502 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1503 ksprintf(buf,"!i%s",tc); /* format for printing */
1504 erase(x,y,width,1); /* clear the area */
1505 putxy(x,y,buf); /* write */
1506 xp = strlen(tc); /* cursor always at end */
1507 move(x+xp,y); /* position the cursor */
1512 switch(extended) /* escape handling */
1515 if (c == 0x1b) /* esc? */
1517 extended = 1; /* flag and spin */
1521 break; /* nope, drop through */
1523 case 1: /* there was an escape prefix */
1524 if (c == '[' || c == 'O') /* second character in sequence */
1530 return(KEY_EXIT); /* double esc exits */
1532 break; /* nup, not a sequence. */
1536 switch(c) /* looks like the real McCoy */
1539 VetRet(KEY_UP); /* leave if OK */
1542 VetRet(KEY_DOWN); /* leave if OK */
1545 VetRet(KEY_RIGHT); /* leave if OK */
1548 VetRet(KEY_LEFT); /* leave if OK */
1558 case '\t': /* trying to tab off */
1559 VetRet(KEY_TAB); /* verify and maybe return */
1569 case '\177': /* BS or DEL */
1570 if (ro) /* readonly? */
1572 puthelp(" !iThis value cannot be edited (Press ESC)");
1573 while(kgetchar() != 0x1b); /* wait for key */
1574 return(KEY_NULL); /* spin */
1576 if (xp) /* still something left to delete */
1578 i = (hex ? i/0x10u : i/10); /* strip last digit */
1579 delta = 1; /* force update */
1602 if (ro) /* readonly? */
1604 puthelp(" !iThis value cannot be edited (Press ESC)");
1605 while(kgetchar() != 0x1b); /* wait for key */
1606 return(KEY_NULL); /* spin */
1608 if (xp >= width) /* no room for more characters anyway */
1612 if ((c >= '0') && (c <= '9'))
1614 i = i*0x10 + (c-'0'); /* update value */
1618 if ((c >= 'a') && (c <= 'f'))
1620 i = i*0x10 + (c-'a'+0xa);
1624 if ((c >= 'A') && (c <= 'F'))
1626 i = i*0x10 + (c-'A'+0xa);
1631 if ((c >= '0') && (c <= '9'))
1633 i = i*10 + (c-'0'); /* update value */
1634 delta = 1; /* force redraw */
1647 ** Edit the parameters for (dev)
1649 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1650 ** possible for this to spin in an endless loop...
1651 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1652 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1653 ** +--------------------------------------------------------------------------------+
1654 ** 17-|--------------------------------------------------------------------------------|
1655 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1656 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1657 ** 20-| Flags : 0x0000 DRQ number : 00 |
1658 ** 21-|--------------------------------------------------------------------------------|
1660 ** The "intelligence" in this function that hops around based on the directional
1661 ** returns from editval isn't very smart, and depends on the layout above.
1664 editparams(DEV_LIST *dev)
1667 char buf[16]; /* needs to fit the device name */
1669 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1670 ksprintf(buf,"!b%s",dev->dev);
1677 if (dev->iobase > 0)
1679 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1680 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1700 puthelp(" Interrupt number (Decimal, 1-15)");
1701 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1713 if (dev->iobase > 0)
1724 puthelp(" Device-specific flag values.");
1725 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1739 if (dev->iobase > 0)
1759 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1760 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1767 if (dev->iobase > 0)
1789 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1790 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1819 puthelp(" Device DMA request number (Decimal, 1-7)");
1820 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1843 dev->changed = 1; /* mark as changed */
1846 static char *helptext[] =
1848 " Using the UserConfig kernel settings editor",
1849 " -------------------------------------------",
1855 "The screen displays a list of available drivers, divided into two",
1856 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1857 "by default collapsed and can be expanded to show all the drivers",
1858 "available in each category. The parameters for the currently selected",
1859 "driver are shown at the bottom of the screen.",
1861 "- - Moving around -",
1863 "To move in the current list, use the UP and DOWN cursor keys to select",
1864 "an item (the selected item will be highlighted). If the item is a",
1865 "category name, you may alternatively expand or collapse the list of",
1866 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1867 "expanded, you can select each driver in the same manner and either:",
1869 " - change its parameters using [!bENTER!n]",
1870 " - move it to the Inactive list using [!bDEL!n]",
1872 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1873 "you need to move a driver from the Inactive list back to the Active",
1874 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1875 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1876 "its place in the Active list.",
1878 "- - Altering the list/parameters -",
1880 "Any drivers for devices not installed in your system should be moved",
1881 "to the Inactive list, until there are no remaining parameter conflicts",
1882 "between the drivers, as indicated at the top.",
1884 "Once the list of Active drivers only contains entries for the devices",
1885 "present in your system, you can set their parameters (Interrupt, DMA",
1886 "channel, I/O addresses). To do this, select the driver and press",
1887 "[!bENTER!n]: it is now possible to edit the settings at the",
1888 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1889 "finished, use [!bQ!n] to return to the list.",
1891 "- - Saving changes -",
1893 "When all settings seem correct, and you wish to proceed with the",
1894 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1895 "confirm your choice.",
1904 ** Displays help text onscreen for people that are confused, using a simple
1910 int topline = 0; /* where we are in the text */
1911 int line = 0; /* last line we displayed */
1915 for (;;) /* loop until user quits */
1917 /* display help text */
1920 clear(); /* remove everything else */
1921 for (line = topline;
1922 (line < (topline + 24)) && (helptext[line]);
1924 putxy(0,line-topline,helptext[line]);
1929 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1932 c = kgetchar(); /* so what do they say? */
1939 case 'B': /* wired into 'more' users' fingers */
1940 if (topline > 0) /* room to go up? */
1943 if (topline < 0) /* don't go too far */
1951 case ' ': /* expected by most people */
1952 if (helptext[line]) /* maybe more below? */
1961 redraw(); /* restore the screen */
1969 ** High-level control functions
1976 ** Handle user movement within (*list) in the region starting at (row) onscreen with
1977 ** (num) lines, starting at (*ofs) offset from row onscreen.
1978 ** Pass (detail) on to drawing routines.
1980 ** If the user hits a key other than a cursor key, maybe return a code.
1982 ** (*list) points to the device at the top line in the region, (*ofs) is the
1983 ** position of the highlight within the region. All routines below
1984 ** this take only a device and an absolute row : use ofsent() to find the
1985 ** device, and add (*ofs) to (row) to find the absolute row.
1988 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
1999 showparams(ofsent(*ofs,*list)); /* show device parameters */
2000 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2004 c = kgetchar(); /* get a character */
2005 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2007 extended = 0; /* no longer */
2010 case 588: /* syscons' idea of 'up' */
2012 if (*ofs) /* just a move onscreen */
2014 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2015 (*ofs)--; /* move up */
2017 lp = prevent(*list); /* can we go up? */
2020 *list = lp; /* yes, move up list */
2021 drawlist(row,num,detail,*list);
2026 case 596: /* dooby-do */
2027 case 'B': /* down */
2028 lp = ofsent(*ofs,*list); /* get current item */
2030 break; /* nothing more to move to */
2031 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2032 if (*ofs < (num-1)) /* room to move onscreen? */
2036 *list = nextent(*list); /* scroll region down */
2037 drawlist(row,num,detail,*list);
2049 case '[': /* cheat : always preceeds cursor move */
2050 case 'O': /* ANSI application key mode */
2059 return(KEY_EXIT); /* user requests exit */
2063 return(KEY_DO); /* "do" something */
2068 return(KEY_DEL); /* "delete" response */
2072 return(KEY_UNZOOM); /* expand everything */
2076 return(KEY_ZOOM); /* collapse everything */
2079 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2080 return(KEY_TAB); /* "move" response */
2082 case '\014': /* ^L, redraw */
2085 case '?': /* helptext */
2097 ** Do the fullscreen config thang
2102 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2106 initlist(&inactive);
2112 conflicts = findconflict(active); /* find conflicts in the active list only */
2120 case 0: /* active devices */
2121 ret = dolist(1,8,1,&actofs,&alist,
2122 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2126 mode = 1; /* swap lists */
2143 collapselist(active);
2148 dp = ofsent(actofs,alist); /* get current device */
2149 if (dp) /* paranoia... */
2151 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2153 if (dp == alist) /* moving top item on list? */
2157 alist = dp->next; /* point list to non-moving item */
2159 alist = dp->prev; /* end of list, go back instead */
2162 if (!dp->next) /* moving last item on list? */
2165 dp->conflicts = 0; /* no conflicts on the inactive list */
2166 movedev(dp,inactive); /* shift to inactive list */
2167 conflicts = findconflict(active); /* update conflict tags */
2169 redrawactive(); /* redraw */
2174 case KEY_DO: /* edit device parameters */
2175 dp = ofsent(actofs,alist); /* get current device */
2176 if (dp) /* paranoia... */
2178 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2180 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2182 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2184 conflicts = findconflict(active); /* update conflict tags */
2185 }else{ /* DO on comment = zoom */
2186 switch(dp->comment) /* Depends on current state */
2188 case DEV_COMMENT: /* not currently zoomed */
2189 dp->comment = DEV_ZOOMED;
2193 dp->comment = DEV_COMMENT;
2203 case 1: /* inactive devices */
2204 ret = dolist(10,7,0,&inactofs,&ilist,
2205 " [!bEnter!n] Enable device ");
2219 expandlist(inactive);
2226 collapselist(inactive);
2231 dp = ofsent(inactofs,ilist); /* get current device */
2232 if (dp) /* paranoia... */
2234 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2236 if (dp == ilist) /* moving top of list? */
2240 ilist = dp->next; /* point list to non-moving item */
2242 ilist = dp->prev; /* can't go down, go up instead */
2245 if (!dp->next) /* last entry on list? */
2246 inactofs--; /* shift cursor up one */
2249 movedev(dp,active); /* shift to active list */
2250 conflicts = findconflict(active); /* update conflict tags */
2252 alist = dp; /* put at top and current */
2254 while(dp->comment == DEV_DEVICE)
2255 dp = dp->prev; /* forcibly unzoom section */
2256 dp ->comment = DEV_COMMENT;
2257 mode = 0; /* and swap modes to follow it */
2259 }else{ /* DO on comment = zoom */
2260 switch(dp->comment) /* Depends on current state */
2262 case DEV_COMMENT: /* not currently zoomed */
2263 dp->comment = DEV_ZOOMED;
2267 dp->comment = DEV_COMMENT;
2271 redrawactive(); /* redraw */
2276 default: /* nothing else relevant here */
2281 mode = 0; /* shouldn't happen... */
2284 /* handle returns that are the same for both modes */
2291 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2294 case 2: /* cancel */
2298 case 1: /* save and exit */
2300 savelist(inactive,0);
2303 nukelist(active); /* clean up after ourselves */
2313 #endif /* VISUAL_USERCONFIG */
2316 * Copyright (c) 1991 Regents of the University of California.
2317 * All rights reserved.
2318 * Copyright (c) 1994 Jordan K. Hubbard
2319 * All rights reserved.
2320 * Copyright (c) 1994 David Greenman
2321 * All rights reserved.
2323 * Many additional changes by Bruce Evans
2325 * This code is derived from software contributed by the
2326 * University of California Berkeley, Jordan K. Hubbard,
2327 * David Greenman and Bruce Evans.
2329 * Redistribution and use in source and binary forms, with or without
2330 * modification, are permitted provided that the following conditions
2332 * 1. Redistributions of source code must retain the above copyright
2333 * notice, this list of conditions and the following disclaimer.
2334 * 2. Redistributions in binary form must reproduce the above copyright
2335 * notice, this list of conditions and the following disclaimer in the
2336 * documentation and/or other materials provided with the distribution.
2337 * 3. All advertising materials mentioning features or use of this software
2338 * must display the following acknowledgement:
2339 * This product includes software developed by the University of
2340 * California, Berkeley and its contributors.
2341 * 4. Neither the name of the University nor the names of its contributors
2342 * may be used to endorse or promote products derived from this software
2343 * without specific prior written permission.
2345 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2346 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2347 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2348 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2349 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2350 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2351 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2352 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2353 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2354 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2357 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2360 #define PARM_DEVSPEC 0x1
2361 #define PARM_INT 0x2
2362 #define PARM_ADDR 0x3
2363 #define PARM_STRING 0x4
2365 typedef struct _cmdparm {
2368 struct uc_device *dparm;
2377 typedef int (*CmdFunc)(CmdParm *);
2379 typedef struct _cmd {
2387 static void lsscsi(void);
2388 static int list_scsi(CmdParm *);
2391 static int lsdevtab(struct uc_device *);
2392 static struct uc_device *find_device(char *, int);
2393 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2394 static void cngets(char *, int);
2395 static Cmd *parse_cmd(char *);
2396 static int parse_args(const char *, CmdParm *);
2397 static int save_dev(struct uc_device *);
2399 static int list_devices(CmdParm *);
2400 static int set_device_ioaddr(CmdParm *);
2401 static int set_device_irq(CmdParm *);
2402 static int set_device_drq(CmdParm *);
2403 static int set_device_iosize(CmdParm *);
2404 static int set_device_mem(CmdParm *);
2405 static int set_device_flags(CmdParm *);
2406 static int set_device_enable(CmdParm *);
2407 static int set_device_disable(CmdParm *);
2408 static int quitfunc(CmdParm *);
2409 static int helpfunc(CmdParm *);
2410 static int introfunc(CmdParm *);
2413 static int lspnp(void);
2414 static int set_pnp_parms(CmdParm *);
2419 static CmdParm addr_parms[] = {
2420 { PARM_DEVSPEC, {} },
2425 static CmdParm int_parms[] = {
2426 { PARM_DEVSPEC, {} },
2431 static CmdParm dev_parms[] = {
2432 { PARM_DEVSPEC, {} },
2437 static CmdParm string_arg[] = {
2438 { PARM_STRING, {} },
2443 static Cmd CmdList[] = {
2444 { "?", helpfunc, NULL }, /* ? (help) */
2445 { "di", set_device_disable, dev_parms }, /* disable dev */
2446 { "dr", set_device_drq, int_parms }, /* drq dev # */
2447 { "en", set_device_enable, dev_parms }, /* enable dev */
2448 { "ex", quitfunc, NULL }, /* exit (quit) */
2449 { "f", set_device_flags, int_parms }, /* flags dev mask */
2450 { "h", helpfunc, NULL }, /* help */
2451 { "intro", introfunc, NULL }, /* intro screen */
2452 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2453 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2454 { "ir", set_device_irq, int_parms }, /* irq dev # */
2455 { "l", list_devices, NULL }, /* ls, list */
2457 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2459 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2460 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2461 { "q", quitfunc, NULL }, /* quit */
2463 { "s", list_scsi, NULL }, /* scsi */
2465 #ifdef VISUAL_USERCONFIG
2466 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2468 { NULL, NULL, NULL },
2474 static char banner = 1;
2480 init_config_script();
2483 /* Only display signon banner if we are about to go interactive */
2484 if (!has_config_script()) {
2485 if (!(boothowto & RB_CONFIG))
2486 #ifdef INTRO_USERCONFIG
2493 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2494 " Type \"help\" for help"
2495 #ifdef VISUAL_USERCONFIG
2496 " or \"visual\" to go to the visual\n"
2497 " configuration interface (requires MGA/VGA display or\n"
2498 " serial terminal capable of displaying ANSI graphics)"
2504 kprintf("config> ");
2506 if (input[0] == '\0')
2508 cmd = parse_cmd(input);
2510 kprintf("Invalid command or syntax. Type `?' for help.\n");
2513 rval = (*cmd->handler)(cmd->parms);
2522 parse_cmd(char *cmd)
2526 for (cp = CmdList; cp->name; cp++) {
2527 int len = strlen(cp->name);
2529 if (!strncmp(cp->name, cmd, len)) {
2530 while (*cmd && *cmd != ' ' && *cmd != '\t')
2532 if (parse_args(cmd, cp->parms))
2542 parse_args(const char *cmd, CmdParm *parms)
2547 if (*cmd == ' ' || *cmd == '\t') {
2551 if (parms == NULL || parms->type == -1) {
2554 kprintf("Extra arg(s): %s\n", cmd);
2557 if (parms->type == PARM_DEVSPEC) {
2562 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2563 (*cmd >= '0' && *cmd <= '9')))
2564 devname[i++] = *(cmd++);
2566 if (*cmd >= '0' && *cmd <= '9') {
2567 unit = strtoul(cmd, &ptr, 10);
2569 kprintf("Invalid device number\n");
2570 /* XXX should print invalid token here and elsewhere. */
2573 /* XXX else should require end of token. */
2576 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2577 kprintf("No such device: %s%d\n", devname, unit);
2583 if (parms->type == PARM_INT) {
2584 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2586 kprintf("Invalid numeric argument\n");
2593 if (parms->type == PARM_ADDR) {
2594 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2596 kprintf("Invalid address argument\n");
2603 if (parms->type == PARM_STRING) {
2604 parms->parm.u.sparm = cmd;
2612 list_devices(CmdParm *parms)
2615 if (lsdevtab(uc_devtab)) return 0;
2617 if (lspnp()) return 0;
2623 set_device_ioaddr(CmdParm *parms)
2625 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2626 save_dev(parms[0].parm.dparm);
2631 set_device_irq(CmdParm *parms)
2635 irq = parms[1].parm.iparm;
2637 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2640 else if (irq != -1 && irq > 15) {
2641 kprintf("An IRQ > 15 would be invalid.\n");
2644 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2645 save_dev(parms[0].parm.dparm);
2650 set_device_drq(CmdParm *parms)
2655 * The bounds checking is just to ensure that the value can be printed
2656 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2658 drq = parms[1].parm.iparm;
2659 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2660 save_dev(parms[0].parm.dparm);
2665 set_device_iosize(CmdParm *parms)
2667 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2668 save_dev(parms[0].parm.dparm);
2673 set_device_mem(CmdParm *parms)
2675 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2676 save_dev(parms[0].parm.dparm);
2681 set_device_flags(CmdParm *parms)
2683 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2684 save_dev(parms[0].parm.dparm);
2689 set_device_enable(CmdParm *parms)
2691 parms[0].parm.dparm->id_enabled = TRUE;
2692 save_dev(parms[0].parm.dparm);
2697 set_device_disable(CmdParm *parms)
2699 parms[0].parm.dparm->id_enabled = FALSE;
2700 save_dev(parms[0].parm.dparm);
2707 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2713 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2716 * Output the pnp_ldn_overrides[] table.
2718 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2719 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2720 if(error) return(error);
2725 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2726 0, 0, sysctl_machdep_uc_pnplist, "A",
2727 "List of PnP overrides changed in UserConfig");
2730 * this function sets the kernel table to override bios PnP
2734 set_pnp_parms(CmdParm *parms)
2736 u_long idx, val, ldn, csn;
2739 const char *p = parms[0].parm.u.sparm;
2742 csn=strtoul(p,&q, 0);
2743 ldn=strtoul(q,&q, 0);
2744 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2745 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2746 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2749 for (i=0; i < MAX_PNP_LDN; i++) {
2750 if (pnp_ldn_overrides[i].csn == csn &&
2751 pnp_ldn_overrides[i].ldn == ldn)
2754 if (i==MAX_PNP_LDN) {
2755 for (i=0; i < MAX_PNP_LDN; i++) {
2756 if (pnp_ldn_overrides[i].csn <1 ||
2757 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2761 if (i==MAX_PNP_LDN) {
2762 kprintf("sorry, no PnP entries available, try delete one\n");
2765 d = pnp_ldn_overrides[i] ;
2771 if (!strncmp(p,"irq",3)) {
2772 idx=strtoul(p+3,&q, 0);
2773 val=strtoul(q,&q, 0);
2774 if (idx >=0 && idx < 2) d.irq[idx] = val;
2775 } else if (!strncmp(p,"flags",5)) {
2776 idx=strtoul(p+5,&q, 0);
2778 } else if (!strncmp(p,"drq",3)) {
2779 idx=strtoul(p+3,&q, 0);
2780 val=strtoul(q,&q, 0);
2781 if (idx >=0 && idx < 2) d.drq[idx] = val;
2782 } else if (!strncmp(p,"port",4)) {
2783 idx=strtoul(p+4,&q, 0);
2784 val=strtoul(q,&q, 0);
2785 if (idx >=0 && idx < 8) d.port[idx] = val;
2786 } else if (!strncmp(p,"mem",3)) {
2787 idx=strtoul(p+3,&q, 0);
2788 val=strtoul(q,&q, 0);
2789 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2790 } else if (!strncmp(p,"bios",4)) {
2793 } else if (!strncmp(p,"os",2)) {
2796 } else if (!strncmp(p,"disable",7)) {
2799 } else if (!strncmp(p,"enable",6)) {
2802 } else if (!strncmp(p,"delete",6)) {
2803 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2804 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2807 kprintf("unknown command <%s>\n", p);
2810 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2812 pnp_ldn_overrides[i] = d ;
2818 quitfunc(CmdParm *parms)
2821 * If kernel config supplied, and we are parsing it, and -c also supplied,
2822 * ignore a quit command, This provides a safety mechanism to allow
2823 * recovery from a damaged/buggy kernel config.
2825 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2831 helpfunc(CmdParm *parms)
2834 "Command\t\t\tDescription\n"
2835 "-------\t\t\t-----------\n"
2836 "ls\t\t\tList currently configured devices\n"
2837 "port <devname> <addr>\tSet device port (i/o address)\n"
2838 "irq <devname> <number>\tSet device irq\n"
2839 "drq <devname> <number>\tSet device drq\n"
2840 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2841 "iosize <devname> <size>\tSet device memory size\n"
2842 "flags <devname> <mask>\tSet device flags\n"
2843 "enable <devname>\tEnable device\n"
2844 "disable <devname>\tDisable device (will not be probed)\n");
2847 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2848 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2849 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2850 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2851 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2852 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2855 "quit\t\t\tExit this configuration utility\n"
2856 "reset\t\t\tReset CPU\n");
2857 #ifdef VISUAL_USERCONFIG
2858 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2861 "help\t\t\tThis message\n\n"
2862 "Commands may be abbreviated to a unique prefix\n");
2866 #if defined (VISUAL_USERCONFIG)
2868 center(int y, char *str)
2870 putxy((80 - strlen(str)) / 2, y, str);
2875 introfunc(CmdParm *parms)
2877 #if defined (VISUAL_USERCONFIG)
2878 int curr_item, first_time, extended = 0;
2879 static char *choices[] = {
2880 " Skip kernel configuration and continue with installation ",
2881 " Start kernel configuration in full-screen visual mode ",
2882 " Start kernel configuration in CLI mode ",
2886 center(2, "!bKernel Configuration Menu!n");
2895 for (i = 0; i < 3; i++) {
2899 strcat(tmp, choices[i]);
2902 putxy(10, 5 + i, tmp);
2906 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2907 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2908 putxy(2, 12, "match your hardware configuration.");
2909 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2910 putxy(2, 15, "(press Down-Arrow then ENTER).");
2911 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2912 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2913 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2914 putxy(2, 21, "then simply press ENTER or Q now.");
2918 move(0, 0); /* move the cursor out of the way */
2921 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2922 extended = 0; /* no longer */
2931 case 'B': /* down */
2943 case '[': /* cheat : always preceeds cursor move */
2944 case 'O': /* ANSI application key mode */
2955 return 1; /* user requests exit */
2957 case '1': /* select an item */
2981 case 'D': /* down */
2994 else if (curr_item == 1)
2995 return visuserconfig();
2997 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
2998 /* enable quitfunc */
2999 userconfig_boot_parsing=0;
3001 boothowto |= RB_CONFIG; /* force -c */
3008 #else /* !VISUAL_USERCONFIG */
3010 #endif /* VISUAL_USERCONFIG */
3017 struct pnp_cinfo *c;
3021 for (i=0; i< MAX_PNP_LDN; i++) {
3022 c = &pnp_ldn_overrides[i];
3023 if (c->csn >0 && c->csn != 255) {
3025 static char pfmt[] =
3026 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3027 static char mfmt[] =
3028 "mem 0x%x 0x%x 0x%x 0x%x";
3031 if (!userconfig_boot_parsing) {
3033 if (kgetchar() == 'q') {
3041 if (lineno == 0 || first)
3042 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3044 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3046 c->override ? "OS ":"BIOS",
3047 c->enable ? "Y":"N",
3048 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3050 kprintf("flags 0x%08lx ",c->flags);
3051 for (pmax = 7; pmax >=0 ; pmax--)
3052 if (c->port[pmax]!=0) break;
3053 for (mmax = 3; mmax >=0 ; mmax--)
3054 if (c->mem[mmax].base!=0) break;
3057 buf[10 + 5*pmax]='\0';
3059 c->port[0], c->port[1], c->port[2], c->port[3],
3060 c->port[4], c->port[5], c->port[6], c->port[7]);
3064 buf[8 + 5*mmax]='\0';
3066 c->mem[0].base, c->mem[1].base,
3067 c->mem[2].base, c->mem[3].base);
3077 lsdevtab(struct uc_device *dt)
3079 for (; dt->id_id != 0; dt++) {
3084 if (!userconfig_boot_parsing) {
3085 if (kgetchar() == 'q') {
3095 "Device port irq drq iomem iosize unit flags enab\n"
3099 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3100 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3101 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3102 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3103 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3104 dt->id_enabled ? "Yes" : "No");
3114 int count = resource_count();
3120 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3123 for (i = 0; i < count; i++) {
3124 name = resource_query_name(i);
3125 unit = resource_query_unit(i);
3127 continue; /* skip wildcards */
3128 uc_devtab[dt].id_id = id++;
3129 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3131 resource_int_value(name, unit, "irq", &val);
3132 uc_devtab[dt].id_irq = (1 << val);
3133 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3134 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3135 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3136 uc_devtab[dt].id_unit = unit;
3137 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3139 resource_int_value(name, unit, "disabled", &val);
3140 uc_devtab[dt].id_enabled = !val;
3141 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3142 strcpy(uc_devtab[dt].id_name, name);
3151 int count = resource_count();
3153 for (i = 0; i < count; i++)
3154 if (uc_devtab[i].id_name)
3155 kfree(uc_devtab[i].id_name, M_DEVL);
3156 kfree(uc_devtab, M_DEVL);
3159 static struct uc_device *
3160 find_device(char *devname, int unit)
3162 struct uc_device *ret;
3164 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3169 static struct uc_device *
3170 search_devtable(struct uc_device *dt, char *devname, int unit)
3172 for (; dt->id_id != 0; dt++)
3173 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3179 cngets(char *input, int maxin)
3185 /* Treat ^H or ^? as backspace */
3186 if ((c == '\010' || c == '\177')) {
3188 kprintf("\010 \010");
3189 *--input = '\0', --nchars;
3193 /* Treat ^U or ^X as kill line */
3194 else if ((c == '\025' || c == '\030')) {
3196 kprintf("\010 \010");
3197 *--input = '\0', --nchars;
3202 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3206 *input++ = (u_char)c;
3212 /* scsi: Support for displaying configured SCSI devices.
3213 * There is no way to edit them, and this is inconsistent
3214 * with the ISA method. This is here as a basis for further work.
3217 type_text(char *name) /* XXX: This is bogus */
3219 if (strcmp(name, "sd") == 0)
3222 if (strcmp(name, "st") == 0)
3228 id_put(char *desc, int id)
3230 if (id != SCCONF_UNSPEC)
3233 kprintf("%s", desc);
3235 if (id == SCCONF_ANY)
3247 kprintf("scsi: (can't be edited):\n");
3249 for (i = 0; scsi_cinit[i].driver; i++)
3251 id_put("controller scbus", scsi_cinit[i].scbus);
3253 if (scsi_cinit[i].unit != -1)
3256 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3262 for (i = 0; scsi_dinit[i].name; i++)
3264 kprintf("%s ", type_text(scsi_dinit[i].name));
3266 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3267 id_put(" at scbus", scsi_dinit[i].cunit);
3268 id_put(" target ", scsi_dinit[i].target);
3269 id_put(" lun ", scsi_dinit[i].lun);
3271 if (scsi_dinit[i].flags)
3272 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3279 list_scsi(CmdParm *parms)
3288 save_resource(struct uc_device *idev)
3293 name = idev->id_name;
3294 unit = idev->id_unit;
3295 resource_set_int(name, unit, "port", idev->id_iobase);
3296 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3297 resource_set_int(name, unit, "drq", idev->id_drq);
3298 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3299 resource_set_int(name, unit, "msize", idev->id_msize);
3300 resource_set_int(name, unit, "flags", idev->id_flags);
3301 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3305 save_dev(struct uc_device *idev)
3307 struct uc_device *id_p,*id_pn;
3308 char *name = idev->id_name;
3310 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3311 if (id_p->id_id == idev->id_id) {
3312 id_pn = id_p->id_next;
3314 kfree(id_p->id_name, M_DEVL);
3315 bcopy(idev,id_p,sizeof(struct uc_device));
3316 save_resource(idev);
3317 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3318 strcpy(id_p->id_name, name);
3319 id_p->id_next = id_pn;
3323 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3324 bcopy(idev,id_pn,sizeof(struct uc_device));
3325 save_resource(idev);
3326 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3327 strcpy(id_pn->id_name, name);
3328 id_pn->id_next = uc_devlist;