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