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