kernel: Drop ISA support from most remaining drivers that had some.
[dragonfly.git] / sys / platform / pc32 / i386 / userconfig.c
1 /**
2  ** Copyright (c) 1995
3  **      Michael Smith, msmith@freebsd.org.  All rights reserved.
4  **
5  ** This code contains a module marked :
6
7  * Copyright (c) 1991 Regents of the University of California.
8  * All rights reserved.
9  * Copyright (c) 1994 Jordan K. Hubbard
10  * All rights reserved.
11  * Copyright (c) 1994 David Greenman
12  * All rights reserved.
13  *
14  * Many additional changes by Bruce Evans
15  *
16  * This code is derived from software contributed by the
17  * University of California Berkeley, Jordan K. Hubbard,
18  * David Greenman and Bruce Evans.
19
20  ** As such, it contains code subject to the above copyrights.
21  ** The module and its copyright can be found below.
22  ** 
23  ** Redistribution and use in source and binary forms, with or without
24  ** modification, are permitted provided that the following conditions
25  ** are met:
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.
37  **
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.
48  **
49  ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
50  **/
51
52 /**
53  ** USERCONFIG
54  **
55  ** Kernel boot-time configuration manipulation tool for FreeBSD.
56  **
57  ** Two modes of operation are supported : the default is the line-editor mode,
58  ** the command "visual" invokes the fullscreen mode.
59  **
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.
62  **/
63
64 /**
65  ** USERCONFIG, visual mode.
66  **
67  **   msmith@freebsd.org
68  **
69  ** Look for "EDIT THIS LIST" to add to the list of known devices
70  ** 
71  **
72  ** There are a number of assumptions made in this code.
73  ** 
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.
80  **
81  ** Devices marked as disabled are imported as such.
82  **
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.
86  **
87  ** XXX - TODO:
88  ** 
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.)
95  **
96  ** - Only display headings with devices under them. (difficult)
97  **/
98
99 #include "opt_userconfig.h"
100
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>
108 #include <sys/bus.h>
109 #include <sys/cons.h>
110
111 #include <machine/md_var.h>
112 #include <machine/limits.h>
113
114 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
115
116 #undef NPNP
117 #define NPNP 0
118
119 #if NPNP > 0
120 #include <machine_base/isa/pnp.h>
121 #endif
122
123 static MALLOC_DEFINE(M_DEVL, "uc_devlist", "uc_device lists in userconfig()");
124
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 */
128
129 static int userconfig_boot_parsing;     /* set if we are reading from the boot instructions */
130
131 static void load_devtab(void);
132 static void free_devtab(void);
133 static void save_resource(struct uc_device *);
134
135 static int
136 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS)
137 {
138         struct uc_device *id;
139         int error=0;
140         char name[8];
141
142         if(!req->oldptr) {
143                 /* Only sizing */
144                 id=uc_devlist;
145                 while(id) {
146                         error+=sizeof(struct uc_device)+8;
147                         id=id->id_next;
148                 }
149                 return(SYSCTL_OUT(req,0,error));
150         } else {
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').
154                  */
155                 id=uc_devlist;
156                 while(id) {
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,
162                                 8,req);
163                         if(error) return(error);
164                         id=id->id_next;
165                 }
166                 return(0);
167         }
168 }
169
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");
173
174 /*
175 ** Obtain command input.
176 **
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
182 ** will exit.
183 **
184 ** Note that quit commands encountered in the script will be
185 ** ignored if the RB_CONFIG flag is supplied.
186 */
187 static const char       *config_script;
188 static int              config_script_size; /* use of int for -ve magic value */
189
190 #define has_config_script()     (config_script_size > 0)
191
192 static int
193 init_config_script(void)
194 {
195     caddr_t             autoentry, autoattr;
196
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;
207         /* sanity check */
208         if ((config_script_size == 0) || (config_script == NULL)) {
209             config_script_size = 0;
210             config_script = NULL;
211         }
212     }
213     return has_config_script();
214 }
215
216 static int
217 kgetchar(void)
218 {
219     int                 c = -1;
220 #ifdef INTRO_USERCONFIG
221     static int          intro = 0;
222 #endif
223     
224     if (has_config_script()) 
225     {
226         /* Consume character from loaded userconfig script, display */
227         userconfig_boot_parsing = 1;
228         c = *config_script;
229         config_script++;
230         config_script_size--;
231
232     } else {
233         
234 #ifdef INTRO_USERCONFIG
235         if (userconfig_boot_parsing) {
236             if (!(boothowto & RB_CONFIG)) {
237                 /* userconfig_script, !RB_CONFIG -> quit */
238                 if (intro == 0) {
239                     c = 'q';
240                     config_script = "uit\n";
241                     config_script_size = strlen(config_script);
242                     /* userconfig_script will be 1 on the next pass */
243                 }
244             } else {
245                 /* userconfig_script, RB_CONFIG -> cngetc() */
246             }
247         } else {
248             if (!(boothowto & RB_CONFIG)) {
249                 /* no userconfig_script, !RB_CONFIG -> show intro */
250                 if (intro == 0) {
251                     intro = 1;
252                     c = 'i';
253                     config_script = "ntro\n";
254                     config_script_size = strlen(config_script);
255                     /* userconfig_script will be 1 on the next pass */
256                 }
257             } else {
258                 /* no userconfig_script, RB_CONFIG -> cngetc() */
259             }
260         }
261 #else /* !INTRO_USERCONFIG */
262         /* assert(boothowto & RB_CONFIG) */
263 #endif /* INTRO_USERCONFIG */
264         userconfig_boot_parsing = 0;
265         if (c <= 0)
266             c = cngetc();
267     }
268     return(c);
269 }
270
271 #ifndef FALSE
272 #define FALSE   (0)
273 #define TRUE    (!FALSE)
274 #endif
275
276 #ifdef VISUAL_USERCONFIG
277
278 typedef struct
279 {
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 */
284 } DEV_INFO;
285
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)
295
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 */
302
303
304 typedef struct 
305 {
306     char        name[60];
307     int         number;
308 } DEVCLASS_INFO;
309
310 static DEVCLASS_INFO devclass_names[] = {
311 {       "Storage :        ",    CLS_STORAGE},
312 {       "Communications : ",    CLS_COMMS},
313 {       "Input :          ",    CLS_INPUT},
314 {       "Miscellaneous :  ",    CLS_MISC},
315 {       "",0}};
316
317
318 /********************* EDIT THIS LIST **********************/
319
320 /** Notes :
321  ** 
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.
326  **/
327
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},
334
335 {"sio",         "8250/16450/16550 Serial port",         0,              CLS_COMMS},
336 {"ppc",         "Parallel Port chipset",                0,              CLS_COMMS},
337
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},
343
344 {"apm",         "Advanced Power Management",            FLG_FIXED,      CLS_MISC},
345 {"pcic",        "PC-card controller",                   0,              CLS_MISC},
346 {"npx",         "Math coprocessor",                     FLG_IMMUTABLE,  CLS_MISC},
347 {"vga",         "Catchall PCI VGA driver",              FLG_INVISIBLE,  CLS_MISC},
348 {"","",0,0}};
349
350
351 typedef struct _devlist_struct
352 {
353     char        name[80];
354     int         attrib;                 /* flag values as per the FLG_* defines above */
355     int         class;                  /* disk, etc as per the CLS_* defines above */
356     char        dev[16];
357     int         iobase,irq,drq,maddr,msize,unit,flags,id;
358     int         comment;                /* 0 = device, 1 = comment, 2 = collapsed comment */
359     int         conflicts;              /* set/reset by findconflict, count of conflicts */
360     int         changed;                /* nonzero if the device has been edited */
361     struct uc_device    *device;
362     struct _devlist_struct *prev,*next;
363 } DEV_LIST;
364
365
366 #define DEV_DEVICE      0
367 #define DEV_COMMENT     1
368 #define DEV_ZOOMED      2
369
370 #define LIST_CURRENT    (1<<0)
371 #define LIST_SELECTED   (1<<1)
372
373 #define KEY_EXIT        0       /* return codes from dolist() and friends */
374 #define KEY_DO          1
375 #define KEY_DEL         2
376 #define KEY_TAB         3
377 #define KEY_REDRAW      4
378
379 #define KEY_UP          5       /* these only returned from editval() */
380 #define KEY_DOWN        6
381 #define KEY_LEFT        7
382 #define KEY_RIGHT       8
383 #define KEY_NULL        9       /* this allows us to spin & redraw */
384
385 #define KEY_ZOOM        10      /* these for zoom all/collapse all */
386 #define KEY_UNZOOM      11
387
388 #define KEY_HELP        12      /* duh? */
389
390 static void redraw(void);
391 static void insdev(DEV_LIST *dev, DEV_LIST *list);
392 static int  devinfo(DEV_LIST *dev);
393 static int  visuserconfig(void);
394
395 static DEV_LIST *active = NULL,*inactive = NULL;        /* driver lists */
396 static DEV_LIST *alist,*ilist;                          /* visible heads of the driver lists */
397 static DEV_LIST scratch;                                /* scratch record */
398 static int      conflicts;                              /* total conflict count */
399
400
401 static char lines[] = "--------------------------------------------------------------------------------";
402 static char spaces[] = "                                                                                     ";
403
404
405 /**
406  ** Device manipulation stuff : find, describe, configure.
407  **/
408
409 /**
410  ** setdev
411  **
412  ** Sets the device referenced by (*dev) to the parameters in the struct,
413  ** and the enable flag according to (enabled)
414  **/
415 static void 
416 setdev(DEV_LIST *dev, int enabled)
417 {
418     dev->device->id_iobase = dev->iobase;                               /* copy happy */
419     dev->device->id_irq = (u_short)(dev->irq < 16 ? 1<<dev->irq : 0);   /* IRQ is bitfield */
420     dev->device->id_drq = (short)dev->drq;
421     dev->device->id_maddr = (caddr_t)dev->maddr;
422     dev->device->id_msize = dev->msize;
423     dev->device->id_flags = dev->flags;
424     dev->device->id_enabled = enabled;
425 }
426
427
428 /**
429  ** getdevs
430  **
431  ** Walk the kernel device tables and build the active and inactive lists
432  **/
433 static void 
434 getdevs(void)
435 {
436     int                 i;
437     struct uc_device    *ap;
438
439         ap = uc_devtab;                         /* pointer to array of devices */
440         for (i = 0; ap[i].id_id; i++)                   /* for each device in this table */
441         {
442             scratch.unit = ap[i].id_unit;               /* device parameters */
443             strcpy(scratch.dev,ap[i].id_name);
444             scratch.iobase = ap[i].id_iobase;
445             scratch.irq = ffs(ap[i].id_irq)-1;
446             scratch.drq = ap[i].id_drq;
447             scratch.maddr = (int)ap[i].id_maddr;
448             scratch.msize = ap[i].id_msize;
449             scratch.flags = ap[i].id_flags;
450
451             scratch.comment = DEV_DEVICE;               /* admin stuff */
452             scratch.conflicts = 0;
453             scratch.device = &ap[i];                    /* save pointer for later reference */
454             scratch.changed = 0;
455             if (!devinfo(&scratch))                     /* get more info on the device */
456                 insdev(&scratch,ap[i].id_enabled?active:inactive);
457         }
458 }
459
460
461 /**
462  ** Devinfo
463  **
464  ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
465  ** If the device is unknown, put it in the CLS_MISC class, with no flags.
466  **
467  ** If the device is marked "invisible", return nonzero; the caller should
468  ** not insert any such device into either list.
469  **
470  **/
471 static int
472 devinfo(DEV_LIST *dev)
473 {
474     int         i;
475
476     for (i = 0; device_info[i].class; i++)
477     {
478         if (!strcmp(dev->dev,device_info[i].dev))
479         {
480             if (device_info[i].attrib & FLG_INVISIBLE)  /* forget we ever saw this one */
481                 return(1);
482             strcpy(dev->name,device_info[i].name);      /* get the name */
483             dev->attrib = device_info[i].attrib;
484             dev->class = device_info[i].class;
485             return(0);
486         }
487     }
488     strcpy(dev->name,"Unknown device");
489     dev->attrib = 0;
490     dev->class = CLS_MISC;
491     return(0);
492 }
493     
494
495 /**
496  ** List manipulation stuff : add, move, initialise, free, traverse
497  **
498  ** Note that there are assumptions throughout this code that
499  ** the first entry in a list will never move. (assumed to be
500  ** a comment).
501  **/
502
503
504 /**
505  ** Adddev
506  ** 
507  ** appends a copy of (dev) to the end of (*list)
508  **/
509 static void 
510 addev(DEV_LIST *dev, DEV_LIST **list)
511 {
512
513     DEV_LIST    *lp,*ap;
514
515     lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
516     bcopy(dev,lp,sizeof(DEV_LIST));                     /* create copied record */
517
518     if (*list)                                          /* list exists */
519     {
520         ap = *list;
521         while(ap->next)
522             ap = ap->next;                              /* scoot to end of list */
523         lp->prev = ap;
524         lp->next = NULL;
525         ap->next = lp;
526     }else{                                              /* list does not yet exist */
527         *list = lp;
528         lp->prev = lp->next = NULL;                     /* list now exists */
529     }
530 }
531
532
533 /**
534  ** Findspot
535  **
536  ** Finds the 'appropriate' place for (dev) in (list)
537  **
538  ** 'Appropriate' means in numeric order with other devices of the same type,
539  ** or in alphabetic order following a comment of the appropriate type.
540  ** or at the end of the list if an appropriate comment is not found. (this should
541  ** never happen)
542  ** (Note that the appropriate point is never the top, but may be the bottom)
543  **/
544 static DEV_LIST *
545 findspot(DEV_LIST *dev, DEV_LIST *list)
546 {
547     DEV_LIST    *ap = NULL;
548
549     /* search for a previous instance of the same device */
550     for (ap = list; ap; ap = ap->next)
551     {
552         if (ap->comment != DEV_DEVICE)                  /* ignore comments */
553             continue;
554         if (!strcmp(dev->dev,ap->dev))                  /* same base device */
555         {
556             if ((dev->unit <= ap->unit)                 /* belongs before (equal is bad) */
557                 || !ap->next)                           /* or end of list */
558             {
559                 ap = ap->prev;                          /* back up one */
560                 break;                                  /* done here */
561             }
562             if (ap->next)                                       /* if the next item exists */
563             {
564                 if (ap->next->comment != DEV_DEVICE)    /* next is a comment */
565                     break;
566                 if (strcmp(dev->dev,ap->next->dev))             /* next is a different device */
567                     break;
568             }
569         }
570     }
571
572     if (!ap)                                            /* not sure yet */
573     {
574         /* search for a class that the device might belong to */
575         for (ap = list; ap; ap = ap->next)
576         {
577             if (ap->comment != DEV_DEVICE)              /* look for simlar devices */
578                 continue;
579             if (dev->class != ap->class)                /* of same class too 8) */
580                 continue;
581             if (strcmp(dev->dev,ap->dev) < 0)           /* belongs before the current entry */
582             {
583                 ap = ap->prev;                          /* back up one */
584                 break;                                  /* done here */
585             }
586             if (ap->next)                               /* if the next item exists */
587                 if (ap->next->comment != DEV_DEVICE)    /* next is a comment, go here */
588                     break;
589         }
590     }
591
592     if (!ap)                                            /* didn't find a match */
593     {
594         for (ap = list; ap->next; ap = ap->next)        /* try for a matching comment */
595             if ((ap->comment != DEV_DEVICE) 
596                 && (ap->class == dev->class))           /* appropriate place? */
597                 break;
598     }                                                   /* or just put up with last */
599
600     return(ap);
601 }
602
603
604 /**
605  ** Insdev
606  **
607  ** Inserts a copy of (dev) at the appropriate point in (list)
608  **/
609 static void 
610 insdev(DEV_LIST *dev, DEV_LIST *list)
611 {
612     DEV_LIST    *lp,*ap;
613
614     lp = (DEV_LIST *)kmalloc(sizeof(DEV_LIST),M_DEVL,M_WAITOK);
615     bcopy(dev,lp,sizeof(DEV_LIST));                     /* create copied record */
616
617     ap = findspot(lp,list);                             /* find appropriate spot */
618     lp->next = ap->next;                                /* point to next */
619     if (ap->next)
620         ap->next->prev = lp;                            /* point next to new */
621     lp->prev = ap;                                      /* point new to current */
622     ap->next = lp;                                      /* and current to new */
623 }
624
625
626 /**
627  ** Movedev
628  **
629  ** Moves (dev) from its current list to an appropriate place in (list)
630  ** (dev) may not come from the top of a list, but it may from the bottom.
631  **/
632 static void 
633 movedev(DEV_LIST *dev, DEV_LIST *list)
634 {
635     DEV_LIST    *ap;
636
637     ap = findspot(dev,list);
638     dev->prev->next = dev->next;                        /* remove from old list */
639     if (dev->next)
640         dev->next->prev = dev->prev;
641     
642     dev->next = ap->next;                               /* insert in new list */
643     if (ap->next)
644         ap->next->prev = dev;                           /* point next to new */
645     dev->prev = ap;                                     /* point new to current */
646     ap->next = dev;                                     /* and current to new */
647 }
648
649
650 /**
651  ** Initlist
652  **
653  ** Initialises (*list) with the basic headings
654  **/
655 static void 
656 initlist(DEV_LIST **list)
657 {
658     int         i;
659
660     for(i = 0; devclass_names[i].name[0]; i++)          /* for each devtype name */
661     {
662         strcpy(scratch.name,devclass_names[i].name);
663         scratch.comment = DEV_ZOOMED;
664         scratch.class = devclass_names[i].number;
665         scratch.attrib = FLG_MANDATORY;                 /* can't be moved */
666         addev(&scratch,list);                           /* add to the list */
667     }
668 }
669
670
671 /**
672  ** savelist
673  **
674  ** Walks (list) and saves the settings of any entry marked as changed.
675  **
676  ** The device's active field is set according to (active).
677  **
678  ** Builds the uc_devlist used by kget to extract the changed device information.
679  ** The code for this was taken almost verbatim from the original module.
680  **/
681 static void
682 savelist(DEV_LIST *list, int active)
683 {
684     struct uc_device    *id_p,*id_pn;
685     char *name;
686
687     while (list)
688     {
689         if ((list->comment == DEV_DEVICE) &&            /* is a device */
690             (list->changed) &&                          /* has been changed */
691             (list->device != NULL)) {                   /* has an uc_device structure */
692
693             setdev(list,active);                        /* set the device itself */
694
695             id_pn = NULL;
696             for (id_p=uc_devlist; id_p; id_p=id_p->id_next) 
697             {                                           /* look on the list for it */
698                 if (id_p->id_id == list->device->id_id) 
699                 {
700                     name = list->device->id_name;
701                     id_pn = id_p->id_next;
702                     if (id_p->id_name)
703                             kfree(id_p->id_name, M_DEVL);
704                     bcopy(list->device,id_p,sizeof(struct uc_device));
705                     save_resource(list->device);
706                     id_p->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
707                     strcpy(id_p->id_name, name);
708                     id_pn->id_next = uc_devlist;
709                     id_p->id_next = id_pn;
710                     break;
711                 }
712             }
713             if (!id_pn)                                 /* not already on the list */
714             {
715                 name = list->device->id_name;
716                 id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
717                 bcopy(list->device,id_pn,sizeof(struct uc_device));
718                 save_resource(list->device);
719                 id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
720                 strcpy(id_pn->id_name, name);
721                 id_pn->id_next = uc_devlist;
722                 uc_devlist = id_pn;                     /* park at top of list */
723             }
724         }
725         list = list->next;
726     }
727 }
728
729
730 /**
731  ** nukelist
732  **
733  ** Frees all storage in use by a (list).
734  **/
735 static void 
736 nukelist(DEV_LIST *list)
737 {
738     DEV_LIST    *dp;
739
740     if (!list)
741         return;
742     while(list->prev)                                   /* walk to head of list */
743         list = list->prev;
744
745     while(list)
746     {
747         dp = list;
748         list = list->next;
749         kfree(dp,M_DEVL);
750     }
751 }
752
753
754 /**
755  ** prevent
756  **
757  ** Returns the previous entry in (list), skipping zoomed regions.  Returns NULL
758  ** if there is no previous entry. (Only possible if list->prev == NULL given the
759  ** premise that there is always a comment at the head of the list)
760  **/
761 static DEV_LIST *
762 prevent(DEV_LIST *list)
763 {
764     DEV_LIST    *dp;
765
766     if (!list)
767         return(NULL);
768     dp = list->prev;                    /* start back one */
769     while(dp)
770     {
771         if (dp->comment == DEV_ZOOMED)  /* previous section is zoomed */
772             return(dp);                 /* so skip to comment */
773         if (dp->comment == DEV_COMMENT) /* not zoomed */
774             return(list->prev);         /* one back as normal */
775         dp = dp->prev;                  /* backpedal */
776     }
777     return(dp);                         /* NULL, we can assume */
778 }
779
780
781 /**
782  ** nextent
783  **
784  ** Returns the next entry in (list), skipping zoomed regions.  Returns NULL
785  ** if there is no next entry. (Possible if the current entry is last, or
786  ** if the current entry is the last heading and it's collapsed)
787  **/
788 static DEV_LIST *
789 nextent(DEV_LIST *list)
790 {
791     DEV_LIST    *dp;
792
793     if (!list)
794         return(NULL);
795     if (list->comment != DEV_ZOOMED)    /* no reason to skip */
796         return(list->next);
797     dp = list->next;
798     while(dp)
799     {
800         if (dp->comment != DEV_DEVICE)  /* found another heading */
801             break;
802         dp = dp->next;
803     }
804     return(dp);                         /* back we go */
805 }
806     
807
808 /**
809  ** ofsent
810  **
811  ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist 
812  **/
813 static DEV_LIST *
814 ofsent(int ofs, DEV_LIST *list)
815 {
816     while (ofs-- && list)
817         list = nextent(list);
818     return(list);
819 }
820
821
822 /**
823  ** findconflict
824  **
825  ** Scans every element of (list) and sets the conflict tags appropriately
826  ** Returns the number of conflicts found.
827  **/
828 static int
829 findconflict(DEV_LIST *list)
830 {
831     int         count = 0;                      /* number of conflicts found */
832     DEV_LIST    *dp,*sp;
833
834     for (dp = list; dp; dp = dp->next)          /* over the whole list */
835     {
836         if (dp->comment != DEV_DEVICE)          /* comments don't usually conflict */
837             continue;
838
839         dp->conflicts = 0;                      /* assume the best */
840         for (sp = list; sp; sp = sp->next)      /* scan the entire list for conflicts */
841         {
842             if (sp->comment != DEV_DEVICE)      /* likewise */
843                 continue;
844
845             if (sp == dp)                       /* always conflict with itself */
846                 continue;
847
848             if ((dp->iobase > 0) &&             /* iobase conflict? */
849                 (dp->iobase == sp->iobase))
850                 dp->conflicts = 1;
851             if ((dp->irq > 0) &&                /* irq conflict? */
852                 (dp->irq == sp->irq))
853                 dp->conflicts = 1;
854             if ((dp->drq > 0) &&                /* drq conflict? */
855                 (dp->drq == sp->drq))
856                 dp->conflicts = 1;
857             if ((sp->maddr > 0) &&              /* maddr/msize conflict? */
858                 (dp->maddr > 0) &&
859                 (sp->maddr + ((sp->msize == 0) ? 1 : sp->msize) > dp->maddr) &&
860                 (dp->maddr + ((dp->msize == 0) ? 1 : dp->msize) > sp->maddr))
861                 dp->conflicts = 1;
862         }
863         count += dp->conflicts;                 /* count conflicts */
864     }
865     return(count);
866 }
867
868
869 /**
870  ** expandlist
871  **
872  ** Unzooms all headings in (list)
873  **/
874 static void
875 expandlist(DEV_LIST *list)
876 {
877     while(list)
878     {
879         if (list->comment == DEV_COMMENT)
880             list->comment = DEV_ZOOMED;
881         list = list->next;
882     }
883 }
884
885
886 /**
887  ** collapselist
888  **
889  ** Zooms all headings in (list)
890  **/
891 static void
892 collapselist(DEV_LIST *list)
893 {
894     while(list)
895     {
896         if (list->comment == DEV_ZOOMED)
897             list->comment = DEV_COMMENT;
898         list = list->next;
899     }
900 }
901
902
903 /**
904  ** Screen-manipulation stuff
905  **
906  ** This is the basic screen layout :
907  **
908  **     0    5   10   15   20   25   30   35   40   45   50   55   60   67   70   75
909  **     |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
910  **    +--------------------------------------------------------------------------------+
911  ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
912  ** 1 -| ........................                                    .......  ..  0x....|
913  ** 2 -| ........................                                    .......  ..  0x....|
914  ** 3 -| ........................                                    .......  ..  0x....|
915  ** 4 -| ........................                                    .......  ..  0x....|
916  ** 5 -| ........................                                    .......  ..  0x....|
917  ** 6 -| ........................                                    .......  ..  0x....|
918  ** 7 -| ........................                                    .......  ..  0x....|
919  ** 8 -| ........................                                    .......  ..  0x....|
920  ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
921  ** 10-| ........................                                    .......            |
922  ** 11-| ........................                                    .......            |
923  ** 12-| ........................                                    .......            |
924  ** 13-| ........................                                    .......            |
925  ** 14-| ........................                                    .......            |
926  ** 15-| ........................                                    .......            |
927  ** 16-| ........................                                    .......            |
928  ** 17-|------------------------------------------------------UP-DOWN-------------------|
929  ** 18-| Relevant parameters for the current device                                     |
930  ** 19-|                                                                                |
931  ** 20-|                                                                                |
932  ** 21-|--------------------------------------------------------------------------------|
933  ** 22-| Help texts go here                                                             |
934  ** 23-|                                                                                |
935  **    +--------------------------------------------------------------------------------+
936  **
937  ** Help texts
938  **
939  ** On a collapsed comment :
940  **
941  ** [Enter] Expand device list      [z]   Expand all lists
942  ** [TAB]   Change fields           [Q]   Save and Exit
943  **
944  ** On an expanded comment :
945  ** 
946  ** [Enter] Collapse device list    [Z]   Collapse all lists
947  ** [TAB]   Change fields           [Q]   Save and Exit
948  **
949  ** On a comment with no followers
950  **
951  ** 
952  ** [TAB]   Change fields           [Q]   Save and Exit
953  **
954  ** On a device in the active list
955  **
956  ** [Enter] Edit device parameters  [DEL] Disable device
957  ** [TAB]   Change fields           [Q]   Save and Exit             [?] Help
958  **
959  ** On a device in the inactive list
960  **
961  ** [Enter] Enable device
962  ** [TAB]   Change fields           [Q]   Save and Exit             [?] Help
963  **
964  ** While editing parameters
965  **
966  ** <parameter-specific help here>
967  ** [TAB]   Change fields           [Q]   Save device parameters
968  **/
969
970
971
972 /**
973  **
974  ** The base-level screen primitives :
975  **
976  ** bold()      - enter bold mode               \E[1m     (md)
977  ** inverse()   - enter inverse mode            \E[7m     (so)
978  ** normal()    - clear bold/inverse mode       \E[m      (se)
979  ** clear()     - clear the screen              \E[H\E[J  (ce)
980  ** move(x,y)   - move the cursor to x,y        \E[y;xH:  (cm)
981  **/
982
983 static void 
984 bold(void)
985 {
986     kprintf("\033[1m");
987 }
988
989 static void 
990 inverse(void)
991 {
992     kprintf("\033[7m");
993 }
994
995 static void 
996 normal(void)
997 {
998     kprintf("\033[m");
999 }
1000
1001 static void 
1002 clear(void)
1003 {
1004     normal();
1005     kprintf("\033[H\033[J");
1006 }
1007
1008 static void 
1009 move(int x, int y)
1010 {
1011     kprintf("\033[%d;%dH",y+1,x+1);
1012 }
1013
1014
1015 /**
1016  **
1017  ** High-level screen primitives :
1018  ** 
1019  ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1020  ** putxy(x,y,str)      - put (str) at (x,y), supports embedded formatting
1021  ** erase(x,y,w,h)      - clear the box (x,y,w,h)
1022  ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1023  ** putmsg(str)         - put (str) in the message area
1024  ** puthelp(str)        - put (str) in the upper helpline
1025  ** pad(str,len)        - pad (str) to (len) with spaces
1026  ** drawline(row,detail,list,inverse,*dhelp)
1027  **                     - draws a line for (*list) at (row) onscreen.  If (detail) is 
1028  **                       nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1029  **                       draw the line in inverse video, and display (*dhelp) on the
1030  **                       helpline.
1031  ** drawlist(row,num,detail,list)
1032  **                     - draw (num) entries from (list) at (row) onscreen, passile (detail)
1033  **                       through to drawline().
1034  ** showparams(dev)     - displays the relevant parameters for (dev) below the lists onscreen.
1035  ** yesno(str)          - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1036  ** redraw();           - Redraws the entire screen layout, including the 
1037  **                     - two list panels.
1038  **/
1039
1040 /** 
1041  ** putxy
1042  **   writes (str) at x,y onscreen
1043  ** putxyl
1044  **   writes up to (len) of (str) at x,y onscreen.
1045  **
1046  ** Supports embedded formatting :
1047  ** !i - inverse mode.
1048  ** !b - bold mode.
1049  ** !n - normal mode.
1050  **/
1051 static void 
1052 putxyl(int x, int y, char *str, int len)
1053 {
1054     move(x,y);
1055     normal();
1056
1057     while((*str) && (len--))
1058     {
1059         if (*str == '!')                /* format escape? */
1060         {
1061             switch(*(str+1))            /* depending on the next character */
1062             {
1063             case 'i':
1064                 inverse();
1065                 str +=2;                /* skip formatting */
1066                 len++;                  /* doesn't count for length */
1067                 break;
1068                 
1069             case 'b':
1070                 bold();
1071                 str  +=2;               /* skip formatting */
1072                 len++;                  /* doesn't count for length */
1073                 break;
1074
1075             case 'n':
1076                 normal();
1077                 str +=2;                /* skip formatting */
1078                 len++;                  /* doesn't count for length */
1079                 break;
1080                 
1081             default:
1082                 kprintf("%c", *str++);  /* not an escape */
1083             }
1084         }else{
1085             kprintf("%c", *str++);              /* emit the character */
1086         }
1087     }
1088 }
1089
1090 #define putxy(x,y,str)  putxyl(x,y,str,-1)
1091
1092
1093 /**
1094  ** erase
1095  **
1096  ** Erases the region (x,y,w,h)
1097  **/
1098 static void 
1099 erase(int x, int y, int w, int h)
1100 {
1101     int         i;
1102
1103     normal();
1104     for (i = 0; i < h; i++)
1105         putxyl(x,y++,spaces,w);
1106 }
1107
1108
1109 /** 
1110  ** txtbox
1111  **
1112  ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1113  ** putxy.  Lines are not wrapped, newlines must be forced with \n.
1114  **/
1115 static void 
1116 txtbox(int x, int y, int w, int h, char *str)
1117 {
1118     int         i = 0;
1119
1120     h--;
1121     while((str[i]) && h)
1122     {
1123         if (str[i] == '\n')                     /* newline */
1124         {
1125             putxyl(x,y,str,(i<w)?i:w);          /* write lesser of i or w */
1126             y++;                                /* move down */
1127             h--;                                /* room for one less */
1128             str += (i+1);                       /* skip first newline */
1129             i = 0;                              /* zero offset */
1130         }else{
1131             i++;                                /* next character */
1132         }
1133     }
1134     if (h)                                      /* end of string, not region */
1135         putxyl(x,y,str,w);
1136 }
1137
1138
1139 /**
1140  ** putmsg
1141  **
1142  ** writes (msg) in the helptext area
1143  **/
1144 static void 
1145 putmsg(char *msg)
1146 {
1147     erase(0,18,80,3);                           /* clear area */
1148     txtbox(0,18,80,3,msg);
1149 }
1150
1151
1152 /**
1153  ** puthelp
1154  **
1155  ** Writes (msg) in the helpline area
1156  **/
1157 static void 
1158 puthelp(char *msg)
1159 {
1160     erase(0,22,80,1);
1161     putxy(0,22,msg);
1162 }
1163
1164
1165 /**
1166  ** masterhelp
1167  **
1168  ** Draws the help message at the bottom of the screen
1169  **/
1170 static void
1171 masterhelp(char *msg)
1172 {
1173     erase(0,23,80,1);
1174     putxy(0,23,msg);
1175 }
1176
1177
1178 /**
1179  ** pad 
1180  **
1181  ** space-pads a (str) to (len) characters
1182  **/
1183 static void 
1184 pad(char *str, int len)
1185 {
1186     int         i;
1187
1188     for (i = 0; str[i]; i++)                    /* find the end of the string */
1189         ;
1190     if (i >= len)                               /* no padding needed */
1191         return;
1192     while(i < len)                              /* pad */
1193         str[i++] = ' ';
1194     str[i] = '\0';
1195 }
1196                                                    
1197
1198 /**
1199  ** drawline
1200  **
1201  ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1202  ** the port and IRQ fields if (detail) is nonzero.  If (inverse), in inverse video.
1203  **
1204  ** The text (dhelp) is displayed if the item is a normal device, otherwise
1205  ** help is shown for normal or zoomed comments
1206  **/
1207 static void 
1208 drawline(int row, int detail, DEV_LIST *list, int inverse, char *dhelp)
1209 {
1210     char        lbuf[90],nb[70],db[20],ib[16],pb[16];
1211     
1212     if (list->comment == DEV_DEVICE)
1213     {
1214         nb[0] = ' ';
1215         strncpy(nb+1,list->name,57);
1216     }else{
1217         strncpy(nb,list->name,58);
1218         if ((list->comment == DEV_ZOOMED) && (list->next))
1219             if (list->next->comment == DEV_DEVICE)      /* only mention if there's something hidden */
1220                 strcat(nb,"  (Collapsed)");
1221     }
1222     nb[58] = '\0';
1223     pad(nb,60);
1224     if (list->conflicts)                        /* device in conflict? */
1225     {
1226         if (inverse)
1227         {
1228             strcpy(nb+54," !nCONF!i ");         /* tag conflict, careful of length */
1229         }else{
1230             strcpy(nb+54," !iCONF!n ");         /* tag conflict, careful of length */
1231         }
1232     }
1233     if (list->comment == DEV_DEVICE)
1234     {
1235         ksprintf(db,"%s%d",list->dev,list->unit);
1236         pad(db,8);
1237     }else{
1238         strcpy(db,"        ");
1239     }
1240     if ((list->irq > 0) && detail && (list->comment == DEV_DEVICE))
1241     {
1242         ksprintf(ib," %d",list->irq);
1243         pad(ib,4);
1244     }else{
1245         strcpy(ib,"    ");
1246     }
1247     if ((list->iobase > 0) && detail && (list->comment == DEV_DEVICE))
1248     {
1249         ksprintf(pb,"0x%x",list->iobase);
1250         pad(pb,7);
1251     }else{
1252         strcpy(pb,"       ");
1253     }
1254
1255     ksprintf(lbuf,"  %s%s%s%s%s",inverse?"!i":"",nb,db,ib,pb);
1256
1257     putxyl(0,row,lbuf,80);
1258     if (dhelp)
1259     {
1260         switch(list->comment)
1261         {
1262         case DEV_DEVICE:        /* ordinary device */
1263             puthelp(dhelp);
1264             break;
1265         case DEV_COMMENT:
1266             puthelp("");
1267             if (list->next)
1268                 if (list->next->comment == DEV_DEVICE)
1269                     puthelp("  [!bEnter!n] Collapse device list    [!bC!n]    Collapse all lists");
1270             break;
1271         case DEV_ZOOMED:        
1272             puthelp("");
1273             if (list->next)
1274                 if (list->next->comment == DEV_DEVICE)
1275                     puthelp("  [!bEnter!n] Expand device list      [!bX!n]    Expand all lists");
1276             break;
1277         default:
1278             puthelp("  WARNING: This list entry corrupted!");
1279             break;
1280         }
1281     }
1282     move(0,row);                                /* put the cursor somewhere relevant */
1283 }
1284
1285
1286 /**
1287  ** drawlist
1288  **
1289  ** Displays (num) lines of the contents of (list) at (row), optionally
1290  ** displaying the port and IRQ fields as well if (detail) is nonzero.
1291  **/
1292 static void 
1293 drawlist(int row, int num, int detail, DEV_LIST *list)
1294 {
1295     int         ofs;
1296
1297     for(ofs = 0; ofs < num; ofs++)
1298     {
1299         if (list)
1300         {
1301             drawline(row+ofs,detail,list,0,NULL);       /* NULL -> don't draw empty help string */
1302             list = nextent(list);                       /* move down visible list */
1303         }else{
1304             erase(0,row+ofs,80,1);
1305         }
1306     }
1307 }
1308
1309
1310 /**
1311  ** redrawactive
1312  **
1313  ** Redraws the active list 
1314  **/
1315 static void
1316 redrawactive(void)
1317 {
1318     char        cbuf[16];
1319
1320     if (conflicts)
1321     {
1322         ksprintf(cbuf,"!i%d conflict%s-",conflicts,(conflicts>1)?"s":"");
1323         putxy(45,0,cbuf);
1324     }else{
1325         putxyl(45,0,lines,16);
1326     }
1327     drawlist(1,8,1,alist);                      /* draw device lists */
1328 }
1329
1330 /**
1331  ** redrawinactive
1332  **
1333  ** Redraws the inactive list 
1334  **/
1335 static void
1336 redrawinactive(void)
1337 {
1338     drawlist(10,7,0,ilist);                     /* draw device lists */
1339 }
1340
1341
1342 /**
1343  ** redraw
1344  **
1345  ** Clear the screen and redraw the entire layout
1346  **/
1347 static void 
1348 redraw(void)
1349 {
1350     clear();
1351     putxy(0,0,lines);
1352     putxy(3,0,"!bActive!n-!bDrivers");
1353     putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1354     putxy(0,9,lines);
1355     putxy(3,9,"!bInactive!n-!bDrivers");
1356     putxy(63,9,"!bDev");
1357     putxy(0,17,lines);
1358     putxy(0,21,lines);
1359     masterhelp("  [!bTAB!n]   Change fields           [!bQ!n]   Save and Exit             [!b?!n] Help");
1360
1361     redrawactive();
1362     redrawinactive();
1363 }
1364
1365
1366 /**
1367  ** yesnocancel
1368  **
1369  ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1370  ** 2 if they hit 'c' or 'C',  or 0 for 'n' or 'N'.
1371  **/
1372 static int
1373 yesnocancel(char *str)
1374 {
1375
1376     putmsg(str);
1377     for(;;)
1378         switch(kgetchar())
1379         {
1380         case -1:
1381         case 'n':
1382         case 'N':
1383             return(0);
1384             
1385         case 'y':
1386         case 'Y':
1387             return(1);
1388             
1389         case 'c':
1390         case 'C':
1391             return(2);
1392         }
1393 }
1394
1395
1396 /**
1397  ** showparams
1398  **
1399  ** Show device parameters in the region below the lists
1400  **
1401  **     0    5   10   15   20   25   30   35   40   45   50   55   60   67   70   75
1402  **     |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1403  **    +--------------------------------------------------------------------------------+
1404  ** 17-|--------------------------------------------------------------------------------|
1405  ** 18-| Port address : 0x0000     Memory address : 0x00000   Conflict allowed          |
1406  ** 19-| IRQ number   : 00         Memory size    : 0x0000                              |
1407  ** 20-| Flags        : 0x0000     DRQ number     : 00                                  |
1408  ** 21-|--------------------------------------------------------------------------------|
1409  **/
1410 static void 
1411 showparams(DEV_LIST *dev)
1412 {
1413     char        buf[80];
1414
1415     erase(0,18,80,3);                           /* clear area */
1416     if (!dev)
1417         return;
1418     if (dev->comment != DEV_DEVICE)
1419         return;
1420
1421
1422     if (dev->iobase > 0)
1423     {
1424         ksprintf(buf,"Port address : 0x%x",dev->iobase);
1425         putxy(1,18,buf);
1426     }
1427             
1428     if (dev->irq > 0)
1429     {
1430         ksprintf(buf,"IRQ number   : %d",dev->irq);
1431         putxy(1,19,buf);
1432     }
1433     ksprintf(buf,"Flags        : 0x%x",dev->flags);
1434     putxy(1,20,buf);
1435     if (dev->maddr > 0)
1436     {
1437         ksprintf(buf,"Memory address : 0x%x",dev->maddr);
1438         putxy(26,18,buf);
1439     }
1440     if (dev->msize > 0)
1441     {
1442         ksprintf(buf,"Memory size    : 0x%x",dev->msize);
1443         putxy(26,19,buf);
1444     }
1445
1446     if (dev->drq > 0)
1447     {
1448         ksprintf(buf,"DRQ number     : %d",dev->drq);
1449         putxy(26,20,buf);
1450     }
1451 }
1452
1453
1454 /**
1455  ** Editing functions for device parameters
1456  **
1457  ** editval(x,y,width,hex,min,max,val)  - Edit (*val) in a field (width) wide at (x,y)
1458  **                                       onscreen.  Refuse values outsise (min) and (max).
1459  ** editparams(dev)                     - Edit the parameters for (dev)
1460  **/
1461
1462
1463 #define VetRet(code)                                                    \
1464 {                                                                       \
1465     if ((i >= min) && (i <= max))       /* legit? */                    \
1466     {                                                                   \
1467         *val = i;                                                       \
1468         ksprintf(buf,hex?"0x%x":"%d",i);                                \
1469         putxy(hex?x-2:x,y,buf);                                         \
1470         return(code);                   /* all done and exit */         \
1471     }                                                                   \
1472     i = *val;                           /* restore original value */    \
1473     delta = 1;                          /* restore other stuff */       \
1474 }
1475
1476
1477 /**
1478  ** editval
1479  **
1480  ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1481  ** in a field (width) wide. (Allow one space)
1482  ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1483  **
1484  ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1485  **/
1486 static int 
1487 editval(int x, int y, int width, int hex, int min, int max, int *val, int ro)
1488 {
1489     int         i = *val;                       /* work with copy of the value */
1490     char        buf[2+11+1],tc[11+1];           /* display buffer, text copy */
1491     int         xp = 0;                         /* cursor offset into text copy */
1492     int         delta = 1;                      /* force redraw first time in */
1493     int         c;
1494     int         extended = 0;                   /* stage counter for extended key sequences */
1495
1496     if (hex)                                    /* we presume there's a leading 0x onscreen */
1497         putxy(x-2,y,"!i0x");                    /* coz there sure is now */
1498         
1499     for (;;)
1500     {
1501         if (delta)                              /* only update if necessary */
1502         {
1503             ksprintf(tc,hex?"%x":"%d",i);       /* make a text copy of the value */
1504             ksprintf(buf,"!i%s",tc);            /* format for printing */
1505             erase(x,y,width,1);                 /* clear the area */
1506             putxy(x,y,buf);                     /* write */
1507             xp = strlen(tc);                    /* cursor always at end */
1508             move(x+xp,y);                       /* position the cursor */
1509         }
1510
1511         c = kgetchar();
1512
1513         switch(extended)                        /* escape handling */
1514         {
1515         case 0:
1516             if (c == 0x1b)                      /* esc? */
1517             {
1518                 extended = 1;                   /* flag and spin */
1519                 continue;
1520             }
1521             extended = 0;
1522             break;                              /* nope, drop through */
1523         
1524         case 1:                                 /* there was an escape prefix */
1525             if (c == '[' || c == 'O')           /* second character in sequence */
1526             {
1527                 extended = 2;
1528                 continue;
1529             }
1530             if (c == 0x1b)
1531                 return(KEY_EXIT);               /* double esc exits */
1532             extended = 0;
1533             break;                              /* nup, not a sequence. */
1534
1535         case 2:
1536             extended = 0;
1537             switch(c)                           /* looks like the real McCoy */
1538             {
1539             case 'A':
1540                 VetRet(KEY_UP);                 /* leave if OK */
1541                 continue;
1542             case 'B':
1543                 VetRet(KEY_DOWN);               /* leave if OK */
1544                 continue;
1545             case 'C':
1546                 VetRet(KEY_RIGHT);              /* leave if OK */
1547                 continue;
1548             case 'D':
1549                 VetRet(KEY_LEFT);               /* leave if OK */
1550                 continue;
1551                 
1552             default:
1553                 continue;
1554             }
1555         }
1556     
1557         switch(c)
1558         {
1559         case '\t':                              /* trying to tab off */
1560             VetRet(KEY_TAB);                    /* verify and maybe return */
1561             break;
1562
1563         case -1:
1564         case 'q':
1565         case 'Q':
1566             VetRet(KEY_EXIT);
1567             break;
1568             
1569         case '\b':
1570         case '\177':                            /* BS or DEL */
1571             if (ro)                             /* readonly? */
1572             {
1573                 puthelp(" !iThis value cannot be edited (Press ESC)");
1574                 while(kgetchar() != 0x1b);      /* wait for key */
1575                 return(KEY_NULL);               /* spin */
1576             }
1577             if (xp)                             /* still something left to delete */
1578             {
1579                 i = (hex ? i/0x10u : i/10);     /* strip last digit */
1580                 delta = 1;                      /* force update */
1581             }
1582             break;
1583
1584         case 588:
1585             VetRet(KEY_UP);
1586             break;
1587
1588         case '\r':
1589         case '\n':
1590         case 596:
1591             VetRet(KEY_DOWN);
1592             break;
1593
1594         case 591:
1595             VetRet(KEY_LEFT);
1596             break;
1597
1598         case 593:
1599             VetRet(KEY_RIGHT);
1600             break;
1601                 
1602         default:
1603             if (ro)                             /* readonly? */
1604             {
1605                 puthelp(" !iThis value cannot be edited (Press ESC)");
1606                 while(kgetchar() != 0x1b);      /* wait for key */
1607                 return(KEY_NULL);               /* spin */
1608             }
1609             if (xp >= width)                    /* no room for more characters anyway */
1610                 break;
1611             if (hex)
1612             {
1613                 if ((c >= '0') && (c <= '9'))
1614                 {
1615                     i = i*0x10 + (c-'0');       /* update value */
1616                     delta = 1;
1617                     break;
1618                 }
1619                 if ((c >= 'a') && (c <= 'f'))
1620                 {
1621                     i = i*0x10 + (c-'a'+0xa);
1622                     delta = 1;
1623                     break;
1624                 }
1625                 if ((c >= 'A') && (c <= 'F'))
1626                 {
1627                     i = i*0x10 + (c-'A'+0xa);
1628                     delta = 1;
1629                     break;
1630                 }
1631             }else{
1632                 if ((c >= '0') && (c <= '9'))
1633                 {
1634                     i = i*10 + (c-'0');         /* update value */
1635                     delta = 1;                  /* force redraw */
1636                     break;
1637                 }
1638             }
1639             break;
1640         }
1641     }
1642 }
1643
1644
1645 /**
1646  ** editparams
1647  **
1648  ** Edit the parameters for (dev)
1649  **
1650  ** Note that it's _always_ possible to edit the flags, otherwise it might be
1651  ** possible for this to spin in an endless loop...
1652  **     0    5   10   15   20   25   30   35   40   45   50   55   60   67   70   75
1653  **     |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1654  **    +--------------------------------------------------------------------------------+
1655  ** 17-|--------------------------------------------------------------------------------|
1656  ** 18-| Port address : 0x0000     Memory address : 0x00000   Conflict allowed          |
1657  ** 19-| IRQ number   : 00         Memory size    : 0x0000                              |
1658  ** 20-| Flags        : 0x0000     DRQ number     : 00                                  |
1659  ** 21-|--------------------------------------------------------------------------------|
1660  **
1661  ** The "intelligence" in this function that hops around based on the directional
1662  ** returns from editval isn't very smart, and depends on the layout above.
1663  **/
1664 static void 
1665 editparams(DEV_LIST *dev)
1666 {
1667     int         ret;
1668     char        buf[16];                /* needs to fit the device name */
1669
1670     putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1671     ksprintf(buf,"!b%s",dev->dev);
1672     putxy(24,17,buf);
1673
1674     erase(1,22,80,1);
1675     for (;;)
1676     {
1677     ep_iobase:
1678         if (dev->iobase > 0)
1679         {
1680             puthelp("  IO Port address (Hexadecimal, 0x1-0xffff)");
1681             ret = editval(18,18,5,1,0x1,0xffff,&(dev->iobase),(dev->attrib & FLG_FIXIOBASE));
1682             switch(ret)
1683             {
1684             case KEY_EXIT:
1685                 goto ep_exit;
1686
1687             case KEY_RIGHT:
1688                 if (dev->maddr > 0)
1689                     goto ep_maddr;
1690                 break;
1691
1692             case KEY_TAB:
1693             case KEY_DOWN:
1694                 goto ep_irq;
1695             }
1696             goto ep_iobase;
1697         }
1698     ep_irq:
1699         if (dev->irq > 0)
1700         {
1701             puthelp("  Interrupt number (Decimal, 1-15)");
1702             ret = editval(16,19,3,0,1,15,&(dev->irq),(dev->attrib & FLG_FIXIRQ));
1703             switch(ret)
1704             {
1705             case KEY_EXIT:
1706                 goto ep_exit;
1707
1708             case KEY_RIGHT:
1709                 if (dev->msize > 0)
1710                     goto ep_msize;
1711                 break;
1712
1713             case KEY_UP:
1714                 if (dev->iobase > 0)
1715                     goto ep_iobase;
1716                 break;
1717
1718             case KEY_TAB:
1719             case KEY_DOWN:
1720                 goto ep_flags;
1721             }
1722             goto ep_irq;
1723         }
1724     ep_flags:
1725         puthelp("  Device-specific flag values.");
1726         ret = editval(18,20,8,1,INT_MIN,INT_MAX,&(dev->flags),0);
1727         switch(ret)
1728         {
1729         case KEY_EXIT:
1730             goto ep_exit;
1731
1732         case KEY_RIGHT:
1733             if (dev->drq > 0) 
1734                 goto ep_drq;
1735             break;
1736
1737         case KEY_UP:
1738             if (dev->irq > 0)
1739                 goto ep_irq;
1740             if (dev->iobase > 0)
1741                 goto ep_iobase;
1742             break;
1743
1744         case KEY_DOWN:
1745             if (dev->maddr > 0)
1746                 goto ep_maddr;
1747             if (dev->msize > 0)
1748                 goto ep_msize;
1749             if (dev->drq > 0)
1750                 goto ep_drq;
1751             break;
1752
1753         case KEY_TAB:
1754             goto ep_maddr;
1755         }
1756         goto ep_flags;
1757     ep_maddr:
1758         if (dev->maddr > 0)
1759         {
1760             puthelp("  Device memory start address (Hexadecimal, 0x1-0xfffff)");
1761             ret = editval(45,18,6,1,0x1,0xfffff,&(dev->maddr),(dev->attrib & FLG_FIXMADDR));
1762             switch(ret)
1763             {
1764             case KEY_EXIT:
1765                 goto ep_exit;
1766
1767             case KEY_LEFT:
1768                 if (dev->iobase > 0)
1769                     goto ep_iobase;
1770                 break;
1771
1772             case KEY_UP:
1773                 goto ep_flags;
1774
1775             case KEY_DOWN:
1776                 if (dev->msize > 0)
1777                     goto ep_msize;
1778                 if (dev->drq > 0)
1779                     goto ep_drq;
1780                 break;
1781
1782             case KEY_TAB:
1783                 goto ep_msize;
1784             }
1785             goto ep_maddr;
1786         }
1787     ep_msize:
1788         if (dev->msize > 0)
1789         {
1790             puthelp("  Device memory size (Hexadecimal, 0x1-0x10000)");
1791             ret = editval(45,19,5,1,0x1,0x10000,&(dev->msize),(dev->attrib & FLG_FIXMSIZE));
1792             switch(ret)
1793             {
1794             case KEY_EXIT:
1795                 goto ep_exit;
1796
1797             case KEY_LEFT:
1798                 if (dev->irq > 0)
1799                     goto ep_irq;
1800                 break;
1801
1802             case KEY_UP:
1803                 if (dev->maddr > 0)
1804                     goto ep_maddr;
1805                 goto ep_flags;
1806
1807             case KEY_DOWN:
1808                 if (dev->drq > 0)
1809                     goto ep_drq;
1810                 break;
1811
1812             case KEY_TAB:
1813                 goto ep_drq;
1814             }
1815             goto ep_msize;
1816         }
1817     ep_drq:
1818         if (dev->drq > 0)
1819         {
1820             puthelp("  Device DMA request number (Decimal, 1-7)");
1821             ret = editval(43,20,2,0,1,7,&(dev->drq),(dev->attrib & FLG_FIXDRQ));
1822             switch(ret)
1823             {
1824             case KEY_EXIT:
1825                 goto ep_exit;
1826
1827             case KEY_LEFT:
1828                 goto ep_flags;
1829
1830             case KEY_UP:
1831                 if (dev->msize > 0)
1832                     goto ep_msize;
1833                 if (dev->maddr > 0)
1834                     goto ep_maddr;
1835                 goto ep_flags;
1836
1837             case KEY_TAB:
1838                 goto ep_iobase;
1839             }
1840             goto ep_drq;
1841         }
1842     }
1843     ep_exit:
1844     dev->changed = 1;                                   /* mark as changed */
1845 }
1846
1847 static char *helptext[] =
1848 {
1849     "                Using the UserConfig kernel settings editor",
1850     "                -------------------------------------------",
1851     "",
1852     "VISUAL MODE:",
1853     "",
1854     "- - Layout -",
1855     "",
1856     "The screen displays a list of available drivers, divided into two",
1857     "scrolling lists: Active Drivers, and Inactive Drivers.  Each list is",
1858     "by default collapsed and can be expanded to show all the drivers",
1859     "available in each category.  The parameters for the currently selected",
1860     "driver are shown at the bottom of the screen.",
1861     "",
1862     "- - Moving around -",
1863     "",
1864     "To move in the current list, use the UP and DOWN cursor keys to select",
1865     "an item (the selected item will be highlighted).  If the item is a",
1866     "category name, you may alternatively expand or collapse the list of",
1867     "drivers for that category by pressing [!bENTER!n].  Once the category is",
1868     "expanded, you can select each driver in the same manner and either:",
1869     "",
1870     "  - change its parameters using [!bENTER!n]",
1871     "  - move it to the Inactive list using [!bDEL!n]",
1872     "",
1873     "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1874     "you need to move a driver from the Inactive list back to the Active",
1875     "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1876     "necessary, and press [!bENTER!n] -- the device will be moved back to",
1877     "its place in the Active list.",
1878     "",
1879     "- - Altering the list/parameters -",
1880     "",
1881     "Any drivers for devices not installed in your system should be moved",
1882     "to the Inactive list, until there are no remaining parameter conflicts",
1883     "between the drivers, as indicated at the top.",
1884     "",
1885     "Once the list of Active drivers only contains entries for the devices",
1886     "present in your system, you can set their parameters (Interrupt, DMA",
1887     "channel, I/O addresses).  To do this, select the driver and press",
1888     "[!bENTER!n]: it is now possible to edit the settings at the",
1889     "bottom of the screen.  Use [!bTAB!n] to change fields, and when you are",
1890     "finished, use [!bQ!n] to return to the list.",
1891     "",
1892     "- - Saving changes -",
1893     "",
1894     "When all settings seem correct, and you wish to proceed with the",
1895     "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1896     "confirm your choice.",
1897     "",
1898     NULL
1899 };
1900
1901
1902 /**
1903  ** helpscreen
1904  **
1905  ** Displays help text onscreen for people that are confused, using a simple
1906  ** pager.
1907  **/
1908 static void
1909 helpscreen(void) 
1910 {
1911     int         topline = 0;                    /* where we are in the text */
1912     int         line = 0;                       /* last line we displayed */
1913     int         c, delta = 1;
1914     char        prompt[80];
1915
1916     for (;;)                                    /* loop until user quits */
1917     {
1918         /* display help text */
1919         if (delta) 
1920         {
1921             clear();                            /* remove everything else */
1922             for (line = topline; 
1923                  (line < (topline + 24)) && (helptext[line]); 
1924                  line++)
1925                 putxy(0,line-topline,helptext[line]);
1926             delta = 0;
1927         }
1928         
1929         /* prompt */
1930         ksprintf(prompt,"!i --%s-- [U]p [D]own [Q]uit !n",helptext[line] ? "MORE" : "END");
1931         putxy(0,24,prompt);
1932         
1933         c = kgetchar();                         /* so what do they say? */
1934         
1935         switch (c)
1936         {
1937         case 'u':
1938         case 'U':
1939         case 'b':
1940         case 'B':                               /* wired into 'more' users' fingers */
1941             if (topline > 0)                    /* room to go up? */
1942             {
1943                 topline -= 24;
1944                 if (topline < 0)                /* don't go too far */
1945                     topline = 0;
1946                 delta = 1;
1947             }
1948             break;
1949
1950         case 'd':
1951         case 'D':
1952         case ' ':                               /* expected by most people */
1953             if (helptext[line])                 /* maybe more below? */
1954             {
1955                 topline += 24;
1956                 delta = 1;
1957             }
1958             break;
1959             
1960         case 'q':
1961         case 'Q':
1962             redraw();                           /* restore the screen */
1963             return;
1964         }
1965     }
1966 }
1967
1968
1969 /** 
1970  ** High-level control functions
1971  **/
1972
1973
1974 /**
1975  ** dolist
1976  **
1977  ** Handle user movement within (*list) in the region starting at (row) onscreen with
1978  ** (num) lines, starting at (*ofs) offset from row onscreen.
1979  ** Pass (detail) on to drawing routines.
1980  **
1981  ** If the user hits a key other than a cursor key, maybe return a code.
1982  **
1983  ** (*list) points to the device at the top line in the region, (*ofs) is the 
1984  ** position of the highlight within the region.  All routines below
1985  ** this take only a device and an absolute row : use ofsent() to find the 
1986  ** device, and add (*ofs) to (row) to find the absolute row.
1987  **/
1988 static int 
1989 dolist(int row, int num, int detail, int *ofs, DEV_LIST **list, char *dhelp)
1990 {
1991     int         extended = 0;
1992     int         c;
1993     DEV_LIST    *lp;
1994     int         delta = 1;
1995     
1996     for(;;)
1997     {
1998         if (delta)
1999         {
2000             showparams(ofsent(*ofs,*list));                             /* show device parameters */
2001             drawline(row+*ofs,detail,ofsent(*ofs,*list),1,dhelp);       /* highlight current line */
2002             delta = 0;
2003         }
2004
2005         c = kgetchar();                         /* get a character */
2006         if ((extended == 2) || (c==588) || (c==596))    /* console gives "alternative" codes */
2007         {
2008             extended = 0;                       /* no longer */
2009             switch(c)
2010             {
2011             case 588:                           /* syscons' idea of 'up' */
2012             case 'A':                           /* up */
2013                 if (*ofs)                       /* just a move onscreen */
2014                 {
2015                     drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);/* unhighlight current line */
2016                     (*ofs)--;                   /* move up */
2017                 }else{
2018                     lp = prevent(*list);        /* can we go up? */
2019                     if (!lp)                    /* no */
2020                         break;
2021                     *list = lp;                 /* yes, move up list */
2022                     drawlist(row,num,detail,*list);
2023                 }
2024                 delta = 1;
2025                 break;
2026
2027             case 596:                           /* dooby-do */
2028             case 'B':                           /* down */
2029                 lp = ofsent(*ofs,*list);        /* get current item */
2030                 if (!nextent(lp))
2031                     break;                      /* nothing more to move to */
2032                 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);   /* unhighlight current line */
2033                 if (*ofs < (num-1))             /* room to move onscreen? */
2034                 {
2035                     (*ofs)++;               
2036                 }else{
2037                     *list = nextent(*list);     /* scroll region down */
2038                     drawlist(row,num,detail,*list);
2039                 }               
2040                 delta = 1;
2041                 break;
2042             }
2043         }else{
2044             switch(c)
2045             {
2046             case '\033':
2047                 extended=1;
2048                 break;
2049                     
2050             case '[':                           /* cheat : always preceeds cursor move */
2051             case 'O':                           /* ANSI application key mode */
2052                 if (extended==1)
2053                     extended=2;
2054                 else
2055                     extended=0;
2056                 break;
2057                 
2058             case 'Q':
2059             case 'q':
2060                 return(KEY_EXIT);               /* user requests exit */
2061
2062             case '\r':                          
2063             case '\n':
2064                 return(KEY_DO);                 /* "do" something */
2065
2066             case '\b':
2067             case '\177':
2068             case 599:
2069                 return(KEY_DEL);                /* "delete" response */
2070
2071             case 'X':
2072             case 'x':
2073                 return(KEY_UNZOOM);             /* expand everything */
2074                 
2075             case 'C':
2076             case 'c':
2077                 return(KEY_ZOOM);               /* collapse everything */
2078
2079             case '\t':
2080                 drawline(row+*ofs,detail,ofsent(*ofs,*list),0,dhelp);   /* unhighlight current line */
2081                 return(KEY_TAB);                                /* "move" response */
2082                 
2083             case '\014':                        /* ^L, redraw */
2084                 return(KEY_REDRAW);
2085                 
2086             case '?':                           /* helptext */
2087                 return(KEY_HELP);
2088                 
2089             }
2090         }
2091     }           
2092 }
2093
2094
2095 /**
2096  ** visuserconfig
2097  ** 
2098  ** Do the fullscreen config thang
2099  **/
2100 static int
2101 visuserconfig(void)
2102 {
2103     int actofs = 0, inactofs = 0, mode = 0, ret = -1, i;
2104     DEV_LIST    *dp;
2105     
2106     initlist(&active);
2107     initlist(&inactive);
2108     alist = active;
2109     ilist = inactive;
2110
2111     getdevs();
2112
2113     conflicts = findconflict(active);           /* find conflicts in the active list only */
2114
2115     redraw();
2116
2117     for(;;)
2118     {
2119         switch(mode)
2120         {
2121         case 0:                                 /* active devices */
2122             ret = dolist(1,8,1,&actofs,&alist,
2123                          "  [!bEnter!n] Edit device parameters  [!bDEL!n] Disable device");
2124             switch(ret)
2125             {
2126             case KEY_TAB:
2127                 mode = 1;                       /* swap lists */
2128                 break;
2129
2130             case KEY_REDRAW:
2131                 redraw();
2132                 break;
2133
2134             case KEY_ZOOM:
2135                 alist = active;
2136                 actofs = 0;
2137                 expandlist(active);
2138                 redrawactive();
2139                 break;
2140
2141             case KEY_UNZOOM:
2142                 alist = active;
2143                 actofs = 0;
2144                 collapselist(active);
2145                 redrawactive();
2146                 break;
2147
2148             case KEY_DEL:
2149                 dp = ofsent(actofs,alist);      /* get current device */
2150                 if (dp)                         /* paranoia... */
2151                 {
2152                     if (dp->attrib & FLG_MANDATORY)     /* can't be deleted */
2153                         break;
2154                     if (dp == alist)            /* moving top item on list? */
2155                     {
2156                         if (dp->next)
2157                         {
2158                             alist = dp->next;   /* point list to non-moving item */
2159                         }else{
2160                             alist = dp->prev;   /* end of list, go back instead */
2161                         }
2162                     }else{
2163                         if (!dp->next)          /* moving last item on list? */
2164                             actofs--;
2165                     }
2166                     dp->conflicts = 0;          /* no conflicts on the inactive list */
2167                     movedev(dp,inactive);       /* shift to inactive list */
2168                     conflicts = findconflict(active);   /* update conflict tags */
2169                     dp->changed = 1;
2170                     redrawactive();                     /* redraw */
2171                     redrawinactive();
2172                 }
2173                 break;
2174                 
2175             case KEY_DO:                        /* edit device parameters */
2176                 dp = ofsent(actofs,alist);      /* get current device */
2177                 if (dp)                         /* paranoia... */
2178                 {
2179                     if (dp->comment == DEV_DEVICE)      /* can't edit comments, zoom? */
2180                     {
2181                         masterhelp("  [!bTAB!n]   Change fields           [!bQ!n]   Save device parameters");
2182                         editparams(dp);
2183                         masterhelp("  [!bTAB!n]   Change fields           [!bQ!n]   Save and Exit             [!b?!n] Help");
2184                         putxy(0,17,lines);
2185                         conflicts = findconflict(active);       /* update conflict tags */
2186                     }else{                              /* DO on comment = zoom */
2187                         switch(dp->comment)             /* Depends on current state */
2188                         {
2189                         case DEV_COMMENT:               /* not currently zoomed */
2190                             dp->comment = DEV_ZOOMED;
2191                             break;
2192
2193                         case DEV_ZOOMED:
2194                             dp->comment = DEV_COMMENT;
2195                             break;
2196                         }
2197                     }
2198                     redrawactive();
2199                 }
2200                 break;
2201             }
2202             break;
2203
2204         case 1:                                 /* inactive devices */
2205             ret = dolist(10,7,0,&inactofs,&ilist,
2206                          "  [!bEnter!n] Enable device                                   ");
2207             switch(ret)
2208             {
2209             case KEY_TAB:
2210                 mode = 0;
2211                 break;
2212
2213             case KEY_REDRAW:
2214                 redraw();
2215                 break;
2216
2217             case KEY_ZOOM:
2218                 ilist = inactive;
2219                 inactofs = 0;
2220                 expandlist(inactive);
2221                 redrawinactive();
2222                 break;
2223
2224             case KEY_UNZOOM:
2225                 ilist = inactive;
2226                 inactofs = 0;
2227                 collapselist(inactive);
2228                 redrawinactive();
2229                 break;
2230
2231             case KEY_DO:
2232                 dp = ofsent(inactofs,ilist);    /* get current device */
2233                 if (dp)                         /* paranoia... */
2234                 {
2235                     if (dp->comment == DEV_DEVICE)      /* can't move comments, zoom? */
2236                     {
2237                         if (dp == ilist)                /* moving top of list? */
2238                         {
2239                             if (dp->next)
2240                             {
2241                                 ilist = dp->next;       /* point list to non-moving item */
2242                             }else{
2243                                 ilist = dp->prev;       /* can't go down, go up instead */
2244                             }
2245                         }else{
2246                             if (!dp->next)              /* last entry on list? */
2247                                 inactofs--;             /* shift cursor up one */
2248                         }
2249
2250                         movedev(dp,active);             /* shift to active list */
2251                         conflicts = findconflict(active);       /* update conflict tags */
2252                         dp->changed = 1;
2253                         alist = dp;                     /* put at top and current */
2254                         actofs = 0;
2255                         while(dp->comment == DEV_DEVICE)
2256                             dp = dp->prev;              /* forcibly unzoom section */
2257                         dp ->comment = DEV_COMMENT;
2258                         mode = 0;                       /* and swap modes to follow it */
2259
2260                     }else{                              /* DO on comment = zoom */
2261                         switch(dp->comment)             /* Depends on current state */
2262                         {
2263                         case DEV_COMMENT:               /* not currently zoomed */
2264                             dp->comment = DEV_ZOOMED;
2265                             break;
2266
2267                         case DEV_ZOOMED:
2268                             dp->comment = DEV_COMMENT;
2269                             break;
2270                         }
2271                     }
2272                     redrawactive();                     /* redraw */
2273                     redrawinactive();
2274                 }
2275                 break;
2276
2277             default:                            /* nothing else relevant here */
2278                 break;
2279             }
2280             break;
2281         default:
2282             mode = 0;                           /* shouldn't happen... */
2283         }
2284
2285         /* handle returns that are the same for both modes */
2286         switch (ret) {
2287         case KEY_HELP:
2288             helpscreen();
2289             break;
2290             
2291         case KEY_EXIT:
2292             i = yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2293             switch(i)
2294             {
2295             case 2:                             /* cancel */
2296                 redraw();
2297                 break;
2298                 
2299             case 1:                             /* save and exit */
2300                 savelist(active,1);
2301                 savelist(inactive,0);
2302
2303             case 0:                             /* exit */
2304                 nukelist(active);               /* clean up after ourselves */
2305                 nukelist(inactive);
2306                 normal();
2307                 clear();
2308                 return(1);
2309             }
2310             break;
2311         }
2312     }
2313 }
2314 #endif /* VISUAL_USERCONFIG */
2315
2316 /*
2317  * Copyright (c) 1991 Regents of the University of California.
2318  * All rights reserved.
2319  * Copyright (c) 1994 Jordan K. Hubbard
2320  * All rights reserved.
2321  * Copyright (c) 1994 David Greenman
2322  * All rights reserved.
2323  *
2324  * Many additional changes by Bruce Evans
2325  *
2326  * This code is derived from software contributed by the
2327  * University of California Berkeley, Jordan K. Hubbard,
2328  * David Greenman and Bruce Evans.
2329  *
2330  * Redistribution and use in source and binary forms, with or without
2331  * modification, are permitted provided that the following conditions
2332  * are met:
2333  * 1. Redistributions of source code must retain the above copyright
2334  *    notice, this list of conditions and the following disclaimer.
2335  * 2. Redistributions in binary form must reproduce the above copyright
2336  *    notice, this list of conditions and the following disclaimer in the
2337  *    documentation and/or other materials provided with the distribution.
2338  * 3. All advertising materials mentioning features or use of this software
2339  *    must display the following acknowledgement:
2340  *      This product includes software developed by the University of
2341  *      California, Berkeley and its contributors.
2342  * 4. Neither the name of the University nor the names of its contributors
2343  *    may be used to endorse or promote products derived from this software
2344  *    without specific prior written permission.
2345  *
2346  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2347  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2348  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2350  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2351  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2352  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2353  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2354  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2355  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2356  * SUCH DAMAGE.
2357  *
2358  * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2359  */
2360
2361 #define PARM_DEVSPEC    0x1
2362 #define PARM_INT        0x2
2363 #define PARM_ADDR       0x3
2364 #define PARM_STRING     0x4
2365
2366 typedef struct _cmdparm {
2367     int type;
2368     union {
2369         struct uc_device *dparm;
2370         int iparm;
2371         union {
2372                 void *aparm;
2373                 const char *sparm;
2374         } u;
2375     } parm;
2376 } CmdParm;
2377
2378 typedef int (*CmdFunc)(CmdParm *);
2379
2380 typedef struct _cmd {
2381     char *name;
2382     CmdFunc handler;
2383     CmdParm *parms;
2384 } Cmd;
2385
2386
2387 #if 0
2388 static void lsscsi(void);
2389 static int list_scsi(CmdParm *);
2390 #endif
2391
2392 static int lsdevtab(struct uc_device *);
2393 static struct uc_device *find_device(char *, int);
2394 static struct uc_device *search_devtable(struct uc_device *, char *, int);
2395 static void cngets(char *, int);
2396 static Cmd *parse_cmd(char *);
2397 static int parse_args(const char *, CmdParm *);
2398 static int save_dev(struct uc_device *);
2399
2400 static int list_devices(CmdParm *);
2401 static int set_device_ioaddr(CmdParm *);
2402 static int set_device_irq(CmdParm *);
2403 static int set_device_drq(CmdParm *);
2404 static int set_device_iosize(CmdParm *);
2405 static int set_device_mem(CmdParm *);
2406 static int set_device_flags(CmdParm *);
2407 static int set_device_enable(CmdParm *);
2408 static int set_device_disable(CmdParm *);
2409 static int quitfunc(CmdParm *);
2410 static int helpfunc(CmdParm *);
2411 static int introfunc(CmdParm *);
2412
2413 #if NPNP > 0
2414 static int lspnp(void);
2415 static int set_pnp_parms(CmdParm *);
2416 #endif
2417
2418 static int lineno;
2419
2420 static CmdParm addr_parms[] = {
2421     { PARM_DEVSPEC, {} },
2422     { PARM_ADDR, {} },
2423     { -1, {} },
2424 };
2425
2426 static CmdParm int_parms[] = {
2427     { PARM_DEVSPEC, {} },
2428     { PARM_INT, {} },
2429     { -1, {} },
2430 };
2431
2432 static CmdParm dev_parms[] = {
2433     { PARM_DEVSPEC, {} },
2434     { -1, {} },
2435 };
2436
2437 #if NPNP > 0
2438 static CmdParm string_arg[] = {
2439     { PARM_STRING, {} },
2440     { -1, {} },
2441 };
2442 #endif
2443
2444 static Cmd CmdList[] = {
2445     { "?",      helpfunc,               NULL },         /* ? (help)     */
2446     { "di",     set_device_disable,     dev_parms },    /* disable dev  */
2447     { "dr",     set_device_drq,         int_parms },    /* drq dev #    */
2448     { "en",     set_device_enable,      dev_parms },    /* enable dev   */
2449     { "ex",     quitfunc,               NULL },         /* exit (quit)  */
2450     { "f",      set_device_flags,       int_parms },    /* flags dev mask */
2451     { "h",      helpfunc,               NULL },         /* help         */
2452     { "intro",  introfunc,              NULL },         /* intro screen */
2453     { "iom",    set_device_mem,         addr_parms },   /* iomem dev addr */
2454     { "ios",    set_device_iosize,      int_parms },    /* iosize dev size */
2455     { "ir",     set_device_irq,         int_parms },    /* irq dev #    */
2456     { "l",      list_devices,           NULL },         /* ls, list     */
2457 #if NPNP > 0
2458     { "pn",     set_pnp_parms,          string_arg },   /* pnp ... */
2459 #endif
2460     { "po",     set_device_ioaddr,      int_parms },    /* port dev addr */
2461     { "res",    (CmdFunc)cpu_reset,     NULL },         /* reset CPU    */
2462     { "q",      quitfunc,               NULL },         /* quit         */
2463 #if 0
2464     { "s",      list_scsi,              NULL },         /* scsi */
2465 #endif
2466 #ifdef VISUAL_USERCONFIG
2467     { "v",      (CmdFunc)visuserconfig, NULL },         /* visual mode */
2468 #endif
2469     { NULL,     NULL,                   NULL },
2470 };
2471
2472 void
2473 userconfig(void)
2474 {
2475     static char banner = 1;
2476     char input[80];
2477     int rval;
2478     Cmd *cmd;
2479
2480     load_devtab();
2481     init_config_script();
2482     while (1) {
2483
2484         /* Only display signon banner if we are about to go interactive */
2485         if (!has_config_script()) {
2486             if (!(boothowto & RB_CONFIG))
2487 #ifdef INTRO_USERCONFIG
2488                 banner = 0;
2489 #else
2490                 return;
2491 #endif
2492             if (banner) {
2493                 banner = 0;
2494                 kprintf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2495                        " Type \"help\" for help" 
2496 #ifdef VISUAL_USERCONFIG
2497                        " or \"visual\" to go to the visual\n"
2498                        " configuration interface (requires MGA/VGA display or\n"
2499                        " serial terminal capable of displaying ANSI graphics)"
2500 #endif
2501                        ".\n");
2502             }
2503         }
2504
2505         kprintf("config> ");
2506         cngets(input, 80);
2507         if (input[0] == '\0')
2508             continue;
2509         cmd = parse_cmd(input);
2510         if (!cmd) {
2511             kprintf("Invalid command or syntax.  Type `?' for help.\n");
2512             continue;
2513         }
2514         rval = (*cmd->handler)(cmd->parms);
2515         if (rval) {
2516             free_devtab();
2517             return;
2518         }
2519     }
2520 }
2521
2522 static Cmd *
2523 parse_cmd(char *cmd)
2524 {
2525     Cmd *cp;
2526
2527     for (cp = CmdList; cp->name; cp++) {
2528         int len = strlen(cp->name);
2529
2530         if (!strncmp(cp->name, cmd, len)) {
2531             while (*cmd && *cmd != ' ' && *cmd != '\t')
2532                 ++cmd;
2533             if (parse_args(cmd, cp->parms))
2534                 return NULL;
2535             else
2536                 return cp;
2537         }
2538     }
2539     return NULL;
2540 }
2541
2542 static int
2543 parse_args(const char *cmd, CmdParm *parms)
2544 {
2545     while (1) {
2546         char *ptr;
2547
2548         if (*cmd == ' ' || *cmd == '\t') {
2549             ++cmd;
2550             continue;
2551         }
2552         if (parms == NULL || parms->type == -1) {
2553                 if (*cmd == '\0')
2554                         return 0;
2555                 kprintf("Extra arg(s): %s\n", cmd);
2556                 return 1;
2557         }
2558         if (parms->type == PARM_DEVSPEC) {
2559             int i = 0;
2560             char devname[64];
2561             int unit = 0;
2562
2563             while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
2564               (*cmd >= '0' && *cmd <= '9')))
2565                 devname[i++] = *(cmd++);
2566             devname[i] = '\0';
2567             if (*cmd >= '0' && *cmd <= '9') {
2568                 unit = strtoul(cmd, &ptr, 10);
2569                 if (cmd == ptr) {
2570                     kprintf("Invalid device number\n");
2571                     /* XXX should print invalid token here and elsewhere. */
2572                     return 1;
2573                 }
2574                 /* XXX else should require end of token. */
2575                 cmd = ptr;
2576             }
2577             if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
2578                 kprintf("No such device: %s%d\n", devname, unit);
2579                 return 1;
2580             }
2581             ++parms;
2582             continue;
2583         }
2584         if (parms->type == PARM_INT) {
2585             parms->parm.iparm = strtoul(cmd, &ptr, 0);
2586             if (cmd == ptr) {
2587                 kprintf("Invalid numeric argument\n");
2588                 return 1;
2589             }
2590             cmd = ptr;
2591             ++parms;
2592             continue;
2593         }
2594         if (parms->type == PARM_ADDR) {
2595             parms->parm.u.aparm = (void *)(uintptr_t)strtoul(cmd, &ptr, 0);
2596             if (cmd == ptr) {
2597                 kprintf("Invalid address argument\n");
2598                 return 1;
2599             }
2600             cmd = ptr;
2601             ++parms;
2602             continue;
2603         }
2604         if (parms->type == PARM_STRING) {
2605             parms->parm.u.sparm = cmd;
2606             return 0;
2607         }
2608     }
2609     return 0;
2610 }
2611
2612 static int
2613 list_devices(CmdParm *parms)
2614 {
2615     lineno = 0;
2616     if (lsdevtab(uc_devtab)) return 0;
2617 #if NPNP > 0
2618     if (lspnp()) return 0;
2619 #endif
2620     return 0;
2621 }
2622
2623 static int
2624 set_device_ioaddr(CmdParm *parms)
2625 {
2626     parms[0].parm.dparm->id_iobase = parms[1].parm.iparm;
2627     save_dev(parms[0].parm.dparm);
2628     return 0;
2629 }
2630
2631 static int
2632 set_device_irq(CmdParm *parms)
2633 {
2634     unsigned irq;
2635
2636     irq = parms[1].parm.iparm;
2637     if (irq == 2) {
2638         kprintf("Warning: Remapping IRQ 2 to IRQ 9\n");
2639         irq = 9;
2640     }
2641     else if (irq != -1 && irq > 15) {
2642         kprintf("An IRQ > 15 would be invalid.\n");
2643         return 0;
2644     }
2645     parms[0].parm.dparm->id_irq = (irq < 16 ? 1 << irq : 0);
2646     save_dev(parms[0].parm.dparm);
2647     return 0;
2648 }
2649
2650 static int
2651 set_device_drq(CmdParm *parms)
2652 {
2653     unsigned drq;
2654
2655     /*
2656      * The bounds checking is just to ensure that the value can be printed
2657      * in 5 characters.  32768 gets converted to -32768 and doesn't fit.
2658      */
2659     drq = parms[1].parm.iparm;
2660     parms[0].parm.dparm->id_drq = (drq < 32768 ? drq : -1);
2661     save_dev(parms[0].parm.dparm);
2662     return 0;
2663 }
2664
2665 static int
2666 set_device_iosize(CmdParm *parms)
2667 {
2668     parms[0].parm.dparm->id_msize = parms[1].parm.iparm;
2669     save_dev(parms[0].parm.dparm);
2670     return 0;
2671 }
2672
2673 static int
2674 set_device_mem(CmdParm *parms)
2675 {
2676     parms[0].parm.dparm->id_maddr = parms[1].parm.u.aparm;
2677     save_dev(parms[0].parm.dparm);
2678     return 0;
2679 }
2680
2681 static int
2682 set_device_flags(CmdParm *parms)
2683 {
2684     parms[0].parm.dparm->id_flags = parms[1].parm.iparm;
2685     save_dev(parms[0].parm.dparm);
2686     return 0;
2687 }
2688
2689 static int
2690 set_device_enable(CmdParm *parms)
2691 {
2692     parms[0].parm.dparm->id_enabled = TRUE;
2693     save_dev(parms[0].parm.dparm);
2694     return 0;
2695 }
2696
2697 static int
2698 set_device_disable(CmdParm *parms)
2699 {
2700     parms[0].parm.dparm->id_enabled = FALSE;
2701     save_dev(parms[0].parm.dparm);
2702     return 0;
2703 }
2704
2705 #if NPNP > 0
2706
2707 static int
2708 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS)
2709 {
2710         int error=0;
2711
2712         if(!req->oldptr) {
2713                 /* Only sizing */
2714                 return(SYSCTL_OUT(req,0,sizeof(struct pnp_cinfo)*MAX_PNP_LDN));
2715         } else {
2716                 /*
2717                  * Output the pnp_ldn_overrides[] table.
2718                  */
2719                 error=sysctl_handle_opaque(oidp,&pnp_ldn_overrides,
2720                         sizeof(struct pnp_cinfo)*MAX_PNP_LDN,req);
2721                 if(error) return(error);
2722                 return(0);
2723         }
2724 }
2725
2726 SYSCTL_PROC( _machdep, OID_AUTO, uc_pnplist, CTLFLAG_RD,
2727         0, 0, sysctl_machdep_uc_pnplist, "A",
2728         "List of PnP overrides changed in UserConfig");
2729
2730 /*
2731  * this function sets the kernel table to override bios PnP
2732  * configuration.
2733  */
2734 static int      
2735 set_pnp_parms(CmdParm *parms)      
2736 {   
2737     u_long idx, val, ldn, csn;
2738     int i;
2739     char *q;
2740     const char *p = parms[0].parm.u.sparm;
2741     struct pnp_cinfo d;
2742
2743     csn=strtoul(p,&q, 0);
2744     ldn=strtoul(q,&q, 0);
2745     for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2746     if (csn < 1 || csn > MAX_PNP_CARDS || ldn >= MAX_PNP_LDN) {
2747         kprintf("bad csn/ldn %ld:%ld\n", csn, ldn);
2748         return 0;
2749     }
2750     for (i=0; i < MAX_PNP_LDN; i++) {
2751         if (pnp_ldn_overrides[i].csn == csn &&
2752             pnp_ldn_overrides[i].ldn == ldn)
2753                 break;
2754     }
2755     if (i==MAX_PNP_LDN) {
2756         for (i=0; i < MAX_PNP_LDN; i++) {
2757             if (pnp_ldn_overrides[i].csn <1 ||
2758                  pnp_ldn_overrides[i].csn > MAX_PNP_CARDS)
2759                  break;
2760         }
2761     }
2762     if (i==MAX_PNP_LDN) {
2763         kprintf("sorry, no PnP entries available, try delete one\n");
2764         return 0 ;
2765     }
2766     d = pnp_ldn_overrides[i] ;
2767     d.csn = csn;
2768     d.ldn = ldn ;
2769     while (*p) {
2770         idx = 0;
2771         val = 0;
2772         if (!strncmp(p,"irq",3)) {
2773             idx=strtoul(p+3,&q, 0);
2774             val=strtoul(q,&q, 0);
2775             if (idx >=0 && idx < 2) d.irq[idx] = val;
2776         } else if (!strncmp(p,"flags",5)) {
2777             idx=strtoul(p+5,&q, 0);
2778             d.flags = idx;
2779         } else if (!strncmp(p,"drq",3)) {
2780             idx=strtoul(p+3,&q, 0);
2781             val=strtoul(q,&q, 0);
2782             if (idx >=0 && idx < 2) d.drq[idx] = val;
2783         } else if (!strncmp(p,"port",4)) {
2784             idx=strtoul(p+4,&q, 0);
2785             val=strtoul(q,&q, 0);
2786             if (idx >=0 && idx < 8) d.port[idx] = val;
2787         } else if (!strncmp(p,"mem",3)) {
2788             idx=strtoul(p+3,&q, 0);
2789             val=strtoul(q,&q, 0);
2790             if (idx >=0 && idx < 4) d.mem[idx].base = val;
2791         } else if (!strncmp(p,"bios",4)) {
2792             q = p+ 4;
2793             d.override = 0 ;
2794         } else if (!strncmp(p,"os",2)) {
2795             q = p+2 ;
2796             d.override = 1 ;
2797         } else if (!strncmp(p,"disable",7)) {
2798             q = p+7 ;
2799             d.enable = 0 ;
2800         } else if (!strncmp(p,"enable",6)) {
2801             q = p+6;
2802             d.enable = 1 ;
2803         } else if (!strncmp(p,"delete",6)) {
2804             bzero(&pnp_ldn_overrides[i], sizeof (pnp_ldn_overrides[i]));
2805             if (i==0) pnp_ldn_overrides[i].csn = 255;/* not reinit */
2806             return 0;
2807         } else {
2808             kprintf("unknown command <%s>\n", p);
2809             break;
2810         }
2811         for (p=q; *p && (*p==' ' || *p=='\t'); p++) ;
2812     }
2813     pnp_ldn_overrides[i] = d ;
2814     return 0; 
2815 }
2816 #endif /* NPNP */
2817
2818 static int
2819 quitfunc(CmdParm *parms)
2820 {
2821     /*
2822      * If kernel config supplied, and we are parsing it, and -c also supplied,
2823      * ignore a quit command,  This provides a safety mechanism to allow
2824      * recovery from a damaged/buggy kernel config.
2825      */
2826     if ((boothowto & RB_CONFIG) && userconfig_boot_parsing)
2827         return 0;
2828     return 1;
2829 }
2830
2831 static int
2832 helpfunc(CmdParm *parms)
2833 {
2834     kprintf(
2835     "Command\t\t\tDescription\n"
2836     "-------\t\t\t-----------\n"
2837     "ls\t\t\tList currently configured devices\n"
2838     "port <devname> <addr>\tSet device port (i/o address)\n"
2839     "irq <devname> <number>\tSet device irq\n"
2840     "drq <devname> <number>\tSet device drq\n"
2841     "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2842     "iosize <devname> <size>\tSet device memory size\n"
2843     "flags <devname> <mask>\tSet device flags\n"
2844     "enable <devname>\tEnable device\n"
2845     "disable <devname>\tDisable device (will not be probed)\n");
2846 #if NPNP > 0
2847     kprintf(
2848     "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2849     "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2850     "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2851     "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2852     "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2853     "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2854 #endif
2855     kprintf(
2856     "quit\t\t\tExit this configuration utility\n"
2857     "reset\t\t\tReset CPU\n");
2858 #ifdef VISUAL_USERCONFIG
2859     kprintf("visual\t\t\tGo to fullscreen mode.\n");
2860 #endif
2861     kprintf(
2862     "help\t\t\tThis message\n\n"
2863     "Commands may be abbreviated to a unique prefix\n");
2864     return 0;
2865 }
2866
2867 #if defined (VISUAL_USERCONFIG)
2868 static void
2869 center(int y, char *str)
2870 {
2871     putxy((80 - strlen(str)) / 2, y, str);
2872 }
2873 #endif
2874
2875 static int
2876 introfunc(CmdParm *parms)
2877 {
2878 #if defined (VISUAL_USERCONFIG)
2879     int curr_item, first_time, extended = 0;
2880     static char *choices[] = {
2881         " Skip kernel configuration and continue with installation ",
2882         " Start kernel configuration in full-screen visual mode    ",
2883         " Start kernel configuration in CLI mode                   ",
2884     };
2885
2886     clear();
2887     center(2, "!bKernel Configuration Menu!n");
2888
2889     curr_item = 0;
2890     first_time = 1;
2891     while (1) {
2892         char tmp[80];
2893         int c, i;
2894
2895         if (!extended) { 
2896             for (i = 0; i < 3; i++) {
2897                 tmp[0] = '\0';
2898                 if (curr_item == i)
2899                     strcpy(tmp, "!i");
2900                 strcat(tmp, choices[i]);
2901                 if (curr_item == i)
2902                     strcat(tmp, "!n");
2903                 putxy(10, 5 + i, tmp);
2904             }
2905
2906             if (first_time) {
2907                 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
2908                 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
2909                 putxy(2, 12, "match your hardware configuration.");
2910                 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
2911                 putxy(2, 15, "(press Down-Arrow then ENTER).");
2912                 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
2913                 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
2914                 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
2915                 putxy(2, 21, "then simply press ENTER or Q now.");
2916                 first_time = 0;
2917             }
2918             
2919             move(0, 0); /* move the cursor out of the way */
2920         }
2921         c = kgetchar();
2922         if ((extended == 2) || (c == 588) || (c == 596)) {      /* console gives "alternative" codes */
2923             extended = 0;               /* no longer */
2924             switch (c) {
2925             case 588:
2926             case 'A':                           /* up */
2927                 if (curr_item > 0)
2928                     --curr_item;
2929                 break;
2930
2931             case 596:
2932             case 'B':                           /* down */
2933                 if (curr_item < 2)
2934                     ++curr_item;
2935                 break;
2936             }
2937         }
2938         else {
2939             switch(c) {
2940             case '\033':
2941                 extended = 1;
2942                 break;
2943                     
2944             case '[':                           /* cheat : always preceeds cursor move */
2945             case 'O':                           /* ANSI application key mode */
2946                 if (extended == 1)
2947                     extended = 2;
2948                 else
2949                     extended = 0;
2950                 break;
2951                 
2952             case -1:
2953             case 'Q':
2954             case 'q':
2955                 clear();
2956                 return 1;       /* user requests exit */
2957
2958             case '1':                           /* select an item */
2959             case 'S':
2960             case 's':
2961                 curr_item = 0;
2962                 break;
2963             case '2':
2964             case 'V':
2965             case 'v':
2966                 curr_item = 1;
2967                 break;
2968             case '3':
2969             case 'C':
2970             case 'c':
2971                 curr_item = 2;
2972                 break;
2973
2974             case 'U':                           /* up */
2975             case 'u':
2976             case 'P':
2977             case 'p':
2978                 if (curr_item > 0)
2979                     --curr_item;
2980                 break;
2981
2982             case 'D':                           /* down */
2983             case 'd':
2984             case 'N':
2985             case 'n':
2986                 if (curr_item < 2)
2987                     ++curr_item;
2988                 break;
2989
2990             case '\r':                          
2991             case '\n':
2992                 clear();
2993                 if (!curr_item)
2994                     return 1;
2995                 else if (curr_item == 1)
2996                     return visuserconfig();
2997                 else {
2998                     putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
2999                     /* enable quitfunc */
3000                     userconfig_boot_parsing=0;
3001                     move (0, 3);
3002                     boothowto |= RB_CONFIG;     /* force -c */
3003                     return 0;
3004                 }
3005                 break;
3006             }
3007         }
3008     }
3009 #else   /* !VISUAL_USERCONFIG */
3010     return 0;
3011 #endif  /* VISUAL_USERCONFIG */
3012 }
3013
3014 #if NPNP > 0
3015 static int
3016 lspnp(void)
3017 {
3018     struct pnp_cinfo *c;
3019     int i, first = 1;
3020
3021
3022     for (i=0; i< MAX_PNP_LDN; i++) {
3023         c = &pnp_ldn_overrides[i];
3024         if (c->csn >0 && c->csn != 255) {
3025             int pmax, mmax;
3026             static char pfmt[] =
3027                 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3028             static char mfmt[] =
3029                 "mem 0x%x 0x%x 0x%x 0x%x";
3030             char buf[256];
3031             if (lineno >= 23) {
3032                     if (!userconfig_boot_parsing) {
3033                             kprintf("<More> ");
3034                             if (kgetchar() == 'q') {
3035                                     kprintf("quit\n");
3036                                     return (1);
3037                             }
3038                             kprintf("\n");
3039                     }
3040                     lineno = 0;
3041             }
3042             if (lineno == 0 || first)
3043                 kprintf("CSN LDN conf en irqs  drqs others (PnP devices)\n");
3044             first = 0 ;
3045             kprintf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3046                 c->csn, c->ldn,
3047                 c->override ? "OS  ":"BIOS",
3048                 c->enable ? "Y":"N",
3049                 c->irq[0], c->irq[1], c->drq[0], c->drq[1]);
3050             if (c->flags)
3051                 kprintf("flags 0x%08lx ",c->flags);
3052             for (pmax = 7; pmax >=0 ; pmax--)
3053                 if (c->port[pmax]!=0) break;
3054             for (mmax = 3; mmax >=0 ; mmax--)
3055                 if (c->mem[mmax].base!=0) break;
3056             if (pmax>=0) {
3057                 strcpy(buf, pfmt);
3058                 buf[10 + 5*pmax]='\0';
3059                 kprintf(buf,
3060                     c->port[0], c->port[1], c->port[2], c->port[3],
3061                     c->port[4], c->port[5], c->port[6], c->port[7]);
3062             }
3063             if (mmax>=0) {
3064                 strcpy(buf, mfmt);
3065                 buf[8 + 5*mmax]='\0';
3066                 kprintf(buf,
3067                     c->mem[0].base, c->mem[1].base,
3068                     c->mem[2].base, c->mem[3].base);
3069             }
3070             kprintf("\n");
3071         }
3072     }
3073     return 0 ;
3074 }
3075 #endif /* NPNP */
3076                 
3077 static int
3078 lsdevtab(struct uc_device *dt)
3079 {
3080     for (; dt->id_id != 0; dt++) {
3081         char dname[80];
3082
3083         if (lineno >= 23) {
3084                 kprintf("<More> ");
3085                 if (!userconfig_boot_parsing) {
3086                         if (kgetchar() == 'q') {
3087                                 kprintf("quit\n");
3088                                 return (1);
3089                         }
3090                         kprintf("\n");
3091                 }
3092                 lineno = 0;
3093         }
3094         if (lineno == 0) {
3095                 kprintf(
3096 "Device   port       irq   drq   iomem   iosize   unit  flags      enab\n"
3097                     );
3098                 ++lineno;
3099         }
3100         ksprintf(dname, "%s%d", dt->id_name, dt->id_unit);
3101         kprintf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3102             dname, /* dt->id_id, dt->id_driver(by name), */ dt->id_iobase,
3103             ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr, dt->id_msize,
3104             /* dt->id_intr(by name), */ dt->id_unit, dt->id_flags,
3105             dt->id_enabled ? "Yes" : "No");
3106         ++lineno;
3107     }
3108     return(0);
3109 }
3110
3111 static void
3112 load_devtab(void)
3113 {
3114     int i, val;
3115     int count = resource_count();
3116     int id = 1;
3117     int dt;
3118     char *name;
3119     int unit;
3120
3121     uc_devtab = kmalloc(sizeof(struct uc_device)*(count + 1), M_DEVL,
3122         M_WAITOK | M_ZERO);
3123     dt = 0;
3124     for (i = 0; i < count; i++) {
3125         name = resource_query_name(i);
3126         unit = resource_query_unit(i);
3127         if (unit < 0)
3128             continue;   /* skip wildcards */
3129         uc_devtab[dt].id_id = id++;
3130         resource_int_value(name, unit, "port", &uc_devtab[dt].id_iobase);
3131         val = 0;
3132         resource_int_value(name, unit, "irq", &val);
3133         uc_devtab[dt].id_irq = (1 << val);
3134         resource_int_value(name, unit, "drq", &uc_devtab[dt].id_drq);
3135         resource_int_value(name, unit, "maddr",(int *)&uc_devtab[dt].id_maddr);
3136         resource_int_value(name, unit, "msize", &uc_devtab[dt].id_msize);
3137         uc_devtab[dt].id_unit = unit;
3138         resource_int_value(name, unit, "flags", &uc_devtab[dt].id_flags);
3139         val = 0;
3140         resource_int_value(name, unit, "disabled", &val);
3141         uc_devtab[dt].id_enabled = !val;
3142         uc_devtab[dt].id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3143         strcpy(uc_devtab[dt].id_name, name);
3144         dt++;
3145     }
3146 }
3147
3148 static void
3149 free_devtab(void)
3150 {
3151     int i;
3152     int count = resource_count();
3153
3154     for (i = 0; i < count; i++)
3155         if (uc_devtab[i].id_name)
3156             kfree(uc_devtab[i].id_name, M_DEVL);
3157     kfree(uc_devtab, M_DEVL);
3158 }
3159     
3160 static struct uc_device *
3161 find_device(char *devname, int unit)
3162 {
3163     struct uc_device *ret;
3164
3165     if ((ret = search_devtable(uc_devtab, devname, unit)) != NULL)
3166         return ret;
3167     return NULL;
3168 }
3169
3170 static struct uc_device *
3171 search_devtable(struct uc_device *dt, char *devname, int unit)
3172 {
3173     for (; dt->id_id != 0; dt++)
3174         if (!strcmp(dt->id_name, devname) && dt->id_unit == unit)
3175             return dt;
3176     return NULL;
3177 }
3178
3179 static void
3180 cngets(char *input, int maxin)
3181 {
3182     int c, nchars = 0;
3183
3184     while (1) {
3185         c = kgetchar();
3186         /* Treat ^H or ^? as backspace */
3187         if ((c == '\010' || c == '\177')) {
3188                 if (nchars) {
3189                         kprintf("\010 \010");
3190                         *--input = '\0', --nchars;
3191                 }
3192                 continue;
3193         }
3194         /* Treat ^U or ^X as kill line */
3195         else if ((c == '\025' || c == '\030')) {
3196                 while (nchars) {
3197                         kprintf("\010 \010");
3198                         *--input = '\0', --nchars;
3199                 }
3200                 continue;
3201         }
3202         kprintf("%c", c);
3203         if ((++nchars == maxin) || (c == '\n') || (c == '\r') || ( c == -1)) {
3204             *input = '\0';
3205             break;
3206         }
3207         *input++ = (u_char)c;
3208     }
3209 }
3210
3211
3212 #if 0
3213 /* scsi: Support for displaying configured SCSI devices.
3214  * There is no way to edit them, and this is inconsistent
3215  * with the ISA method.  This is here as a basis for further work.
3216  */
3217 static char *
3218 type_text(char *name)   /* XXX: This is bogus */
3219 {
3220         if (strcmp(name, "sd") == 0)
3221                 return "disk";
3222
3223         if (strcmp(name, "st") == 0)
3224                 return "tape";
3225
3226         return "device";
3227 }
3228
3229 id_put(char *desc, int id)
3230 {
3231     if (id != SCCONF_UNSPEC)
3232     {
3233         if (desc)
3234             kprintf("%s", desc);
3235
3236         if (id == SCCONF_ANY)
3237             kprintf("?");
3238         else
3239             kprintf("%d", id);
3240     }
3241 }
3242
3243 static void
3244 lsscsi(void)
3245 {
3246     int i;
3247
3248     kprintf("scsi: (can't be edited):\n");
3249
3250     for (i = 0; scsi_cinit[i].driver; i++)
3251     {
3252         id_put("controller scbus", scsi_cinit[i].scbus);
3253
3254         if (scsi_cinit[i].unit != -1)
3255         {
3256             kprintf(" at ");
3257             id_put(scsi_cinit[i].driver, scsi_cinit[i].unit);
3258         }
3259
3260         kprintf("\n");
3261     }
3262
3263     for (i = 0; scsi_dinit[i].name; i++)
3264     {
3265                 kprintf("%s ", type_text(scsi_dinit[i].name));
3266
3267                 id_put(scsi_dinit[i].name, scsi_dinit[i].unit);
3268                 id_put(" at scbus", scsi_dinit[i].cunit);
3269                 id_put(" target ", scsi_dinit[i].target);
3270                 id_put(" lun ", scsi_dinit[i].lun);
3271
3272                 if (scsi_dinit[i].flags)
3273                 kprintf(" flags 0x%x\n", scsi_dinit[i].flags);
3274
3275                 kprintf("\n");
3276     }
3277 }
3278
3279 static int
3280 list_scsi(CmdParm *parms)
3281 {
3282     lineno = 0;
3283     lsscsi();
3284     return 0;
3285 }
3286 #endif
3287
3288 static void
3289 save_resource(struct uc_device *idev)
3290 {
3291     char *name;
3292     int unit;
3293
3294     name = idev->id_name;
3295     unit = idev->id_unit;
3296     resource_set_int(name, unit, "port", idev->id_iobase);
3297     resource_set_int(name, unit, "irq", ffs(idev->id_irq) - 1);
3298     resource_set_int(name, unit, "drq", idev->id_drq);
3299     resource_set_int(name, unit, "maddr", (int)idev->id_maddr);
3300     resource_set_int(name, unit, "msize", idev->id_msize);
3301     resource_set_int(name, unit, "flags", idev->id_flags);
3302     resource_set_int(name, unit, "disabled", !idev->id_enabled);
3303 }
3304
3305 static int
3306 save_dev(struct uc_device *idev)
3307 {
3308         struct uc_device        *id_p,*id_pn;
3309         char *name = idev->id_name;
3310
3311         for (id_p = uc_devlist; id_p; id_p = id_p->id_next) {
3312                 if (id_p->id_id == idev->id_id) {
3313                         id_pn = id_p->id_next;
3314                         if (id_p->id_name)
3315                                 kfree(id_p->id_name, M_DEVL);
3316                         bcopy(idev,id_p,sizeof(struct uc_device));
3317                         save_resource(idev);
3318                         id_p->id_name = kmalloc(strlen(name)+1, M_DEVL,M_WAITOK);
3319                         strcpy(id_p->id_name, name);
3320                         id_p->id_next = id_pn;
3321                         return 1;
3322                 }
3323         }
3324         id_pn = kmalloc(sizeof(struct uc_device),M_DEVL,M_WAITOK);
3325         bcopy(idev,id_pn,sizeof(struct uc_device));
3326         save_resource(idev);
3327         id_pn->id_name = kmalloc(strlen(name) + 1, M_DEVL,M_WAITOK);
3328         strcpy(id_pn->id_name, name);
3329         id_pn->id_next = uc_devlist;
3330         uc_devlist = id_pn;
3331         return 0;
3332 }
3333
3334