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