autoconf.c revision 50184
14Srgrimes/*-
24Srgrimes * Copyright (c) 1990 The Regents of the University of California.
34Srgrimes * All rights reserved.
44Srgrimes *
54Srgrimes * This code is derived from software contributed to Berkeley by
64Srgrimes * William Jolitz.
74Srgrimes *
84Srgrimes * Redistribution and use in source and binary forms, with or without
94Srgrimes * modification, are permitted provided that the following conditions
104Srgrimes * are met:
114Srgrimes * 1. Redistributions of source code must retain the above copyright
124Srgrimes *    notice, this list of conditions and the following disclaimer.
134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
144Srgrimes *    notice, this list of conditions and the following disclaimer in the
154Srgrimes *    documentation and/or other materials provided with the distribution.
164Srgrimes * 3. All advertising materials mentioning features or use of this software
174Srgrimes *    must display the following acknowledgement:
184Srgrimes *	This product includes software developed by the University of
194Srgrimes *	California, Berkeley and its contributors.
204Srgrimes * 4. Neither the name of the University nor the names of its contributors
214Srgrimes *    may be used to endorse or promote products derived from this software
224Srgrimes *    without specific prior written permission.
234Srgrimes *
244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344Srgrimes * SUCH DAMAGE.
354Srgrimes *
36620Srgrimes *	from: @(#)autoconf.c	7.1 (Berkeley) 5/9/91
3750184Speter *	$Id: autoconf.c,v 1.132 1999/08/13 10:29:16 phk Exp $
384Srgrimes */
394Srgrimes
404Srgrimes/*
414Srgrimes * Setup the system to run on the current machine.
424Srgrimes *
438876Srgrimes * Configure() is called at boot time and initializes the vba
444Srgrimes * device tables and the memory controller monitoring.  Available
454Srgrimes * devices are determined (from possibilities mentioned in ioconf.c),
464Srgrimes * and the drivers are initialized.
474Srgrimes */
4832358Seivind#include "opt_bootp.h"
4932726Seivind#include "opt_ffs.h"
5025460Sjoerg#include "opt_cd9660.h"
5137272Sjmg#include "opt_nfsroot.h"
5245720Speter#include "opt_bus.h"
5346806Sphk#include "opt_rootdevname.h"
5425164Speter
552056Swollman#include <sys/param.h>
562056Swollman#include <sys/systm.h>
5745720Speter#include <sys/bus.h>
582056Swollman#include <sys/conf.h>
5931328Speter#include <sys/disklabel.h>
6036809Sbde#include <sys/diskslice.h>
612056Swollman#include <sys/reboot.h>
622056Swollman#include <sys/kernel.h>
6336809Sbde#include <sys/malloc.h>
6412604Sbde#include <sys/mount.h>
6512649Speter#include <sys/sysctl.h>
6649558Sphk#include <sys/cons.h>
674Srgrimes
6820641Sbde#include <machine/bootinfo.h>
6931337Sbde#include <machine/ipl.h>
707090Sbde#include <machine/md_var.h>
7127288Sfsmp#ifdef APIC_IO
7225164Speter#include <machine/smp.h>
7325164Speter#endif /* APIC_IO */
7427288Sfsmp
7529243Sjmg#include "pnp.h"
7629243Sjmg#if NPNP > 0
7729243Sjmg#include <i386/isa/pnp.h>
7829243Sjmg#endif
7929243Sjmg
8046915Speterdevice_t isa_bus_device = 0;
8146915Speter
8242817Speterstatic void	configure_first __P((void *));
8312604Sbdestatic void	configure __P((void *));
8442817Speterstatic void	configure_final __P((void *));
8512604Sbde
8612848Sbdestatic void	configure_finish __P((void));
8712848Sbdestatic void	configure_start __P((void));
8847444Sjb#if defined(FFS) || defined(FFS_ROOT)
8912848Sbdestatic void	setroot __P((void));
9047444Sjb#endif
9146806Sphkstatic int	setrootbyname __P((char *name));
9246806Sphkstatic void	gets __P((char *));
9312848Sbde
9442817SpeterSYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL);
9542817Speter/* SI_ORDER_SECOND is hookable */
9642817SpeterSYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);
9742817Speter/* SI_ORDER_MIDDLE is hookable */
9842817SpeterSYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL);
9942817Speter
10046806Sphkdev_t	rootdev = NODEV;
10146806Sphkdev_t	dumpdev = NODEV;
10242817Speter
10339982Sobrien#if defined(CD9660) || defined(CD9660_ROOT)
10422521Sdyson
10525460Sjoerg#include <sys/fcntl.h>
10625460Sjoerg#include <sys/proc.h>
10725460Sjoerg#include <sys/stat.h>
10825460Sjoerg#include <machine/clock.h>
10922521Sdyson
11025460Sjoerg/*
11125460Sjoerg * XXX All this CD-ROM root stuff is fairly messy.  Ick.
11225460Sjoerg *
11325460Sjoerg * We need to try out all our potential CDROM drives, so we need a table.
11425460Sjoerg */
1157731Sphkstatic struct {
1167731Sphk	char *name;
1177731Sphk	int major;
1187731Sphk} try_cdrom[] = {
1197731Sphk	{ "cd", 6 },
1207731Sphk	{ "mcd", 7 },
1217731Sphk	{ "scd", 16 },
1227731Sphk	{ "matcd", 17 },
12325460Sjoerg	{ "wcd", 19 },
1247731Sphk	{ 0, 0}
1257731Sphk};
1267731Sphk
12725460Sjoergstatic int	find_cdrom_root __P((void));
12812604Sbde
12912604Sbdestatic int
13025460Sjoergfind_cdrom_root()
1317731Sphk{
13225460Sjoerg	int i, j, error;
13337389Sjulian	struct cdevsw *bd;
13425460Sjoerg	dev_t orootdev;
1357731Sphk
13625460Sjoerg#if CD9660_ROOTDELAY > 0
13725460Sjoerg	DELAY(CD9660_ROOTDELAY * 1000000);
13825460Sjoerg#endif
13925460Sjoerg	orootdev = rootdev;
14025460Sjoerg	for (i = 0 ; i < 2; i++)
14125460Sjoerg		for (j = 0 ; try_cdrom[j].name ; j++) {
14247640Sphk			if (try_cdrom[j].major >= NUMCDEVSW)
14325460Sjoerg				continue;
14447680Sphk			rootdev = makebdev(try_cdrom[j].major, i * 8);
14549679Sphk			bd = devsw(rootdev);
14625460Sjoerg			if (bd == NULL || bd->d_open == NULL)
14725460Sjoerg				continue;
14825460Sjoerg			if (bootverbose)
14948531Speter				printf("trying %s%d as rootdev (%p)\n",
15048531Speter				       try_cdrom[j].name, i, (void *)rootdev);
15125460Sjoerg			error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
15225460Sjoerg			if (error == 0) {
15325460Sjoerg				if (bd->d_close != NULL)
15425460Sjoerg					(bd->d_close)(rootdev, FREAD, S_IFBLK,
15525460Sjoerg						      curproc);
15625460Sjoerg				return 0;
15725460Sjoerg			}
1587731Sphk		}
15925460Sjoerg
16025460Sjoerg	rootdev = orootdev;
1617731Sphk	return EINVAL;
1627731Sphk}
16339982Sobrien#endif /* CD9660 || CD9660_ROOT */
1647731Sphk
16512604Sbdestatic void
1667818Sdufaultconfigure_start()
1677818Sdufault{
1687818Sdufault}
1697818Sdufault
17012604Sbdestatic void
1717818Sdufaultconfigure_finish()
1727818Sdufault{
1737818Sdufault}
1747818Sdufault
17545720Speterdevice_t nexus_dev;
17645720Speter
1774Srgrimes/*
1784Srgrimes * Determine i/o configuration for a machine.
1794Srgrimes */
18010665Sbdestatic void
18142817Speterconfigure_first(dummy)
18242817Speter	void *dummy;
18342817Speter{
18442817Speter
18542817Speter	configure_start();		/* DDB hook? */
18642817Speter}
18742817Speter
18842817Speterstatic void
18910665Sbdeconfigure(dummy)
19010653Sdg	void *dummy;
1914Srgrimes{
1924Srgrimes
19329675Sgibbs	/*
19450184Speter	 * Activate the ICU's.  Note that we are explicitly at splhigh()
19550184Speter	 * at present as we have no way to disable stray PCI level triggered
19650184Speter	 * interrupts until the devices have had a driver attached.  This
19750184Speter	 * is particularly a problem when the interrupts are shared.  For
19850184Speter	 * example, if IRQ 10 is shared between a disk and network device
19950184Speter	 * and the disk device generates an interrupt, if we "activate"
20050184Speter	 * IRQ 10 when the network driver is set up, then we will get
20150184Speter	 * recursive interrupt 10's as nothing will know how to turn off
20250184Speter	 * the disk device's interrupt.
20350184Speter	 *
20450184Speter	 * Having the ICU's active means we can probe interrupt routing to
20550184Speter	 * see if a device causes the corresponding pending bit to be set.
20650184Speter	 *
20750184Speter	 * This is all rather inconvenient.
20829675Sgibbs	 */
20927288Sfsmp#ifdef APIC_IO
21027288Sfsmp	bsp_apic_configure();
21125172Speter	enable_intr();
21227288Sfsmp#else
21327288Sfsmp	enable_intr();
21425172Speter	INTREN(IRQ_SLAVE);
21527288Sfsmp#endif /* APIC_IO */
21612791Sgibbs
21745720Speter	/* nexus0 is the top of the i386 device tree */
21845720Speter	device_add_child(root_bus, "nexus", 0, 0);
21912791Sgibbs
22038779Snsouch	/* initialize new bus architecture */
22138779Snsouch	root_bus_configure();
22238779Snsouch
22350184Speter#if NPNP > 0
22450184Speter	/* Activate PNP. If no drivers are found, let ISA probe them.. */
22550184Speter	pnp_configure();
22650184Speter#endif
22750184Speter
22850184Speter	/*
22950184Speter	 * Explicitly probe and attach ISA last.  The isa bus saves
23050184Speter	 * it's device node at attach time for us here.
23150184Speter	 */
23245720Speter	if (isa_bus_device)
23345720Speter		bus_generic_attach(isa_bus_device);
23445720Speter
23531336Sbde	/*
23631336Sbde	 * Now we're ready to handle (pending) interrupts.
23731336Sbde	 * XXX this is slightly misplaced.
23831336Sbde	 */
23931336Sbde	spl0();
24031336Sbde
24131337Sbde	/*
24231337Sbde	 * Allow lowering of the ipl to the lowest kernel level if we
24331337Sbde	 * panic (or call tsleep() before clearing `cold').  No level is
24431337Sbde	 * completely safe (since a panic may occur in a critical region
24531337Sbde	 * at splhigh()), but we want at least bio interrupts to work.
24631337Sbde	 */
24731337Sbde	safepri = cpl;
24842817Speter}
24931337Sbde
25042817Speterstatic void
25142817Speterconfigure_final(dummy)
25242817Speter	void *dummy;
25342817Speter{
25442817Speter	int i;
25522564Sbde
25642817Speter	configure_finish();			/* DDB hook? */
2577818Sdufault
25810665Sbde	cninit_finish();
25910665Sbde
26020641Sbde	if (bootverbose) {
26127561Sfsmp
26227561Sfsmp#ifdef APIC_IO
26327615Sfsmp		imen_dump();
26427561Sfsmp#endif /* APIC_IO */
26527561Sfsmp
26620641Sbde		/*
26720641Sbde		 * Print out the BIOS's idea of the disk geometries.
26820641Sbde		 */
26920641Sbde		printf("BIOS Geometries:\n");
27020641Sbde		for (i = 0; i < N_BIOS_GEOM; i++) {
27120641Sbde			unsigned long bios_geom;
27220641Sbde			int max_cylinder, max_head, max_sector;
27320641Sbde
27420641Sbde			bios_geom = bootinfo.bi_bios_geom[i];
27520641Sbde
27620641Sbde			/*
27720641Sbde			 * XXX the bootstrap punts a 1200K floppy geometry
27820641Sbde			 * when the get-disk-geometry interrupt fails.  Skip
27920641Sbde			 * drives that have this geometry.
28020641Sbde			 */
28120641Sbde			if (bios_geom == 0x4f010f)
28220641Sbde				continue;
28320641Sbde
28420641Sbde			printf(" %x:%08lx ", i, bios_geom);
28520641Sbde			max_cylinder = bios_geom >> 16;
28620641Sbde			max_head = (bios_geom >> 8) & 0xff;
28720641Sbde			max_sector = bios_geom & 0xff;
28820641Sbde			printf(
28920641Sbde		"0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
29020641Sbde			       max_cylinder, max_cylinder + 1,
29120641Sbde			       max_head, max_head + 1,
29220641Sbde			       max_sector, max_sector);
29320641Sbde		}
29420641Sbde		printf(" %d accounted for\n", bootinfo.bi_n_bios_used);
29520641Sbde
29616075Sjoerg		printf("Device configuration finished.\n");
29720641Sbde	}
29829675Sgibbs	cold = 0;
29929675Sgibbs}
30016075Sjoerg
30135319Sjulian
30229675Sgibbsvoid
30329675Sgibbscpu_rootconf()
30429675Sgibbs{
30529675Sgibbs	/*
30629675Sgibbs	 * XXX NetBSD has a much cleaner approach to finding root.
30729675Sgibbs	 * XXX We should adopt their code.
30829675Sgibbs	 */
30939982Sobrien#if defined(CD9660) || defined(CD9660_ROOT)
31022521Sdyson	if ((boothowto & RB_CDROM)) {
31116075Sjoerg		if (bootverbose)
31216075Sjoerg			printf("Considering CD-ROM root f/s.\n");
31325460Sjoerg		/* NB: find_cdrom_root() sets rootdev if successful. */
31425460Sjoerg		if (find_cdrom_root() == 0)
31525460Sjoerg			mountrootfsname = "cd9660";
31625460Sjoerg		else if (bootverbose)
31725460Sjoerg			printf("No CD-ROM available as root f/s.\n");
31816075Sjoerg	}
3197731Sphk#endif
3208007Sphk
32125723Stegge#ifdef BOOTP_NFSROOT
32225723Stegge	if (!mountrootfsname && !nfs_diskless_valid) {
32325723Stegge		if (bootverbose)
32425723Stegge			printf("Considering BOOTP NFS root f/s.\n");
32525723Stegge		mountrootfsname = "nfs";
32625723Stegge	}
32725723Stegge#endif /* BOOTP_NFSROOT */
32839982Sobrien#if defined(NFS) || defined(NFS_ROOT)
32922564Sbde	if (!mountrootfsname && nfs_diskless_valid) {
33022564Sbde		if (bootverbose)
33122564Sbde			printf("Considering NFS root f/s.\n");
33222564Sbde		mountrootfsname = "nfs";
33322564Sbde	}
33422564Sbde#endif /* NFS */
33522564Sbde
33639982Sobrien#if defined(FFS) || defined(FFS_ROOT)
33722521Sdyson	if (!mountrootfsname) {
33822521Sdyson		mountrootfsname = "ufs";
33916075Sjoerg		if (bootverbose)
34016075Sjoerg			printf("Considering FFS root f/s.\n");
34145703Sbde		if (boothowto & RB_ASKNAME)
34245703Sbde			setconf();
34345703Sbde		else
3445321Sjkh			setroot();
3453795Sphk	}
3464Srgrimes#endif
34722564Sbde
34822521Sdyson	if (!mountrootfsname) {
3494370Sphk		panic("Nobody wants to mount my root for me");
3504370Sphk	}
35129675Sgibbs}
35217355Sbde
3538833Sdgu_long	bootdev = 0;		/* not a dev_t - encoding is different */
3544Srgrimes
3551289Sache#define FDMAJOR 2
3561290Sache#define FDUNITSHIFT     6
3574Srgrimes
35847444Sjb#if defined(FFS) || defined(FFS_ROOT)
3594Srgrimes/*
3604Srgrimes * Attempt to find the device from which we were booted.
3614Srgrimes * If we can do so, and not instructed not to do so,
36236809Sbde * set rootdevs[] and rootdevnames[] to correspond to the
36336809Sbde * boot device(s).
3644Srgrimes */
365798Swollmanstatic void
3664Srgrimessetroot()
3674Srgrimes{
36836809Sbde	int majdev, mindev, unit, slice, part;
36946773Sphk	dev_t newrootdev, dev;
37036809Sbde	char partname[2];
37136809Sbde	char *sname;
3724Srgrimes
37346806Sphk	if (boothowto & RB_DFLTROOT) {
37446808Sphk#ifdef ROOTDEVNAME
37546806Sphk		setrootbyname(ROOTDEVNAME);
37646808Sphk#else
37746808Sphk		setconf();
37846808Sphk#endif
3794Srgrimes		return;
38046806Sphk	}
38148512Sphk	if ((bootdev & B_MAGICMASK) != B_DEVMAGIC) {
38248512Sphk		printf("No B_DEVMAGIC\n");
38348512Sphk		setconf();
38446806Sphk		return;
38548512Sphk	}
38636809Sbde	majdev = B_TYPE(bootdev);
38747680Sphk	dev = makebdev(majdev, 0);
38849679Sphk	if (devsw(dev) == NULL) {
38948521Speter		printf("No bdevsw (majdev=%d bootdev=%p)\n", majdev,
39048521Speter		    (void *)bootdev);
39148512Sphk		setconf();
39236809Sbde		return;
39348512Sphk	}
39436809Sbde	unit = B_UNIT(bootdev);
39536809Sbde	slice = B_SLICE(bootdev);
39636809Sbde	if (slice == WHOLE_DISK_SLICE)
39734624Smsmith		slice = COMPATIBILITY_SLICE;
39848512Sphk	if (slice < 0 || slice >= MAX_SLICES) {
39948512Sphk		printf("bad slice\n");
40048512Sphk		setconf();
4014Srgrimes		return;
40248512Sphk	}
40336809Sbde
40436809Sbde	/*
40536809Sbde	 * XXX kludge for inconsistent unit numbering and lack of slice
40636809Sbde	 * support for floppies.
40736809Sbde	 */
4081290Sache	if (majdev == FDMAJOR) {
40936809Sbde		slice = COMPATIBILITY_SLICE;
4102400Sache		part = RAW_PART;
4111290Sache		mindev = unit << FDUNITSHIFT;
41236809Sbde	} else {
41336809Sbde		part = B_PARTITION(bootdev);
41434622Smsmith		mindev = dkmakeminor(unit, slice, part);
4151290Sache	}
41636809Sbde
41747680Sphk	newrootdev = makebdev(majdev, mindev);
41836809Sbde	rootdevs[0] = newrootdev;
41949679Sphk	sname = dsname(devsw(newrootdev)->d_name, unit, slice, part, partname);
42036809Sbde	rootdevnames[0] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT);
42136809Sbde	sprintf(rootdevnames[0], "%s%s", sname, partname);
42236809Sbde
4234Srgrimes	/*
42436809Sbde	 * For properly dangerously dedicated disks (ones with a historical
42536809Sbde	 * bogus partition table), the boot blocks will give slice = 4, but
42636809Sbde	 * the kernel will only provide the compatibility slice since it
42736809Sbde	 * knows that slice 4 is not a real slice.  Arrange to try mounting
42836809Sbde	 * the compatibility slice as root if mounting the slice passed by
42936809Sbde	 * the boot blocks fails.  This handles the dangerously dedicated
43036809Sbde	 * case and perhaps others.
4314Srgrimes	 */
43236809Sbde	if (slice == COMPATIBILITY_SLICE)
4334Srgrimes		return;
43436809Sbde	slice = COMPATIBILITY_SLICE;
43536809Sbde	rootdevs[1] = dkmodslice(newrootdev, slice);
43649679Sphk	sname = dsname(devsw(newrootdev)->d_name, unit, slice, part, partname);
43736809Sbde	rootdevnames[1] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT);
43836809Sbde	sprintf(rootdevnames[1], "%s%s", sname, partname);
4394Srgrimes}
44047444Sjb#endif
44112649Speter
44235319Sjulian
44312649Speter
44446806Sphkstatic int
44546806Sphksetrootbyname(char *name)
44646806Sphk{
44746806Sphk	char *cp;
44846806Sphk	int bd, unit, slice, part;
44946806Sphk	dev_t dev;
45046806Sphk
45148512Sphk	printf("setrootbyname(\"%s\")\n", name);
45246806Sphk	slice = 0;
45346806Sphk	part = 0;
45446806Sphk	cp = name;
45546806Sphk	while (cp != '\0' && (*cp < '0' || *cp > '9'))
45646806Sphk		cp++;
45746806Sphk	if (cp == name) {
45846806Sphk		printf("missing device name\n");
45946806Sphk		return(1);
46046806Sphk	}
46146806Sphk	if (*cp == '\0') {
46246806Sphk		printf("missing unit number\n");
46346806Sphk		return(1);
46446806Sphk	}
46546806Sphk	unit = *cp - '0';
46646806Sphk	*cp++ = '\0';
46747640Sphk	for (bd = 0; bd < NUMCDEVSW; bd++) {
46847680Sphk		dev = makebdev(bd, 0);
46949679Sphk		if (devsw(dev) != NULL &&
47049679Sphk		    strcmp(devsw(dev)->d_name, name) == 0)
47146806Sphk			goto gotit;
47246806Sphk	}
47346806Sphk	return (2);
47446806Sphkgotit:
47546806Sphk	while (*cp >= '0' && *cp <= '9')
47646806Sphk		unit += 10 * unit + *cp++ - '0';
47746806Sphk	if (*cp == 's' && cp[1] >= '0' && cp[1] <= '9') {
47849474Sphk		slice = cp[1] - '0' + 1;
47946806Sphk		cp += 2;
48046806Sphk	}
48146806Sphk	if (*cp >= 'a' && *cp <= 'h') {
48246806Sphk		part = *cp - 'a';
48346806Sphk		cp++;
48446806Sphk	}
48546806Sphk	if (*cp != '\0') {
48646806Sphk		printf("junk after name\n");
48746806Sphk		return (1);
48846806Sphk	}
48947680Sphk	rootdev = makebdev(bd, dkmakeminor(unit, slice, part));
49048521Speter	printf("driver=%s, unit=%d, slice=%d, part=%d -> rootdev=%p\n",
49148521Speter		name, unit, slice, part, (void *)rootdev);
49246806Sphk	return 0;
49346806Sphk}
49446806Sphk
49546806Sphkvoid
49646806Sphksetconf()
49746806Sphk{
49846806Sphk	char name[128];
49946806Sphk	int i;
50046806Sphk	dev_t dev;
50146806Sphk
50246806Sphk	for(;;) {
50346806Sphk		printf("root device? ");
50446806Sphk		gets(name);
50546806Sphk		i = setrootbyname(name);
50646806Sphk		if (!i)
50746806Sphk			return;
50846806Sphk
50946806Sphk		printf("use one of:\n");
51047640Sphk		for (i = 0; i < NUMCDEVSW; i++) {
51147680Sphk			dev = makebdev(i, 0);
51249679Sphk			if (devsw(dev) != NULL)
51349679Sphk			    printf(" \"%s\"", devsw(dev)->d_name);
51446806Sphk		}
51548512Sphk		printf("\nfollowed by a unit number...\n");
51646806Sphk	}
51746806Sphk}
51846806Sphk
51946806Sphkstatic void
52046806Sphkgets(cp)
52146806Sphk	char *cp;
52246806Sphk{
52346806Sphk	register char *lp;
52446806Sphk	register int c;
52546806Sphk
52646806Sphk	lp = cp;
52746806Sphk	for (;;) {
52846806Sphk		printf("%c", c = cngetc() & 0177);
52946806Sphk		switch (c) {
53046806Sphk		case -1:
53146806Sphk		case '\n':
53246806Sphk		case '\r':
53346806Sphk			*lp++ = '\0';
53446806Sphk			return;
53546806Sphk		case '\b':
53646806Sphk		case '\177':
53746806Sphk			if (lp > cp) {
53846806Sphk				printf(" \b");
53946806Sphk				lp--;
54046806Sphk			}
54146806Sphk			continue;
54246806Sphk		case '#':
54346806Sphk			lp--;
54446806Sphk			if (lp < cp)
54546806Sphk				lp = cp;
54646806Sphk			continue;
54746806Sphk		case '@':
54846806Sphk		case 'u' & 037:
54946806Sphk			lp = cp;
55046806Sphk			printf("%c", '\n');
55146806Sphk			continue;
55246806Sphk		default:
55346806Sphk			*lp++ = c;
55446806Sphk		}
55546806Sphk	}
55646806Sphk}
557