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