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