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