3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
5 ** This code contains a module marked :
7 * Copyright (c) 1991 Regents of the University of California.
9 * Copyright (c) 1994 Jordan K. Hubbard
10 * All rights reserved.
11 * Copyright (c) 1994 David Greenman
12 * All rights reserved.
14 * Many additional changes by Bruce Evans
16 * This code is derived from software contributed by the
17 * University of California Berkeley, Jordan K. Hubbard,
18 * David Greenman and Bruce Evans.
20 ** As such, it contains code subject to the above copyrights.
21 ** The module and its copyright can be found below.
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
26 ** 1. Redistributions of source code must retain the above copyright
27 ** notice, this list of conditions and the following disclaimer as
28 ** the first lines of this file unmodified.
29 ** 2. Redistributions in binary form must reproduce the above copyright
30 ** notice, this list of conditions and the following disclaimer in the
31 ** documentation and/or other materials provided with the distribution.
32 ** 3. All advertising materials mentioning features or use of this software
33 ** must display the following acknowledgment:
34 ** This product includes software developed by Michael Smith.
35 ** 4. The name of the author may not be used to endorse or promote products
36 ** derived from this software without specific prior written permission.
38 ** THIS SOFTWARE IS PROVIDED BY MICHAEL SMITH ``AS IS'' AND ANY EXPRESS OR
39 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 ** IN NO EVENT SHALL MICHAEL SMITH BE LIABLE FOR ANY DIRECT, INDIRECT,
42 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
55 ** Kernel boot-time configuration manipulation tool for FreeBSD.
57 ** Two modes of operation are supported : the default is the line-editor mode,
58 ** the command "visual" invokes the fullscreen mode.
60 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
61 ** fullscreen mode requires syscons or a minimal-ansi serial console.
65 ** USERCONFIG, visual mode.
69 ** Look for "EDIT THIS LIST" to add to the list of known devices
72 ** There are a number of assumptions made in this code.
74 ** - That the console supports a minimal set of ANSI escape sequences
75 ** (See the screen manipulation section for a summary)
76 ** and has at least 24 rows.
77 ** - That values less than or equal to zero for any of the device
78 ** parameters indicate that the driver does not use the parameter.
79 ** - That flags are _always_ editable.
81 ** Devices marked as disabled are imported as such.
83 ** For this tool to be useful, the list of devices below _MUST_ be updated
84 ** when a new driver is brought into the kernel. It is not possible to
85 ** extract this information from the drivers in the kernel.
89 ** - Display _what_ a device conflicts with.
90 ** - Implement page up/down (as what?)
91 ** - Wizard mode (no restrictions)
92 ** - Find out how to put syscons back into low-intensity mode so that the
93 ** !b escape is useful on the console. (It seems to be that it actually
94 ** gets low/high intensity backwards. That looks OK.)
96 ** - Only display headings with devices under them. (difficult)
99 #include "opt_userconfig.h"
101 #include <sys/param.h>
102 #include <sys/systm.h>
103 #include <sys/kernel.h>
104 #include <sys/malloc.h>
105 #include <sys/reboot.h>
106 #include <sys/linker.h>
107 #include <sys/sysctl.h>
109 #include <sys/cons.h>
111 #include <machine/md_var.h>
112 #include <machine/limits.h>
114 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
120 #include <machine_base/isa/pnp.h>
123 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
125 #include <machine/uc_device.h>
126 static struct uc_device *uc_devlist; /* list read by kget to extract changes */
127 static struct uc_device *uc_devtab; /* fake uc_device table */
129 static int userconfig_boot_parsing; /* set if we are reading from the boot instructions */
131 static void load_devtab(void);
132 static void free_devtab(void);
133 static void save_resource(struct uc_device *);
136 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
138 struct uc_device *id;
146 error+=sizeof(struct uc_device)+8;
149 return(SYSCTL_OUT(req,0,error));
151 /* Output the data. The buffer is filled with consecutive
152 * struct uc_device and char buf[8], containing the name
153 * (not guaranteed to end with '\0').
157 error=sysctl_handle_opaque(oidp,id,
158 sizeof(struct uc_device),req);
159 if(error) return(error);
160 strncpy(name,id->id_name,8);
161 error=sysctl_handle_opaque(oidp,name,
163 if(error) return(error);
170 SYSCTL_PROC( _machdep, OID_AUTO, uc_devlist, CTLFLAG_RD,
171 0, 0, sysctl_machdep_uc_devlist, "A",
172 "List of ISA devices changed in UserConfig");
175 ** Obtain command input.
177 ** Initially, input is read from a possibly-loaded script.
178 ** At the end of the script, or if no script is supplied,
179 ** behaviour is determined by the RB_CONFIG (-c) flag. If
180 ** the flag is set, user input is read from the console; if
181 ** unset, the 'quit' command is invoked and userconfig
184 ** Note that quit commands encountered in the script will be
185 ** ignored if the RB_CONFIG flag is supplied.
187 static const char *config_script;
188 static int config_script_size; /* use of int for -ve magic value */
190 #define has_config_script() (config_script_size > 0)
193 init_config_script(void)
195 caddr_t autoentry, autoattr;
197 /* Look for loaded userconfig script */
198 autoentry = preload_search_by_type("userconfig_script");
199 if (autoentry != NULL) {
200 /* We have one, get size and data */
201 config_script_size = 0;
202 if ((autoattr = preload_search_info(autoentry, MODINFO_SIZE)) != NULL)
203 config_script_size = (size_t)*(u_int32_t *)autoattr;
204 config_script = NULL;
205 if ((autoattr = preload_search_info(autoentry, MODINFO_ADDR)) != NULL)
206 config_script = *(const char **)autoattr;
208 if ((config_script_size == 0) || (config_script == NULL)) {
209 config_script_size = 0;
210 config_script = NULL;
213 return has_config_script();
220 #ifdef INTRO_USERCONFIG
221 static int intro = 0;
224 if (has_config_script())
226 /* Consume character from loaded userconfig script, display */
227 userconfig_boot_parsing = 1;
230 config_script_size--;
234 #ifdef INTRO_USERCONFIG
235 if (userconfig_boot_parsing) {
236 if (!(boothowto & RB_CONFIG)) {
237 /* userconfig_script, !RB_CONFIG -> quit */
240 config_script = "uit\n";
241 config_script_size = strlen(config_script);
242 /* userconfig_script will be 1 on the next pass */
245 /* userconfig_script, RB_CONFIG -> cngetc() */
248 if (!(boothowto & RB_CONFIG)) {
249 /* no userconfig_script, !RB_CONFIG -> show intro */
253 config_script = "ntro\n";
254 config_script_size = strlen(config_script);
255 /* userconfig_script will be 1 on the next pass */
258 /* no userconfig_script, RB_CONFIG -> cngetc() */
261 #else /* !INTRO_USERCONFIG */
262 /* assert(boothowto & RB_CONFIG) */
263 #endif /* INTRO_USERCONFIG */
264 userconfig_boot_parsing = 0;
273 #define TRUE (!FALSE)
276 #ifdef VISUAL_USERCONFIG
280 char dev[16]; /* device basename */
281 char name[60]; /* long name */
282 int attrib; /* things to do with the device */
283 int class; /* device classification */
286 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
287 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
288 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
289 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
290 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
291 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
292 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
293 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
294 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
296 #define CLS_STORAGE 1 /* storage devices */
297 #define CLS_NETWORK 2 /* network interfaces */
298 #define CLS_COMMS 3 /* serial, parallel ports */
299 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
300 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
301 #define CLS_MISC 255 /* none of the above */
310 static DEVCLASS_INFO devclass_names[] = {
311 { "Storage : ", CLS_STORAGE},
312 { "Network : ", CLS_NETWORK},
313 { "Communications : ", CLS_COMMS},
314 { "Input : ", CLS_INPUT},
315 { "Miscellaneous : ", CLS_MISC},
319 /********************* EDIT THIS LIST **********************/
323 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
324 ** - XXX The list below should be reviewed by the driver authors to verify
325 ** that the correct flags have been set for each driver, and that the
326 ** descriptions are accurate.
329 static DEV_INFO device_info[] = {
330 /*---Name----- ---Description---------------------------------------------- */
331 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE},
332 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE},
333 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE},
334 {"fdc", "Floppy disk controller", FLG_FIXED, CLS_STORAGE},
335 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE, CLS_STORAGE},
336 {"fd", "Floppy disk device", FLG_INVISIBLE, CLS_STORAGE},
338 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK},
339 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK},
340 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK},
341 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK},
342 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK},
343 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK},
344 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK},
345 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
346 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK},
348 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS},
349 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS},
350 {"ppc", "Parallel Port chipset", 0, CLS_COMMS},
352 {"atkbdc", "Keyboard controller", FLG_INVISIBLE, CLS_INPUT},
353 {"atkbd", "Keyboard", FLG_FIXED, CLS_INPUT},
354 {"psm", "PS/2 Mouse", FLG_FIXED, CLS_INPUT},
355 {"joy", "Joystick", FLG_FIXED, CLS_INPUT},
356 {"sc", "Syscons console driver", FLG_IMMUTABLE, CLS_INPUT},
358 {"apm", "Advanced Power Management", FLG_FIXED, CLS_MISC},
359 {"pcic", "PC-card controller", 0, CLS_MISC},
360 {"npx", "Math coprocessor", FLG_IMMUTABLE, CLS_MISC},
361 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC},
365 typedef struct _devlist_struct
368 int attrib; /* flag values as per the FLG_* defines above */
369 int class; /* disk, etc as per the CLS_* defines above */
371 int iobase,irq,drq,maddr,msize,unit,flags,id;
372 int comment; /* 0 = device, 1 = comment, 2 = collapsed comment */
373 int conflicts; /* set/reset by findconflict, count of conflicts */
374 int changed; /* nonzero if the device has been edited */
375 struct uc_device *device;
376 struct _devlist_struct *prev,*next;
381 #define DEV_COMMENT 1
384 #define LIST_CURRENT (1<<0)
385 #define LIST_SELECTED (1<<1)
387 #define KEY_EXIT 0 /* return codes from dolist() and friends */
393 #define KEY_UP 5 /* these only returned from editval() */
397 #define KEY_NULL 9 /* this allows us to spin & redraw */
399 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
400 #define KEY_UNZOOM 11
402 #define KEY_HELP 12 /* duh? */
404 static void redraw(void);
405 static void insdev(DEV_LIST *dev, DEV_LIST *list);
406 static int devinfo(DEV_LIST *dev);
407 static int visuserconfig(void);
409 static DEV_LIST *active = NULL,*inactive = NULL; /* driver lists */
410 static DEV_LIST *alist,*ilist; /* visible heads of the driver lists */
411 static DEV_LIST scratch; /* scratch record */
412 static int conflicts; /* total conflict count */
415 static char lines[] = "--------------------------------------------------------------------------------";
416 static char spaces[] = " ";
420 ** Device manipulation stuff : find, describe, configure.
426 ** Sets the device referenced by (*dev) to the parameters in the struct,
427 ** and the enable flag according to (enabled)
430 setdev(DEV_LIST *dev, int enabled)
432 dev->device->id_iobase = dev->iobase; /* copy happy */
433 dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0); /* IRQ is bitfield */
434 dev->device->id_drq = (short)dev->drq;
435 dev->device->id_maddr = (caddr_t)dev->maddr;
436 dev->device->id_msize = dev->msize;
437 dev->device->id_flags = dev->flags;
438 dev->device->id_enabled = enabled;
445 ** Walk the kernel device tables and build the active and inactive lists
451 struct uc_device *ap;
453 ap = uc_devtab; /* pointer to array of devices */
454 for (i = 0; ap[i].id_id; i++) /* for each device in this table */
456 scratch.unit = ap[i].id_unit; /* device parameters */
457 strcpy(scratch.dev,ap[i].id_name);
458 scratch.iobase = ap[i].id_iobase;
459 scratch.irq = ffs(ap[i].id_irq)-1;
460 scratch.drq = ap[i].id_drq;
461 scratch.maddr = (int)ap[i].id_maddr;
462 scratch.msize = ap[i].id_msize;
463 scratch.flags = ap[i].id_flags;
465 scratch.comment = DEV_DEVICE; /* admin stuff */
466 scratch.conflicts = 0;
467 scratch.device = &ap[i]; /* save pointer for later reference */
469 if (!devinfo(&scratch)) /* get more info on the device */
470 insdev(&scratch,ap[i].id_enabled?active:inactive);
478 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
479 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
481 ** If the device is marked "invisible", return nonzero; the caller should
482 ** not insert any such device into either list.
486 devinfo(DEV_LIST *dev)
490 for (i = 0; device_info[i].class; i++)
492 if (!strcmp(dev->dev,device_info[i].dev))
494 if (device_info[i].attrib & FLG_INVISIBLE) /* forget we ever saw this one */
496 strcpy(dev->name,device_info[i].name); /* get the name */
497 dev->attrib = device_info[i].attrib;
498 dev->class = device_info[i].class;
502 strcpy(dev->name,"Unknown device");
504 dev->class = CLS_MISC;
510 ** List manipulation stuff : add, move, initialise, free, traverse
512 ** Note that there are assumptions throughout this code that
513 ** the first entry in a list will never move. (assumed to be
521 ** appends a copy of (dev) to the end of (*list)
524 addev(DEV_LIST *dev, DEV_LIST **list)
529 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
530 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
532 if (*list) /* list exists */
536 ap = ap->next; /* scoot to end of list */
540 }else{ /* list does not yet exist */
542 lp->prev = lp->next = NULL; /* list now exists */
550 ** Finds the 'appropriate' place for (dev) in (list)
552 ** 'Appropriate' means in numeric order with other devices of the same type,
553 ** or in alphabetic order following a comment of the appropriate type.
554 ** or at the end of the list if an appropriate comment is not found. (this should
556 ** (Note that the appropriate point is never the top, but may be the bottom)
559 findspot(DEV_LIST *dev, DEV_LIST *list)
563 /* search for a previous instance of the same device */
564 for (ap = list; ap; ap = ap->next)
566 if (ap->comment != DEV_DEVICE) /* ignore comments */
568 if (!strcmp(dev->dev,ap->dev)) /* same base device */
570 if ((dev->unit <= ap->unit) /* belongs before (equal is bad) */
571 || !ap->next) /* or end of list */
573 ap = ap->prev; /* back up one */
574 break; /* done here */
576 if (ap->next) /* if the next item exists */
578 if (ap->next->comment != DEV_DEVICE) /* next is a comment */
580 if (strcmp(dev->dev,ap->next->dev)) /* next is a different device */
586 if (!ap) /* not sure yet */
588 /* search for a class that the device might belong to */
589 for (ap = list; ap; ap = ap->next)
591 if (ap->comment != DEV_DEVICE) /* look for simlar devices */
593 if (dev->class != ap->class) /* of same class too 8) */
595 if (strcmp(dev->dev,ap->dev) < 0) /* belongs before the current entry */
597 ap = ap->prev; /* back up one */
598 break; /* done here */
600 if (ap->next) /* if the next item exists */
601 if (ap->next->comment != DEV_DEVICE) /* next is a comment, go here */
606 if (!ap) /* didn't find a match */
608 for (ap = list; ap->next; ap = ap->next) /* try for a matching comment */
609 if ((ap->comment != DEV_DEVICE)
610 && (ap->class == dev->class)) /* appropriate place? */
612 } /* or just put up with last */
621 ** Inserts a copy of (dev) at the appropriate point in (list)
624 insdev(DEV_LIST *dev, DEV_LIST *list)
628 lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
629 bcopy(dev,lp,sizeof(DEV_LIST)); /* create copied record */
631 ap = findspot(lp,list); /* find appropriate spot */
632 lp->next = ap->next; /* point to next */
634 ap->next->prev = lp; /* point next to new */
635 lp->prev = ap; /* point new to current */
636 ap->next = lp; /* and current to new */
643 ** Moves (dev) from its current list to an appropriate place in (list)
644 ** (dev) may not come from the top of a list, but it may from the bottom.
647 movedev(DEV_LIST *dev, DEV_LIST *list)
651 ap = findspot(dev,list);
652 dev->prev->next = dev->next; /* remove from old list */
654 dev->next->prev = dev->prev;
656 dev->next = ap->next; /* insert in new list */
658 ap->next->prev = dev; /* point next to new */
659 dev->prev = ap; /* point new to current */
660 ap->next = dev; /* and current to new */
667 ** Initialises (*list) with the basic headings
670 initlist(DEV_LIST **list)
674 for(i = 0; devclass_names[i].name[0]; i++) /* for each devtype name */
676 strcpy(scratch.name,devclass_names[i].name);
677 scratch.comment = DEV_ZOOMED;
678 scratch.class = devclass_names[i].number;
679 scratch.attrib = FLG_MANDATORY; /* can't be moved */
680 addev(&scratch,list); /* add to the list */
688 ** Walks (list) and saves the settings of any entry marked as changed.
690 ** The device's active field is set according to (active).
692 ** Builds the uc_devlist used by kget to extract the changed device information.
693 ** The code for this was taken almost verbatim from the original module.
696 savelist(DEV_LIST *list, int active)
698 struct uc_device *id_p,*id_pn;
703 if ((list->comment == DEV_DEVICE) && /* is a device */
704 (list->changed) && /* has been changed */
705 (list->device != NULL)) { /* has an uc_device structure */
707 setdev(list,active); /* set the device itself */
710 for (id_p=uc_devlist; id_p; id_p=id_p->id_next)
711 { /* look on the list for it */
712 if (id_p->id_id == list->device->id_id)
714 name = list->device->id_name;
715 id_pn = id_p->id_next;
717 kfree(id_p->id_name, M_DEVL);
718 bcopy(list->device,id_p,sizeof(struct uc_device));
719 save_resource(list->device);
720 id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
721 strcpy(id_p->id_name, name);
722 id_pn->id_next = uc_devlist;
723 id_p->id_next = id_pn;
727 if (!id_pn) /* not already on the list */
729 name = list->device->id_name;
730 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
731 bcopy(list->device,id_pn,sizeof(struct uc_device));
732 save_resource(list->device);
733 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
734 strcpy(id_pn->id_name, name);
735 id_pn->id_next = uc_devlist;
736 uc_devlist = id_pn; /* park at top of list */
747 ** Frees all storage in use by a (list).
750 nukelist(DEV_LIST *list)
756 while(list->prev) /* walk to head of list */
771 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
772 ** if there is no previous entry. (Only possible if list->prev == NULL given the
773 ** premise that there is always a comment at the head of the list)
776 prevent(DEV_LIST *list)
782 dp = list->prev; /* start back one */
785 if (dp->comment == DEV_ZOOMED) /* previous section is zoomed */
786 return(dp); /* so skip to comment */
787 if (dp->comment == DEV_COMMENT) /* not zoomed */
788 return(list->prev); /* one back as normal */
789 dp = dp->prev; /* backpedal */
791 return(dp); /* NULL, we can assume */
798 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
799 ** if there is no next entry. (Possible if the current entry is last, or
800 ** if the current entry is the last heading and it's collapsed)
803 nextent(DEV_LIST *list)
809 if (list->comment != DEV_ZOOMED) /* no reason to skip */
814 if (dp->comment != DEV_DEVICE) /* found another heading */
818 return(dp); /* back we go */
825 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
828 ofsent(int ofs, DEV_LIST *list)
830 while (ofs-- && list)
831 list = nextent(list);
839 ** Scans every element of (list) and sets the conflict tags appropriately
840 ** Returns the number of conflicts found.
843 findconflict(DEV_LIST *list)
845 int count = 0; /* number of conflicts found */
848 for (dp = list; dp; dp = dp->next) /* over the whole list */
850 if (dp->comment != DEV_DEVICE) /* comments don't usually conflict */
853 dp->conflicts = 0; /* assume the best */
854 for (sp = list; sp; sp = sp->next) /* scan the entire list for conflicts */
856 if (sp->comment != DEV_DEVICE) /* likewise */
859 if (sp == dp) /* always conflict with itself */
862 if ((dp->iobase > 0) && /* iobase conflict? */
863 (dp->iobase == sp->iobase))
865 if ((dp->irq > 0) && /* irq conflict? */
866 (dp->irq == sp->irq))
868 if ((dp->drq > 0) && /* drq conflict? */
869 (dp->drq == sp->drq))
871 if ((sp->maddr > 0) && /* maddr/msize conflict? */
873 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
874 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
877 count += dp->conflicts; /* count conflicts */
886 ** Unzooms all headings in (list)
889 expandlist(DEV_LIST *list)
893 if (list->comment == DEV_COMMENT)
894 list->comment = DEV_ZOOMED;
903 ** Zooms all headings in (list)
906 collapselist(DEV_LIST *list)
910 if (list->comment == DEV_ZOOMED)
911 list->comment = DEV_COMMENT;
918 ** Screen-manipulation stuff
920 ** This is the basic screen layout :
922 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
923 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
924 ** +--------------------------------------------------------------------------------+
925 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
926 ** 1 -| ........................ ....... .. 0x....|
927 ** 2 -| ........................ ....... .. 0x....|
928 ** 3 -| ........................ ....... .. 0x....|
929 ** 4 -| ........................ ....... .. 0x....|
930 ** 5 -| ........................ ....... .. 0x....|
931 ** 6 -| ........................ ....... .. 0x....|
932 ** 7 -| ........................ ....... .. 0x....|
933 ** 8 -| ........................ ....... .. 0x....|
934 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
935 ** 10-| ........................ ....... |
936 ** 11-| ........................ ....... |
937 ** 12-| ........................ ....... |
938 ** 13-| ........................ ....... |
939 ** 14-| ........................ ....... |
940 ** 15-| ........................ ....... |
941 ** 16-| ........................ ....... |
942 ** 17-|------------------------------------------------------UP-DOWN-------------------|
943 ** 18-| Relevant parameters for the current device |
946 ** 21-|--------------------------------------------------------------------------------|
947 ** 22-| Help texts go here |
949 ** +--------------------------------------------------------------------------------+
953 ** On a collapsed comment :
955 ** [Enter] Expand device list [z] Expand all lists
956 ** [TAB] Change fields [Q] Save and Exit
958 ** On an expanded comment :
960 ** [Enter] Collapse device list [Z] Collapse all lists
961 ** [TAB] Change fields [Q] Save and Exit
963 ** On a comment with no followers
966 ** [TAB] Change fields [Q] Save and Exit
968 ** On a device in the active list
970 ** [Enter] Edit device parameters [DEL] Disable device
971 ** [TAB] Change fields [Q] Save and Exit [?] Help
973 ** On a device in the inactive list
975 ** [Enter] Enable device
976 ** [TAB] Change fields [Q] Save and Exit [?] Help
978 ** While editing parameters
980 ** <parameter-specific help here>
981 ** [TAB] Change fields [Q] Save device parameters
988 ** The base-level screen primitives :
990 ** bold() - enter bold mode \E[1m (md)
991 ** inverse() - enter inverse mode \E[7m (so)
992 ** normal() - clear bold/inverse mode \E[m (se)
993 ** clear() - clear the screen \E[H\E[J (ce)
994 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1019 kprintf("\033[H\033[J");
1025 kprintf("\033[%d;%dH",y+1,x+1);
1031 ** High-level screen primitives :
1033 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1034 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1035 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1036 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1037 ** putmsg(str) - put (str) in the message area
1038 ** puthelp(str) - put (str) in the upper helpline
1039 ** pad(str,len) - pad (str) to (len) with spaces
1040 ** drawline(row,detail,list,inverse,*dhelp)
1041 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1042 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1043 ** draw the line in inverse video, and display (*dhelp) on the
1045 ** drawlist(row,num,detail,list)
1046 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1047 ** through to drawline().
1048 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1049 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1050 ** redraw(); - Redraws the entire screen layout, including the
1051 ** - two list panels.
1056 ** writes (str) at x,y onscreen
1058 ** writes up to (len) of (str) at x,y onscreen.
1060 ** Supports embedded formatting :
1061 ** !i - inverse mode.
1063 ** !n - normal mode.
1066 putxyl(int x, int y, char *str, int len)
1071 while((*str) && (len--))
1073 if (*str == '!') /* format escape? */
1075 switch(*(str+1)) /* depending on the next character */
1079 str +=2; /* skip formatting */
1080 len++; /* doesn't count for length */
1085 str +=2; /* skip formatting */
1086 len++; /* doesn't count for length */
1091 str +=2; /* skip formatting */
1092 len++; /* doesn't count for length */
1096 kprintf("%c", *str++); /* not an escape */
1099 kprintf("%c", *str++); /* emit the character */
1104 #define putxy(x,y,str) putxyl(x,y,str,-1)
1110 ** Erases the region (x,y,w,h)
1113 erase(int x, int y, int w, int h)
1118 for (i = 0; i < h; i++)
1119 putxyl(x,y++,spaces,w);
1126 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1127 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1130 txtbox(int x, int y, int w, int h, char *str)
1135 while((str[i]) && h)
1137 if (str[i] == '\n') /* newline */
1139 putxyl(x,y,str,(i<w)?i:w); /* write lesser of i or w */
1140 y++; /* move down */
1141 h--; /* room for one less */
1142 str += (i+1); /* skip first newline */
1143 i = 0; /* zero offset */
1145 i++; /* next character */
1148 if (h) /* end of string, not region */
1156 ** writes (msg) in the helptext area
1161 erase(0,18,80,3); /* clear area */
1162 txtbox(0,18,80,3,msg);
1169 ** Writes (msg) in the helpline area
1182 ** Draws the help message at the bottom of the screen
1185 masterhelp(char *msg)
1195 ** space-pads a (str) to (len) characters
1198 pad(char *str, int len)
1202 for (i = 0; str[i]; i++) /* find the end of the string */
1204 if (i >= len) /* no padding needed */
1206 while(i < len) /* pad */
1215 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1216 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1218 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1219 ** help is shown for normal or zoomed comments
1222 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1224 char lbuf[90],nb[70],db[20],ib[16],pb[16];
1226 if (list->comment == DEV_DEVICE)
1229 strncpy(nb+1,list->name,57);
1231 strncpy(nb,list->name,58);
1232 if ((list->comment == DEV_ZOOMED) && (list->next))
1233 if (list->next->comment == DEV_DEVICE) /* only mention if there's something hidden */
1234 strcat(nb," (Collapsed)");
1238 if (list->conflicts) /* device in conflict? */
1242 strcpy(nb+54," !nCONF!i "); /* tag conflict, careful of length */
1244 strcpy(nb+54," !iCONF!n "); /* tag conflict, careful of length */
1247 if (list->comment == DEV_DEVICE)
1249 ksprintf(db,"%s%d",list->dev,list->unit);
1254 if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1256 ksprintf(ib," %d",list->irq);
1261 if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1263 ksprintf(pb,"0x%x",list->iobase);
1269 ksprintf(lbuf," %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1271 putxyl(0,row,lbuf,80);
1274 switch(list->comment)
1276 case DEV_DEVICE: /* ordinary device */
1282 if (list->next->comment == DEV_DEVICE)
1283 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1288 if (list->next->comment == DEV_DEVICE)
1289 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1292 puthelp(" WARNING: This list entry corrupted!");
1296 move(0,row); /* put the cursor somewhere relevant */
1303 ** Displays (num) lines of the contents of (list) at (row), optionally
1304 ** displaying the port and IRQ fields as well if (detail) is nonzero.
1307 drawlist(int row, int num, int detail, DEV_LIST *list)
1311 for(ofs = 0; ofs < num; ofs++)
1315 drawline(row+ofs,detail,list,0,NULL); /* NULL -> don't draw empty help string */
1316 list = nextent(list); /* move down visible list */
1318 erase(0,row+ofs,80,1);
1327 ** Redraws the active list
1336 ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1339 putxyl(45,0,lines,16);
1341 drawlist(1,8,1,alist); /* draw device lists */
1347 ** Redraws the inactive list
1350 redrawinactive(void)
1352 drawlist(10,7,0,ilist); /* draw device lists */
1359 ** Clear the screen and redraw the entire layout
1366 putxy(3,0,"!bActive!n-!bDrivers");
1367 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1369 putxy(3,9,"!bInactive!n-!bDrivers");
1370 putxy(63,9,"!bDev");
1373 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1383 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1384 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1387 yesnocancel(char *str)
1413 ** Show device parameters in the region below the lists
1415 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1416 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1417 ** +--------------------------------------------------------------------------------+
1418 ** 17-|--------------------------------------------------------------------------------|
1419 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1420 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1421 ** 20-| Flags : 0x0000 DRQ number : 00 |
1422 ** 21-|--------------------------------------------------------------------------------|
1425 showparams(DEV_LIST *dev)
1429 erase(0,18,80,3); /* clear area */
1432 if (dev->comment != DEV_DEVICE)
1436 if (dev->iobase > 0)
1438 ksprintf(buf,"Port address : 0x%x",dev->iobase);
1444 ksprintf(buf,"IRQ number : %d",dev->irq);
1447 ksprintf(buf,"Flags : 0x%x",dev->flags);
1451 ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1456 ksprintf(buf,"Memory size : 0x%x",dev->msize);
1462 ksprintf(buf,"DRQ number : %d",dev->drq);
1469 ** Editing functions for device parameters
1471 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1472 ** onscreen. Refuse values outsise (min) and (max).
1473 ** editparams(dev) - Edit the parameters for (dev)
1477 #define VetRet(code) \
1479 if ((i >= min) && (i <= max)) /* legit? */ \
1482 ksprintf(buf,hex?"0x%x":"%d",i); \
1483 putxy(hex?x-2:x,y,buf); \
1484 return(code); /* all done and exit */ \
1486 i = *val; /* restore original value */ \
1487 delta = 1; /* restore other stuff */ \
1494 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1495 ** in a field (width) wide. (Allow one space)
1496 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1498 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1501 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1503 int i = *val; /* work with copy of the value */
1504 char buf[2+11+1],tc[11+1]; /* display buffer, text copy */
1505 int xp = 0; /* cursor offset into text copy */
1506 int delta = 1; /* force redraw first time in */
1508 int extended = 0; /* stage counter for extended key sequences */
1510 if (hex) /* we presume there's a leading 0x onscreen */
1511 putxy(x-2,y,"!i0x"); /* coz there sure is now */
1515 if (delta) /* only update if necessary */
1517 ksprintf(tc,hex?"%x":"%d",i); /* make a text copy of the value */
1518 ksprintf(buf,"!i%s",tc); /* format for printing */
1519 erase(x,y,width,1); /* clear the area */
1520 putxy(x,y,buf); /* write */
1521 xp = strlen(tc); /* cursor always at end */
1522 move(x+xp,y); /* position the cursor */
1527 switch(extended) /* escape handling */
1530 if (c == 0x1b) /* esc? */
1532 extended = 1; /* flag and spin */
1536 break; /* nope, drop through */
1538 case 1: /* there was an escape prefix */
1539 if (c == '[' || c == 'O') /* second character in sequence */
1545 return(KEY_EXIT); /* double esc exits */
1547 break; /* nup, not a sequence. */
1551 switch(c) /* looks like the real McCoy */
1554 VetRet(KEY_UP); /* leave if OK */
1557 VetRet(KEY_DOWN); /* leave if OK */
1560 VetRet(KEY_RIGHT); /* leave if OK */
1563 VetRet(KEY_LEFT); /* leave if OK */
1573 case '\t': /* trying to tab off */
1574 VetRet(KEY_TAB); /* verify and maybe return */
1584 case '\177': /* BS or DEL */
1585 if (ro) /* readonly? */
1587 puthelp(" !iThis value cannot be edited (Press ESC)");
1588 while(kgetchar() != 0x1b); /* wait for key */
1589 return(KEY_NULL); /* spin */
1591 if (xp) /* still something left to delete */
1593 i = (hex ? i/0x10u : i/10); /* strip last digit */
1594 delta = 1; /* force update */
1617 if (ro) /* readonly? */
1619 puthelp(" !iThis value cannot be edited (Press ESC)");
1620 while(kgetchar() != 0x1b); /* wait for key */
1621 return(KEY_NULL); /* spin */
1623 if (xp >= width) /* no room for more characters anyway */
1627 if ((c >= '0') && (c <= '9'))
1629 i = i*0x10 + (c-'0'); /* update value */
1633 if ((c >= 'a') && (c <= 'f'))
1635 i = i*0x10 + (c-'a'+0xa);
1639 if ((c >= 'A') && (c <= 'F'))
1641 i = i*0x10 + (c-'A'+0xa);
1646 if ((c >= '0') && (c <= '9'))
1648 i = i*10 + (c-'0'); /* update value */
1649 delta = 1; /* force redraw */
1662 ** Edit the parameters for (dev)
1664 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1665 ** possible for this to spin in an endless loop...
1666 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1667 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1668 ** +--------------------------------------------------------------------------------+
1669 ** 17-|--------------------------------------------------------------------------------|
1670 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1671 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1672 ** 20-| Flags : 0x0000 DRQ number : 00 |
1673 ** 21-|--------------------------------------------------------------------------------|
1675 ** The "intelligence" in this function that hops around based on the directional
1676 ** returns from editval isn't very smart, and depends on the layout above.
1679 editparams(DEV_LIST *dev)
1682 char buf[16]; /* needs to fit the device name */
1684 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1685 ksprintf(buf,"!b%s",dev->dev);
1692 if (dev->iobase > 0)
1694 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1695 ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1715 puthelp(" Interrupt number (Decimal, 1-15)");
1716 ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1728 if (dev->iobase > 0)
1739 puthelp(" Device-specific flag values.");
1740 ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1754 if (dev->iobase > 0)
1774 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1775 ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1782 if (dev->iobase > 0)
1804 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1805 ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1834 puthelp(" Device DMA request number (Decimal, 1-7)");
1835 ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1858 dev->changed = 1; /* mark as changed */
1861 static char *helptext[] =
1863 " Using the UserConfig kernel settings editor",
1864 " -------------------------------------------",
1870 "The screen displays a list of available drivers, divided into two",
1871 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1872 "by default collapsed and can be expanded to show all the drivers",
1873 "available in each category. The parameters for the currently selected",
1874 "driver are shown at the bottom of the screen.",
1876 "- - Moving around -",
1878 "To move in the current list, use the UP and DOWN cursor keys to select",
1879 "an item (the selected item will be highlighted). If the item is a",
1880 "category name, you may alternatively expand or collapse the list of",
1881 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1882 "expanded, you can select each driver in the same manner and either:",
1884 " - change its parameters using [!bENTER!n]",
1885 " - move it to the Inactive list using [!bDEL!n]",
1887 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1888 "you need to move a driver from the Inactive list back to the Active",
1889 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1890 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1891 "its place in the Active list.",
1893 "- - Altering the list/parameters -",
1895 "Any drivers for devices not installed in your system should be moved",
1896 "to the Inactive list, until there are no remaining parameter conflicts",
1897 "between the drivers, as indicated at the top.",
1899 "Once the list of Active drivers only contains entries for the devices",
1900 "present in your system, you can set their parameters (Interrupt, DMA",
1901 "channel, I/O addresses). To do this, select the driver and press",
1902 "[!bENTER!n]: it is now possible to edit the settings at the",
1903 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1904 "finished, use [!bQ!n] to return to the list.",
1906 "- - Saving changes -",
1908 "When all settings seem correct, and you wish to proceed with the",
1909 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1910 "confirm your choice.",
1919 ** Displays help text onscreen for people that are confused, using a simple
1925 int topline = 0; /* where we are in the text */
1926 int line = 0; /* last line we displayed */
1930 for (;;) /* loop until user quits */
1932 /* display help text */
1935 clear(); /* remove everything else */
1936 for (line = topline;
1937 (line < (topline + 24)) && (helptext[line]);
1939 putxy(0,line-topline,helptext[line]);
1944 ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1947 c = kgetchar(); /* so what do they say? */
1954 case 'B': /* wired into 'more' users' fingers */
1955 if (topline > 0) /* room to go up? */
1958 if (topline < 0) /* don't go too far */
1966 case ' ': /* expected by most people */
1967 if (helptext[line]) /* maybe more below? */
1976 redraw(); /* restore the screen */
1984 ** High-level control functions
1991 ** Handle user movement within (*list) in the region starting at (row) onscreen with
1992 ** (num) lines, starting at (*ofs) offset from row onscreen.
1993 ** Pass (detail) on to drawing routines.
1995 ** If the user hits a key other than a cursor key, maybe return a code.
1997 ** (*list) points to the device at the top line in the region, (*ofs) is the
1998 ** position of the highlight within the region. All routines below
1999 ** this take only a device and an absolute row : use ofsent() to find the
2000 ** device, and add (*ofs) to (row) to find the absolute row.
2003 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
2014 showparams(ofsent(*ofs,*list)); /* show device parameters */
2015 drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp); /* highlight current line */
2019 c = kgetchar(); /* get a character */
2020 if ((extended == 2) || (c==588) || (c==596)) /* console gives "alternative" codes */
2022 extended = 0; /* no longer */
2025 case 588: /* syscons' idea of 'up' */
2027 if (*ofs) /* just a move onscreen */
2029 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2030 (*ofs)--; /* move up */
2032 lp = prevent(*list); /* can we go up? */
2035 *list = lp; /* yes, move up list */
2036 drawlist(row,num,detail,*list);
2041 case 596: /* dooby-do */
2042 case 'B': /* down */
2043 lp = ofsent(*ofs,*list); /* get current item */
2045 break; /* nothing more to move to */
2046 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2047 if (*ofs < (num-1)) /* room to move onscreen? */
2051 *list = nextent(*list); /* scroll region down */
2052 drawlist(row,num,detail,*list);
2064 case '[': /* cheat : always preceeds cursor move */
2065 case 'O': /* ANSI application key mode */
2074 return(KEY_EXIT); /* user requests exit */
2078 return(KEY_DO); /* "do" something */
2083 return(KEY_DEL); /* "delete" response */
2087 return(KEY_UNZOOM); /* expand everything */
2091 return(KEY_ZOOM); /* collapse everything */
2094 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp); /* unhighlight current line */
2095 return(KEY_TAB); /* "move" response */
2097 case '\014': /* ^L, redraw */
2100 case '?': /* helptext */
2112 ** Do the fullscreen config thang
2117 int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2121 initlist(&inactive);
2127 conflicts = findconflict(active); /* find conflicts in the active list only */
2135 case 0: /* active devices */
2136 ret = dolist(1,8,1,&actofs,&alist,
2137 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2141 mode = 1; /* swap lists */
2158 collapselist(active);
2163 dp = ofsent(actofs,alist); /* get current device */
2164 if (dp) /* paranoia... */
2166 if (dp->attrib & FLG_MANDATORY) /* can't be deleted */
2168 if (dp == alist) /* moving top item on list? */
2172 alist = dp->next; /* point list to non-moving item */
2174 alist = dp->prev; /* end of list, go back instead */
2177 if (!dp->next) /* moving last item on list? */
2180 dp->conflicts = 0; /* no conflicts on the inactive list */
2181 movedev(dp,inactive); /* shift to inactive list */
2182 conflicts = findconflict(active); /* update conflict tags */
2184 redrawactive(); /* redraw */
2189 case KEY_DO: /* edit device parameters */
2190 dp = ofsent(actofs,alist); /* get current device */
2191 if (dp) /* paranoia... */
2193 if (dp->comment == DEV_DEVICE) /* can't edit comments, zoom? */
2195 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2197 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2199 conflicts = findconflict(active); /* update conflict tags */
2200 }else{ /* DO on comment = zoom */
2201 switch(dp->comment) /* Depends on current state */
2203 case DEV_COMMENT: /* not currently zoomed */
2204 dp->comment = DEV_ZOOMED;
2208 dp->comment = DEV_COMMENT;
2218 case 1: /* inactive devices */
2219 ret = dolist(10,7,0,&inactofs,&ilist,
2220 " [!bEnter!n] Enable device ");
2234 expandlist(inactive);
2241 collapselist(inactive);
2246 dp = ofsent(inactofs,ilist); /* get current device */
2247 if (dp) /* paranoia... */
2249 if (dp->comment == DEV_DEVICE) /* can't move comments, zoom? */
2251 if (dp == ilist) /* moving top of list? */
2255 ilist = dp->next; /* point list to non-moving item */
2257 ilist = dp->prev; /* can't go down, go up instead */
2260 if (!dp->next) /* last entry on list? */
2261 inactofs--; /* shift cursor up one */
2264 movedev(dp,active); /* shift to active list */
2265 conflicts = findconflict(active); /* update conflict tags */
2267 alist = dp; /* put at top and current */
2269 while(dp->comment == DEV_DEVICE)
2270 dp = dp->prev; /* forcibly unzoom section */
2271 dp ->comment = DEV_COMMENT;
2272 mode = 0; /* and swap modes to follow it */
2274 }else{ /* DO on comment = zoom */
2275 switch(dp->comment) /* Depends on current state */
2277 case DEV_COMMENT: /* not currently zoomed */
2278 dp->comment = DEV_ZOOMED;
2282 dp->comment = DEV_COMMENT;
2286 redrawactive(); /* redraw */
2291 default: /* nothing else relevant here */
2296 mode = 0; /* shouldn't happen... */
2299 /* handle returns that are the same for both modes */
2306 i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2309 case 2: /* cancel */
2313 case 1: /* save and exit */
2315 savelist(inactive,0);
2318 nukelist(active); /* clean up after ourselves */
2328 #endif /* VISUAL_USERCONFIG */
2331 * Copyright (c) 1991 Regents of the University of California.
2332 * All rights reserved.
2333 * Copyright (c) 1994 Jordan K. Hubbard
2334 * All rights reserved.
2335 * Copyright (c) 1994 David Greenman
2336 * All rights reserved.
2338 * Many additional changes by Bruce Evans
2340 * This code is derived from software contributed by the
2341 * University of California Berkeley, Jordan K. Hubbard,
2342 * David Greenman and Bruce Evans.
2344 * Redistribution and use in source and binary forms, with or without
2345 * modification, are permitted provided that the following conditions
2347 * 1. Redistributions of source code must retain the above copyright
2348 * notice, this list of conditions and the following disclaimer.
2349 * 2. Redistributions in binary form must reproduce the above copyright
2350 * notice, this list of conditions and the following disclaimer in the
2351 * documentation and/or other materials provided with the distribution.
2352 * 3. All advertising materials mentioning features or use of this software
2353 * must display the following acknowledgement:
2354 * This product includes software developed by the University of
2355 * California, Berkeley and its contributors.
2356 * 4. Neither the name of the University nor the names of its contributors
2357 * may be used to endorse or promote products derived from this software
2358 * without specific prior written permission.
2360 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2362 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2363 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2364 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2365 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2366 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2367 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2368 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2369 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2372 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2375 #define PARM_DEVSPEC 0x1
2376 #define PARM_INT 0x2
2377 #define PARM_ADDR 0x3
2378 #define PARM_STRING 0x4
2380 typedef struct _cmdparm {
2383 struct uc_device *dparm;
2392 typedef int (*CmdFunc)(CmdParm *);
2394 typedef struct _cmd {
2402 static void lsscsi(void);
2403 static int list_scsi(CmdParm *);
2406 static int lsdevtab(struct uc_device *);
2407 static struct uc_device *find_device(char *, int);
2408 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2409 static void cngets(char *, int);
2410 static Cmd *parse_cmd(char *);
2411 static int parse_args(const char *, CmdParm *);
2412 static int save_dev(struct uc_device *);
2414 static int list_devices(CmdParm *);
2415 static int set_device_ioaddr(CmdParm *);
2416 static int set_device_irq(CmdParm *);
2417 static int set_device_drq(CmdParm *);
2418 static int set_device_iosize(CmdParm *);
2419 static int set_device_mem(CmdParm *);
2420 static int set_device_flags(CmdParm *);
2421 static int set_device_enable(CmdParm *);
2422 static int set_device_disable(CmdParm *);
2423 static int quitfunc(CmdParm *);
2424 static int helpfunc(CmdParm *);
2425 static int introfunc(CmdParm *);
2428 static int lspnp(void);
2429 static int set_pnp_parms(CmdParm *);
2434 static CmdParm addr_parms[] = {
2435 { PARM_DEVSPEC, {} },
2440 static CmdParm int_parms[] = {
2441 { PARM_DEVSPEC, {} },
2446 static CmdParm dev_parms[] = {
2447 { PARM_DEVSPEC, {} },
2452 static CmdParm string_arg[] = {
2453 { PARM_STRING, {} },
2458 static Cmd CmdList[] = {
2459 { "?", helpfunc, NULL }, /* ? (help) */
2460 { "di", set_device_disable, dev_parms }, /* disable dev */
2461 { "dr", set_device_drq, int_parms }, /* drq dev # */
2462 { "en", set_device_enable, dev_parms }, /* enable dev */
2463 { "ex", quitfunc, NULL }, /* exit (quit) */
2464 { "f", set_device_flags, int_parms }, /* flags dev mask */
2465 { "h", helpfunc, NULL }, /* help */
2466 { "intro", introfunc, NULL }, /* intro screen */
2467 { "iom", set_device_mem, addr_parms }, /* iomem dev addr */
2468 { "ios", set_device_iosize, int_parms }, /* iosize dev size */
2469 { "ir", set_device_irq, int_parms }, /* irq dev # */
2470 { "l", list_devices, NULL }, /* ls, list */
2472 { "pn", set_pnp_parms, string_arg }, /* pnp ... */
2474 { "po", set_device_ioaddr, int_parms }, /* port dev addr */
2475 { "res", (CmdFunc)cpu_reset, NULL }, /* reset CPU */
2476 { "q", quitfunc, NULL }, /* quit */
2478 { "s", list_scsi, NULL }, /* scsi */
2480 #ifdef VISUAL_USERCONFIG
2481 { "v", (CmdFunc)visuserconfig, NULL }, /* visual mode */
2483 { NULL, NULL, NULL },
2489 static char banner = 1;
2495 init_config_script();
2498 /* Only display signon banner if we are about to go interactive */
2499 if (!has_config_script()) {
2500 if (!(boothowto & RB_CONFIG))
2501 #ifdef INTRO_USERCONFIG
2508 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2509 " Type \"help\" for help"
2510 #ifdef VISUAL_USERCONFIG
2511 " or \"visual\" to go to the visual\n"
2512 " configuration interface (requires MGA/VGA display or\n"
2513 " serial terminal capable of displaying ANSI graphics)"
2519 kprintf("config> ");
2521 if (input[0] == '\0')
2523 cmd = parse_cmd(input);
2525 kprintf("Invalid command or syntax. Type `?' for help.\n");
2528 rval = (*cmd->handler)(cmd->parms);
2537 parse_cmd(char *cmd)
2541 for (cp = CmdList; cp->name; cp++) {
2542 int len = strlen(cp->name);
2544 if (!strncmp(cp->name, cmd, len)) {
2545 while (*cmd && *cmd != ' ' && *cmd != '\t')
2547 if (parse_args(cmd, cp->parms))
2557 parse_args(const char *cmd, CmdParm *parms)
2562 if (*cmd == ' ' || *cmd == '\t') {
2566 if (parms == NULL || parms->type == -1) {
2569 kprintf("Extra arg(s): %s\n", cmd);
2572 if (parms->type == PARM_DEVSPEC) {
2577 while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2578 (*cmd >= '0' && *cmd <= '9')))
2579 devname[i++] = *(cmd++);
2581 if (*cmd >= '0' && *cmd <= '9') {
2582 unit = strtoul(cmd, &ptr, 10);
2584 kprintf("Invalid device number\n");
2585 /* XXX should print invalid token here and elsewhere. */
2588 /* XXX else should require end of token. */
2591 if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2592 kprintf("No such device: %s%d\n", devname, unit);
2598 if (parms->type == PARM_INT) {
2599 parms->parm.iparm = strtoul(cmd, &ptr, 0);
2601 kprintf("Invalid numeric argument\n");
2608 if (parms->type == PARM_ADDR) {
2609 parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2611 kprintf("Invalid address argument\n");
2618 if (parms->type == PARM_STRING) {
2619 parms->parm.u.sparm = cmd;
2627 list_devices(CmdParm *parms)
2630 if (lsdevtab(uc_devtab)) return 0;
2632 if (lspnp()) return 0;
2638 set_device_ioaddr(CmdParm *parms)
2640 parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2641 save_dev(parms[0].parm.dparm);
2646 set_device_irq(CmdParm *parms)
2650 irq = parms[1].parm.iparm;
2652 kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2655 else if (irq != -1 && irq > 15) {
2656 kprintf("An IRQ > 15 would be invalid.\n");
2659 parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2660 save_dev(parms[0].parm.dparm);
2665 set_device_drq(CmdParm *parms)
2670 * The bounds checking is just to ensure that the value can be printed
2671 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2673 drq = parms[1].parm.iparm;
2674 parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2675 save_dev(parms[0].parm.dparm);
2680 set_device_iosize(CmdParm *parms)
2682 parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2683 save_dev(parms[0].parm.dparm);
2688 set_device_mem(CmdParm *parms)
2690 parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2691 save_dev(parms[0].parm.dparm);
2696 set_device_flags(CmdParm *parms)
2698 parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2699 save_dev(parms[0].parm.dparm);
2704 set_device_enable(CmdParm *parms)
2706 parms[0].parm.dparm->id_enabled = TRUE;
2707 save_dev(parms[0].parm.dparm);
2712 set_device_disable(CmdParm *parms)
2714 parms[0].parm.dparm->id_enabled = FALSE;
2715 save_dev(parms[0].parm.dparm);
2722 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2728 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2731 * Output the pnp_ldn_overrides[] table.
2733 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2734 sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2735 if(error) return(error);
2740 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2741 0, 0, sysctl_machdep_uc_pnplist, "A",
2742 "List of PnP overrides changed in UserConfig");
2745 * this function sets the kernel table to override bios PnP
2749 set_pnp_parms(CmdParm *parms)
2751 u_long idx, val, ldn, csn;
2754 const char *p = parms[0].parm.u.sparm;
2757 csn=strtoul(p,&q, 0);
2758 ldn=strtoul(q,&q, 0);
2759 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2760 if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2761 kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2764 for (i=0; i < MAX_PNP_LDN; i++) {
2765 if (pnp_ldn_overrides[i].csn == csn &&
2766 pnp_ldn_overrides[i].ldn == ldn)
2769 if (i==MAX_PNP_LDN) {
2770 for (i=0; i < MAX_PNP_LDN; i++) {
2771 if (pnp_ldn_overrides[i].csn <1 ||
2772 pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2776 if (i==MAX_PNP_LDN) {
2777 kprintf("sorry, no PnP entries available, try delete one\n");
2780 d = pnp_ldn_overrides[i] ;
2786 if (!strncmp(p,"irq",3)) {
2787 idx=strtoul(p+3,&q, 0);
2788 val=strtoul(q,&q, 0);
2789 if (idx >=0 && idx < 2) d.irq[idx] = val;
2790 } else if (!strncmp(p,"flags",5)) {
2791 idx=strtoul(p+5,&q, 0);
2793 } else if (!strncmp(p,"drq",3)) {
2794 idx=strtoul(p+3,&q, 0);
2795 val=strtoul(q,&q, 0);
2796 if (idx >=0 && idx < 2) d.drq[idx] = val;
2797 } else if (!strncmp(p,"port",4)) {
2798 idx=strtoul(p+4,&q, 0);
2799 val=strtoul(q,&q, 0);
2800 if (idx >=0 && idx < 8) d.port[idx] = val;
2801 } else if (!strncmp(p,"mem",3)) {
2802 idx=strtoul(p+3,&q, 0);
2803 val=strtoul(q,&q, 0);
2804 if (idx >=0 && idx < 4) d.mem[idx].base = val;
2805 } else if (!strncmp(p,"bios",4)) {
2808 } else if (!strncmp(p,"os",2)) {
2811 } else if (!strncmp(p,"disable",7)) {
2814 } else if (!strncmp(p,"enable",6)) {
2817 } else if (!strncmp(p,"delete",6)) {
2818 bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2819 if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2822 kprintf("unknown command <%s>\n", p);
2825 for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2827 pnp_ldn_overrides[i] = d ;
2833 quitfunc(CmdParm *parms)
2836 * If kernel config supplied, and we are parsing it, and -c also supplied,
2837 * ignore a quit command, This provides a safety mechanism to allow
2838 * recovery from a damaged/buggy kernel config.
2840 if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2846 helpfunc(CmdParm *parms)
2849 "Command\t\t\tDescription\n"
2850 "-------\t\t\t-----------\n"
2851 "ls\t\t\tList currently configured devices\n"
2852 "port <devname> <addr>\tSet device port (i/o address)\n"
2853 "irq <devname> <number>\tSet device irq\n"
2854 "drq <devname> <number>\tSet device drq\n"
2855 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2856 "iosize <devname> <size>\tSet device memory size\n"
2857 "flags <devname> <mask>\tSet device flags\n"
2858 "enable <devname>\tEnable device\n"
2859 "disable <devname>\tDisable device (will not be probed)\n");
2862 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2863 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2864 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2865 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2866 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2867 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2870 "quit\t\t\tExit this configuration utility\n"
2871 "reset\t\t\tReset CPU\n");
2872 #ifdef VISUAL_USERCONFIG
2873 kprintf("visual\t\t\tGo to fullscreen mode.\n");
2876 "help\t\t\tThis message\n\n"
2877 "Commands may be abbreviated to a unique prefix\n");
2881 #if defined (VISUAL_USERCONFIG)
2883 center(int y, char *str)
2885 putxy((80 - strlen(str)) / 2, y, str);
2890 introfunc(CmdParm *parms)
2892 #if defined (VISUAL_USERCONFIG)
2893 int curr_item, first_time, extended = 0;
2894 static char *choices[] = {
2895 " Skip kernel configuration and continue with installation ",
2896 " Start kernel configuration in full-screen visual mode ",
2897 " Start kernel configuration in CLI mode ",
2901 center(2, "!bKernel Configuration Menu!n");
2910 for (i = 0; i < 3; i++) {
2914 strcat(tmp, choices[i]);
2917 putxy(10, 5 + i, tmp);
2921 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2922 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2923 putxy(2, 12, "match your hardware configuration.");
2924 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2925 putxy(2, 15, "(press Down-Arrow then ENTER).");
2926 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2927 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2928 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2929 putxy(2, 21, "then simply press ENTER or Q now.");
2933 move(0, 0); /* move the cursor out of the way */
2936 if ((extended == 2) || (c == 588) || (c == 596)) { /* console gives "alternative" codes */
2937 extended = 0; /* no longer */
2946 case 'B': /* down */
2958 case '[': /* cheat : always preceeds cursor move */
2959 case 'O': /* ANSI application key mode */
2970 return 1; /* user requests exit */
2972 case '1': /* select an item */
2996 case 'D': /* down */
3009 else if (curr_item == 1)
3010 return visuserconfig();
3012 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3013 /* enable quitfunc */
3014 userconfig_boot_parsing=0;
3016 boothowto |= RB_CONFIG; /* force -c */
3023 #else /* !VISUAL_USERCONFIG */
3025 #endif /* VISUAL_USERCONFIG */
3032 struct pnp_cinfo *c;
3036 for (i=0; i< MAX_PNP_LDN; i++) {
3037 c = &pnp_ldn_overrides[i];
3038 if (c->csn >0 && c->csn != 255) {
3040 static char pfmt[] =
3041 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3042 static char mfmt[] =
3043 "mem 0x%x 0x%x 0x%x 0x%x";
3046 if (!userconfig_boot_parsing) {
3048 if (kgetchar() == 'q') {
3056 if (lineno == 0 || first)
3057 kprintf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3059 kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3061 c->override ? "OS ":"BIOS",
3062 c->enable ? "Y":"N",
3063 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3065 kprintf("flags 0x%08lx ",c->flags);
3066 for (pmax = 7; pmax >=0 ; pmax--)
3067 if (c->port[pmax]!=0) break;
3068 for (mmax = 3; mmax >=0 ; mmax--)
3069 if (c->mem[mmax].base!=0) break;
3072 buf[10 + 5*pmax]='\0';
3074 c->port[0], c->port[1], c->port[2], c->port[3],
3075 c->port[4], c->port[5], c->port[6], c->port[7]);
3079 buf[8 + 5*mmax]='\0';
3081 c->mem[0].base, c->mem[1].base,
3082 c->mem[2].base, c->mem[3].base);
3092 lsdevtab(struct uc_device *dt)
3094 for (; dt->id_id != 0; dt++) {
3099 if (!userconfig_boot_parsing) {
3100 if (kgetchar() == 'q') {
3110 "Device port irq drq iomem iosize unit flags enab\n"
3114 ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3115 kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3116 dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3117 ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3118 /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3119 dt->id_enabled ? "Yes" : "No");
3129 int count = resource_count();
3135 uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3138 for (i = 0; i < count; i++) {
3139 name = resource_query_name(i);
3140 unit = resource_query_unit(i);
3142 continue; /* skip wildcards */
3143 uc_devtab[dt].id_id = id++;
3144 resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3146 resource_int_value(name, unit, "irq", &val);
3147 uc_devtab[dt].id_irq = (1 << val);
3148 resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3149 resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3150 resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3151 uc_devtab[dt].id_unit = unit;
3152 resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3154 resource_int_value(name, unit, "disabled", &val);
3155 uc_devtab[dt].id_enabled = !val;
3156 uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3157 strcpy(uc_devtab[dt].id_name, name);
3166 int count = resource_count();
3168 for (i = 0; i < count; i++)
3169 if (uc_devtab[i].id_name)
3170 kfree(uc_devtab[i].id_name, M_DEVL);
3171 kfree(uc_devtab, M_DEVL);
3174 static struct uc_device *
3175 find_device(char *devname, int unit)
3177 struct uc_device *ret;
3179 if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3184 static struct uc_device *
3185 search_devtable(struct uc_device *dt, char *devname, int unit)
3187 for (; dt->id_id != 0; dt++)
3188 if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3194 cngets(char *input, int maxin)
3200 /* Treat ^H or ^? as backspace */
3201 if ((c == '\010' || c == '\177')) {
3203 kprintf("\010 \010");
3204 *--input = '\0', --nchars;
3208 /* Treat ^U or ^X as kill line */
3209 else if ((c == '\025' || c == '\030')) {
3211 kprintf("\010 \010");
3212 *--input = '\0', --nchars;
3217 if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3221 *input++ = (u_char)c;
3227 /* scsi: Support for displaying configured SCSI devices.
3228 * There is no way to edit them, and this is inconsistent
3229 * with the ISA method. This is here as a basis for further work.
3232 type_text(char *name) /* XXX: This is bogus */
3234 if (strcmp(name, "sd") == 0)
3237 if (strcmp(name, "st") == 0)
3243 id_put(char *desc, int id)
3245 if (id != SCCONF_UNSPEC)
3248 kprintf("%s", desc);
3250 if (id == SCCONF_ANY)
3262 kprintf("scsi: (can't be edited):\n");
3264 for (i = 0; scsi_cinit[i].driver; i++)
3266 id_put("controller scbus", scsi_cinit[i].scbus);
3268 if (scsi_cinit[i].unit != -1)
3271 id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3277 for (i = 0; scsi_dinit[i].name; i++)
3279 kprintf("%s ", type_text(scsi_dinit[i].name));
3281 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3282 id_put(" at scbus", scsi_dinit[i].cunit);
3283 id_put(" target ", scsi_dinit[i].target);
3284 id_put(" lun ", scsi_dinit[i].lun);
3286 if (scsi_dinit[i].flags)
3287 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3294 list_scsi(CmdParm *parms)
3303 save_resource(struct uc_device *idev)
3308 name = idev->id_name;
3309 unit = idev->id_unit;
3310 resource_set_int(name, unit, "port", idev->id_iobase);
3311 resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3312 resource_set_int(name, unit, "drq", idev->id_drq);
3313 resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3314 resource_set_int(name, unit, "msize", idev->id_msize);
3315 resource_set_int(name, unit, "flags", idev->id_flags);
3316 resource_set_int(name, unit, "disabled", !idev->id_enabled);
3320 save_dev(struct uc_device *idev)
3322 struct uc_device *id_p,*id_pn;
3323 char *name = idev->id_name;
3325 for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3326 if (id_p->id_id == idev->id_id) {
3327 id_pn = id_p->id_next;
3329 kfree(id_p->id_name, M_DEVL);
3330 bcopy(idev,id_p,sizeof(struct uc_device));
3331 save_resource(idev);
3332 id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3333 strcpy(id_p->id_name, name);
3334 id_p->id_next = id_pn;
3338 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3339 bcopy(idev,id_pn,sizeof(struct uc_device));
3340 save_resource(idev);
3341 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3342 strcpy(id_pn->id_name, name);
3343 id_pn->id_next = uc_devlist;