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