3 ** Michael Smith, msmith@freebsd.org. All rights reserved.
5 ** This code contains a module marked :
7 * Copyright (c) 1991 Regents of the University of California.
9 * Copyright (c) 1994 Jordan K. Hubbard
10 * All rights reserved.
11 * Copyright (c) 1994 David Greenman
12 * All rights reserved.
14 * Many additional changes by Bruce Evans
16 * This code is derived from software contributed by the
17 * University of California Berkeley, Jordan K. Hubbard,
18 * David Greenman and Bruce Evans.
20 ** As such, it contains code subject to the above copyrights.
21 ** The module and its copyright can be found below.
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
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.
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.
49 ** $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
50 ** $DragonFly: src/sys/platform/pc32/i386/userconfig.c,v 1.11 2006/12/20 18:14:42 dillon Exp $
56 ** Kernel boot-time configuration manipulation tool for FreeBSD.
58 ** Two modes of operation are supported : the default is the line-editor mode,
59 ** the command "visual" invokes the fullscreen mode.
61 ** The line-editor mode is the old favorite from FreeBSD 2.0/20.05 &c., the
62 ** fullscreen mode requires syscons or a minimal-ansi serial console.
66 ** USERCONFIG, visual mode.
70 ** Look for "EDIT THIS LIST" to add to the list of known devices
73 ** There are a number of assumptions made in this code.
75 ** - That the console supports a minimal set of ANSI escape sequences
76 ** (See the screen manipulation section for a summary)
77 ** and has at least 24 rows.
78 ** - That values less than or equal to zero for any of the device
79 ** parameters indicate that the driver does not use the parameter.
80 ** - That flags are _always_ editable.
82 ** Devices marked as disabled are imported as such.
84 ** For this tool to be useful, the list of devices below _MUST_ be updated
85 ** when a new driver is brought into the kernel. It is not possible to
86 ** extract this information from the drivers in the kernel.
90 ** - Display _what_ a device conflicts with.
91 ** - Implement page up/down (as what?)
92 ** - Wizard mode (no restrictions)
93 ** - Find out how to put syscons back into low-intensity mode so that the
94 ** !b escape is useful on the console. (It seems to be that it actually
95 ** gets low/high intensity backwards. That looks OK.)
97 ** - Only display headings with devices under them. (difficult)
100 #include "opt_userconfig.h"
101 #define COMPAT_OLDISA /* get the definitions */
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/kernel.h>
106 #include <sys/malloc.h>
107 #include <sys/reboot.h>
108 #include <sys/linker.h>
109 #include <sys/sysctl.h>
111 #include <sys/cons.h>
113 #include <machine/md_var.h>
114 #include <machine/limits.h>
116 #define _BUS_ISA_ARCH_ISA_DEVICE_H_
122 #include <machine_base/isa/pnp.h>
125 static MALLOC_DEFINE(M_DEVL
, "uc_devlist", "uc_device lists in userconfig()");
127 #include <machine/uc_device.h>
128 static struct uc_device
*uc_devlist
; /* list read by kget to extract changes */
129 static struct uc_device
*uc_devtab
; /* fake uc_device table */
131 static int userconfig_boot_parsing
; /* set if we are reading from the boot instructions */
133 static void load_devtab(void);
134 static void free_devtab(void);
135 static void save_resource(struct uc_device
*);
138 sysctl_machdep_uc_devlist(SYSCTL_HANDLER_ARGS
)
140 struct uc_device
*id
;
148 error
+=sizeof(struct uc_device
)+8;
151 return(SYSCTL_OUT(req
,0,error
));
153 /* Output the data. The buffer is filled with consecutive
154 * struct uc_device and char buf[8], containing the name
155 * (not guaranteed to end with '\0').
159 error
=sysctl_handle_opaque(oidp
,id
,
160 sizeof(struct uc_device
),req
);
161 if(error
) return(error
);
162 strncpy(name
,id
->id_name
,8);
163 error
=sysctl_handle_opaque(oidp
,name
,
165 if(error
) return(error
);
172 SYSCTL_PROC( _machdep
, OID_AUTO
, uc_devlist
, CTLFLAG_RD
,
173 0, 0, sysctl_machdep_uc_devlist
, "A",
174 "List of ISA devices changed in UserConfig");
177 ** Obtain command input.
179 ** Initially, input is read from a possibly-loaded script.
180 ** At the end of the script, or if no script is supplied,
181 ** behaviour is determined by the RB_CONFIG (-c) flag. If
182 ** the flag is set, user input is read from the console; if
183 ** unset, the 'quit' command is invoked and userconfig
186 ** Note that quit commands encountered in the script will be
187 ** ignored if the RB_CONFIG flag is supplied.
189 static const char *config_script
;
190 static int config_script_size
; /* use of int for -ve magic value */
192 #define has_config_script() (config_script_size > 0)
195 init_config_script(void)
197 caddr_t autoentry
, autoattr
;
199 /* Look for loaded userconfig script */
200 autoentry
= preload_search_by_type("userconfig_script");
201 if (autoentry
!= NULL
) {
202 /* We have one, get size and data */
203 config_script_size
= 0;
204 if ((autoattr
= preload_search_info(autoentry
, MODINFO_SIZE
)) != NULL
)
205 config_script_size
= (size_t)*(u_int32_t
*)autoattr
;
206 config_script
= NULL
;
207 if ((autoattr
= preload_search_info(autoentry
, MODINFO_ADDR
)) != NULL
)
208 config_script
= *(const char **)autoattr
;
210 if ((config_script_size
== 0) || (config_script
== NULL
)) {
211 config_script_size
= 0;
212 config_script
= NULL
;
215 return has_config_script();
222 #ifdef INTRO_USERCONFIG
223 static int intro
= 0;
226 if (has_config_script())
228 /* Consume character from loaded userconfig script, display */
229 userconfig_boot_parsing
= 1;
232 config_script_size
--;
236 #ifdef INTRO_USERCONFIG
237 if (userconfig_boot_parsing
) {
238 if (!(boothowto
& RB_CONFIG
)) {
239 /* userconfig_script, !RB_CONFIG -> quit */
242 config_script
= "uit\n";
243 config_script_size
= strlen(config_script
);
244 /* userconfig_script will be 1 on the next pass */
247 /* userconfig_script, RB_CONFIG -> cngetc() */
250 if (!(boothowto
& RB_CONFIG
)) {
251 /* no userconfig_script, !RB_CONFIG -> show intro */
255 config_script
= "ntro\n";
256 config_script_size
= strlen(config_script
);
257 /* userconfig_script will be 1 on the next pass */
260 /* no userconfig_script, RB_CONFIG -> cngetc() */
263 #else /* !INTRO_USERCONFIG */
264 /* assert(boothowto & RB_CONFIG) */
265 #endif /* INTRO_USERCONFIG */
266 userconfig_boot_parsing
= 0;
275 #define TRUE (!FALSE)
278 #ifdef VISUAL_USERCONFIG
282 char dev
[16]; /* device basename */
283 char name
[60]; /* long name */
284 int attrib
; /* things to do with the device */
285 int class; /* device classification */
288 #define FLG_INVISIBLE (1<<0) /* device should not be shown */
289 #define FLG_MANDATORY (1<<1) /* device can be edited but not disabled */
290 #define FLG_FIXIRQ (1<<2) /* device IRQ cannot be changed */
291 #define FLG_FIXIOBASE (1<<3) /* device iobase cannot be changed */
292 #define FLG_FIXMADDR (1<<4) /* device maddr cannot be changed */
293 #define FLG_FIXMSIZE (1<<5) /* device msize cannot be changed */
294 #define FLG_FIXDRQ (1<<6) /* device DRQ cannot be changed */
295 #define FLG_FIXED (FLG_FIXIRQ|FLG_FIXIOBASE|FLG_FIXMADDR|FLG_FIXMSIZE|FLG_FIXDRQ)
296 #define FLG_IMMUTABLE (FLG_FIXED|FLG_MANDATORY)
298 #define CLS_STORAGE 1 /* storage devices */
299 #define CLS_NETWORK 2 /* network interfaces */
300 #define CLS_COMMS 3 /* serial, parallel ports */
301 #define CLS_INPUT 4 /* user input : mice, keyboards, joysticks etc */
302 #define CLS_MMEDIA 5 /* "multimedia" devices (sound, video, etc) */
303 #define CLS_MISC 255 /* none of the above */
312 static DEVCLASS_INFO devclass_names
[] = {
313 { "Storage : ", CLS_STORAGE
},
314 { "Network : ", CLS_NETWORK
},
315 { "Communications : ", CLS_COMMS
},
316 { "Input : ", CLS_INPUT
},
317 { "Multimedia : ", CLS_MMEDIA
},
318 { "Miscellaneous : ", CLS_MISC
},
322 /********************* EDIT THIS LIST **********************/
326 ** - Devices that shouldn't be seen or removed should be marked FLG_INVISIBLE.
327 ** - XXX The list below should be reviewed by the driver authors to verify
328 ** that the correct flags have been set for each driver, and that the
329 ** descriptions are accurate.
332 static DEV_INFO device_info
[] = {
333 /*---Name----- ---Description---------------------------------------------- */
334 {"adv", "AdvanSys SCSI narrow controller", 0, CLS_STORAGE
},
335 {"bt", "Buslogic SCSI controller", 0, CLS_STORAGE
},
336 {"aha", "Adaptec 154x SCSI controller", 0, CLS_STORAGE
},
337 {"aic", "Adaptec 152x SCSI and compatible sound cards", 0, CLS_STORAGE
},
338 {"nca", "ProAudio Spectrum SCSI and compatibles", 0, CLS_STORAGE
},
339 {"sea", "Seagate ST01/ST02 SCSI and compatibles", 0, CLS_STORAGE
},
340 {"stg", "TMC 18C30/18C50 based SCSI cards", 0, CLS_STORAGE
},
341 {"wdc", "IDE/ESDI/MFM disk controller", 0, CLS_STORAGE
},
342 {"ata", "ATA/ATAPI compatible disk controller", 0, CLS_STORAGE
},
343 {"fdc", "Floppy disk controller", FLG_FIXED
, CLS_STORAGE
},
344 {"mcd", "Mitsumi CD-ROM", 0, CLS_STORAGE
},
345 {"scd", "Sony CD-ROM", 0, CLS_STORAGE
},
346 {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE
},
347 {"wd", "IDE or ST506 compatible storage device", FLG_INVISIBLE
, CLS_STORAGE
},
348 {"ad", "ATA/ATAPI compatible storage device", FLG_INVISIBLE
, CLS_STORAGE
},
349 {"fd", "Floppy disk device", FLG_INVISIBLE
, CLS_STORAGE
},
351 {"cm", "SMC COM90Cx6-based Arcnet adapters", 0, CLS_NETWORK
},
352 {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK
},
353 {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK
},
354 {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK
},
355 {"ep", "3C509 Ethernet adapter", 0, CLS_NETWORK
},
356 {"ex", "Intel EtherExpress Pro/10 Ethernet adapter", 0, CLS_NETWORK
},
357 {"fe", "Fujitsu MB86960A/MB86965A Ethernet adapters", 0, CLS_NETWORK
},
358 {"ie", "AT&T Starlan 10 and EN100, 3C507, NI5210 Ethernet adapters",0,CLS_NETWORK
},
359 {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK
},
360 {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK
},
361 {"sn", "SMC/Megahertz Ethernet adapters", 0,CLS_NETWORK
},
362 {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK
},
363 {"rdp", "RealTek RTL8002 Pocket Ethernet", 0, CLS_NETWORK
},
364 {"sbni", "Granch SBNI12-xx adapters", 0, CLS_NETWORK
},
366 {"sio", "8250/16450/16550 Serial port", 0, CLS_COMMS
},
367 {"cx", "Cronyx/Sigma multiport sync/async adapter",0, CLS_COMMS
},
368 {"rc", "RISCom/8 multiport async adapter", 0, CLS_COMMS
},
369 {"cy", "Cyclades multiport async adapter", 0, CLS_COMMS
},
370 {"dgb", "Digiboard PC/Xe, PC/Xi async adapter", 0, CLS_COMMS
},
371 {"si", "Specialix SI/XIO/SX async adapter", 0, CLS_COMMS
},
372 {"stl", "Stallion EasyIO/Easy Connection 8/32 async adapter",0, CLS_COMMS
},
373 {"stli", "Stallion intelligent async adapter" ,0, CLS_COMMS
},
374 {"ppc", "Parallel Port chipset", 0, CLS_COMMS
},
375 {"gp", "National Instruments AT-GPIB/TNT driver", 0, CLS_COMMS
},
377 {"atkbdc", "Keyboard controller", FLG_INVISIBLE
, CLS_INPUT
},
378 {"atkbd", "Keyboard", FLG_FIXED
, CLS_INPUT
},
379 {"mse", "Microsoft Bus Mouse", 0, CLS_INPUT
},
380 {"psm", "PS/2 Mouse", FLG_FIXED
, CLS_INPUT
},
381 {"joy", "Joystick", FLG_FIXED
, CLS_INPUT
},
382 {"sc", "Syscons console driver", FLG_IMMUTABLE
, CLS_INPUT
},
384 {"sbc", "PCM Creative SoundBlaster/ESS/Avance sounce cards", 0,CLS_MMEDIA
},
385 {"gusc", "PCM Gravis UltraSound sound cards", 0, CLS_MMEDIA
},
386 {"pcm", "PCM Generic soundcard support", 0, CLS_MMEDIA
},
387 {"sb", "VOXWARE Soundblaster PCM (SB/Pro/16, ProAudio Spectrum)",0,CLS_MMEDIA
},
388 {"sbxvi", "VOXWARE Soundblaster 16", 0, CLS_MMEDIA
},
389 {"sbmidi", "VOXWARE Soundblaster MIDI interface", 0, CLS_MMEDIA
},
390 {"pas", "VOXWARE ProAudio Spectrum PCM and MIDI", 0, CLS_MMEDIA
},
391 {"gus", "VOXWARE Gravis Ultrasound, Ultrasound 16 and Ultrasound MAX",0,CLS_MMEDIA
},
392 {"gusxvi", "VOXWARE Gravis Ultrasound 16-bit PCM", 0, CLS_MMEDIA
},
393 {"gusmax", "VOXWARE Gravis Ultrasound MAX", 0, CLS_MMEDIA
},
394 {"mss", "VOXWARE Microsoft Sound System", 0, CLS_MMEDIA
},
395 {"opl", "VOXWARE OPL-2/3 FM, SB/Pro/16, ProAudio Spectrum",0,CLS_MMEDIA
},
396 {"mpu", "VOXWARE Roland MPU401 MIDI", 0, CLS_MMEDIA
},
397 {"sscape", "VOXWARE Ensoniq Soundscape MIDI interface", 0, CLS_MMEDIA
},
398 {"sscape_mss", "VOXWARE Ensoniq Soundscape PCM", 0, CLS_MMEDIA
},
399 {"uart", "VOXWARE 6850 MIDI UART", 0, CLS_MMEDIA
},
400 {"pca", "PC speaker PCM audio driver", FLG_FIXED
, CLS_MMEDIA
},
401 {"ctx", "Coretex-I frame grabber", 0, CLS_MMEDIA
},
402 {"spigot", "Creative Labs Video Spigot video capture", 0, CLS_MMEDIA
},
403 {"scc", "IBM Smart Capture Card", 0, CLS_MMEDIA
},
404 {"gsc", "Genius GS-4500 hand scanner", 0, CLS_MMEDIA
},
405 {"asc", "AmiScan scanner", 0, CLS_MMEDIA
},
407 {"apm", "Advanced Power Management", FLG_FIXED
, CLS_MISC
},
408 {"labpc", "National Instruments Lab-PC/Lab-PC+", 0, CLS_MISC
},
409 {"pcic", "PC-card controller", 0, CLS_MISC
},
410 {"npx", "Math coprocessor", FLG_IMMUTABLE
, CLS_MISC
},
411 {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE
, CLS_MISC
},
415 typedef struct _devlist_struct
418 int attrib
; /* flag values as per the FLG_* defines above */
419 int class; /* disk, etc as per the CLS_* defines above */
421 int iobase
,irq
,drq
,maddr
,msize
,unit
,flags
,id
;
422 int comment
; /* 0 = device, 1 = comment, 2 = collapsed comment */
423 int conflicts
; /* set/reset by findconflict, count of conflicts */
424 int changed
; /* nonzero if the device has been edited */
425 struct uc_device
*device
;
426 struct _devlist_struct
*prev
,*next
;
431 #define DEV_COMMENT 1
434 #define LIST_CURRENT (1<<0)
435 #define LIST_SELECTED (1<<1)
437 #define KEY_EXIT 0 /* return codes from dolist() and friends */
443 #define KEY_UP 5 /* these only returned from editval() */
447 #define KEY_NULL 9 /* this allows us to spin & redraw */
449 #define KEY_ZOOM 10 /* these for zoom all/collapse all */
450 #define KEY_UNZOOM 11
452 #define KEY_HELP 12 /* duh? */
454 static void redraw(void);
455 static void insdev(DEV_LIST
*dev
, DEV_LIST
*list
);
456 static int devinfo(DEV_LIST
*dev
);
457 static int visuserconfig(void);
459 static DEV_LIST
*active
= NULL
,*inactive
= NULL
; /* driver lists */
460 static DEV_LIST
*alist
,*ilist
; /* visible heads of the driver lists */
461 static DEV_LIST scratch
; /* scratch record */
462 static int conflicts
; /* total conflict count */
465 static char lines
[] = "--------------------------------------------------------------------------------";
466 static char spaces
[] = " ";
470 ** Device manipulation stuff : find, describe, configure.
476 ** Sets the device referenced by (*dev) to the parameters in the struct,
477 ** and the enable flag according to (enabled)
480 setdev(DEV_LIST
*dev
, int enabled
)
482 dev
->device
->id_iobase
= dev
->iobase
; /* copy happy */
483 dev
->device
->id_irq
= (u_short
)(dev
->irq
< 16 ? 1<<dev
->irq
: 0); /* IRQ is bitfield */
484 dev
->device
->id_drq
= (short)dev
->drq
;
485 dev
->device
->id_maddr
= (caddr_t
)dev
->maddr
;
486 dev
->device
->id_msize
= dev
->msize
;
487 dev
->device
->id_flags
= dev
->flags
;
488 dev
->device
->id_enabled
= enabled
;
495 ** Walk the kernel device tables and build the active and inactive lists
501 struct uc_device
*ap
;
503 ap
= uc_devtab
; /* pointer to array of devices */
504 for (i
= 0; ap
[i
].id_id
; i
++) /* for each device in this table */
506 scratch
.unit
= ap
[i
].id_unit
; /* device parameters */
507 strcpy(scratch
.dev
,ap
[i
].id_name
);
508 scratch
.iobase
= ap
[i
].id_iobase
;
509 scratch
.irq
= ffs(ap
[i
].id_irq
)-1;
510 scratch
.drq
= ap
[i
].id_drq
;
511 scratch
.maddr
= (int)ap
[i
].id_maddr
;
512 scratch
.msize
= ap
[i
].id_msize
;
513 scratch
.flags
= ap
[i
].id_flags
;
515 scratch
.comment
= DEV_DEVICE
; /* admin stuff */
516 scratch
.conflicts
= 0;
517 scratch
.device
= &ap
[i
]; /* save pointer for later reference */
519 if (!devinfo(&scratch
)) /* get more info on the device */
520 insdev(&scratch
,ap
[i
].id_enabled
?active
:inactive
);
528 ** Fill in (dev->name), (dev->attrib) and (dev->type) from the device_info array.
529 ** If the device is unknown, put it in the CLS_MISC class, with no flags.
531 ** If the device is marked "invisible", return nonzero; the caller should
532 ** not insert any such device into either list.
536 devinfo(DEV_LIST
*dev
)
540 for (i
= 0; device_info
[i
].class; i
++)
542 if (!strcmp(dev
->dev
,device_info
[i
].dev
))
544 if (device_info
[i
].attrib
& FLG_INVISIBLE
) /* forget we ever saw this one */
546 strcpy(dev
->name
,device_info
[i
].name
); /* get the name */
547 dev
->attrib
= device_info
[i
].attrib
;
548 dev
->class = device_info
[i
].class;
552 strcpy(dev
->name
,"Unknown device");
554 dev
->class = CLS_MISC
;
560 ** List manipulation stuff : add, move, initialise, free, traverse
562 ** Note that there are assumptions throughout this code that
563 ** the first entry in a list will never move. (assumed to be
571 ** appends a copy of (dev) to the end of (*list)
574 addev(DEV_LIST
*dev
, DEV_LIST
**list
)
579 lp
= (DEV_LIST
*)kmalloc(sizeof(DEV_LIST
),M_DEVL
,M_WAITOK
);
580 bcopy(dev
,lp
,sizeof(DEV_LIST
)); /* create copied record */
582 if (*list
) /* list exists */
586 ap
= ap
->next
; /* scoot to end of list */
590 }else{ /* list does not yet exist */
592 lp
->prev
= lp
->next
= NULL
; /* list now exists */
600 ** Finds the 'appropriate' place for (dev) in (list)
602 ** 'Appropriate' means in numeric order with other devices of the same type,
603 ** or in alphabetic order following a comment of the appropriate type.
604 ** or at the end of the list if an appropriate comment is not found. (this should
606 ** (Note that the appropriate point is never the top, but may be the bottom)
609 findspot(DEV_LIST
*dev
, DEV_LIST
*list
)
613 /* search for a previous instance of the same device */
614 for (ap
= list
; ap
; ap
= ap
->next
)
616 if (ap
->comment
!= DEV_DEVICE
) /* ignore comments */
618 if (!strcmp(dev
->dev
,ap
->dev
)) /* same base device */
620 if ((dev
->unit
<= ap
->unit
) /* belongs before (equal is bad) */
621 || !ap
->next
) /* or end of list */
623 ap
= ap
->prev
; /* back up one */
624 break; /* done here */
626 if (ap
->next
) /* if the next item exists */
628 if (ap
->next
->comment
!= DEV_DEVICE
) /* next is a comment */
630 if (strcmp(dev
->dev
,ap
->next
->dev
)) /* next is a different device */
636 if (!ap
) /* not sure yet */
638 /* search for a class that the device might belong to */
639 for (ap
= list
; ap
; ap
= ap
->next
)
641 if (ap
->comment
!= DEV_DEVICE
) /* look for simlar devices */
643 if (dev
->class != ap
->class) /* of same class too 8) */
645 if (strcmp(dev
->dev
,ap
->dev
) < 0) /* belongs before the current entry */
647 ap
= ap
->prev
; /* back up one */
648 break; /* done here */
650 if (ap
->next
) /* if the next item exists */
651 if (ap
->next
->comment
!= DEV_DEVICE
) /* next is a comment, go here */
656 if (!ap
) /* didn't find a match */
658 for (ap
= list
; ap
->next
; ap
= ap
->next
) /* try for a matching comment */
659 if ((ap
->comment
!= DEV_DEVICE
)
660 && (ap
->class == dev
->class)) /* appropriate place? */
662 } /* or just put up with last */
671 ** Inserts a copy of (dev) at the appropriate point in (list)
674 insdev(DEV_LIST
*dev
, DEV_LIST
*list
)
678 lp
= (DEV_LIST
*)kmalloc(sizeof(DEV_LIST
),M_DEVL
,M_WAITOK
);
679 bcopy(dev
,lp
,sizeof(DEV_LIST
)); /* create copied record */
681 ap
= findspot(lp
,list
); /* find appropriate spot */
682 lp
->next
= ap
->next
; /* point to next */
684 ap
->next
->prev
= lp
; /* point next to new */
685 lp
->prev
= ap
; /* point new to current */
686 ap
->next
= lp
; /* and current to new */
693 ** Moves (dev) from its current list to an appropriate place in (list)
694 ** (dev) may not come from the top of a list, but it may from the bottom.
697 movedev(DEV_LIST
*dev
, DEV_LIST
*list
)
701 ap
= findspot(dev
,list
);
702 dev
->prev
->next
= dev
->next
; /* remove from old list */
704 dev
->next
->prev
= dev
->prev
;
706 dev
->next
= ap
->next
; /* insert in new list */
708 ap
->next
->prev
= dev
; /* point next to new */
709 dev
->prev
= ap
; /* point new to current */
710 ap
->next
= dev
; /* and current to new */
717 ** Initialises (*list) with the basic headings
720 initlist(DEV_LIST
**list
)
724 for(i
= 0; devclass_names
[i
].name
[0]; i
++) /* for each devtype name */
726 strcpy(scratch
.name
,devclass_names
[i
].name
);
727 scratch
.comment
= DEV_ZOOMED
;
728 scratch
.class = devclass_names
[i
].number
;
729 scratch
.attrib
= FLG_MANDATORY
; /* can't be moved */
730 addev(&scratch
,list
); /* add to the list */
738 ** Walks (list) and saves the settings of any entry marked as changed.
740 ** The device's active field is set according to (active).
742 ** Builds the uc_devlist used by kget to extract the changed device information.
743 ** The code for this was taken almost verbatim from the original module.
746 savelist(DEV_LIST
*list
, int active
)
748 struct uc_device
*id_p
,*id_pn
;
753 if ((list
->comment
== DEV_DEVICE
) && /* is a device */
754 (list
->changed
) && /* has been changed */
755 (list
->device
!= NULL
)) { /* has an uc_device structure */
757 setdev(list
,active
); /* set the device itself */
760 for (id_p
=uc_devlist
; id_p
; id_p
=id_p
->id_next
)
761 { /* look on the list for it */
762 if (id_p
->id_id
== list
->device
->id_id
)
764 name
= list
->device
->id_name
;
765 id_pn
= id_p
->id_next
;
767 kfree(id_p
->id_name
, M_DEVL
);
768 bcopy(list
->device
,id_p
,sizeof(struct uc_device
));
769 save_resource(list
->device
);
770 id_p
->id_name
= kmalloc(strlen(name
) + 1, M_DEVL
,M_WAITOK
);
771 strcpy(id_p
->id_name
, name
);
772 id_pn
->id_next
= uc_devlist
;
773 id_p
->id_next
= id_pn
;
777 if (!id_pn
) /* not already on the list */
779 name
= list
->device
->id_name
;
780 id_pn
= kmalloc(sizeof(struct uc_device
),M_DEVL
,M_WAITOK
);
781 bcopy(list
->device
,id_pn
,sizeof(struct uc_device
));
782 save_resource(list
->device
);
783 id_pn
->id_name
= kmalloc(strlen(name
) + 1, M_DEVL
,M_WAITOK
);
784 strcpy(id_pn
->id_name
, name
);
785 id_pn
->id_next
= uc_devlist
;
786 uc_devlist
= id_pn
; /* park at top of list */
797 ** Frees all storage in use by a (list).
800 nukelist(DEV_LIST
*list
)
806 while(list
->prev
) /* walk to head of list */
821 ** Returns the previous entry in (list), skipping zoomed regions. Returns NULL
822 ** if there is no previous entry. (Only possible if list->prev == NULL given the
823 ** premise that there is always a comment at the head of the list)
826 prevent(DEV_LIST
*list
)
832 dp
= list
->prev
; /* start back one */
835 if (dp
->comment
== DEV_ZOOMED
) /* previous section is zoomed */
836 return(dp
); /* so skip to comment */
837 if (dp
->comment
== DEV_COMMENT
) /* not zoomed */
838 return(list
->prev
); /* one back as normal */
839 dp
= dp
->prev
; /* backpedal */
841 return(dp
); /* NULL, we can assume */
848 ** Returns the next entry in (list), skipping zoomed regions. Returns NULL
849 ** if there is no next entry. (Possible if the current entry is last, or
850 ** if the current entry is the last heading and it's collapsed)
853 nextent(DEV_LIST
*list
)
859 if (list
->comment
!= DEV_ZOOMED
) /* no reason to skip */
864 if (dp
->comment
!= DEV_DEVICE
) /* found another heading */
868 return(dp
); /* back we go */
875 ** Returns the (ofs)th entry down from (list), or NULL if it doesn't exist
878 ofsent(int ofs
, DEV_LIST
*list
)
880 while (ofs
-- && list
)
881 list
= nextent(list
);
889 ** Scans every element of (list) and sets the conflict tags appropriately
890 ** Returns the number of conflicts found.
893 findconflict(DEV_LIST
*list
)
895 int count
= 0; /* number of conflicts found */
898 for (dp
= list
; dp
; dp
= dp
->next
) /* over the whole list */
900 if (dp
->comment
!= DEV_DEVICE
) /* comments don't usually conflict */
903 dp
->conflicts
= 0; /* assume the best */
904 for (sp
= list
; sp
; sp
= sp
->next
) /* scan the entire list for conflicts */
906 if (sp
->comment
!= DEV_DEVICE
) /* likewise */
909 if (sp
== dp
) /* always conflict with itself */
912 if ((dp
->iobase
> 0) && /* iobase conflict? */
913 (dp
->iobase
== sp
->iobase
))
915 if ((dp
->irq
> 0) && /* irq conflict? */
916 (dp
->irq
== sp
->irq
))
918 if ((dp
->drq
> 0) && /* drq conflict? */
919 (dp
->drq
== sp
->drq
))
921 if ((sp
->maddr
> 0) && /* maddr/msize conflict? */
923 (sp
->maddr
+ ((sp
->msize
== 0) ? 1 : sp
->msize
) > dp
->maddr
) &&
924 (dp
->maddr
+ ((dp
->msize
== 0) ? 1 : dp
->msize
) > sp
->maddr
))
927 count
+= dp
->conflicts
; /* count conflicts */
936 ** Unzooms all headings in (list)
939 expandlist(DEV_LIST
*list
)
943 if (list
->comment
== DEV_COMMENT
)
944 list
->comment
= DEV_ZOOMED
;
953 ** Zooms all headings in (list)
956 collapselist(DEV_LIST
*list
)
960 if (list
->comment
== DEV_ZOOMED
)
961 list
->comment
= DEV_COMMENT
;
968 ** Screen-manipulation stuff
970 ** This is the basic screen layout :
972 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
973 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
974 ** +--------------------------------------------------------------------------------+
975 ** 0 -|---Active Drivers----------------------------xx Conflicts------Dev---IRQ--Port--|
976 ** 1 -| ........................ ....... .. 0x....|
977 ** 2 -| ........................ ....... .. 0x....|
978 ** 3 -| ........................ ....... .. 0x....|
979 ** 4 -| ........................ ....... .. 0x....|
980 ** 5 -| ........................ ....... .. 0x....|
981 ** 6 -| ........................ ....... .. 0x....|
982 ** 7 -| ........................ ....... .. 0x....|
983 ** 8 -| ........................ ....... .. 0x....|
984 ** 9 -|---Inactive Drivers--------------------------------------------Dev--------------|
985 ** 10-| ........................ ....... |
986 ** 11-| ........................ ....... |
987 ** 12-| ........................ ....... |
988 ** 13-| ........................ ....... |
989 ** 14-| ........................ ....... |
990 ** 15-| ........................ ....... |
991 ** 16-| ........................ ....... |
992 ** 17-|------------------------------------------------------UP-DOWN-------------------|
993 ** 18-| Relevant parameters for the current device |
996 ** 21-|--------------------------------------------------------------------------------|
997 ** 22-| Help texts go here |
999 ** +--------------------------------------------------------------------------------+
1003 ** On a collapsed comment :
1005 ** [Enter] Expand device list [z] Expand all lists
1006 ** [TAB] Change fields [Q] Save and Exit
1008 ** On an expanded comment :
1010 ** [Enter] Collapse device list [Z] Collapse all lists
1011 ** [TAB] Change fields [Q] Save and Exit
1013 ** On a comment with no followers
1016 ** [TAB] Change fields [Q] Save and Exit
1018 ** On a device in the active list
1020 ** [Enter] Edit device parameters [DEL] Disable device
1021 ** [TAB] Change fields [Q] Save and Exit [?] Help
1023 ** On a device in the inactive list
1025 ** [Enter] Enable device
1026 ** [TAB] Change fields [Q] Save and Exit [?] Help
1028 ** While editing parameters
1030 ** <parameter-specific help here>
1031 ** [TAB] Change fields [Q] Save device parameters
1038 ** The base-level screen primitives :
1040 ** bold() - enter bold mode \E[1m (md)
1041 ** inverse() - enter inverse mode \E[7m (so)
1042 ** normal() - clear bold/inverse mode \E[m (se)
1043 ** clear() - clear the screen \E[H\E[J (ce)
1044 ** move(x,y) - move the cursor to x,y \E[y;xH: (cm)
1069 printf("\033[H\033[J");
1075 printf("\033[%d;%dH",y
+1,x
+1);
1081 ** High-level screen primitives :
1083 ** putxyl(x,y,str,len) - put (len) bytes of (str) at (x,y), supports embedded formatting
1084 ** putxy(x,y,str) - put (str) at (x,y), supports embedded formatting
1085 ** erase(x,y,w,h) - clear the box (x,y,w,h)
1086 ** txtbox(x,y,w,y,str) - put (str) in a region at (x,y,w,h)
1087 ** putmsg(str) - put (str) in the message area
1088 ** puthelp(str) - put (str) in the upper helpline
1089 ** pad(str,len) - pad (str) to (len) with spaces
1090 ** drawline(row,detail,list,inverse,*dhelp)
1091 ** - draws a line for (*list) at (row) onscreen. If (detail) is
1092 ** nonzero, include port, IRQ and maddr, if (inverse) is nonzero,
1093 ** draw the line in inverse video, and display (*dhelp) on the
1095 ** drawlist(row,num,detail,list)
1096 ** - draw (num) entries from (list) at (row) onscreen, passile (detail)
1097 ** through to drawline().
1098 ** showparams(dev) - displays the relevant parameters for (dev) below the lists onscreen.
1099 ** yesno(str) - displays (str) in the message area, and returns nonzero on 'y' or 'Y'
1100 ** redraw(); - Redraws the entire screen layout, including the
1101 ** - two list panels.
1106 ** writes (str) at x,y onscreen
1108 ** writes up to (len) of (str) at x,y onscreen.
1110 ** Supports embedded formatting :
1111 ** !i - inverse mode.
1113 ** !n - normal mode.
1116 putxyl(int x
, int y
, char *str
, int len
)
1121 while((*str
) && (len
--))
1123 if (*str
== '!') /* format escape? */
1125 switch(*(str
+1)) /* depending on the next character */
1129 str
+=2; /* skip formatting */
1130 len
++; /* doesn't count for length */
1135 str
+=2; /* skip formatting */
1136 len
++; /* doesn't count for length */
1141 str
+=2; /* skip formatting */
1142 len
++; /* doesn't count for length */
1146 cnputc(*str
++); /* not an escape */
1149 cnputc(*str
++); /* emit the character */
1154 #define putxy(x,y,str) putxyl(x,y,str,-1)
1160 ** Erases the region (x,y,w,h)
1163 erase(int x
, int y
, int w
, int h
)
1168 for (i
= 0; i
< h
; i
++)
1169 putxyl(x
,y
++,spaces
,w
);
1176 ** Writes (str) into the region (x,y,w,h), supports embedded formatting using
1177 ** putxy. Lines are not wrapped, newlines must be forced with \n.
1180 txtbox(int x
, int y
, int w
, int h
, char *str
)
1185 while((str
[i
]) && h
)
1187 if (str
[i
] == '\n') /* newline */
1189 putxyl(x
,y
,str
,(i
<w
)?i
:w
); /* write lesser of i or w */
1190 y
++; /* move down */
1191 h
--; /* room for one less */
1192 str
+= (i
+1); /* skip first newline */
1193 i
= 0; /* zero offset */
1195 i
++; /* next character */
1198 if (h
) /* end of string, not region */
1206 ** writes (msg) in the helptext area
1211 erase(0,18,80,3); /* clear area */
1212 txtbox(0,18,80,3,msg
);
1219 ** Writes (msg) in the helpline area
1232 ** Draws the help message at the bottom of the screen
1235 masterhelp(char *msg
)
1245 ** space-pads a (str) to (len) characters
1248 pad(char *str
, int len
)
1252 for (i
= 0; str
[i
]; i
++) /* find the end of the string */
1254 if (i
>= len
) /* no padding needed */
1256 while(i
< len
) /* pad */
1265 ** Displays entry (ofs) of (list) in region at (row) onscreen, optionally displaying
1266 ** the port and IRQ fields if (detail) is nonzero. If (inverse), in inverse video.
1268 ** The text (dhelp) is displayed if the item is a normal device, otherwise
1269 ** help is shown for normal or zoomed comments
1272 drawline(int row
, int detail
, DEV_LIST
*list
, int inverse
, char *dhelp
)
1274 char lbuf
[90],nb
[70],db
[20],ib
[16],pb
[16];
1276 if (list
->comment
== DEV_DEVICE
)
1279 strncpy(nb
+1,list
->name
,57);
1281 strncpy(nb
,list
->name
,58);
1282 if ((list
->comment
== DEV_ZOOMED
) && (list
->next
))
1283 if (list
->next
->comment
== DEV_DEVICE
) /* only mention if there's something hidden */
1284 strcat(nb
," (Collapsed)");
1288 if (list
->conflicts
) /* device in conflict? */
1292 strcpy(nb
+54," !nCONF!i "); /* tag conflict, careful of length */
1294 strcpy(nb
+54," !iCONF!n "); /* tag conflict, careful of length */
1297 if (list
->comment
== DEV_DEVICE
)
1299 ksprintf(db
,"%s%d",list
->dev
,list
->unit
);
1304 if ((list
->irq
> 0) && detail
&& (list
->comment
== DEV_DEVICE
))
1306 ksprintf(ib
," %d",list
->irq
);
1311 if ((list
->iobase
> 0) && detail
&& (list
->comment
== DEV_DEVICE
))
1313 ksprintf(pb
,"0x%x",list
->iobase
);
1319 ksprintf(lbuf
," %s%s%s%s%s",inverse
?"!i":"",nb
,db
,ib
,pb
);
1321 putxyl(0,row
,lbuf
,80);
1324 switch(list
->comment
)
1326 case DEV_DEVICE
: /* ordinary device */
1332 if (list
->next
->comment
== DEV_DEVICE
)
1333 puthelp(" [!bEnter!n] Collapse device list [!bC!n] Collapse all lists");
1338 if (list
->next
->comment
== DEV_DEVICE
)
1339 puthelp(" [!bEnter!n] Expand device list [!bX!n] Expand all lists");
1342 puthelp(" WARNING: This list entry corrupted!");
1346 move(0,row
); /* put the cursor somewhere relevant */
1353 ** Displays (num) lines of the contents of (list) at (row), optionally displaying the
1354 ** port and IRQ fields as well if (detail) is nonzero
1356 ** printf in the kernel is essentially useless, so we do most of the hard work ourselves here.
1359 drawlist(int row
, int num
, int detail
, DEV_LIST
*list
)
1363 for(ofs
= 0; ofs
< num
; ofs
++)
1367 drawline(row
+ofs
,detail
,list
,0,NULL
); /* NULL -> don't draw empty help string */
1368 list
= nextent(list
); /* move down visible list */
1370 erase(0,row
+ofs
,80,1);
1379 ** Redraws the active list
1388 ksprintf(cbuf
,"!i%d conflict%s-",conflicts
,(conflicts
>1)?"s":"");
1391 putxyl(45,0,lines
,16);
1393 drawlist(1,8,1,alist
); /* draw device lists */
1399 ** Redraws the inactive list
1402 redrawinactive(void)
1404 drawlist(10,7,0,ilist
); /* draw device lists */
1411 ** Clear the screen and redraw the entire layout
1418 putxy(3,0,"!bActive!n-!bDrivers");
1419 putxy(63,0,"!bDev!n---!bIRQ!n--!bPort");
1421 putxy(3,9,"!bInactive!n-!bDrivers");
1422 putxy(63,9,"!bDev");
1425 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
1435 ** Put (str) in the message area, and return 1 if the user hits 'y' or 'Y',
1436 ** 2 if they hit 'c' or 'C', or 0 for 'n' or 'N'.
1439 yesnocancel(char *str
)
1465 ** Show device parameters in the region below the lists
1467 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1468 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1469 ** +--------------------------------------------------------------------------------+
1470 ** 17-|--------------------------------------------------------------------------------|
1471 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1472 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1473 ** 20-| Flags : 0x0000 DRQ number : 00 |
1474 ** 21-|--------------------------------------------------------------------------------|
1477 showparams(DEV_LIST
*dev
)
1481 erase(0,18,80,3); /* clear area */
1484 if (dev
->comment
!= DEV_DEVICE
)
1488 if (dev
->iobase
> 0)
1490 ksprintf(buf
,"Port address : 0x%x",dev
->iobase
);
1496 ksprintf(buf
,"IRQ number : %d",dev
->irq
);
1499 ksprintf(buf
,"Flags : 0x%x",dev
->flags
);
1503 ksprintf(buf
,"Memory address : 0x%x",dev
->maddr
);
1508 ksprintf(buf
,"Memory size : 0x%x",dev
->msize
);
1514 ksprintf(buf
,"DRQ number : %d",dev
->drq
);
1521 ** Editing functions for device parameters
1523 ** editval(x,y,width,hex,min,max,val) - Edit (*val) in a field (width) wide at (x,y)
1524 ** onscreen. Refuse values outsise (min) and (max).
1525 ** editparams(dev) - Edit the parameters for (dev)
1529 #define VetRet(code) \
1531 if ((i >= min) && (i <= max)) /* legit? */ \
1534 ksprintf(buf,hex?"0x%x":"%d",i); \
1535 putxy(hex?x-2:x,y,buf); \
1536 return(code); /* all done and exit */ \
1538 i = *val; /* restore original value */ \
1539 delta = 1; /* restore other stuff */ \
1546 ** Edit (*val) at (x,y) in (hex)?hex:decimal mode, allowing values between (min) and (max)
1547 ** in a field (width) wide. (Allow one space)
1548 ** If (ro) is set, we're in "readonly" mode, so disallow edits.
1550 ** Return KEY_TAB on \t, KEY_EXIT on 'q'
1553 editval(int x
, int y
, int width
, int hex
, int min
, int max
, int *val
, int ro
)
1555 int i
= *val
; /* work with copy of the value */
1556 char buf
[2+11+1],tc
[11+1]; /* display buffer, text copy */
1557 int xp
= 0; /* cursor offset into text copy */
1558 int delta
= 1; /* force redraw first time in */
1560 int extended
= 0; /* stage counter for extended key sequences */
1562 if (hex
) /* we presume there's a leading 0x onscreen */
1563 putxy(x
-2,y
,"!i0x"); /* coz there sure is now */
1567 if (delta
) /* only update if necessary */
1569 ksprintf(tc
,hex
?"%x":"%d",i
); /* make a text copy of the value */
1570 ksprintf(buf
,"!i%s",tc
); /* format for printing */
1571 erase(x
,y
,width
,1); /* clear the area */
1572 putxy(x
,y
,buf
); /* write */
1573 xp
= strlen(tc
); /* cursor always at end */
1574 move(x
+xp
,y
); /* position the cursor */
1579 switch(extended
) /* escape handling */
1582 if (c
== 0x1b) /* esc? */
1584 extended
= 1; /* flag and spin */
1588 break; /* nope, drop through */
1590 case 1: /* there was an escape prefix */
1591 if (c
== '[' || c
== 'O') /* second character in sequence */
1597 return(KEY_EXIT
); /* double esc exits */
1599 break; /* nup, not a sequence. */
1603 switch(c
) /* looks like the real McCoy */
1606 VetRet(KEY_UP
); /* leave if OK */
1609 VetRet(KEY_DOWN
); /* leave if OK */
1612 VetRet(KEY_RIGHT
); /* leave if OK */
1615 VetRet(KEY_LEFT
); /* leave if OK */
1625 case '\t': /* trying to tab off */
1626 VetRet(KEY_TAB
); /* verify and maybe return */
1636 case '\177': /* BS or DEL */
1637 if (ro
) /* readonly? */
1639 puthelp(" !iThis value cannot be edited (Press ESC)");
1640 while(kgetchar() != 0x1b); /* wait for key */
1641 return(KEY_NULL
); /* spin */
1643 if (xp
) /* still something left to delete */
1645 i
= (hex
? i
/0x10u
: i
/10); /* strip last digit */
1646 delta
= 1; /* force update */
1669 if (ro
) /* readonly? */
1671 puthelp(" !iThis value cannot be edited (Press ESC)");
1672 while(kgetchar() != 0x1b); /* wait for key */
1673 return(KEY_NULL
); /* spin */
1675 if (xp
>= width
) /* no room for more characters anyway */
1679 if ((c
>= '0') && (c
<= '9'))
1681 i
= i
*0x10 + (c
-'0'); /* update value */
1685 if ((c
>= 'a') && (c
<= 'f'))
1687 i
= i
*0x10 + (c
-'a'+0xa);
1691 if ((c
>= 'A') && (c
<= 'F'))
1693 i
= i
*0x10 + (c
-'A'+0xa);
1698 if ((c
>= '0') && (c
<= '9'))
1700 i
= i
*10 + (c
-'0'); /* update value */
1701 delta
= 1; /* force redraw */
1714 ** Edit the parameters for (dev)
1716 ** Note that it's _always_ possible to edit the flags, otherwise it might be
1717 ** possible for this to spin in an endless loop...
1718 ** 0 5 10 15 20 25 30 35 40 45 50 55 60 67 70 75
1719 ** |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....
1720 ** +--------------------------------------------------------------------------------+
1721 ** 17-|--------------------------------------------------------------------------------|
1722 ** 18-| Port address : 0x0000 Memory address : 0x00000 Conflict allowed |
1723 ** 19-| IRQ number : 00 Memory size : 0x0000 |
1724 ** 20-| Flags : 0x0000 DRQ number : 00 |
1725 ** 21-|--------------------------------------------------------------------------------|
1727 ** The "intelligence" in this function that hops around based on the directional
1728 ** returns from editval isn't very smart, and depends on the layout above.
1731 editparams(DEV_LIST
*dev
)
1734 char buf
[16]; /* needs to fit the device name */
1736 putxy(2,17,"!bParameters!n-!bfor!n-!bdevice!n-");
1737 ksprintf(buf
,"!b%s",dev
->dev
);
1744 if (dev
->iobase
> 0)
1746 puthelp(" IO Port address (Hexadecimal, 0x1-0xffff)");
1747 ret
= editval(18,18,5,1,0x1,0xffff,&(dev
->iobase
),(dev
->attrib
& FLG_FIXIOBASE
));
1767 puthelp(" Interrupt number (Decimal, 1-15)");
1768 ret
= editval(16,19,3,0,1,15,&(dev
->irq
),(dev
->attrib
& FLG_FIXIRQ
));
1780 if (dev
->iobase
> 0)
1791 puthelp(" Device-specific flag values.");
1792 ret
= editval(18,20,8,1,INT_MIN
,INT_MAX
,&(dev
->flags
),0);
1806 if (dev
->iobase
> 0)
1826 puthelp(" Device memory start address (Hexadecimal, 0x1-0xfffff)");
1827 ret
= editval(45,18,6,1,0x1,0xfffff,&(dev
->maddr
),(dev
->attrib
& FLG_FIXMADDR
));
1834 if (dev
->iobase
> 0)
1856 puthelp(" Device memory size (Hexadecimal, 0x1-0x10000)");
1857 ret
= editval(45,19,5,1,0x1,0x10000,&(dev
->msize
),(dev
->attrib
& FLG_FIXMSIZE
));
1886 puthelp(" Device DMA request number (Decimal, 1-7)");
1887 ret
= editval(43,20,2,0,1,7,&(dev
->drq
),(dev
->attrib
& FLG_FIXDRQ
));
1910 dev
->changed
= 1; /* mark as changed */
1913 static char *helptext
[] =
1915 " Using the UserConfig kernel settings editor",
1916 " -------------------------------------------",
1922 "The screen displays a list of available drivers, divided into two",
1923 "scrolling lists: Active Drivers, and Inactive Drivers. Each list is",
1924 "by default collapsed and can be expanded to show all the drivers",
1925 "available in each category. The parameters for the currently selected",
1926 "driver are shown at the bottom of the screen.",
1928 "- - Moving around -",
1930 "To move in the current list, use the UP and DOWN cursor keys to select",
1931 "an item (the selected item will be highlighted). If the item is a",
1932 "category name, you may alternatively expand or collapse the list of",
1933 "drivers for that category by pressing [!bENTER!n]. Once the category is",
1934 "expanded, you can select each driver in the same manner and either:",
1936 " - change its parameters using [!bENTER!n]",
1937 " - move it to the Inactive list using [!bDEL!n]",
1939 "Use the [!bTAB!n] key to toggle between the Active and Inactive list; if",
1940 "you need to move a driver from the Inactive list back to the Active",
1941 "one, select it in the Inactive list, using [!bTAB!n] to change lists if",
1942 "necessary, and press [!bENTER!n] -- the device will be moved back to",
1943 "its place in the Active list.",
1945 "- - Altering the list/parameters -",
1947 "Any drivers for devices not installed in your system should be moved",
1948 "to the Inactive list, until there are no remaining parameter conflicts",
1949 "between the drivers, as indicated at the top.",
1951 "Once the list of Active drivers only contains entries for the devices",
1952 "present in your system, you can set their parameters (Interrupt, DMA",
1953 "channel, I/O addresses). To do this, select the driver and press",
1954 "[!bENTER!n]: it is now possible to edit the settings at the",
1955 "bottom of the screen. Use [!bTAB!n] to change fields, and when you are",
1956 "finished, use [!bQ!n] to return to the list.",
1958 "- - Saving changes -",
1960 "When all settings seem correct, and you wish to proceed with the",
1961 "kernel device probing and boot, press [!bQ!n] -- you will be asked to",
1962 "confirm your choice.",
1971 ** Displays help text onscreen for people that are confused, using a simple
1977 int topline
= 0; /* where we are in the text */
1978 int line
= 0; /* last line we displayed */
1982 for (;;) /* loop until user quits */
1984 /* display help text */
1987 clear(); /* remove everything else */
1988 for (line
= topline
;
1989 (line
< (topline
+ 24)) && (helptext
[line
]);
1991 putxy(0,line
-topline
,helptext
[line
]);
1996 ksprintf(prompt
,"!i --%s-- [U]p [D]own [Q]uit !n",helptext
[line
] ? "MORE" : "END");
1999 c
= kgetchar(); /* so what do they say? */
2006 case 'B': /* wired into 'more' users' fingers */
2007 if (topline
> 0) /* room to go up? */
2010 if (topline
< 0) /* don't go too far */
2018 case ' ': /* expected by most people */
2019 if (helptext
[line
]) /* maybe more below? */
2028 redraw(); /* restore the screen */
2036 ** High-level control functions
2043 ** Handle user movement within (*list) in the region starting at (row) onscreen with
2044 ** (num) lines, starting at (*ofs) offset from row onscreen.
2045 ** Pass (detail) on to drawing routines.
2047 ** If the user hits a key other than a cursor key, maybe return a code.
2049 ** (*list) points to the device at the top line in the region, (*ofs) is the
2050 ** position of the highlight within the region. All routines below
2051 ** this take only a device and an absolute row : use ofsent() to find the
2052 ** device, and add (*ofs) to (row) to find the absolute row.
2055 dolist(int row
, int num
, int detail
, int *ofs
, DEV_LIST
**list
, char *dhelp
)
2066 showparams(ofsent(*ofs
,*list
)); /* show device parameters */
2067 drawline(row
+*ofs
,detail
,ofsent(*ofs
,*list
),1,dhelp
); /* highlight current line */
2071 c
= kgetchar(); /* get a character */
2072 if ((extended
== 2) || (c
==588) || (c
==596)) /* console gives "alternative" codes */
2074 extended
= 0; /* no longer */
2077 case 588: /* syscons' idea of 'up' */
2079 if (*ofs
) /* just a move onscreen */
2081 drawline(row
+*ofs
,detail
,ofsent(*ofs
,*list
),0,dhelp
);/* unhighlight current line */
2082 (*ofs
)--; /* move up */
2084 lp
= prevent(*list
); /* can we go up? */
2087 *list
= lp
; /* yes, move up list */
2088 drawlist(row
,num
,detail
,*list
);
2093 case 596: /* dooby-do */
2094 case 'B': /* down */
2095 lp
= ofsent(*ofs
,*list
); /* get current item */
2097 break; /* nothing more to move to */
2098 drawline(row
+*ofs
,detail
,ofsent(*ofs
,*list
),0,dhelp
); /* unhighlight current line */
2099 if (*ofs
< (num
-1)) /* room to move onscreen? */
2103 *list
= nextent(*list
); /* scroll region down */
2104 drawlist(row
,num
,detail
,*list
);
2116 case '[': /* cheat : always preceeds cursor move */
2117 case 'O': /* ANSI application key mode */
2126 return(KEY_EXIT
); /* user requests exit */
2130 return(KEY_DO
); /* "do" something */
2135 return(KEY_DEL
); /* "delete" response */
2139 return(KEY_UNZOOM
); /* expand everything */
2143 return(KEY_ZOOM
); /* collapse everything */
2146 drawline(row
+*ofs
,detail
,ofsent(*ofs
,*list
),0,dhelp
); /* unhighlight current line */
2147 return(KEY_TAB
); /* "move" response */
2149 case '\014': /* ^L, redraw */
2152 case '?': /* helptext */
2164 ** Do the fullscreen config thang
2169 int actofs
= 0, inactofs
= 0, mode
= 0, ret
= -1, i
;
2173 initlist(&inactive
);
2179 conflicts
= findconflict(active
); /* find conflicts in the active list only */
2187 case 0: /* active devices */
2188 ret
= dolist(1,8,1,&actofs
,&alist
,
2189 " [!bEnter!n] Edit device parameters [!bDEL!n] Disable device");
2193 mode
= 1; /* swap lists */
2210 collapselist(active
);
2215 dp
= ofsent(actofs
,alist
); /* get current device */
2216 if (dp
) /* paranoia... */
2218 if (dp
->attrib
& FLG_MANDATORY
) /* can't be deleted */
2220 if (dp
== alist
) /* moving top item on list? */
2224 alist
= dp
->next
; /* point list to non-moving item */
2226 alist
= dp
->prev
; /* end of list, go back instead */
2229 if (!dp
->next
) /* moving last item on list? */
2232 dp
->conflicts
= 0; /* no conflicts on the inactive list */
2233 movedev(dp
,inactive
); /* shift to inactive list */
2234 conflicts
= findconflict(active
); /* update conflict tags */
2236 redrawactive(); /* redraw */
2241 case KEY_DO
: /* edit device parameters */
2242 dp
= ofsent(actofs
,alist
); /* get current device */
2243 if (dp
) /* paranoia... */
2245 if (dp
->comment
== DEV_DEVICE
) /* can't edit comments, zoom? */
2247 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save device parameters");
2249 masterhelp(" [!bTAB!n] Change fields [!bQ!n] Save and Exit [!b?!n] Help");
2251 conflicts
= findconflict(active
); /* update conflict tags */
2252 }else{ /* DO on comment = zoom */
2253 switch(dp
->comment
) /* Depends on current state */
2255 case DEV_COMMENT
: /* not currently zoomed */
2256 dp
->comment
= DEV_ZOOMED
;
2260 dp
->comment
= DEV_COMMENT
;
2270 case 1: /* inactive devices */
2271 ret
= dolist(10,7,0,&inactofs
,&ilist
,
2272 " [!bEnter!n] Enable device ");
2286 expandlist(inactive
);
2293 collapselist(inactive
);
2298 dp
= ofsent(inactofs
,ilist
); /* get current device */
2299 if (dp
) /* paranoia... */
2301 if (dp
->comment
== DEV_DEVICE
) /* can't move comments, zoom? */
2303 if (dp
== ilist
) /* moving top of list? */
2307 ilist
= dp
->next
; /* point list to non-moving item */
2309 ilist
= dp
->prev
; /* can't go down, go up instead */
2312 if (!dp
->next
) /* last entry on list? */
2313 inactofs
--; /* shift cursor up one */
2316 movedev(dp
,active
); /* shift to active list */
2317 conflicts
= findconflict(active
); /* update conflict tags */
2319 alist
= dp
; /* put at top and current */
2321 while(dp
->comment
== DEV_DEVICE
)
2322 dp
= dp
->prev
; /* forcibly unzoom section */
2323 dp
->comment
= DEV_COMMENT
;
2324 mode
= 0; /* and swap modes to follow it */
2326 }else{ /* DO on comment = zoom */
2327 switch(dp
->comment
) /* Depends on current state */
2329 case DEV_COMMENT
: /* not currently zoomed */
2330 dp
->comment
= DEV_ZOOMED
;
2334 dp
->comment
= DEV_COMMENT
;
2338 redrawactive(); /* redraw */
2343 default: /* nothing else relevant here */
2348 mode
= 0; /* shouldn't happen... */
2351 /* handle returns that are the same for both modes */
2358 i
= yesnocancel(" Save these parameters before exiting? ([!bY!n]es/[!bN!n]o/[!bC!n]ancel) ");
2361 case 2: /* cancel */
2365 case 1: /* save and exit */
2367 savelist(inactive
,0);
2370 nukelist(active
); /* clean up after ourselves */
2380 #endif /* VISUAL_USERCONFIG */
2383 * Copyright (c) 1991 Regents of the University of California.
2384 * All rights reserved.
2385 * Copyright (c) 1994 Jordan K. Hubbard
2386 * All rights reserved.
2387 * Copyright (c) 1994 David Greenman
2388 * All rights reserved.
2390 * Many additional changes by Bruce Evans
2392 * This code is derived from software contributed by the
2393 * University of California Berkeley, Jordan K. Hubbard,
2394 * David Greenman and Bruce Evans.
2396 * Redistribution and use in source and binary forms, with or without
2397 * modification, are permitted provided that the following conditions
2399 * 1. Redistributions of source code must retain the above copyright
2400 * notice, this list of conditions and the following disclaimer.
2401 * 2. Redistributions in binary form must reproduce the above copyright
2402 * notice, this list of conditions and the following disclaimer in the
2403 * documentation and/or other materials provided with the distribution.
2404 * 3. All advertising materials mentioning features or use of this software
2405 * must display the following acknowledgement:
2406 * This product includes software developed by the University of
2407 * California, Berkeley and its contributors.
2408 * 4. Neither the name of the University nor the names of its contributors
2409 * may be used to endorse or promote products derived from this software
2410 * without specific prior written permission.
2412 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2413 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2414 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2415 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2416 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2417 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2418 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2419 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2420 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2421 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2424 * $FreeBSD: src/sys/i386/i386/userconfig.c,v 1.175.2.10 2002/10/05 18:31:48 scottl Exp $
2427 #include "use_scbus.h"
2429 #define PARM_DEVSPEC 0x1
2430 #define PARM_INT 0x2
2431 #define PARM_ADDR 0x3
2432 #define PARM_STRING 0x4
2434 typedef struct _cmdparm
{
2437 struct uc_device
*dparm
;
2446 typedef int (*CmdFunc
)(CmdParm
*);
2448 typedef struct _cmd
{
2456 static void lsscsi(void);
2457 static int list_scsi(CmdParm
*);
2460 static int lsdevtab(struct uc_device
*);
2461 static struct uc_device
*find_device(char *, int);
2462 static struct uc_device
*search_devtable(struct uc_device
*, char *, int);
2463 static void cngets(char *, int);
2464 static Cmd
*parse_cmd(char *);
2465 static int parse_args(const char *, CmdParm
*);
2466 static int save_dev(struct uc_device
*);
2468 static int list_devices(CmdParm
*);
2469 static int set_device_ioaddr(CmdParm
*);
2470 static int set_device_irq(CmdParm
*);
2471 static int set_device_drq(CmdParm
*);
2472 static int set_device_iosize(CmdParm
*);
2473 static int set_device_mem(CmdParm
*);
2474 static int set_device_flags(CmdParm
*);
2475 static int set_device_enable(CmdParm
*);
2476 static int set_device_disable(CmdParm
*);
2477 static int quitfunc(CmdParm
*);
2478 static int helpfunc(CmdParm
*);
2479 static int introfunc(CmdParm
*);
2482 static int lspnp(void);
2483 static int set_pnp_parms(CmdParm
*);
2488 #include "use_eisa.h"
2492 #include <bus/eisa/eisaconf.h>
2494 static int set_num_eisa_slots(CmdParm
*);
2496 #endif /* NEISA > 0 */
2498 static CmdParm addr_parms
[] = {
2499 { PARM_DEVSPEC
, {} },
2504 static CmdParm int_parms
[] = {
2505 { PARM_DEVSPEC
, {} },
2510 static CmdParm dev_parms
[] = {
2511 { PARM_DEVSPEC
, {} },
2516 static CmdParm string_arg
[] = {
2517 { PARM_STRING
, {} },
2523 static CmdParm int_arg
[] = {
2527 #endif /* NEISA > 0 */
2529 static Cmd CmdList
[] = {
2530 { "?", helpfunc
, NULL
}, /* ? (help) */
2531 { "di", set_device_disable
, dev_parms
}, /* disable dev */
2532 { "dr", set_device_drq
, int_parms
}, /* drq dev # */
2534 { "ei", set_num_eisa_slots
, int_arg
}, /* # EISA slots */
2535 #endif /* NEISA > 0 */
2536 { "en", set_device_enable
, dev_parms
}, /* enable dev */
2537 { "ex", quitfunc
, NULL
}, /* exit (quit) */
2538 { "f", set_device_flags
, int_parms
}, /* flags dev mask */
2539 { "h", helpfunc
, NULL
}, /* help */
2540 { "intro", introfunc
, NULL
}, /* intro screen */
2541 { "iom", set_device_mem
, addr_parms
}, /* iomem dev addr */
2542 { "ios", set_device_iosize
, int_parms
}, /* iosize dev size */
2543 { "ir", set_device_irq
, int_parms
}, /* irq dev # */
2544 { "l", list_devices
, NULL
}, /* ls, list */
2546 { "pn", set_pnp_parms
, string_arg
}, /* pnp ... */
2548 { "po", set_device_ioaddr
, int_parms
}, /* port dev addr */
2549 { "res", (CmdFunc
)cpu_reset
, NULL
}, /* reset CPU */
2550 { "q", quitfunc
, NULL
}, /* quit */
2552 { "s", list_scsi
, NULL
}, /* scsi */
2554 #ifdef VISUAL_USERCONFIG
2555 { "v", (CmdFunc
)visuserconfig
, NULL
}, /* visual mode */
2557 { NULL
, NULL
, NULL
},
2563 static char banner
= 1;
2569 init_config_script();
2572 /* Only display signon banner if we are about to go interactive */
2573 if (!has_config_script()) {
2574 if (!(boothowto
& RB_CONFIG
))
2575 #ifdef INTRO_USERCONFIG
2582 printf("FreeBSD Kernel Configuration Utility - Version 1.2\n"
2583 " Type \"help\" for help"
2584 #ifdef VISUAL_USERCONFIG
2585 " or \"visual\" to go to the visual\n"
2586 " configuration interface (requires MGA/VGA display or\n"
2587 " serial terminal capable of displaying ANSI graphics)"
2595 if (input
[0] == '\0')
2597 cmd
= parse_cmd(input
);
2599 printf("Invalid command or syntax. Type `?' for help.\n");
2602 rval
= (*cmd
->handler
)(cmd
->parms
);
2611 parse_cmd(char *cmd
)
2615 for (cp
= CmdList
; cp
->name
; cp
++) {
2616 int len
= strlen(cp
->name
);
2618 if (!strncmp(cp
->name
, cmd
, len
)) {
2619 while (*cmd
&& *cmd
!= ' ' && *cmd
!= '\t')
2621 if (parse_args(cmd
, cp
->parms
))
2631 parse_args(const char *cmd
, CmdParm
*parms
)
2636 if (*cmd
== ' ' || *cmd
== '\t') {
2640 if (parms
== NULL
|| parms
->type
== -1) {
2643 printf("Extra arg(s): %s\n", cmd
);
2646 if (parms
->type
== PARM_DEVSPEC
) {
2651 while (*cmd
&& !(*cmd
== ' ' || *cmd
== '\t' ||
2652 (*cmd
>= '0' && *cmd
<= '9')))
2653 devname
[i
++] = *(cmd
++);
2655 if (*cmd
>= '0' && *cmd
<= '9') {
2656 unit
= strtoul(cmd
, &ptr
, 10);
2658 printf("Invalid device number\n");
2659 /* XXX should print invalid token here and elsewhere. */
2662 /* XXX else should require end of token. */
2665 if ((parms
->parm
.dparm
= find_device(devname
, unit
)) == NULL
) {
2666 printf("No such device: %s%d\n", devname
, unit
);
2672 if (parms
->type
== PARM_INT
) {
2673 parms
->parm
.iparm
= strtoul(cmd
, &ptr
, 0);
2675 printf("Invalid numeric argument\n");
2682 if (parms
->type
== PARM_ADDR
) {
2683 parms
->parm
.u
.aparm
= (void *)(uintptr_t)strtoul(cmd
, &ptr
, 0);
2685 printf("Invalid address argument\n");
2692 if (parms
->type
== PARM_STRING
) {
2693 parms
->parm
.u
.sparm
= cmd
;
2701 list_devices(CmdParm
*parms
)
2704 if (lsdevtab(uc_devtab
)) return 0;
2706 if (lspnp()) return 0;
2709 printf("\nNumber of EISA slots to probe: %d\n", num_eisa_slots
);
2710 #endif /* NEISA > 0 */
2715 set_device_ioaddr(CmdParm
*parms
)
2717 parms
[0].parm
.dparm
->id_iobase
= parms
[1].parm
.iparm
;
2718 save_dev(parms
[0].parm
.dparm
);
2723 set_device_irq(CmdParm
*parms
)
2727 irq
= parms
[1].parm
.iparm
;
2729 printf("Warning: Remapping IRQ 2 to IRQ 9\n");
2732 else if (irq
!= -1 && irq
> 15) {
2733 printf("An IRQ > 15 would be invalid.\n");
2736 parms
[0].parm
.dparm
->id_irq
= (irq
< 16 ? 1 << irq
: 0);
2737 save_dev(parms
[0].parm
.dparm
);
2742 set_device_drq(CmdParm
*parms
)
2747 * The bounds checking is just to ensure that the value can be printed
2748 * in 5 characters. 32768 gets converted to -32768 and doesn't fit.
2750 drq
= parms
[1].parm
.iparm
;
2751 parms
[0].parm
.dparm
->id_drq
= (drq
< 32768 ? drq
: -1);
2752 save_dev(parms
[0].parm
.dparm
);
2757 set_device_iosize(CmdParm
*parms
)
2759 parms
[0].parm
.dparm
->id_msize
= parms
[1].parm
.iparm
;
2760 save_dev(parms
[0].parm
.dparm
);
2765 set_device_mem(CmdParm
*parms
)
2767 parms
[0].parm
.dparm
->id_maddr
= parms
[1].parm
.u
.aparm
;
2768 save_dev(parms
[0].parm
.dparm
);
2773 set_device_flags(CmdParm
*parms
)
2775 parms
[0].parm
.dparm
->id_flags
= parms
[1].parm
.iparm
;
2776 save_dev(parms
[0].parm
.dparm
);
2781 set_device_enable(CmdParm
*parms
)
2783 parms
[0].parm
.dparm
->id_enabled
= TRUE
;
2784 save_dev(parms
[0].parm
.dparm
);
2789 set_device_disable(CmdParm
*parms
)
2791 parms
[0].parm
.dparm
->id_enabled
= FALSE
;
2792 save_dev(parms
[0].parm
.dparm
);
2799 sysctl_machdep_uc_pnplist(SYSCTL_HANDLER_ARGS
)
2805 return(SYSCTL_OUT(req
,0,sizeof(struct pnp_cinfo
)*MAX_PNP_LDN
));
2808 * Output the pnp_ldn_overrides[] table.
2810 error
=sysctl_handle_opaque(oidp
,&pnp_ldn_overrides
,
2811 sizeof(struct pnp_cinfo
)*MAX_PNP_LDN
,req
);
2812 if(error
) return(error
);
2817 SYSCTL_PROC( _machdep
, OID_AUTO
, uc_pnplist
, CTLFLAG_RD
,
2818 0, 0, sysctl_machdep_uc_pnplist
, "A",
2819 "List of PnP overrides changed in UserConfig");
2822 * this function sets the kernel table to override bios PnP
2826 set_pnp_parms(CmdParm
*parms
)
2828 u_long idx
, val
, ldn
, csn
;
2831 const char *p
= parms
[0].parm
.u
.sparm
;
2834 csn
=strtoul(p
,&q
, 0);
2835 ldn
=strtoul(q
,&q
, 0);
2836 for (p
=q
; *p
&& (*p
==' ' || *p
=='\t'); p
++) ;
2837 if (csn
< 1 || csn
> MAX_PNP_CARDS
|| ldn
>= MAX_PNP_LDN
) {
2838 printf("bad csn/ldn %ld:%ld\n", csn
, ldn
);
2841 for (i
=0; i
< MAX_PNP_LDN
; i
++) {
2842 if (pnp_ldn_overrides
[i
].csn
== csn
&&
2843 pnp_ldn_overrides
[i
].ldn
== ldn
)
2846 if (i
==MAX_PNP_LDN
) {
2847 for (i
=0; i
< MAX_PNP_LDN
; i
++) {
2848 if (pnp_ldn_overrides
[i
].csn
<1 ||
2849 pnp_ldn_overrides
[i
].csn
> MAX_PNP_CARDS
)
2853 if (i
==MAX_PNP_LDN
) {
2854 printf("sorry, no PnP entries available, try delete one\n");
2857 d
= pnp_ldn_overrides
[i
] ;
2863 if (!strncmp(p
,"irq",3)) {
2864 idx
=strtoul(p
+3,&q
, 0);
2865 val
=strtoul(q
,&q
, 0);
2866 if (idx
>=0 && idx
< 2) d
.irq
[idx
] = val
;
2867 } else if (!strncmp(p
,"flags",5)) {
2868 idx
=strtoul(p
+5,&q
, 0);
2870 } else if (!strncmp(p
,"drq",3)) {
2871 idx
=strtoul(p
+3,&q
, 0);
2872 val
=strtoul(q
,&q
, 0);
2873 if (idx
>=0 && idx
< 2) d
.drq
[idx
] = val
;
2874 } else if (!strncmp(p
,"port",4)) {
2875 idx
=strtoul(p
+4,&q
, 0);
2876 val
=strtoul(q
,&q
, 0);
2877 if (idx
>=0 && idx
< 8) d
.port
[idx
] = val
;
2878 } else if (!strncmp(p
,"mem",3)) {
2879 idx
=strtoul(p
+3,&q
, 0);
2880 val
=strtoul(q
,&q
, 0);
2881 if (idx
>=0 && idx
< 4) d
.mem
[idx
].base
= val
;
2882 } else if (!strncmp(p
,"bios",4)) {
2885 } else if (!strncmp(p
,"os",2)) {
2888 } else if (!strncmp(p
,"disable",7)) {
2891 } else if (!strncmp(p
,"enable",6)) {
2894 } else if (!strncmp(p
,"delete",6)) {
2895 bzero(&pnp_ldn_overrides
[i
], sizeof (pnp_ldn_overrides
[i
]));
2896 if (i
==0) pnp_ldn_overrides
[i
].csn
= 255;/* not reinit */
2899 printf("unknown command <%s>\n", p
);
2902 for (p
=q
; *p
&& (*p
==' ' || *p
=='\t'); p
++) ;
2904 pnp_ldn_overrides
[i
] = d
;
2911 set_num_eisa_slots(CmdParm
*parms
)
2915 num_slots
= parms
[0].parm
.iparm
;
2916 num_eisa_slots
= (num_slots
<= 16 ? num_slots
: 10);
2919 #endif /* NEISA > 0 */
2922 quitfunc(CmdParm
*parms
)
2925 * If kernel config supplied, and we are parsing it, and -c also supplied,
2926 * ignore a quit command, This provides a safety mechanism to allow
2927 * recovery from a damaged/buggy kernel config.
2929 if ((boothowto
& RB_CONFIG
) && userconfig_boot_parsing
)
2935 helpfunc(CmdParm
*parms
)
2938 "Command\t\t\tDescription\n"
2939 "-------\t\t\t-----------\n"
2940 "ls\t\t\tList currently configured devices\n"
2941 "port <devname> <addr>\tSet device port (i/o address)\n"
2942 "irq <devname> <number>\tSet device irq\n"
2943 "drq <devname> <number>\tSet device drq\n"
2944 "iomem <devname> <addr>\tSet device maddr (memory address)\n"
2945 "iosize <devname> <size>\tSet device memory size\n"
2946 "flags <devname> <mask>\tSet device flags\n"
2947 "enable <devname>\tEnable device\n"
2948 "disable <devname>\tDisable device (will not be probed)\n");
2951 "pnp <csn> <ldn> [enable|disable]\tenable/disable device\n"
2952 "pnp <csn> <ldn> [os|bios]\tset parameters using FreeBSD or BIOS\n"
2953 "pnp <csn> <ldn> [portX <addr>]\tset addr for port X (0..7)\n"
2954 "pnp <csn> <ldn> [memX <maddr>]\tset addr for memory range X (0..3)\n"
2955 "pnp <csn> <ldn> [irqX <number>]\tset irq X (0..1) to number, 0=unused\n"
2956 "pnp <csn> <ldn> [drqX <number>]\tset drq X (0..1) to number, 4=unused\n");
2959 printf("eisa <number>\t\tSet the number of EISA slots to probe\n");
2960 #endif /* NEISA > 0 */
2962 "quit\t\t\tExit this configuration utility\n"
2963 "reset\t\t\tReset CPU\n");
2964 #ifdef VISUAL_USERCONFIG
2965 printf("visual\t\t\tGo to fullscreen mode.\n");
2968 "help\t\t\tThis message\n\n"
2969 "Commands may be abbreviated to a unique prefix\n");
2973 #if defined (VISUAL_USERCONFIG)
2975 center(int y
, char *str
)
2977 putxy((80 - strlen(str
)) / 2, y
, str
);
2982 introfunc(CmdParm
*parms
)
2984 #if defined (VISUAL_USERCONFIG)
2985 int curr_item
, first_time
, extended
= 0;
2986 static char *choices
[] = {
2987 " Skip kernel configuration and continue with installation ",
2988 " Start kernel configuration in full-screen visual mode ",
2989 " Start kernel configuration in CLI mode ",
2993 center(2, "!bKernel Configuration Menu!n");
3002 for (i
= 0; i
< 3; i
++) {
3006 strcat(tmp
, choices
[i
]);
3009 putxy(10, 5 + i
, tmp
);
3013 putxy(2, 10, "Here you have the chance to go into kernel configuration mode, making");
3014 putxy(2, 11, "any changes which may be necessary to properly adjust the kernel to");
3015 putxy(2, 12, "match your hardware configuration.");
3016 putxy(2, 14, "If you are installing FreeBSD for the first time, select Visual Mode");
3017 putxy(2, 15, "(press Down-Arrow then ENTER).");
3018 putxy(2, 17, "If you need to do more specialized kernel configuration and are an");
3019 putxy(2, 18, "experienced FreeBSD user, select CLI mode.");
3020 putxy(2, 20, "If you are !icertain!n that you do not need to configure your kernel");
3021 putxy(2, 21, "then simply press ENTER or Q now.");
3025 move(0, 0); /* move the cursor out of the way */
3028 if ((extended
== 2) || (c
== 588) || (c
== 596)) { /* console gives "alternative" codes */
3029 extended
= 0; /* no longer */
3038 case 'B': /* down */
3050 case '[': /* cheat : always preceeds cursor move */
3051 case 'O': /* ANSI application key mode */
3062 return 1; /* user requests exit */
3064 case '1': /* select an item */
3088 case 'D': /* down */
3101 else if (curr_item
== 1)
3102 return visuserconfig();
3104 putxy(0, 1, "Type \"help\" for help or \"quit\" to exit.");
3105 /* enable quitfunc */
3106 userconfig_boot_parsing
=0;
3108 boothowto
|= RB_CONFIG
; /* force -c */
3122 struct pnp_cinfo
*c
;
3126 for (i
=0; i
< MAX_PNP_LDN
; i
++) {
3127 c
= &pnp_ldn_overrides
[i
];
3128 if (c
->csn
>0 && c
->csn
!= 255) {
3130 static char pfmt
[] =
3131 "port 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ";
3132 static char mfmt
[] =
3133 "mem 0x%x 0x%x 0x%x 0x%x";
3136 if (!userconfig_boot_parsing
) {
3138 if (kgetchar() == 'q') {
3146 if (lineno
== 0 || first
)
3147 printf("CSN LDN conf en irqs drqs others (PnP devices)\n");
3149 printf("%3d %3d %4s %2s %2d %-2d %2d %-2d ",
3151 c
->override
? "OS ":"BIOS",
3152 c
->enable
? "Y":"N",
3153 c
->irq
[0], c
->irq
[1], c
->drq
[0], c
->drq
[1]);
3155 printf("flags 0x%08lx ",c
->flags
);
3156 for (pmax
= 7; pmax
>=0 ; pmax
--)
3157 if (c
->port
[pmax
]!=0) break;
3158 for (mmax
= 3; mmax
>=0 ; mmax
--)
3159 if (c
->mem
[mmax
].base
!=0) break;
3162 buf
[10 + 5*pmax
]='\0';
3164 c
->port
[0], c
->port
[1], c
->port
[2], c
->port
[3],
3165 c
->port
[4], c
->port
[5], c
->port
[6], c
->port
[7]);
3169 buf
[8 + 5*mmax
]='\0';
3171 c
->mem
[0].base
, c
->mem
[1].base
,
3172 c
->mem
[2].base
, c
->mem
[3].base
);
3182 lsdevtab(struct uc_device
*dt
)
3184 for (; dt
->id_id
!= 0; dt
++) {
3189 if (!userconfig_boot_parsing
) {
3190 if (kgetchar() == 'q') {
3200 "Device port irq drq iomem iosize unit flags enab\n"
3204 ksprintf(dname
, "%s%d", dt
->id_name
, dt
->id_unit
);
3205 printf("%-9.9s%-#11x%-6d%-6d%-8p%-9d%-6d%-#11x%-5s\n",
3206 dname
, /* dt->id_id, dt->id_driver(by name), */ dt
->id_iobase
,
3207 ffs(dt
->id_irq
) - 1, dt
->id_drq
, dt
->id_maddr
, dt
->id_msize
,
3208 /* dt->id_intr(by name), */ dt
->id_unit
, dt
->id_flags
,
3209 dt
->id_enabled
? "Yes" : "No");
3219 int count
= resource_count();
3225 uc_devtab
= kmalloc(sizeof(struct uc_device
)*(count
+ 1),M_DEVL
,M_WAITOK
);
3226 bzero(uc_devtab
, sizeof(struct uc_device
) * (count
+ 1));
3228 for (i
= 0; i
< count
; i
++) {
3229 name
= resource_query_name(i
);
3230 unit
= resource_query_unit(i
);
3232 continue; /* skip wildcards */
3233 uc_devtab
[dt
].id_id
= id
++;
3234 resource_int_value(name
, unit
, "port", &uc_devtab
[dt
].id_iobase
);
3236 resource_int_value(name
, unit
, "irq", &val
);
3237 uc_devtab
[dt
].id_irq
= (1 << val
);
3238 resource_int_value(name
, unit
, "drq", &uc_devtab
[dt
].id_drq
);
3239 resource_int_value(name
, unit
, "maddr",(int *)&uc_devtab
[dt
].id_maddr
);
3240 resource_int_value(name
, unit
, "msize", &uc_devtab
[dt
].id_msize
);
3241 uc_devtab
[dt
].id_unit
= unit
;
3242 resource_int_value(name
, unit
, "flags", &uc_devtab
[dt
].id_flags
);
3244 resource_int_value(name
, unit
, "disabled", &val
);
3245 uc_devtab
[dt
].id_enabled
= !val
;
3246 uc_devtab
[dt
].id_name
= kmalloc(strlen(name
) + 1, M_DEVL
,M_WAITOK
);
3247 strcpy(uc_devtab
[dt
].id_name
, name
);
3256 int count
= resource_count();
3258 for (i
= 0; i
< count
; i
++)
3259 if (uc_devtab
[i
].id_name
)
3260 kfree(uc_devtab
[i
].id_name
, M_DEVL
);
3261 kfree(uc_devtab
, M_DEVL
);
3264 static struct uc_device
*
3265 find_device(char *devname
, int unit
)
3267 struct uc_device
*ret
;
3269 if ((ret
= search_devtable(uc_devtab
, devname
, unit
)) != NULL
)
3274 static struct uc_device
*
3275 search_devtable(struct uc_device
*dt
, char *devname
, int unit
)
3279 for (i
= 0; dt
->id_id
!= 0; dt
++)
3280 if (!strcmp(dt
->id_name
, devname
) && dt
->id_unit
== unit
)
3286 cngets(char *input
, int maxin
)
3292 /* Treat ^H or ^? as backspace */
3293 if ((c
== '\010' || c
== '\177')) {
3295 printf("\010 \010");
3296 *--input
= '\0', --nchars
;
3300 /* Treat ^U or ^X as kill line */
3301 else if ((c
== '\025' || c
== '\030')) {
3303 printf("\010 \010");
3304 *--input
= '\0', --nchars
;
3309 if ((++nchars
== maxin
) || (c
== '\n') || (c
== '\r') || ( c
== -1)) {
3313 *input
++ = (u_char
)c
;
3319 /* scsi: Support for displaying configured SCSI devices.
3320 * There is no way to edit them, and this is inconsistent
3321 * with the ISA method. This is here as a basis for further work.
3324 type_text(char *name
) /* XXX: This is bogus */
3326 if (strcmp(name
, "sd") == 0)
3329 if (strcmp(name
, "st") == 0)
3335 id_put(char *desc
, int id
)
3337 if (id
!= SCCONF_UNSPEC
)
3342 if (id
== SCCONF_ANY
)
3354 printf("scsi: (can't be edited):\n");
3356 for (i
= 0; scsi_cinit
[i
].driver
; i
++)
3358 id_put("controller scbus", scsi_cinit
[i
].scbus
);
3360 if (scsi_cinit
[i
].unit
!= -1)
3363 id_put(scsi_cinit
[i
].driver
, scsi_cinit
[i
].unit
);
3369 for (i
= 0; scsi_dinit
[i
].name
; i
++)
3371 printf("%s ", type_text(scsi_dinit
[i
].name
));
3373 id_put(scsi_dinit
[i
].name
, scsi_dinit
[i
].unit
);
3374 id_put(" at scbus", scsi_dinit
[i
].cunit
);
3375 id_put(" target ", scsi_dinit
[i
].target
);
3376 id_put(" lun ", scsi_dinit
[i
].lun
);
3378 if (scsi_dinit
[i
].flags
)
3379 printf(" flags 0x%x\n", scsi_dinit
[i
].flags
);
3386 list_scsi(CmdParm
*parms
)
3395 save_resource(struct uc_device
*idev
)
3400 name
= idev
->id_name
;
3401 unit
= idev
->id_unit
;
3402 resource_set_int(name
, unit
, "port", idev
->id_iobase
);
3403 resource_set_int(name
, unit
, "irq", ffs(idev
->id_irq
) - 1);
3404 resource_set_int(name
, unit
, "drq", idev
->id_drq
);
3405 resource_set_int(name
, unit
, "maddr", (int)idev
->id_maddr
);
3406 resource_set_int(name
, unit
, "msize", idev
->id_msize
);
3407 resource_set_int(name
, unit
, "flags", idev
->id_flags
);
3408 resource_set_int(name
, unit
, "disabled", !idev
->id_enabled
);
3412 save_dev(struct uc_device
*idev
)
3414 struct uc_device
*id_p
,*id_pn
;
3415 char *name
= idev
->id_name
;
3417 for (id_p
= uc_devlist
; id_p
; id_p
= id_p
->id_next
) {
3418 if (id_p
->id_id
== idev
->id_id
) {
3419 id_pn
= id_p
->id_next
;
3421 kfree(id_p
->id_name
, M_DEVL
);
3422 bcopy(idev
,id_p
,sizeof(struct uc_device
));
3423 save_resource(idev
);
3424 id_p
->id_name
= kmalloc(strlen(name
)+1, M_DEVL
,M_WAITOK
);
3425 strcpy(id_p
->id_name
, name
);
3426 id_p
->id_next
= id_pn
;
3430 id_pn
= kmalloc(sizeof(struct uc_device
),M_DEVL
,M_WAITOK
);
3431 bcopy(idev
,id_pn
,sizeof(struct uc_device
));
3432 save_resource(idev
);
3433 id_pn
->id_name
= kmalloc(strlen(name
) + 1, M_DEVL
,M_WAITOK
);
3434 strcpy(id_pn
->id_name
, name
);
3435 id_pn
->id_next
= uc_devlist
;