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