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