diff --git a/usr.sbin/pccard/misc/COPYRIGHT b/usr.sbin/pccard/misc/COPYRIGHT deleted file mode 100644 index 4f8c5509a536..000000000000 --- a/usr.sbin/pccard/misc/COPYRIGHT +++ /dev/null @@ -1,11 +0,0 @@ -Original work is copyright (C) Andrew McRae 1994,1995 -Permission is granted to freely copy as long as -all attribution remains and copyright notices are -included, and source made available upon request. - -Parts of this distribution is derived from work -by Barry Jaspan and Keith Moore. - -DISCLAIMER: -There is no warranty for this software. -All responsibility is your own. diff --git a/usr.sbin/pccard/misc/FILES b/usr.sbin/pccard/misc/FILES deleted file mode 100644 index dcb097ab7db2..000000000000 --- a/usr.sbin/pccard/misc/FILES +++ /dev/null @@ -1,12 +0,0 @@ -The files are: - - enabler Sample enabler for connecting drivers - dumpcis Reads and dumps CIS of card. - pccardmem Sets a memory area for use by the driver - rdmap Dumps the current memory and I/O card contexts - rdreg reads a PCIC register - wrreg Writes a PCIC register - wrattr Writes a byte into the card's attribute area. - -The cardd stuff has been updated for the new interfaces, but -hasn't been tested to any real extent. diff --git a/usr.sbin/pccard/misc/INSTALL b/usr.sbin/pccard/misc/INSTALL deleted file mode 100644 index c9f36593d072..000000000000 --- a/usr.sbin/pccard/misc/INSTALL +++ /dev/null @@ -1,34 +0,0 @@ -INSTALLATION ------------- - -1. Copy the source files from the sys directory into your - /sys (or where-ever) tree. There are a number of .diff files - that can be used to modify the following files: - sys/conf/files - sys/i386/i386/autoconf.c - sys/i386/i386/conf.c - There is also a sys/pccard directory that should reside in - /sys/pccard - -2. Make a symbolic link like: - ln -s /sys/pccard /usr/include/pccard - -3. Add a line in the kernel config file: - - controller crd0 - - and rebuild the kernel. Optionally, the PCIC slot driver can - and also built into the kernel by adding the line: - - device pcic0 - -4. Create a device for each slot e.g. - - foreach i (0 1) - mknod /dev/card$i c 50 $i - end - -5. You can use lkm to load the PCIC controller. It can - be unloaded at will. Once loaded, you should assign - some memory via pccardmem for use with read/write. - Normally cardd does this, but I haven't quite finished yet. diff --git a/usr.sbin/pccard/misc/Makefile b/usr.sbin/pccard/misc/Makefile deleted file mode 100644 index 37d953b78500..000000000000 --- a/usr.sbin/pccard/misc/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# Makefile for PCMCIA card programs. -# -CFLAGS = -m486 -g # -DDEBUG - -PROGS = dumpcis rdmap rdreg wrreg pccardmem wrattr enabler - -all: $(PROGS) - -clean: - rm -f *.core core *.o $(PROGS) - -dumpcis: dumpcis.o readcis.o printcis.o - cc -o dumpcis -static dumpcis.o readcis.o printcis.o - -wrattr: wrattr.c - cc $(CFLAGS) -o wrattr wrattr.c - -pccardmem: pccardmem.c - cc $(CFLAGS) -o pccardmem pccardmem.c - -enabler: enabler.c - cc $(CFLAGS) -o enabler enabler.c - -rdmap: rdmap.c - cc $(CFLAGS) -o rdmap rdmap.c - -rdreg: rdreg.c - cc $(CFLAGS) -o rdreg rdreg.c - -wrreg: wrreg.c - cc $(CFLAGS) -o wrreg wrreg.c diff --git a/usr.sbin/pccard/misc/README.old b/usr.sbin/pccard/misc/README.old deleted file mode 100644 index 76e005a9b916..000000000000 --- a/usr.sbin/pccard/misc/README.old +++ /dev/null @@ -1,62 +0,0 @@ -PCMCIA Support for FreeBSD 2.0 ------------------------------- - -This package contains the following: - - - Driver for Intel 83265 PCIC PCMCIA controller - - A PCMCIA daemon for managing card insertions/removals - - Diffs to various source files for adding PCMCIA support - - A sample config file - - Some utility programs for reading card data tuples - - Some documentation. - -What it doesn't include is: - - - Configuration for brand XYZ PCMCIA cards - - Drivers for brand XYZ PCMCIA cards - - Diffs to modify standard drivers to handle card events - -Essentially, this package contains everything required to -add PCMCIA support to FreeBSD 2.0. It does this via a -daemon that manages the PCMCIA slots via a PCIC driver. A configuration -file provides the daemon with the information required to setup -the specific cards, and to manage card insertion and removal. - -This package has been tested on a NEC Versa Laptop. -The first version was developed on FreeBSD 1.1.5.1. - -The main idea behind the package is for pcmciad to detect -inserted cards and match to a card ID in the config file, -then set up the I/O ports and memory window to the card -according to the data for the driver associated with the -card, then attach the kernel driver to the device. Shell -commands can be executed for both insertion and removal of cards, -and different commands can be executed for different cards, -drivers and devices. - -Different kernel drivers may have to have some mods -done to recognise the card once installed; I have included -some diffs to `ed' that allows recognition of a `generic' -NS8390 card. - -Some minor changes were made to ifconfig(8) to allow a -different ethernet address to be assigned to a network -interface, since each card may have different locations -the ethernet address is stored in. - -This is a snapshot of a release for FreeBSD 2.0. It is -basically the 1.1.5.1 release ported for 2.0. I have only -just received a developer's guide for PCMCIA, so I should -have some more stable support soon. - -For instructions on installation, see INSTALL. -There is a man entry on the daemon (pcmciad.8), -and the config file (pcmcia.conf.5). - -Please send mail with any bugs or new card descriptions. - -Enjoy! -Andrew McRae inet: andrew@mega.com.au -MITS Real Time Ltd, uucp: ..!uunet!mega.com.au!andrew -North Ryde 2113 Phone: +61 2 805 0899 -NSW AUSTRALIA Fax: +61 2 887 4847 diff --git a/usr.sbin/pccard/misc/rpti.c b/usr.sbin/pccard/misc/rpti.c deleted file mode 100644 index d97c490f9c59..000000000000 --- a/usr.sbin/pccard/misc/rpti.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Enabler for PCCARD. Used for testing drivers etc. - * Options: - * enabler slot driver [ -m card addr size ] [ -i iobase ] [ -q irq ] - */ -#include -#include -#include -#include -#include - -#include -#include - -void usage(); - - -main(argc, argv) -int argc; -char *argv[]; -{ -struct drv_desc drv; -struct mem_desc mem; -struct io_desc io; -int fd, err, slot, i, card_addr; -char name[32], cmd[256]; -char *p; - - if (argc == 2) - slot = atoi(argv[1]); - else - slot = 0; - if (slot < 0 || slot >= MAXSLOT) - usage("Illegal slot number"); - sprintf(cmd, "util/wrattr %d 100 80", slot); - printf("%s\n", cmd); - system(cmd); - usleep(200*1000); - sprintf(cmd, "util/wrattr %d 100 0", slot); - printf("%s\n", cmd); - system(cmd); - usleep(200*1000); - sprintf(cmd, "util/wrattr %d 100 30", slot); - printf("%s\n", cmd); - system(cmd); - usleep(200*1000); - bzero(&drv, sizeof(drv)); - drv.unit = 0; - strcpy(drv.name, "ed"); - drv.irqmask = 1 << 5; - sprintf(name, "/dev/card%d", slot); - fd = open(name, 2); - if (fd < 0) - { - perror(name); - exit(1); - } -/* - * Map the memory and I/O contexts. - */ - drv.mem = 0xD4000; - if (drv.mem) - { - mem.window = 0; - mem.flags = MDF_ACTIVE; - mem.start = (caddr_t)drv.mem; - mem.size = 16*1024; - mem.card = 0x4000; - if (ioctl(fd, PIOCSMEM, &mem)) - { - perror("Set memory context"); - exit(1); - } - } - drv.iobase = 0x300; - if (drv.iobase) - { - io.window = 0; - io.flags = IODF_ACTIVE|IODF_CS16|IODF_WS; - io.start = drv.iobase; - io.size = 32; /* Blah... */ - if (ioctl(fd, PIOCSIO, &io)) - { - perror("Set I/O context"); - exit(1); - } -#ifdef 0 - io.window = 1; - io.flags = IODF_ACTIVE|IODF_16BIT; - io.start = drv.iobase+16; - io.size = 16; /* Blah... */ - if (ioctl(fd, PIOCSIO, &io)) - { - perror("Set I/O context"); - exit(1); - } -#endif - } - if (ioctl(fd, PIOCSDRV, &drv)) - perror("set driver"); - close(fd); -} -/* - * usage - print usage and exit - */ -void -usage(msg) -char *msg; -{ - fprintf(stderr, "rpti: %s\n", msg); - fprintf(stderr, "Usage: rpti slot driver\n"); - exit(1); -} diff --git a/usr.sbin/pccard/misc/skeldrv.c b/usr.sbin/pccard/misc/skeldrv.c deleted file mode 100644 index ba4386154d4b..000000000000 --- a/usr.sbin/pccard/misc/skeldrv.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - - -main(argc, argv) -int argc; -char *argv[]; -{ -struct drv_desc drv; -int fd, err; - - fd = open("/dev/card0", 0); - if (fd < 0) - { - perror("/dev/card0"); - exit(1); - } - strcpy(drv.name, "skel"); - if (argc == 2) - drv.unit = atoi(argv[1]); - else - drv.unit = 0; - drv.iobase = 0x300; - drv.mem = 0xD4000; - drv.memsize = 16*1024; - drv.irq = 0xFFFF; - drv.flags = 0x1234; - if (ioctl(fd, PIOCSDRV, &drv)) - perror("set driver"); - close(fd); -} diff --git a/usr.sbin/pccard/misc/sys/i386/conf/LAPTOP b/usr.sbin/pccard/misc/sys/i386/conf/LAPTOP deleted file mode 100644 index 9b2678985f8d..000000000000 --- a/usr.sbin/pccard/misc/sys/i386/conf/LAPTOP +++ /dev/null @@ -1,63 +0,0 @@ -# -# GENERIC -- Generic machine with WD/AHx/NCR/BTx family disks -# -# GENERIC,v 1.20 1994/11/18 19:10:25 jkh Exp -# - -machine "i386" -cpu "I386_CPU" -cpu "I486_CPU" -cpu "I586_CPU" -ident LAPTOP -maxusers 4 - -options MATH_EMULATE #Support for x87 emulation -options INET #InterNETworking -options FFS #Berkeley Fast Filesystem -options NFS #Network Filesystem -options MSDOSFS #MSDOS Filesystem -options PROCFS #Process filesystem -options "COMPAT_43" #Compatible with BSD 4.3 -options UCONSOLE #X Console support -options "FAT_CURSOR" #block cursor in syscons or pccons -options "NCONS=4" #4 virtual consoles -options ALLOW_CONFLICT_IOADDR -options PSM_NO_RESET - -config kernel root on wd0 swap on wd0 and wd1 and sd0 and sd1 dumps on wd0 - -controller crd0 -#device pcic0 - - -controller isa0 - -controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr -disk fd0 at fdc0 drive 0 - -controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr -disk wd0 at wdc0 drive 0 - -device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr -device npx0 at isa? port "IO_NPX" irq 13 vector npxintr -device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr - -#device pcic0 at isa? port 0x3E0 tty irq 3 iomem 0xd0000 - -device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr -device sio1 at isa? port "IO_COM2" tty irq 10 vector siointr -#device sio1 at isa? port "IO_COM2" tty flags 0x80 irq 10 vector siointr - -device lpt0 at isa? port? tty irq 7 vector lptintr - -#device ed0 at isa? port 0x300 net flags 0x20 irq 5 iomem 0xd4000 vector edintr - -device apm0 at isa? - -pseudo-device loop -pseudo-device ether -pseudo-device log -pseudo-device sl 2 -pseudo-device pty 16 -pseudo-device speaker -pseudo-device gzip # Exec gzipped a.out's diff --git a/usr.sbin/pccard/misc/sys/pccard/Makefile b/usr.sbin/pccard/misc/sys/pccard/Makefile deleted file mode 100644 index e78a156832c1..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -all: pcic.o ed.o - -CFLAGS = -O -DINET -DKERNEL -DLKM -I/sys - -pcic.o: pcic.c - cc -c $(CFLAGS) pcic.c - -load: pcic.o - modload -e lkm_pcic pcic.o - pccardmem d0000 - -unload: - modunload -n pcic - -skel.o: skel.c - cc -c $(CFLAGS) skel.c - -ldskel: skel.o - modload -e lkm_skel skel.o - -ed.o: if_ed.o lkm_ed.o - ld -r -o ed.o if_ed.o lkm_ed.o - -lded: ed.o - modload -e lkm_ed ed.o diff --git a/usr.sbin/pccard/misc/sys/pccard/README b/usr.sbin/pccard/misc/sys/pccard/README deleted file mode 100644 index cc1ea70013a5..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/README +++ /dev/null @@ -1,13 +0,0 @@ - -This directory contains: - - card.h Include file for driver interface - cis.h CIS defines - slot.h Kernel interface for card/slot driver/devices interface - i82365.h Defines for PCIC device - - pccard.c Mainline PC-Card support functions (card services). - pcic.c PCIC or compatible slot driver (loadable). - skel.c Skeleton loadable driver interfacing to card services. - -The other files are working copies of drivers. diff --git a/usr.sbin/pccard/misc/sys/pccard/bpfilter.h b/usr.sbin/pccard/misc/sys/pccard/bpfilter.h deleted file mode 100644 index 21d2ed822f4a..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/bpfilter.h +++ /dev/null @@ -1 +0,0 @@ -#define NBPFILTER 0 diff --git a/usr.sbin/pccard/misc/sys/pccard/ed.h b/usr.sbin/pccard/misc/sys/pccard/ed.h deleted file mode 100644 index d2d7bac00c8e..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/ed.h +++ /dev/null @@ -1 +0,0 @@ -#define NED 2 diff --git a/usr.sbin/pccard/misc/sys/pccard/if_ed.c b/usr.sbin/pccard/misc/sys/pccard/if_ed.c deleted file mode 100644 index f2c134feb756..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/if_ed.c +++ /dev/null @@ -1,1997 +0,0 @@ -/* - * Device driver for National Semiconductor DS8390/WD83C690 based ethernet - * adapters. By David Greenman, 29-April-1993 - * - * Copied 3 July 1995 from if_ed.c - * - *------------------------------------------------------------------------- - * - * Copyright (c) 1995 Andrew McRae. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Copyright (C) 1993, David Greenman. This software may be used, modified, - * copied, distributed, and sold, in both source and binary form provided - * that the above copyright and these terms are retained. Under no - * circumstances is the author responsible for the proper functioning - * of this software, nor does the author assume any responsibility - * for damages incurred with its use. - * - * $Id: if_ed.c,v 1.69 1995/04/12 20:47:45 wollman Exp $ - */ - -#include "ed.h" -#include "bpfilter.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef INET -#include -#include -#include -#include -#include -#endif - -#ifdef NS -#include -#include -#endif - -#if NBPFILTER > 0 -#include -#include -#endif - -#include - -#include -#include - -#include -#include -#include - -/* For backwards compatibility */ -#ifndef IFF_ALTPHYS -#define IFF_ALTPHYS IFF_LINK0 -#endif - -/* - * ed_softc: per line info and status - */ -static struct ed_softc { - struct arpcom arpcom; /* ethernet common */ - - char *type_str; /* pointer to type string */ - u_char vendor; /* interface vendor */ - u_char type; /* interface type code */ - - u_short asic_addr; /* ASIC I/O bus address */ - u_short nic_addr; /* NIC (DS8390) I/O bus address */ - -/* - * The following 'proto' variable is part of a work-around for 8013EBT asics - * being write-only. It's sort of a prototype/shadow of the real thing. - */ - u_char wd_laar_proto; - u_char cr_proto; - u_char isa16bit; /* width of access to card 0=8 or 1=16 */ - int is790; /* set by the probe code if the card is 790 - * based */ - - caddr_t bpf; /* BPF "magic cookie" */ - caddr_t mem_start; /* NIC memory start address */ - caddr_t mem_end; /* NIC memory end address */ - u_long mem_size; /* total NIC memory size */ - caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */ - - u_char mem_shared; /* NIC memory is shared with host */ - u_char xmit_busy; /* transmitter is busy */ - u_char txb_cnt; /* number of transmit buffers */ - u_char txb_inuse; /* number of TX buffers currently in-use */ - - u_char txb_new; /* pointer to where new buffer will be added */ - u_char txb_next_tx; /* pointer to next buffer ready to xmit */ - u_short txb_len[8]; /* buffered xmit buffer lengths */ - u_char tx_page_start; /* first page of TX buffer area */ - u_char rec_page_start; /* first page of RX ring-buffer */ - u_char rec_page_stop; /* last page of RX ring-buffer */ - u_char next_packet; /* pointer to next unread RX packet */ - struct kern_devconf kdc; /* kernel configuration database info */ -} ed_softc[NED]; - -int ed_attach(struct isa_device *); -void ed_init(int); -int edintr(struct pccard_dev *); -int ed_ioctl(struct ifnet *, int, caddr_t); -int ed_probe(struct isa_device *); -void ed_start(struct ifnet *); -void ed_reset(int); -void ed_watchdog(int); -int ed_probe_generic8390(struct ed_softc *); -int ed_probe_Novell(struct isa_device *); - -void ds_getmcaf(); - -static void ed_get_packet(struct ed_softc *, char *, int /* u_short */ , int); -static void ed_stop(int); - -static inline void ed_rint(); -static inline void ed_xmit(); -static inline char *ed_ring_copy(); - -void ed_pio_readmem(), ed_pio_writemem(); -u_short ed_pio_write_mbufs(); - -void ed_setrcr(struct ifnet *, struct ed_softc *); - -#define ETHER_MIN_LEN 64 -#define ETHER_MAX_LEN 1518 -#define ETHER_ADDR_LEN 6 -#define ETHER_HDR_SIZE 14 - -/* - * The device entry is being removed. Shut it down, - * and turn off interrupts etc. Not called unless - * the device was successfully installed. - */ -void -edunload(struct pccard_dev *dp) -{ - printf("ed%d: unload\n", dp->isahd.id_unit); - ed_stop(dp->isahd.id_unit); -} -/* - * Called when a power down is wanted. Shuts down the - * device and configures the device as unavailable (but - * still loaded...). A resume is done by calling - * edinit with first=0. - */ -void -edsuspend(struct pccard_dev *dp) -{ - printf("ed%d: suspending\n", dp->isahd.id_unit); -} -/* - * Initialize the device. - * if first is set, then initially check for - * the device's existence before initialising it. - * Once initialised, the device table may be set up. - */ -int -edinit(struct pccard_dev *dp, int first) -{ - if (first) - return(ed_probe(&dp->isahd)); - return(0); -} -/* - * Determine if the device is present - * - * on entry: - * a point to a pccard_dev structure - * on exit: - * NULL if device not found - * or # of i/o addresses used (if found) - */ -int -ed_probe(struct isa_device *pdev) -{ -int nports; - - nports = ed_probe_pccard(pdev); - if (nports == 0) - { - nports = ed_probe_Novell(pdev); - } - if (nports) - { - (void)ed_attach(pdev); - return (0); - } - return(ENODEV); -} -int -ed_probe_pccard(struct isa_device *pdev) -{ - struct ed_softc *sc = &ed_softc[pdev->id_unit]; - int n, memsize; - unsigned int *p; - unsigned char tmp; - - sc->asic_addr = pdev->id_iobase + 0x10; - sc->nic_addr = pdev->id_iobase; - printf("Probing at 0x%x, mem 0x%x\n", pdev->id_iobase, - pdev->id_maddr); -/* - * Reset the board by reading/writing a location. - * This may not exist on all boards, but hopefully - * is not invasive. - */ -#if 1 - tmp = inb(sc->asic_addr + ED_PCMCIA_RESET); - DELAY(5000); - outb(sc->asic_addr + ED_PCMCIA_RESET, tmp); - DELAY(5000); -#endif - - /* Make sure that we really have an 8390 based board */ - if (!ed_probe_generic8390(sc)) - return (0); -/* - * Check for shared memory. If we can write to it, then - * set up this as a generic controller with shared memory. - */ - memsize = 0; - if (pdev->id_maddr == 0) - return(0); -/* - * Write a bit pattern to memory. - */ - p = (unsigned int *)pdev->id_maddr; - for (n = 0; n < pdev->id_msize; p++, n += sizeof(*p)) - *p = 0xAA5500FF; -/* - * If it verifies, then shared memory is OK. - * Clear memory after check. - */ - p = (unsigned int *)pdev->id_maddr; - for (n = 0; n < pdev->id_msize; n += sizeof(*p)) { - if (*p != 0xAA5500FF) - break; - *p++ = 0; - } -/* - * If no memory, then can't be a shared memory card. - */ - if (n < 8*1024) - return(0); - if (n < 16*1024) - memsize = 8*1024; - else - memsize = 16*1024; - sc->mem_start = (caddr_t) pdev->id_maddr; - sc->mem_shared = 1; - /* - * allocate one xmit buffer if < 16k, two buffers otherwise - */ - if ((memsize < 16384) || (pdev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) { - sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); - sc->txb_cnt = 1; - sc->rec_page_start = ED_TXBUF_SIZE + ED_PCMCIA_PAGE_OFFSET; - } else { - sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2); - sc->txb_cnt = 2; - sc->rec_page_start = ED_TXBUF_SIZE * 2 + ED_PCMCIA_PAGE_OFFSET; - } - sc->mem_size = memsize; - sc->mem_end = sc->mem_start + memsize; - sc->rec_page_stop = memsize / ED_PAGE_SIZE; - sc->tx_page_start = ED_PCMCIA_PAGE_OFFSET; -/* - * Run 16 bit by default, but allow override. - */ - sc->isa16bit = 1; - if (pdev->id_flags & ED_FLAGS_FORCE_8BIT_MODE) - sc->isa16bit = 0; - -#if 0 - sc->vendor = ED_VENDOR_PCMCIA; -#endif - sc->type_str = "PCMCIA"; - sc->type = ED_TYPE_PCMCIA; - return (4); -} -/* - * Probe and vendor-specific initialization routine for NE1000/2000 boards - */ -int -ed_probe_Novell(isa_dev) - struct isa_device *isa_dev; -{ - struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; - u_int memsize, n; - u_char romdata[16], tmp; - static char test_pattern[32] = "THIS is A memory TEST pattern"; - char test_buffer[32]; - - sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET; - sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET; - - /* XXX - do Novell-specific probe here */ - - /* Reset the board */ -#ifdef GWETHER - outb(sc->asic_addr + ED_NOVELL_RESET, 0); - DELAY(200); -#endif /* GWETHER */ - tmp = inb(sc->asic_addr + ED_NOVELL_RESET); - - /* - * I don't know if this is necessary; probably cruft leftover from - * Clarkson packet driver code. Doesn't do a thing on the boards I've - * tested. -DG [note that a outb(0x84, 0) seems to work here, and is - * non-invasive...but some boards don't seem to reset and I don't have - * complete documentation on what the 'right' thing to do is...so we - * do the invasive thing for now. Yuck.] - */ - outb(sc->asic_addr + ED_NOVELL_RESET, tmp); - DELAY(5000); - - /* - * This is needed because some NE clones apparently don't reset the - * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX - * - this makes the probe invasive! ...Done against my better - * judgement. -DLG - */ - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP); - - DELAY(5000); - - /* Make sure that we really have an 8390 based board */ - if (!ed_probe_generic8390(sc)) - return (0); - - sc->vendor = ED_VENDOR_NOVELL; - sc->mem_shared = 0; - sc->cr_proto = ED_CR_RD2; - isa_dev->id_maddr = 0; - - /* - * Test the ability to read and write to the NIC memory. This has the - * side affect of determining if this is an NE1000 or an NE2000. - */ - - /* - * This prevents packets from being stored in the NIC memory when the - * readmem routine turns on the start bit in the CR. - */ - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON); - - /* Temporarily initialize DCR for byte operations */ - outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); - - outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE); - outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE); - - sc->isa16bit = 0; - - /* - * Write a test pattern in byte mode. If this fails, then there - * probably isn't any memory at 8k - which likely means that the board - * is an NE2000. - */ - ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern)); - ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern)); - - if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) { - /* not an NE1000 - try NE2000 */ - - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON); - outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE); - outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); - - if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE) - { - sc->isa16bit = 0; - outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); - } - else - { - sc->isa16bit = 1; - outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); - } - - /* - * Write a test pattern in word mode. If this also fails, then - * we don't know what this board is. - */ - ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); - ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); - - if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) - return (0); /* not an NE2000 either */ - - sc->type = ED_TYPE_NE2000; - sc->type_str = "NE2000"; - sc->kdc.kdc_description = "Ethernet adapter: NE2000"; - } else { - sc->type = ED_TYPE_NE1000; - sc->type_str = "NE1000"; - sc->kdc.kdc_description = "Ethernet adapter: NE1000"; - } - - /* 8k of memory plus an additional 8k if 16bit */ - memsize = 8192 + sc->isa16bit * 8192; - -#if 0 /* probably not useful - NE boards only come two ways */ - /* allow kernel config file overrides */ - if (isa_dev->id_msize) - memsize = isa_dev->id_msize; -#endif - - sc->mem_size = memsize; - - /* NIC memory doesn't start at zero on an NE board */ - /* The start address is tied to the bus width */ - sc->mem_start = (char *) 8192 + sc->isa16bit * 8192; - sc->mem_end = sc->mem_start + memsize; - sc->tx_page_start = memsize / ED_PAGE_SIZE; - -#ifdef GWETHER - { - int x, i, mstart = 0, msize = 0; - char pbuf0[ED_PAGE_SIZE], pbuf[ED_PAGE_SIZE], tbuf[ED_PAGE_SIZE]; - - for (i = 0; i < ED_PAGE_SIZE; i++) - pbuf0[i] = 0; - - /* Clear all the memory. */ - for (x = 1; x < 256; x++) - ed_pio_writemem(sc, pbuf0, x * 256, ED_PAGE_SIZE); - - /* Search for the start of RAM. */ - for (x = 1; x < 256; x++) { - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (memcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) { - for (i = 0; i < ED_PAGE_SIZE; i++) - pbuf[i] = 255 - x; - ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE); - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (memcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) { - mstart = x * ED_PAGE_SIZE; - msize = ED_PAGE_SIZE; - break; - } - } - } - - if (mstart == 0) { - printf("ed%d: Cannot find start of RAM.\n", isa_dev->id_unit); - return 0; - } - /* Search for the start of RAM. */ - for (x = (mstart / ED_PAGE_SIZE) + 1; x < 256; x++) { - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (memcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) { - for (i = 0; i < ED_PAGE_SIZE; i++) - pbuf[i] = 255 - x; - ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE); - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (memcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) - msize += ED_PAGE_SIZE; - else { - break; - } - } else { - break; - } - } - - if (msize == 0) { - printf("ed%d: Cannot find any RAM, start : %d, x = %d.\n", isa_dev->id_unit, mstart, x); - return 0; - } - printf("ed%d: RAM start at %d, size : %d.\n", isa_dev->id_unit, mstart, msize); - - sc->mem_size = msize; - sc->mem_start = (char *) mstart; - sc->mem_end = (char *) (msize + mstart); - sc->tx_page_start = mstart / ED_PAGE_SIZE; - } -#endif /* GWETHER */ - - /* - * Use one xmit buffer if < 16k, two buffers otherwise (if not told - * otherwise). - */ - if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) - sc->txb_cnt = 1; - else - sc->txb_cnt = 2; - - sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; - sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; - - sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; - - ed_pio_readmem(sc, 0, romdata, 16); - for (n = 0; n < ETHER_ADDR_LEN; n++) - sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)]; - -#ifdef GWETHER - if (sc->arpcom.ac_enaddr[2] == 0x86) { - sc->type_str = "Gateway AT"; - sc->kdc.kdc_description = "Ethernet adapter: Gateway AT"; - } -#endif /* GWETHER */ - - /* clear any pending interrupts that might have occurred above */ - outb(sc->nic_addr + ED_P0_ISR, 0xff); - - return (ED_NOVELL_IO_PORTS); -} - - -/* - * Generic probe routine for testing for the existance of a DS8390. - * Must be called after the NIC has just been reset. This routine - * works by looking at certain register values that are guaranteed - * to be initialized a certain way after power-up or reset. Seems - * not to currently work on the 83C690. - * - * Specifically: - * - * Register reset bits set bits - * Command Register (CR) TXP, STA RD2, STP - * Interrupt Status (ISR) RST - * Interrupt Mask (IMR) All bits - * Data Control (DCR) LAS - * Transmit Config. (TCR) LB1, LB0 - * - * We only look at the CR and ISR registers, however, because looking at - * the others would require changing register pages (which would be - * intrusive if this isn't an 8390). - * - * Return 1 if 8390 was found, 0 if not. - */ - -int -ed_probe_generic8390(sc) - struct ed_softc *sc; -{ - if ((inb(sc->nic_addr + ED_P0_CR) & - (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) != - (ED_CR_RD2 | ED_CR_STP)) - return (0); - if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST) - return (0); - - return (1); -} -/* - * Install interface into kernel networking data structures - */ -int -ed_attach(struct isa_device *pdev) -{ - struct ed_softc *sc = &ed_softc[pdev->id_unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; - - /* - * Set interface to stopped condition (reset) - */ - ed_stop(pdev->id_unit); - - /* - * Initialize ifnet structure - */ - ifp->if_unit = pdev->id_unit; - ifp->if_name = "ed"; - ifp->if_init = ed_init; - ifp->if_output = ether_output; - ifp->if_start = ed_start; - ifp->if_ioctl = ed_ioctl; - ifp->if_reset = ed_reset; - ifp->if_watchdog = ed_watchdog; - - /* - * Set default state for ALTPHYS flag (used to disable the tranceiver - * for AUI operation), based on compile-time config option. - */ - if (pdev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER) - ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | - IFF_MULTICAST | IFF_ALTPHYS); - else - ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | - IFF_MULTICAST); - - /* - * Attach the interface - */ - if_attach(ifp); - - /* - * Print additional info when attached - */ - printf("ed%d: address %s, ", pdev->id_unit, - ether_sprintf(sc->arpcom.ac_enaddr)); - - if (sc->type_str && (*sc->type_str != 0)) - printf("type %s ", sc->type_str); - else - printf("type unknown (0x%x) ", sc->type); - - printf("%s ", sc->isa16bit ? "(16 bit)" : "(8 bit)"); - - printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) && - (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : ""); - - /* - * If BPF is in the kernel, call the attach for it - */ -#if NBPFILTER > 0 - bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - return 1; -} - -/* - * Reset interface. - */ -void -ed_reset(unit) - int unit; -{ - int s; - - s = splimp(); - - /* - * Stop interface and re-initialize. - */ - ed_stop(unit); - ed_init(unit); - - (void) splx(s); -} - -/* - * Take interface offline. - */ -void -ed_stop(unit) - int unit; -{ - struct ed_softc *sc = &ed_softc[unit]; - int n = 5000; - - /* - * Stop everything on the interface, and select page 0 registers. - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - - /* - * Wait for interface to enter stopped state, but limit # of checks to - * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but - * just in case it's an old one. - */ - while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n); -} - -/* - * Device timeout/watchdog routine. Entered if the device neglects to - * generate an interrupt after a transmit has been started on it. - */ -void -ed_watchdog(unit) - int unit; -{ - struct ed_softc *sc = &ed_softc[unit]; - - log(LOG_ERR, "ed%d: device timeout\n", unit); - ++sc->arpcom.ac_if.if_oerrors; - - ed_reset(unit); -} - -/* - * Initialize device. - */ -void -ed_init(unit) - int unit; -{ - struct ed_softc *sc = &ed_softc[unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; - int i, s; - - - /* address not known */ - if (ifp->if_addrlist == (struct ifaddr *) 0) - return; - - /* - * Initialize the NIC in the exact order outlined in the NS manual. - * This init procedure is "mandatory"...don't change what or when - * things happen. - */ - s = splimp(); - - /* reset transmitter flags */ - sc->xmit_busy = 0; - sc->arpcom.ac_if.if_timer = 0; - - sc->txb_inuse = 0; - sc->txb_new = 0; - sc->txb_next_tx = 0; - - /* This variable is used below - don't move this assignment */ - sc->next_packet = sc->rec_page_start + 1; - - /* - * Set interface for page 0, Remote DMA complete, Stopped - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - - if (sc->isa16bit) { - - /* - * Set FIFO threshold to 8, No auto-init Remote DMA, byte - * order=80x86, word-wide DMA xfers, - */ - outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS); - } else { - - /* - * Same as above, but byte-wide DMA xfers - */ - outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); - } - - /* - * Clear Remote Byte Count Registers - */ - outb(sc->nic_addr + ED_P0_RBCR0, 0); - outb(sc->nic_addr + ED_P0_RBCR1, 0); - - /* - * For the moment, don't store incoming packets in memory. - */ - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON); - - /* - * Place NIC in internal loopback mode - */ - outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0); - - /* - * Initialize transmit/receive (ring-buffer) Page Start - */ - outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start); - outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start); - /* Set lower bits of byte addressable framing to 0 */ - if (sc->is790) - outb(sc->nic_addr + 0x09, 0); - - /* - * Initialize Receiver (ring-buffer) Page Stop and Boundry - */ - outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop); - outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start); - - /* - * Clear all interrupts. A '1' in each bit position clears the - * corresponding flag. - */ - outb(sc->nic_addr + ED_P0_ISR, 0xff); - - /* - * Enable the following interrupts: receive/transmit complete, - * receive/transmit error, and Receiver OverWrite. - * - * Counter overflow and Remote DMA complete are *not* enabled. - */ - outb(sc->nic_addr + ED_P0_IMR, - ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | ED_IMR_OVWE); - - /* - * Program Command Register for page 1 - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); - - /* - * Copy out our station address - */ - for (i = 0; i < ETHER_ADDR_LEN; ++i) - outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]); - - /* - * Set Current Page pointer to next_packet (initialized above) - */ - outb(sc->nic_addr + ED_P1_CURR, sc->next_packet); - - /* - * Program Receiver Configuration Register and multicast filter. CR is - * set to page 0 on return. - */ - ed_setrcr(ifp, sc); - - /* - * Take interface out of loopback - */ - outb(sc->nic_addr + ED_P0_TCR, 0); - - /* - * If this is a 3Com board, the tranceiver must be software enabled - * (there is no settable hardware default). - */ - if (sc->vendor == ED_VENDOR_3COM) { - if (ifp->if_flags & IFF_ALTPHYS) { - outb(sc->asic_addr + ED_3COM_CR, 0); - } else { - outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); - } - } - - /* - * Set 'running' flag, and clear output active flag. - */ - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - /* - * ...and attempt to start output - */ - ed_start(ifp); - - (void) splx(s); -} - -/* - * This routine actually starts the transmission on the interface - */ -static inline void -ed_xmit(ifp) - struct ifnet *ifp; -{ - struct ed_softc *sc = &ed_softc[ifp->if_unit]; - unsigned short len; - - len = sc->txb_len[sc->txb_next_tx]; - - /* - * Set NIC for page 0 register access - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STA); - - /* - * Set TX buffer start page - */ - outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start + - sc->txb_next_tx * ED_TXBUF_SIZE); - - /* - * Set TX length - */ - outb(sc->nic_addr + ED_P0_TBCR0, len); - outb(sc->nic_addr + ED_P0_TBCR1, len >> 8); - - /* - * Set page 0, Remote DMA complete, Transmit Packet, and *Start* - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_TXP | ED_CR_STA); - sc->xmit_busy = 1; - - /* - * Point to next transmit buffer slot and wrap if necessary. - */ - sc->txb_next_tx++; - if (sc->txb_next_tx == sc->txb_cnt) - sc->txb_next_tx = 0; - - /* - * Set a timer just in case we never hear from the board again - */ - ifp->if_timer = 2; -} - -/* - * Start output on interface. - * We make two assumptions here: - * 1) that the current priority is set to splimp _before_ this code - * is called *and* is returned to the appropriate priority after - * return - * 2) that the IFF_OACTIVE flag is checked before this code is called - * (i.e. that the output part of the interface is idle) - */ -void -ed_start(ifp) - struct ifnet *ifp; -{ - struct ed_softc *sc = &ed_softc[ifp->if_unit]; - struct mbuf *m0, *m; - caddr_t buffer; - int len; - -outloop: - - /* - * First, see if there are buffered packets and an idle transmitter - - * should never happen at this point. - */ - if (sc->txb_inuse && (sc->xmit_busy == 0)) { - printf("ed: packets buffered, but transmitter idle\n"); - ed_xmit(ifp); - } - - /* - * See if there is room to put another packet in the buffer. - */ - if (sc->txb_inuse == sc->txb_cnt) { - - /* - * No room. Indicate this to the outside world and exit. - */ - ifp->if_flags |= IFF_OACTIVE; - return; - } - IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); - if (m == 0) { - - /* - * We are using the !OACTIVE flag to indicate to the outside - * world that we can accept an additional packet rather than - * that the transmitter is _actually_ active. Indeed, the - * transmitter may be active, but if we haven't filled all the - * buffers with data then we still want to accept more. - */ - ifp->if_flags &= ~IFF_OACTIVE; - return; - } - - /* - * Copy the mbuf chain into the transmit buffer - */ - - m0 = m; - - /* txb_new points to next open buffer slot */ - buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE); - - if (sc->mem_shared) { - - /* - * Special case setup for 16 bit boards... - */ - if (sc->isa16bit) { - switch (sc->vendor) { - - /* - * For 16bit 3Com boards (which have 16k of - * memory), we have the xmit buffers in a - * different page of memory ('page 0') - so - * change pages. - */ - case ED_VENDOR_3COM: - outb(sc->asic_addr + ED_3COM_GACFR, - ED_3COM_GACFR_RSEL); - break; - - /* - * Enable 16bit access to shared memory on - * WD/SMC boards. - */ - case ED_VENDOR_WD_SMC:{ - outb(sc->asic_addr + ED_WD_LAAR, - (sc->wd_laar_proto | ED_WD_LAAR_M16EN)); - if (sc->is790) { - outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB); - } - break; - } - } - } - for (len = 0; m != 0; m = m->m_next) { - bcopy(mtod(m, caddr_t), buffer, m->m_len); - buffer += m->m_len; - len += m->m_len; - } - - /* - * Restore previous shared memory access - */ - if (sc->isa16bit) { - switch (sc->vendor) { - case ED_VENDOR_3COM: - outb(sc->asic_addr + ED_3COM_GACFR, - ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0); - break; - case ED_VENDOR_WD_SMC:{ - if (sc->is790) { - outb(sc->asic_addr + ED_WD_MSR, 0x00); - } - outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto); - break; - } - } - } - } else { - len = ed_pio_write_mbufs(sc, m, buffer); - if (len == 0) - goto outloop; - } - - sc->txb_len[sc->txb_new] = max(len, ETHER_MIN_LEN); - - sc->txb_inuse++; - - /* - * Point to next buffer slot and wrap if necessary. - */ - sc->txb_new++; - if (sc->txb_new == sc->txb_cnt) - sc->txb_new = 0; - - if (sc->xmit_busy == 0) - ed_xmit(ifp); - - /* - * Tap off here if there is a bpf listener. - */ -#if NBPFILTER > 0 - if (sc->bpf) { - bpf_mtap(sc->bpf, m0); - } -#endif - - m_freem(m0); - - /* - * Loop back to the top to possibly buffer more packets - */ - goto outloop; -} - -/* - * Ethernet interface receiver interrupt. - */ -static inline void -ed_rint(unit) - int unit; -{ - register struct ed_softc *sc = &ed_softc[unit]; - u_char boundry; - u_short len; - struct ed_ring packet_hdr; - char *packet_ptr; - - /* - * Set NIC to page 1 registers to get 'current' pointer - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); - - /* - * 'sc->next_packet' is the logical beginning of the ring-buffer - - * i.e. it points to where new data has been buffered. The 'CURR' - * (current) register points to the logical end of the ring-buffer - - * i.e. it points to where additional new data will be added. We loop - * here until the logical beginning equals the logical end (or in - * other words, until the ring-buffer is empty). - */ - while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) { - - /* get pointer to this buffer's header structure */ - packet_ptr = sc->mem_ring + - (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE; - - /* - * The byte count includes a 4 byte header that was added by - * the NIC. - */ - if (sc->mem_shared) - packet_hdr = *(struct ed_ring *) packet_ptr; - else - ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr, - sizeof(packet_hdr)); - len = packet_hdr.count; - if (len > ETHER_MAX_LEN) { - /* - * Length is a wild value. There's a good chance that - * this was caused by the NIC being old and buggy. - * The bug is that the length low byte is duplicated in - * the high byte. Try to recalculate the length based on - * the pointer to the next packet. - */ - /* - * NOTE: sc->next_packet is pointing at the current packet. - */ - len &= ED_PAGE_SIZE - 1; /* preserve offset into page */ - if (packet_hdr.next_packet >= sc->next_packet) { - len += (packet_hdr.next_packet - sc->next_packet) * ED_PAGE_SIZE; - } else { - len += ((packet_hdr.next_packet - sc->rec_page_start) + - (sc->rec_page_stop - sc->next_packet)) * ED_PAGE_SIZE; - } - } - /* - * Be fairly liberal about what we allow as a "reasonable" length - * so that a [crufty] packet will make it to BPF (and can thus - * be analyzed). Note that all that is really important is that - * we have a length that will fit into one mbuf cluster or less; - * the upper layer protocols can then figure out the length from - * their own length field(s). - */ - if ((len <= MCLBYTES) && - (packet_hdr.next_packet >= sc->rec_page_start) && - (packet_hdr.next_packet < sc->rec_page_stop)) { - /* - * Go get packet. - */ - ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring), - len - sizeof(struct ed_ring), packet_hdr.rsr & ED_RSR_PHY); - ++sc->arpcom.ac_if.if_ipackets; - } else { - /* - * Really BAD. The ring pointers are corrupted. - */ - log(LOG_ERR, - "ed%d: NIC memory corrupt - invalid packet length %d\n", - unit, len); - ++sc->arpcom.ac_if.if_ierrors; - ed_reset(unit); - return; - } - - /* - * Update next packet pointer - */ - sc->next_packet = packet_hdr.next_packet; - - /* - * Update NIC boundry pointer - being careful to keep it one - * buffer behind. (as recommended by NS databook) - */ - boundry = sc->next_packet - 1; - if (boundry < sc->rec_page_start) - boundry = sc->rec_page_stop - 1; - - /* - * Set NIC to page 0 registers to update boundry register - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STA); - - outb(sc->nic_addr + ED_P0_BNRY, boundry); - - /* - * Set NIC to page 1 registers before looping to top (prepare - * to get 'CURR' current pointer) - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); - } -} - -/* - * Ethernet interface interrupt processor - */ -int -edintr(struct pccard_dev *pdev) -{ - struct ed_softc *sc = &ed_softc[pdev->isahd.id_unit]; - u_char isr; - int ret = 0; - - /* - * Set NIC to page 0 registers - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STA); - - /* - * loop until there are no more new interrupts - */ - while ((isr = inb(sc->nic_addr + ED_P0_ISR)) != 0) { - - ret = 1; - /* - * reset all the bits that we are 'acknowledging' by writing a - * '1' to each bit position that was set (writing a '1' - * *clears* the bit) - */ - outb(sc->nic_addr + ED_P0_ISR, isr); - - /* - * Handle transmitter interrupts. Handle these first because - * the receiver will reset the board under some conditions. - */ - if (isr & (ED_ISR_PTX | ED_ISR_TXE)) { - u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f; - - /* - * Check for transmit error. If a TX completed with an - * error, we end up throwing the packet away. Really - * the only error that is possible is excessive - * collisions, and in this case it is best to allow - * the automatic mechanisms of TCP to backoff the - * flow. Of course, with UDP we're screwed, but this - * is expected when a network is heavily loaded. - */ - (void) inb(sc->nic_addr + ED_P0_TSR); - if (isr & ED_ISR_TXE) { - - /* - * Excessive collisions (16) - */ - if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT) - && (collisions == 0)) { - - /* - * When collisions total 16, the - * P0_NCR will indicate 0, and the - * TSR_ABT is set. - */ - collisions = 16; - } - - /* - * update output errors counter - */ - ++sc->arpcom.ac_if.if_oerrors; - } else { - - /* - * Update total number of successfully - * transmitted packets. - */ - ++sc->arpcom.ac_if.if_opackets; - } - - /* - * reset tx busy and output active flags - */ - sc->xmit_busy = 0; - sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; - - /* - * clear watchdog timer - */ - sc->arpcom.ac_if.if_timer = 0; - - /* - * Add in total number of collisions on last - * transmission. - */ - sc->arpcom.ac_if.if_collisions += collisions; - - /* - * Decrement buffer in-use count if not zero (can only - * be zero if a transmitter interrupt occured while - * not actually transmitting). If data is ready to - * transmit, start it transmitting, otherwise defer - * until after handling receiver - */ - if (sc->txb_inuse && --sc->txb_inuse) - ed_xmit(&sc->arpcom.ac_if); - } - - /* - * Handle receiver interrupts - */ - if (isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) { - - /* - * Overwrite warning. In order to make sure that a - * lockup of the local DMA hasn't occurred, we reset - * and re-init the NIC. The NSC manual suggests only a - * partial reset/re-init is necessary - but some chips - * seem to want more. The DMA lockup has been seen - * only with early rev chips - Methinks this bug was - * fixed in later revs. -DG - */ - if (isr & ED_ISR_OVW) { - ++sc->arpcom.ac_if.if_ierrors; -#ifdef DIAGNOSTIC - log(LOG_WARNING, - "ed%d: warning - receiver ring buffer overrun\n", - pdev->isahd.id_unit); -#endif - - /* - * Stop/reset/re-init NIC - */ - ed_reset(pdev->isahd.id_unit); - } else { - - /* - * Receiver Error. One or more of: CRC error, - * frame alignment error FIFO overrun, or - * missed packet. - */ - if (isr & ED_ISR_RXE) { - ++sc->arpcom.ac_if.if_ierrors; -#ifdef ED_DEBUG - printf("ed%d: receive error %x\n", pdev->isahd.id_unit, - inb(sc->nic_addr + ED_P0_RSR)); -#endif - } - - /* - * Go get the packet(s) XXX - Doing this on an - * error is dubious because there shouldn't be - * any data to get (we've configured the - * interface to not accept packets with - * errors). - */ - - /* - * Enable 16bit access to shared memory first - * on WD/SMC boards. - */ - if (sc->isa16bit && - (sc->vendor == ED_VENDOR_WD_SMC)) { - - outb(sc->asic_addr + ED_WD_LAAR, - (sc->wd_laar_proto |= - ED_WD_LAAR_M16EN)); - if (sc->is790) { - outb(sc->asic_addr + ED_WD_MSR, - ED_WD_MSR_MENB); - } - } - ed_rint(pdev->isahd.id_unit); - - /* disable 16bit access */ - if (sc->isa16bit && - (sc->vendor == ED_VENDOR_WD_SMC)) { - - if (sc->is790) { - outb(sc->asic_addr + ED_WD_MSR, 0x00); - } - outb(sc->asic_addr + ED_WD_LAAR, - (sc->wd_laar_proto &= - ~ED_WD_LAAR_M16EN)); - } - } - } - - /* - * If it looks like the transmitter can take more data, - * attempt to start output on the interface. This is done - * after handling the receiver to give the receiver priority. - */ - if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) - ed_start(&sc->arpcom.ac_if); - - /* - * return NIC CR to standard state: page 0, remote DMA - * complete, start (toggling the TXP bit off, even if was just - * set in the transmit routine, is *okay* - it is 'edge' - * triggered from low to high) - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STA); - - /* - * If the Network Talley Counters overflow, read them to reset - * them. It appears that old 8390's won't clear the ISR flag - * otherwise - resulting in an infinite loop. - */ - if (isr & ED_ISR_CNT) { - (void) inb(sc->nic_addr + ED_P0_CNTR0); - (void) inb(sc->nic_addr + ED_P0_CNTR1); - (void) inb(sc->nic_addr + ED_P0_CNTR2); - } - } - return(ret); -} - -/* - * Process an ioctl request. This code needs some work - it looks - * pretty ugly. - */ -int -ed_ioctl(ifp, command, data) - register struct ifnet *ifp; - int command; - caddr_t data; -{ - register struct ifaddr *ifa = (struct ifaddr *) data; - struct ed_softc *sc = &ed_softc[ifp->if_unit]; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch (command) { - - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - /* netifs are BUSY when UP */ - - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - ed_init(ifp->if_unit); /* before arpwhohas */ - arp_ifinit((struct arpcom *)ifp, ifa); - break; -#endif -#ifdef NS - - /* - * XXX - This code is probably wrong - */ - case AF_NS: - { - register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); - - if (ns_nullhost(*ina)) - ina->x_host = - *(union ns_host *) (sc->arpcom.ac_enaddr); - else { - bcopy((caddr_t) ina->x_host.c_host, - (caddr_t) sc->arpcom.ac_enaddr, - sizeof(sc->arpcom.ac_enaddr)); - } - - /* - * Set new address - */ - ed_init(ifp->if_unit); - break; - } -#endif - default: - ed_init(ifp->if_unit); - break; - } - break; - - case SIOCGIFADDR: - { - struct sockaddr *sa; - - sa = (struct sockaddr *) & ifr->ifr_data; - bcopy((caddr_t) sc->arpcom.ac_enaddr, - (caddr_t) sa->sa_data, ETHER_ADDR_LEN); - } - break; - - case SIOCSIFFLAGS: - - /* - * If interface is marked down and it is running, then stop it - */ - if (((ifp->if_flags & IFF_UP) == 0) && - (ifp->if_flags & IFF_RUNNING)) { - ed_stop(ifp->if_unit); - ifp->if_flags &= ~IFF_RUNNING; - } else { - - /* - * If interface is marked up and it is stopped, then - * start it - */ - if ((ifp->if_flags & IFF_UP) && - ((ifp->if_flags & IFF_RUNNING) == 0)) - ed_init(ifp->if_unit); - } - -#if NBPFILTER > 0 - - /* - * Promiscuous flag may have changed, so reprogram the RCR. - */ - ed_setrcr(ifp, sc); -#endif - - /* - * An unfortunate hack to provide the (required) software - * control of the tranceiver for 3Com boards. The ALTPHYS flag - * disables the tranceiver if set. - */ - if (sc->vendor == ED_VENDOR_3COM) { - if (ifp->if_flags & IFF_ALTPHYS) { - outb(sc->asic_addr + ED_3COM_CR, 0); - } else { - outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); - } - } - break; - - case SIOCADDMULTI: - case SIOCDELMULTI: - /* - * Update out multicast list. - */ - error = (command == SIOCADDMULTI) ? - ether_addmulti(ifr, &sc->arpcom) : - ether_delmulti(ifr, &sc->arpcom); - - if (error == ENETRESET) { - - /* - * Multicast list has changed; set the hardware filter - * accordingly. - */ - ed_setrcr(ifp, sc); - error = 0; - } - break; - - case SIOCSIFMTU: - /* - * Set the interface MTU. - */ - if (ifr->ifr_mtu > ETHERMTU) { - error = EINVAL; - } else { - ifp->if_mtu = ifr->ifr_mtu; - } - break; - - default: - error = EINVAL; - } - (void) splx(s); - return (error); -} - -/* - * Retreive packet from shared memory and send to the next level up via - * ether_input(). If there is a BPF listener, give a copy to BPF, too. - */ -static void -ed_get_packet(sc, buf, len, multicast) - struct ed_softc *sc; - char *buf; - u_short len; - int multicast; -{ - struct ether_header *eh; - struct mbuf *m; - - /* Allocate a header mbuf */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return; - m->m_pkthdr.rcvif = &sc->arpcom.ac_if; - m->m_pkthdr.len = m->m_len = len; - - /* Attach an mbuf cluster */ - MCLGET(m, M_DONTWAIT); - - /* Insist on getting a cluster */ - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - return; - } - - /* - * The +2 is to longword align the start of the real packet. - * This is important for NFS. - */ - m->m_data += 2; - eh = mtod(m, struct ether_header *); - - /* - * Get packet, including link layer address, from interface. - */ - ed_ring_copy(sc, buf, (char *)eh, len); - -#if NBPFILTER > 0 - - /* - * Check if there's a BPF listener on this interface. If so, hand off - * the raw packet to bpf. - */ - if (sc->bpf) { - bpf_mtap(sc->bpf, m); - - /* - * Note that the interface cannot be in promiscuous mode if - * there are no BPF listeners. And if we are in promiscuous - * mode, we have to check if this packet is really ours. - */ - if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && - bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - sizeof(eh->ether_dhost)) != 0 && multicast == 0) { - m_freem(m); - return; - } - } -#endif - - /* - * Remove link layer address. - */ - m->m_pkthdr.len = m->m_len = len - sizeof(struct ether_header); - m->m_data += sizeof(struct ether_header); - - ether_input(&sc->arpcom.ac_if, eh, m); - return; -} - -/* - * Supporting routines - */ - -/* - * Given a NIC memory source address and a host memory destination - * address, copy 'amount' from NIC to host using Programmed I/O. - * The 'amount' is rounded up to a word - okay as long as mbufs - * are word sized. - * This routine is currently Novell-specific. - */ -void -ed_pio_readmem(sc, src, dst, amount) - struct ed_softc *sc; - unsigned short src; - unsigned char *dst; - unsigned short amount; -{ - /* select page 0 registers */ - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA); - - /* round up to a word */ - if (amount & 1) - ++amount; - - /* set up DMA byte count */ - outb(sc->nic_addr + ED_P0_RBCR0, amount); - outb(sc->nic_addr + ED_P0_RBCR1, amount >> 8); - - /* set up source address in NIC mem */ - outb(sc->nic_addr + ED_P0_RSAR0, src); - outb(sc->nic_addr + ED_P0_RSAR1, src >> 8); - - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA); - - if (sc->isa16bit) { - insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount / 2); - } else - insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount); - -} - -/* - * Stripped down routine for writing a linear buffer to NIC memory. - * Only used in the probe routine to test the memory. 'len' must - * be even. - */ -void -ed_pio_writemem(sc, src, dst, len) - struct ed_softc *sc; - char *src; - unsigned short dst; - unsigned short len; -{ - int maxwait = 200; /* about 240us */ - - /* select page 0 registers */ - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA); - - /* reset remote DMA complete flag */ - outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC); - - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA); - /* set up DMA byte count */ - outb(sc->nic_addr + ED_P0_RBCR0, len); - outb(sc->nic_addr + ED_P0_RBCR1, len >> 8); - - /* set up destination address in NIC mem */ - outb(sc->nic_addr + ED_P0_RSAR0, dst); - outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8); - - /* set remote DMA write */ - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA); - - if (sc->isa16bit) - outsw(sc->asic_addr + ED_NOVELL_DATA, src, len / 2); - else - outsb(sc->asic_addr + ED_NOVELL_DATA, src, len); - - /* - * Wait for remote DMA complete. This is necessary because on the - * transmit side, data is handled internally by the NIC in bursts and - * we can't start another remote DMA until this one completes. Not - * waiting causes really bad things to happen - like the NIC - * irrecoverably jamming the ISA bus. - */ - while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait); -} -my_outsw(int ad, unsigned short *src, int len) -{ - while(--len >= 0) - { - outw(ad, *src++); - printf("*"); - } - printf("<\n"); -} - -/* - * Write an mbuf chain to the destination NIC memory address using - * programmed I/O. - */ -u_short -ed_pio_write_mbufs(sc, m, dst) - struct ed_softc *sc; - struct mbuf *m; - unsigned short dst; -{ - unsigned short total_len, dma_len; - struct mbuf *mp; - int maxwait = 200; /* about 240us */ - - /* First, count up the total number of bytes to copy */ - for (total_len = 0, mp = m; mp; mp = mp->m_next) - total_len += mp->m_len; - - dma_len = total_len; - if (sc->isa16bit && (dma_len & 1)) - dma_len++; - - /* select page 0 registers */ - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA); - - /* reset remote DMA complete flag */ - outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC); - - /* set up DMA byte count */ - outb(sc->nic_addr + ED_P0_RBCR0, dma_len); - outb(sc->nic_addr + ED_P0_RBCR1, dma_len >> 8); - - /* set up destination address in NIC mem */ - outb(sc->nic_addr + ED_P0_RSAR0, dst); - outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8); - - /* set remote DMA write */ - outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA); - - /* - * Transfer the mbuf chain to the NIC memory. - * 16-bit cards require that data be transferred as words, and only words. - * So that case requires some extra code to patch over odd-length mbufs. - */ - - if (!sc->isa16bit) { - /* NE1000s are easy */ - while (m) { - if (m->m_len) { - outsb(sc->asic_addr + ED_NOVELL_DATA, - m->m_data, m->m_len); - } - m = m->m_next; - } - } else { - /* NE2000s are a pain */ - unsigned char *data; - int len, wantbyte; - unsigned char savebyte[2]; - - wantbyte = 0; - - while (m) { - len = m->m_len; - if (len) { - data = mtod(m, caddr_t); - /* finish the last word */ - if (wantbyte) { - savebyte[1] = *data; - outw(sc->asic_addr + ED_NOVELL_DATA, *(u_short *)savebyte); - data++; - len--; - wantbyte = 0; - } - /* output contiguous words */ - if (len > 1) { - outsw(sc->asic_addr + ED_NOVELL_DATA, - data, len >> 1); - data += len & ~1; - len &= 1; - } - /* save last byte, if necessary */ - if (len == 1) { - savebyte[0] = *data; - wantbyte = 1; - } - } - m = m->m_next; - } - /* spit last byte */ - if (wantbyte) { - outw(sc->asic_addr + ED_NOVELL_DATA, *(u_short *)savebyte); - } - } - - /* - * Wait for remote DMA complete. This is necessary because on the - * transmit side, data is handled internally by the NIC in bursts and - * we can't start another remote DMA until this one completes. Not - * waiting causes really bad things to happen - like the NIC - * irrecoverably jamming the ISA bus. - */ - while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait); - - if (!maxwait) { - log(LOG_WARNING, "ed%d: remote transmit DMA failed to complete\n", - sc->arpcom.ac_if.if_unit); - ed_reset(sc->arpcom.ac_if.if_unit); - return(0); - } - return (total_len); -} - -/* - * Given a source and destination address, copy 'amount' of a packet from - * the ring buffer into a linear destination buffer. Takes into account - * ring-wrap. - */ -static inline char * -ed_ring_copy(sc, src, dst, amount) - struct ed_softc *sc; - char *src; - char *dst; - u_short amount; -{ - u_short tmp_amount; - - /* does copy wrap to lower addr in ring buffer? */ - if (src + amount > sc->mem_end) { - tmp_amount = sc->mem_end - src; - - /* copy amount up to end of NIC memory */ - if (sc->mem_shared) - bcopy(src, dst, tmp_amount); - else - ed_pio_readmem(sc, src, dst, tmp_amount); - - amount -= tmp_amount; - src = sc->mem_ring; - dst += tmp_amount; - } - if (sc->mem_shared) - bcopy(src, dst, amount); - else - ed_pio_readmem(sc, src, dst, amount); - - return (src + amount); -} - -void -ed_setrcr(ifp, sc) - struct ifnet *ifp; - struct ed_softc *sc; -{ - int i; - - /* set page 1 registers */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); - - if (ifp->if_flags & IFF_PROMISC) { - - /* - * Reconfigure the multicast filter. - */ - for (i = 0; i < 8; i++) - outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff); - - /* - * And turn on promiscuous mode. Also enable reception of - * runts and packets with CRC & alignment errors. - */ - /* Set page 0 registers */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_PRO | ED_RCR_AM | - ED_RCR_AB | ED_RCR_AR | ED_RCR_SEP); - } else { - /* set up multicast addresses and filter modes */ - if (ifp->if_flags & IFF_MULTICAST) { - u_long mcaf[2]; - - if (ifp->if_flags & IFF_ALLMULTI) { - mcaf[0] = 0xffffffff; - mcaf[1] = 0xffffffff; - } else - ds_getmcaf(sc, mcaf); - - /* - * Set multicast filter on chip. - */ - for (i = 0; i < 8; i++) - outb(sc->nic_addr + ED_P1_MAR0 + i, ((u_char *) mcaf)[i]); - - /* Set page 0 registers */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AM | ED_RCR_AB); - } else { - - /* - * Initialize multicast address hashing registers to - * not accept multicasts. - */ - for (i = 0; i < 8; ++i) - outb(sc->nic_addr + ED_P1_MAR0 + i, 0x00); - - /* Set page 0 registers */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); - } - } - - /* - * Start interface. - */ - outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STA); -} - -/* - * Compute crc for ethernet address - */ -u_long -ds_crc(ep) - u_char *ep; -{ -#define POLYNOMIAL 0x04c11db6 - register u_long crc = 0xffffffffL; - register int carry, i, j; - register u_char b; - - for (i = 6; --i >= 0;) { - b = *ep++; - for (j = 8; --j >= 0;) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) - crc = ((crc ^ POLYNOMIAL) | carry); - } - } - return crc; -#undef POLYNOMIAL -} - -/* - * Compute the multicast address filter from the - * list of multicast addresses we need to listen to. - */ -void -ds_getmcaf(sc, mcaf) - struct ed_softc *sc; - u_long *mcaf; -{ - register u_int index; - register u_char *af = (u_char *) mcaf; - register struct ether_multi *enm; - register struct ether_multistep step; - - mcaf[0] = 0; - mcaf[1] = 0; - - ETHER_FIRST_MULTI(step, &sc->arpcom, enm); - while (enm != NULL) { - if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) { - mcaf[0] = 0xffffffff; - mcaf[1] = 0xffffffff; - return; - } - index = ds_crc(enm->enm_addrlo, 6) >> 26; - af[index >> 3] |= 1 << (index & 7); - - ETHER_NEXT_MULTI(step, enm); - } -} diff --git a/usr.sbin/pccard/misc/sys/pccard/if_edreg.h b/usr.sbin/pccard/misc/sys/pccard/if_edreg.h deleted file mode 100644 index 9644aaf3c324..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/if_edreg.h +++ /dev/null @@ -1,989 +0,0 @@ -/* - * Copyright (C) 1993, David Greenman. This software may be used, modified, - * copied, distributed, and sold, in both source and binary form provided - * that the above copyright and these terms are retained. Under no - * circumstances is the author responsible for the proper functioning - * of this software, nor does the author assume any responsibility - * for damages incurred with its use. - * - * $Id: if_edreg.h,v 1.17 1995/01/23 19:06:08 davidg Exp $ - */ -/* - * National Semiconductor DS8390 NIC register definitions - * - * - * Modification history - * - * Revision 2.2 1993/11/29 16:33:39 davidg - * From Thomas Sandford - * Add support for the 8013W board type - * - * Revision 2.1 1993/11/22 10:52:33 davidg - * patch to add support for SMC8216 (Elite-Ultra) boards - * from Glen H. Lowe - * - * Revision 2.0 93/09/29 00:37:15 davidg - * changed double buffering flag to multi buffering - * made changes/additions for 3c503 multi-buffering - * ...companion to Rev. 2.0 of 'ed' driver. - * - * Revision 1.1 93/06/23 03:01:07 davidg - * Initial revision - * - */ - -/* - * Page 0 register offsets - */ -#define ED_P0_CR 0x00 /* Command Register */ - -#define ED_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */ -#define ED_P0_PSTART 0x01 /* Page Start register (write) */ - -#define ED_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */ -#define ED_P0_PSTOP 0x02 /* Page Stop register (write) */ - -#define ED_P0_BNRY 0x03 /* Boundary Pointer */ - -#define ED_P0_TSR 0x04 /* Transmit Status Register (read) */ -#define ED_P0_TPSR 0x04 /* Transmit Page Start (write) */ - -#define ED_P0_NCR 0x05 /* Number of Collisions Reg (read) */ -#define ED_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */ - -#define ED_P0_FIFO 0x06 /* FIFO register (read) */ -#define ED_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */ - -#define ED_P0_ISR 0x07 /* Interrupt Status Register */ - -#define ED_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */ -#define ED_P0_RSAR0 0x08 /* Remote Start Address low (write) */ - -#define ED_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */ -#define ED_P0_RSAR1 0x09 /* Remote Start Address high (write) */ - -#define ED_P0_RBCR0 0x0a /* Remote Byte Count low (write) */ - -#define ED_P0_RBCR1 0x0b /* Remote Byte Count high (write) */ - -#define ED_P0_RSR 0x0c /* Receive Status (read) */ -#define ED_P0_RCR 0x0c /* Receive Configuration Reg (write) */ - -#define ED_P0_CNTR0 0x0d /* frame alignment error counter (read) */ -#define ED_P0_TCR 0x0d /* Transmit Configuration Reg (write) */ - -#define ED_P0_CNTR1 0x0e /* CRC error counter (read) */ -#define ED_P0_DCR 0x0e /* Data Configuration Reg (write) */ - -#define ED_P0_CNTR2 0x0f /* missed packet counter (read) */ -#define ED_P0_IMR 0x0f /* Interrupt Mask Register (write) */ - -/* - * Page 1 register offsets - */ -#define ED_P1_CR 0x00 /* Command Register */ -#define ED_P1_PAR0 0x01 /* Physical Address Register 0 */ -#define ED_P1_PAR1 0x02 /* Physical Address Register 1 */ -#define ED_P1_PAR2 0x03 /* Physical Address Register 2 */ -#define ED_P1_PAR3 0x04 /* Physical Address Register 3 */ -#define ED_P1_PAR4 0x05 /* Physical Address Register 4 */ -#define ED_P1_PAR5 0x06 /* Physical Address Register 5 */ -#define ED_P1_CURR 0x07 /* Current RX ring-buffer page */ -#define ED_P1_MAR0 0x08 /* Multicast Address Register 0 */ -#define ED_P1_MAR1 0x09 /* Multicast Address Register 1 */ -#define ED_P1_MAR2 0x0a /* Multicast Address Register 2 */ -#define ED_P1_MAR3 0x0b /* Multicast Address Register 3 */ -#define ED_P1_MAR4 0x0c /* Multicast Address Register 4 */ -#define ED_P1_MAR5 0x0d /* Multicast Address Register 5 */ -#define ED_P1_MAR6 0x0e /* Multicast Address Register 6 */ -#define ED_P1_MAR7 0x0f /* Multicast Address Register 7 */ - -/* - * Page 2 register offsets - */ -#define ED_P2_CR 0x00 /* Command Register */ -#define ED_P2_PSTART 0x01 /* Page Start (read) */ -#define ED_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */ -#define ED_P2_PSTOP 0x02 /* Page Stop (read) */ -#define ED_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */ -#define ED_P2_RNPP 0x03 /* Remote Next Packet Pointer */ -#define ED_P2_TPSR 0x04 /* Transmit Page Start (read) */ -#define ED_P2_LNPP 0x05 /* Local Next Packet Pointer */ -#define ED_P2_ACU 0x06 /* Address Counter Upper */ -#define ED_P2_ACL 0x07 /* Address Counter Lower */ -#define ED_P2_RCR 0x0c /* Receive Configuration Register (read) */ -#define ED_P2_TCR 0x0d /* Transmit Configuration Register (read) */ -#define ED_P2_DCR 0x0e /* Data Configuration Register (read) */ -#define ED_P2_IMR 0x0f /* Interrupt Mask Register (read) */ - -/* - * Command Register (CR) definitions - */ - -/* - * STP: SToP. Software reset command. Takes the controller offline. No - * packets will be received or transmitted. Any reception or - * transmission in progress will continue to completion before - * entering reset state. To exit this state, the STP bit must - * reset and the STA bit must be set. The software reset has - * executed only when indicated by the RST bit in the ISR being - * set. - */ -#define ED_CR_STP 0x01 - -/* - * STA: STArt. This bit is used to activate the NIC after either power-up, - * or when the NIC has been put in reset mode by software command - * or error. - */ -#define ED_CR_STA 0x02 - -/* - * TXP: Transmit Packet. This bit must be set to indicate transmission of - * a packet. TXP is internally reset either after the transmission is - * completed or aborted. This bit should be set only after the Transmit - * Byte Count and Transmit Page Start register have been programmed. - */ -#define ED_CR_TXP 0x04 - -/* - * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation - * of the remote DMA channel. RD2 can be set to abort any remote DMA - * command in progress. The Remote Byte Count registers should be cleared - * when a remote DMA has been aborted. The Remote Start Addresses are not - * restored to the starting address if the remote DMA is aborted. - * - * RD2 RD1 RD0 function - * 0 0 0 not allowed - * 0 0 1 remote read - * 0 1 0 remote write - * 0 1 1 send packet - * 1 X X abort - */ -#define ED_CR_RD0 0x08 -#define ED_CR_RD1 0x10 -#define ED_CR_RD2 0x20 - -/* - * PS0, PS1: Page Select. The two bits select which register set or 'page' to - * access. - * - * PS1 PS0 page - * 0 0 0 - * 0 1 1 - * 1 0 2 - * 1 1 reserved - */ -#define ED_CR_PS0 0x40 -#define ED_CR_PS1 0x80 -/* bit encoded aliases */ -#define ED_CR_PAGE_0 0x00 /* (for consistency) */ -#define ED_CR_PAGE_1 0x40 -#define ED_CR_PAGE_2 0x80 - -/* - * Interrupt Status Register (ISR) definitions - */ - -/* - * PRX: Packet Received. Indicates packet received with no errors. - */ -#define ED_ISR_PRX 0x01 - -/* - * PTX: Packet Transmitted. Indicates packet transmitted with no errors. - */ -#define ED_ISR_PTX 0x02 - -/* - * RXE: Receive Error. Indicates that a packet was received with one or more - * the following errors: CRC error, frame alignment error, FIFO overrun, - * missed packet. - */ -#define ED_ISR_RXE 0x04 - -/* - * TXE: Transmission Error. Indicates that an attempt to transmit a packet - * resulted in one or more of the following errors: excessive - * collisions, FIFO underrun. - */ -#define ED_ISR_TXE 0x08 - -/* - * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network - * would exceed (has exceeded?) the boundry pointer, resulting in data - * that was previously received and not yet read from the buffer to be - * overwritten. - */ -#define ED_ISR_OVW 0x10 - -/* - * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley - * Counters has been set. - */ -#define ED_ISR_CNT 0x20 - -/* - * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed. - */ -#define ED_ISR_RDC 0x40 - -/* - * RST: Reset status. Set when the NIC enters the reset state and cleared when a - * Start Command is issued to the CR. This bit is also set when a receive - * ring-buffer overrun (OverWrite) occurs and is cleared when one or more - * packets have been removed from the ring. This is a read-only bit. - */ -#define ED_ISR_RST 0x80 - -/* - * Interrupt Mask Register (IMR) definitions - */ - -/* - * PRXE: Packet Received interrupt Enable. If set, a received packet will cause - * an interrupt. - */ -#define ED_IMR_PRXE 0x01 - -/* - * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when - * a packet transmission completes. - */ -#define ED_IMR_PTXE 0x02 - -/* - * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a - * packet is received with an error. - */ -#define ED_IMR_RXEE 0x04 - -/* - * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever - * a transmission results in an error. - */ -#define ED_IMR_TXEE 0x08 - -/* - * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever - * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded. - */ -#define ED_IMR_OVWE 0x10 - -/* - * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever - * the MSB of one or more of the Network Statistics counters has been set. - */ -#define ED_IMR_CNTE 0x20 - -/* - * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated - * when a remote DMA transfer has completed. - */ -#define ED_IMR_RDCE 0x40 - -/* - * bit 7 is unused/reserved - */ - -/* - * Data Configuration Register (DCR) definitions - */ - -/* - * WTS: Word Transfer Select. WTS establishes byte or word transfers for - * both remote and local DMA transfers - */ -#define ED_DCR_WTS 0x01 - -/* - * BOS: Byte Order Select. BOS sets the byte order for the host. - * Should be 0 for 80x86, and 1 for 68000 series processors - */ -#define ED_DCR_BOS 0x02 - -/* - * LAS: Long Address Select. When LAS is 1, the contents of the remote - * DMA registers RSAR0 and RSAR1 are used to provide A16-A31 - */ -#define ED_DCR_LAS 0x04 - -/* - * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2 - * of the TCR must also be programmed for loopback operation. - * When 1, normal operation is selected. - */ -#define ED_DCR_LS 0x08 - -/* - * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer - * under program control. When 1, remote DMA is automatically initiated - * and the boundry pointer is automatically updated - */ -#define ED_DCR_AR 0x10 - -/* - * FT0, FT1: Fifo Threshold select. - * FT1 FT0 Word-width Byte-width - * 0 0 1 word 2 bytes - * 0 1 2 words 4 bytes - * 1 0 4 words 8 bytes - * 1 1 8 words 12 bytes - * - * During transmission, the FIFO threshold indicates the number of bytes - * or words that the FIFO has filled from the local DMA before BREQ is - * asserted. The transmission threshold is 16 bytes minus the receiver - * threshold. - */ -#define ED_DCR_FT0 0x20 -#define ED_DCR_FT1 0x40 - -/* - * bit 7 (0x80) is unused/reserved - */ - -/* - * Transmit Configuration Register (TCR) definitions - */ - -/* - * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC - * is not appended by the transmitter. - */ -#define ED_TCR_CRC 0x01 - -/* - * LB0, LB1: Loopback control. These two bits set the type of loopback that is - * to be performed. - * - * LB1 LB0 mode - * 0 0 0 - normal operation (DCR_LS = 0) - * 0 1 1 - internal loopback (DCR_LS = 0) - * 1 0 2 - external loopback (DCR_LS = 1) - * 1 1 3 - external loopback (DCR_LS = 0) - */ -#define ED_TCR_LB0 0x02 -#define ED_TCR_LB1 0x04 - -/* - * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows - * another station to disable the NIC's transmitter by transmitting to - * a multicast address hashing to bit 62. Reception of a multicast address - * hashing to bit 63 enables the transmitter. - */ -#define ED_TCR_ATD 0x08 - -/* - * OFST: Collision Offset enable. This bit when set modifies the backoff - * algorithm to allow prioritization of nodes. - */ -#define ED_TCR_OFST 0x10 - -/* - * bits 5, 6, and 7 are unused/reserved - */ - -/* - * Transmit Status Register (TSR) definitions - */ - -/* - * PTX: Packet Transmitted. Indicates successful transmission of packet. - */ -#define ED_TSR_PTX 0x01 - -/* - * bit 1 (0x02) is unused/reserved - */ - -/* - * COL: Transmit Collided. Indicates that the transmission collided at least - * once with another station on the network. - */ -#define ED_TSR_COL 0x04 - -/* - * ABT: Transmit aborted. Indicates that the transmission was aborted due to - * excessive collisions. - */ -#define ED_TSR_ABT 0x08 - -/* - * CRS: Carrier Sense Lost. Indicates that carrier was lost during the - * transmission of the packet. (Transmission is not aborted because - * of a loss of carrier) - */ -#define ED_TSR_CRS 0x10 - -/* - * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/ - * transmission memory before the FIFO emptied. Transmission of the - * packet was aborted. - */ -#define ED_TSR_FU 0x20 - -/* - * CDH: CD Heartbeat. Indicates that the collision detection circuitry - * isn't working correctly during a collision heartbeat test. - */ -#define ED_TSR_CDH 0x40 - -/* - * OWC: Out of Window Collision: Indicates that a collision occurred after - * a slot time (51.2us). The transmission is rescheduled just as in - * normal collisions. - */ -#define ED_TSR_OWC 0x80 - -/* - * Receiver Configuration Register (RCR) definitions - */ - -/* - * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1, - * packets with CRC and frame errors are not discarded. - */ -#define ED_RCR_SEP 0x01 - -/* - * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded. - * If set to 1, packets with less than 64 byte are not discarded. - */ -#define ED_RCR_AR 0x02 - -/* - * AB: Accept Broadcast. If set, packets sent to the broadcast address will be - * accepted. - */ -#define ED_RCR_AB 0x04 - -/* - * AM: Accept Multicast. If set, packets sent to a multicast address are checked - * for a match in the hashing array. If clear, multicast packets are ignored. - */ -#define ED_RCR_AM 0x08 - -/* - * PRO: Promiscuous Physical. If set, all packets with a physical addresses are - * accepted. If clear, a physical destination address must match this - * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM - * must also be set. In addition, the multicast hashing array must be set - * to all 1's so that all multicast addresses are accepted. - */ -#define ED_RCR_PRO 0x10 - -/* - * MON: Monitor Mode. If set, packets will be checked for good CRC and framing, - * but are not stored in the ring-buffer. If clear, packets are stored (normal - * operation). - */ -#define ED_RCR_MON 0x20 - -/* - * bits 6 and 7 are unused/reserved. - */ - -/* - * Receiver Status Register (RSR) definitions - */ - -/* - * PRX: Packet Received without error. - */ -#define ED_RSR_PRX 0x01 - -/* - * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame - * alignment errors. - */ -#define ED_RSR_CRC 0x02 - -/* - * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on - * a byte boundry and the CRC did not match at the last byte boundry. - */ -#define ED_RSR_FAE 0x04 - -/* - * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA) - * causing it to overrun. Reception of the packet is aborted. - */ -#define ED_RSR_FO 0x08 - -/* - * MPA: Missed Packet. Indicates that the received packet couldn't be stored in - * the ring-buffer because of insufficient buffer space (exceeding the - * boundry pointer), or because the transfer to the ring-buffer was inhibited - * by RCR_MON - monitor mode. - */ -#define ED_RSR_MPA 0x10 - -/* - * PHY: Physical address. If 0, the packet received was sent to a physical address. - * If 1, the packet was accepted because of a multicast/broadcast address - * match. - */ -#define ED_RSR_PHY 0x20 - -/* - * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor - * mode. Cleared when the receiver exits monitor mode. - */ -#define ED_RSR_DIS 0x40 - -/* - * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs - * are active, and the transceiver has set the CD line as a result of the - * jabber. - */ -#define ED_RSR_DFR 0x80 - -/* - * receive ring discriptor - * - * The National Semiconductor DS8390 Network interface controller uses - * the following receive ring headers. The way this works is that the - * memory on the interface card is chopped up into 256 bytes blocks. - * A contiguous portion of those blocks are marked for receive packets - * by setting start and end block #'s in the NIC. For each packet that - * is put into the receive ring, one of these headers (4 bytes each) is - * tacked onto the front. The first byte is a copy of the receiver status - * register at the time the packet was received. - */ -struct ed_ring { - u_char rsr; /* receiver status */ - u_char next_packet; /* pointer to next packet */ - u_short count; /* bytes in packet (length + 4) */ -}; - -/* - * Common constants - */ -#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */ -#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */ - -/* - * Vendor types - */ -#define ED_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */ -#define ED_VENDOR_3COM 0x01 /* 3Com */ -#define ED_VENDOR_NOVELL 0x02 /* Novell */ -#define ED_VENDOR_PCMCIA 0x03 /* Generic pcmcia */ - -/* - * Compile-time config flags - */ -/* - * this sets the default for enabling/disablng the tranceiver - */ -#define ED_FLAGS_DISABLE_TRANCEIVER 0x0001 - -/* - * This forces the board to be used in 8/16bit mode even if it - * autoconfigs differently - */ -#define ED_FLAGS_FORCE_8BIT_MODE 0x0002 -#define ED_FLAGS_FORCE_16BIT_MODE 0x0004 - -/* - * This disables the use of double transmit buffers. - */ -#define ED_FLAGS_NO_MULTI_BUFFERING 0x0008 - -/* - * This forces all operations with the NIC memory to use Programmed - * I/O (i.e. not via shared memory) - */ -#define ED_FLAGS_FORCE_PIO 0x0010 - -/* - * Definitions for Western digital/SMC WD80x3 series ASIC - */ -/* - * Memory Select Register (MSR) - */ -#define ED_WD_MSR 0 - -/* next three definitions for Toshiba */ -#define ED_WD_MSR_POW 0x02 /* 0 = power save, 1 = normal (R/W) */ -#define ED_WD_MSR_BSY 0x04 /* gate array busy (R) */ -#define ED_WD_MSR_LEN 0x20 /* data bus width, 0 = 16 bits, - 1 = 8 bits (R/W) */ -#define ED_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */ -#define ED_WD_MSR_MENB 0x40 /* Memory enable */ -#define ED_WD_MSR_RST 0x80 /* Reset board */ - -/* - * Interface Configuration Register (ICR) - */ -#define ED_WD_ICR 1 - -#define ED_WD_ICR_16BIT 0x01 /* 16-bit interface */ -#define ED_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */ -#define ED_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */ -#define ED_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */ -#define ED_WD_ICR_RLA 0x10 /* recall LAN address */ -#define ED_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */ -#define ED_WD_ICR_RIO 0x40 /* recall i/o address */ -#define ED_WD_ICR_STO 0x80 /* store to non-volatile memory */ -#ifdef TOSH_ETHER -#define ED_WD_ICR_MEM 0xe0 /* shared mem address A15-A13 (R/W) */ -#define ED_WD_ICR_MSZ1 0x0f /* memory size, 0x08 = 64K, 0x04 = 32K, - 0x02 = 16K, 0x01 = 8K */ - /* 64K can only be used if mem address - above 1Mb */ - /* IAR holds address A23-A16 (R/W) */ -#endif - -/* - * IO Address Register (IAR) - */ -#define ED_WD_IAR 2 - -/* - * EEROM Address Register - */ -#define ED_WD_EAR 3 - -/* - * Interrupt Request Register (IRR) - */ -#define ED_WD_IRR 4 - -#define ED_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */ -#define ED_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */ -#define ED_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */ -#define ED_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */ -#define ED_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */ - -/* - * The three bits of the encoded IRQ are decoded as follows: - * - * IR2 IR1 IR0 IRQ - * 0 0 0 2/9 - * 0 0 1 3 - * 0 1 0 5 - * 0 1 1 7 - * 1 0 0 10 - * 1 0 1 11 - * 1 1 0 15 - * 1 1 1 4 - */ -#define ED_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */ -#define ED_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */ -#define ED_WD_IRR_IEN 0x80 /* Interrupt enable */ - -/* - * LA Address Register (LAAR) - */ -#define ED_WD_LAAR 5 - -#define ED_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */ -#define ED_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */ -#define ED_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */ -#define ED_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */ - -/* i/o base offset to station address/card-ID PROM */ -#define ED_WD_PROM 8 - -/* - * 83C790 specific registers - */ -/* - * Hardware Support Register (HWR) ('790) - */ -#define ED_WD790_HWR 4 - -#define WD_WD790_HWR_NUKE 0x10 /* hardware reset */ -#define ED_WD790_HWR_LPRM 0x40 /* LAN PROM select */ -#define ED_WD790_HWR_SWH 0x80 /* switch register set */ - -/* - * ICR790 Interrupt Control Register for the 83C790 - */ -#define ED_WD790_ICR 6 - -#define ED_WD790_ICR_EIL 0x01 /* enable interrupts */ - -/* - * REV/IOPA Revision / I/O Pipe register for the 83C79X - */ -#define ED_WD790_REV 7 - -#define ED_WD790 0x20 -#define ED_WD795 0x40 - -/* - * 79X RAM Address Register (RAR) - * Enabled with SWH bit=1 in HWR register - */ -#define ED_WD790_RAR 0x0b - -#define ED_WD790_RAR_SZ8 0x00 /* 8k memory buffer */ -#define ED_WD790_RAR_SZ16 0x10 /* 16k memory buffer */ -#define ED_WD790_RAR_SZ32 0x20 /* 32k memory buffer */ -#define ED_WD790_RAR_SZ64 0x30 /* 64k memory buffer */ - -/* - * General Control Register (GCR) - * Enabled with SWH bit=1 in HWR register - */ -#define ED_WD790_GCR 0x0d - -#define ED_WD790_GCR_IR0 0x04 /* bit 0 of encoded IRQ */ -#define ED_WD790_GCR_IR1 0x08 /* bit 1 of encoded IRQ */ -#define ED_WD790_GCR_ZWSEN 0x20 /* zero wait state enable */ -#define ED_WD790_GCR_IR2 0x40 /* bit 2 of encoded IRQ */ -#define ED_WD790_GCR_LIT 0x01 /* Link Integrity Test Enable */ -/* - * The three bits of the encoded IRQ are decoded as follows: - * - * IR2 IR1 IR0 IRQ - * 0 0 0 none - * 0 0 1 9 - * 0 1 0 3 - * 0 1 1 5 - * 1 0 0 7 - * 1 0 1 10 - * 1 1 0 11 - * 1 1 1 15 - */ - -/* i/o base offset to CARD ID */ -#define ED_WD_CARD_ID ED_WD_PROM+6 - -/* Board type codes in card ID */ -#define ED_TYPE_WD8003S 0x02 -#define ED_TYPE_WD8003E 0x03 -#define ED_TYPE_WD8013EBT 0x05 -#define ED_TYPE_TOSHIBA1 0x11 /* named PCETA1 */ -#define ED_TYPE_TOSHIBA2 0x12 /* named PCETA2 */ -#define ED_TYPE_TOSHIBA3 0x13 /* named PCETB */ -#define ED_TYPE_TOSHIBA4 0x14 /* named PCETC */ -#define ED_TYPE_WD8003W 0x24 -#define ED_TYPE_WD8003EB 0x25 -#define ED_TYPE_WD8013W 0x26 -#define ED_TYPE_WD8013EP 0x27 -#define ED_TYPE_WD8013WC 0x28 -#define ED_TYPE_WD8013EPC 0x29 -#define ED_TYPE_SMC8216T 0x2a -#define ED_TYPE_SMC8216C 0x2b -#define ED_TYPE_WD8013EBP 0x2c - -/* Bit definitions in card ID */ -#define ED_WD_REV_MASK 0x1f /* Revision mask */ -#define ED_WD_SOFTCONFIG 0x20 /* Soft config */ -#define ED_WD_LARGERAM 0x40 /* Large RAM */ -#define ED_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */ - -/* - * Checksum total. All 8 bytes in station address PROM will add up to this - */ -#ifdef TOSH_ETHER -#define ED_WD_ROM_CHECKSUM_TOTAL 0xA5 -#else -#define ED_WD_ROM_CHECKSUM_TOTAL 0xFF -#endif - -#define ED_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */ -#define ED_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */ -#define ED_WD_IO_PORTS 32 /* # of i/o addresses used */ - -#define ED_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */ - -/* - * Definitions for 3Com 3c503 - */ -#define ED_3COM_NIC_OFFSET 0 -#define ED_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */ - -/* - * XXX - The I/O address range is fragmented in the 3c503; this is the - * number of regs at iobase. - */ -#define ED_3COM_IO_PORTS 16 /* # of i/o addresses used */ - -/* tx memory starts in second bank on 8bit cards */ -#define ED_3COM_TX_PAGE_OFFSET_8BIT 0x20 - -/* tx memory starts in first bank on 16bit cards */ -#define ED_3COM_TX_PAGE_OFFSET_16BIT 0x0 - -/* ...and rx memory starts in second bank */ -#define ED_3COM_RX_PAGE_OFFSET_16BIT 0x20 - - -/* - * Page Start Register. Must match PSTART in NIC - */ -#define ED_3COM_PSTR 0 - -/* - * Page Stop Register. Must match PSTOP in NIC - */ -#define ED_3COM_PSPR 1 - -/* - * Drq Timer Register. Determines number of bytes to be transfered during - * a DMA burst. - */ -#define ED_3COM_DQTR 2 - -/* - * Base Configuration Register. Read-only register which contains the - * board-configured I/O base address of the adapter. Bit encoded. - */ -#define ED_3COM_BCFR 3 - -#define ED_3COM_BCFR_2E0 0x01 -#define ED_3COM_BCFR_2A0 0x02 -#define ED_3COM_BCFR_280 0x04 -#define ED_3COM_BCFR_250 0x08 -#define ED_3COM_BCFR_350 0x10 -#define ED_3COM_BCFR_330 0x20 -#define ED_3COM_BCFR_310 0x40 -#define ED_3COM_BCFR_300 0x80 - -/* - * EPROM Configuration Register. Read-only register which contains the - * board-configured memory base address. Bit encoded. - */ -#define ED_3COM_PCFR 4 - -#define ED_3COM_PCFR_C8000 0x10 -#define ED_3COM_PCFR_CC000 0x20 -#define ED_3COM_PCFR_D8000 0x40 -#define ED_3COM_PCFR_DC000 0x80 - -/* - * GA Configuration Register. Gate-Array Configuration Register. - */ -#define ED_3COM_GACFR 5 - -/* - * mbs2 mbs1 mbs0 start address - * 0 0 0 0x0000 - * 0 0 1 0x2000 - * 0 1 0 0x4000 - * 0 1 1 0x6000 - * - * Note that with adapters with only 8K, the setting for 0x2000 must - * always be used. - */ -#define ED_3COM_GACFR_MBS0 0x01 -#define ED_3COM_GACFR_MBS1 0x02 -#define ED_3COM_GACFR_MBS2 0x04 - -#define ED_3COM_GACFR_RSEL 0x08 /* enable shared memory */ -#define ED_3COM_GACFR_TEST 0x10 /* for GA testing */ -#define ED_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */ -#define ED_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */ -#define ED_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */ - -/* - * Control Register. Miscellaneous control functions. - */ -#define ED_3COM_CR 6 - -#define ED_3COM_CR_RST 0x01 /* Reset GA and NIC */ -#define ED_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */ -#define ED_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */ -#define ED_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */ -#define ED_3COM_CR_SHARE 0x10 /* select interrupt sharing option */ -#define ED_3COM_CR_DBSEL 0x20 /* Double buffer select */ -#define ED_3COM_CR_DDIR 0x40 /* DMA direction select */ -#define ED_3COM_CR_START 0x80 /* Start DMA controller */ - -/* - * Status Register. Miscellaneous status information. - */ -#define ED_3COM_STREG 7 - -#define ED_3COM_STREG_REV 0x07 /* GA revision */ -#define ED_3COM_STREG_DIP 0x08 /* DMA in progress */ -#define ED_3COM_STREG_DTC 0x10 /* DMA terminal count */ -#define ED_3COM_STREG_OFLW 0x20 /* Overflow */ -#define ED_3COM_STREG_UFLW 0x40 /* Underflow */ -#define ED_3COM_STREG_DPRDY 0x80 /* Data port ready */ - -/* - * Interrupt/DMA Configuration Register - */ -#define ED_3COM_IDCFR 8 - -#define ED_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */ -#define ED_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */ -#define ED_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */ -#define ED_3COM_IDCFR_UNUSED 0x08 /* not used */ -#define ED_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */ -#define ED_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */ -#define ED_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */ -#define ED_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */ - -/* - * DMA Address Register MSB - */ -#define ED_3COM_DAMSB 9 - -/* - * DMA Address Register LSB - */ -#define ED_3COM_DALSB 0x0a - -/* - * Vector Pointer Register 2 - */ -#define ED_3COM_VPTR2 0x0b - -/* - * Vector Pointer Register 1 - */ -#define ED_3COM_VPTR1 0x0c - -/* - * Vector Pointer Register 0 - */ -#define ED_3COM_VPTR0 0x0d - -/* - * Register File Access MSB - */ -#define ED_3COM_RFMSB 0x0e - -/* - * Register File Access LSB - */ -#define ED_3COM_RFLSB 0x0f - -/* - * Definitions for Novell NE1000/2000 boards - */ - -/* - * Board type codes - */ -#define ED_TYPE_NE1000 0x01 -#define ED_TYPE_NE2000 0x02 - -/* - * Register offsets/total - */ -#define ED_NOVELL_NIC_OFFSET 0x00 -#define ED_NOVELL_ASIC_OFFSET 0x10 -#define ED_NOVELL_IO_PORTS 32 - -/* - * Remote DMA data register; for reading or writing to the NIC mem - * via programmed I/O (offset from ASIC base) - */ -#define ED_NOVELL_DATA 0x00 - -/* - * Reset register; reading from this register causes a board reset - */ -#define ED_NOVELL_RESET 0x0f - -#define ED_TYPE_PCMCIA 0x01 -#define ED_PCMCIA_PAGE_OFFSET 0x40 /* True for all cards I have seen */ -#define ED_PCMCIA_IO_PORTS 32 -#define ED_PCMCIA_RESET 0xF /* Reset port */ diff --git a/usr.sbin/pccard/misc/sys/pccard/lkm_ed.c b/usr.sbin/pccard/misc/sys/pccard/lkm_ed.c deleted file mode 100644 index 7bc1ec7e4e7f..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/lkm_ed.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Loadable kernel module if_ed driver - * 11 July 1995 Andrew McRae - * - *------------------------------------------------------------------------- - * - * Copyright (c) 1995 Andrew McRae. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* - * This defines the lkm_misc module use by modload - * to define the module name. - */ - MOD_MISC( "ed") - - -int edintr(struct pccard_dev *); /* Interrupt handler */ -void edunload(struct pccard_dev *); /* Disable driver */ -void edsuspend(struct pccard_dev *); /* Suspend driver */ -int edinit(struct pccard_dev *, int); /* init device */ - -static struct pccard_drv ed_info = - { - "ed", - edintr, - edunload, - edsuspend, - edinit, - 0, - &net_imask - }; -static int opened; /* Rather minimal device state... */ - -/* - * Module handler that processes loads and unloads. - * Once the module is loaded, the add driver routine is called - * to register the driver. - * If an unload is requested the remove driver routine is - * called to deregister the driver before unloading. - */ -static int -ed_handle( lkmtp, cmd) -struct lkm_table *lkmtp; -int cmd; -{ - int i; - struct lkm_misc *args = lkmtp->private.lkm_misc; - int err = 0; /* default = success*/ - - switch( cmd) { - case LKM_E_LOAD: - - /* - * Don't load twice! (lkmexists() is exported by kern_lkm.c) - */ - if( lkmexists( lkmtp)) - return( EEXIST); -/* - * Now register the driver - */ - pccard_add_driver(&ed_info); - break; /* Success*/ -/* - * Attempt to deregister the driver. - */ - case LKM_E_UNLOAD: - pccard_remove_driver(&ed_info); - break; /* Success*/ - - default: /* we only understand load/unload*/ - err = EINVAL; - break; - } - - return( err); -} - - -/* - * External entry point; should generally match name of .o file. The - * arguments are always the same for all loaded modules. The "load", - * "unload", and "stat" functions in "DISPATCH" will be called under - * their respective circumstances unless their value is "nosys". If - * called, they are called with the same arguments (cmd is included to - * allow the use of a single function, ver is included for version - * matching between modules and the kernel loader for the modules). - * - * Since we expect to link in the kernel and add external symbols to - * the kernel symbol name space in a future version, generally all - * functions used in the implementation of a particular module should - * be static unless they are expected to be seen in other modules or - * to resolve unresolved symbols alread existing in the kernel (the - * second case is not likely to ever occur). - * - * The entry point should return 0 unless it is refusing load (in which - * case it should return an errno from errno.h). - */ -int -lkm_ed(lkmtp, cmd, ver) -struct lkm_table *lkmtp; -int cmd; -int ver; -{ - DISPATCH(lkmtp,cmd,ver,ed_handle,ed_handle,nosys) -} diff --git a/usr.sbin/pccard/misc/sys/pccard/sio.c b/usr.sbin/pccard/misc/sys/pccard/sio.c deleted file mode 100644 index 73d0da2afb90..000000000000 --- a/usr.sbin/pccard/misc/sys/pccard/sio.c +++ /dev/null @@ -1,2463 +0,0 @@ -/*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)com.c 7.5 (Berkeley) 5/16/91 - * $Id: sio.c,v 1.95 1995/04/15 21:45:16 bde Exp $ - */ - -#include "sio.h" -#if NSIO > 0 -/* - * Serial driver, based on 386BSD-0.1 com driver. - * Mostly rewritten to use pseudo-DMA. - * Works for National Semiconductor NS8250-NS16550AF UARTs. - * COM driver, based on HP dca driver. - * - * Changes for PC-Card integration: - * - Added PC-Card driver table and handlers - */ -#include -#include -#include -#include -#define TTYDEFCHARS /* XXX TK2.0 */ -#include -#undef TTYDEFCHARS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include /* XXX just to get at `imen' */ -#include -#include -#include -#include - -#include "crd.h" -#if NCRD > 0 -#include -#include -#endif /* NCRD > 0 */ - -/* - * XXX temporary kludges for 2.0 (XXX TK2.0). - */ -#define TSA_CARR_ON(tp) ((void *)&(tp)->t_rawq) -#define TSA_OCOMPLETE(tp) ((void *)&(tp)->t_outq) -#define TSA_OLOWAT(tp) ((void *)&(tp)->t_outq) -void -termioschars(t) - struct termios *t; -{ - - bcopy(ttydefchars, t->c_cc, sizeof t->c_cc); -} - -#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ -#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE) -#define RS_IBUFSIZE 256 - -#define CALLOUT_MASK 0x80 -#define CONTROL_MASK 0x60 -#define CONTROL_INIT_STATE 0x20 -#define CONTROL_LOCK_STATE 0x40 -#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) -#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) -#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK) - -#ifdef COM_MULTIPORT -/* checks in flags for multiport and which is multiport "master chip" - * for a given card - */ -#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01) -#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff) -#define COM_NOTAST4(dev) ((dev)->id_flags & 0x04) -#endif /* COM_MULTIPORT */ - -#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02) -#define COM_VERBOSE(dev) ((dev)->id_flags & 0x80) - -#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ - -/* - * Input buffer watermarks. - * The external device is asked to stop sending when the buffer exactly reaches - * high water, or when the high level requests it. - * The high level is notified immediately (rather than at a later clock tick) - * when this watermark is reached. - * The buffer size is chosen so the watermark should almost never be reached. - * The low watermark is invisibly 0 since the buffer is always emptied all at - * once. - */ -#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) - -/* - * com state bits. - * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher - * than the other bits so that they can be tested as a group without masking - * off the low bits. - * - * The following com and tty flags correspond closely: - * CS_BUSY = TS_BUSY (maintained by comstart() and comflush()) - * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop()) - * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) - * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) - * TS_FLUSH is not used. - * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. - * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). - */ -#define CS_BUSY 0x80 /* output in progress */ -#define CS_TTGO 0x40 /* output not stopped by XOFF */ -#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ -#define CS_CHECKMSR 1 /* check of MSR scheduled */ -#define CS_CTS_OFLOW 2 /* use CTS output flow control */ -#define CS_DTR_OFF 0x10 /* DTR held off */ -#define CS_ODONE 4 /* output completed */ -#define CS_RTS_IFLOW 8 /* use RTS input flow control */ - -static char const * const error_desc[] = { -#define CE_OVERRUN 0 - "silo overflow", -#define CE_INTERRUPT_BUF_OVERFLOW 1 - "interrupt-level buffer overflow", -#define CE_TTY_BUF_OVERFLOW 2 - "tty-level buffer overflow", -}; - -#define CE_NTYPES 3 -#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) - -/* types. XXX - should be elsewhere */ -typedef u_int Port_t; /* hardware port */ -typedef u_char bool_t; /* boolean */ - -/* com device structure */ -struct com_s { - u_char state; /* miscellaneous flag bits */ - bool_t active_out; /* nonzero if the callout device is open */ - u_char cfcr_image; /* copy of value written to CFCR */ - u_char ftl; /* current rx fifo trigger level */ - u_char ftl_init; /* ftl_max for next open() */ - u_char ftl_max; /* maximum ftl for curent open() */ - bool_t hasfifo; /* nonzero for 16550 UARTs */ - u_char mcr_image; /* copy of value written to MCR */ -#ifdef COM_MULTIPORT - bool_t multiport; /* is this unit part of a multiport device? */ -#endif /* COM_MULTIPORT */ - bool_t no_irq; /* nonzero if irq is not attached */ - bool_t poll; /* nonzero if polling is required */ - int unit; /* unit number */ - int dtr_wait; /* time to hold DTR down on close (* 1/hz) */ - u_int tx_fifo_size; - u_int wopeners; /* # processes waiting for DCD in open() */ - - /* - * The high level of the driver never reads status registers directly - * because there would be too many side effects to handle conveniently. - * Instead, it reads copies of the registers stored here by the - * interrupt handler. - */ - u_char last_modem_status; /* last MSR read by intr handler */ - u_char prev_modem_status; /* last MSR handled by high level */ - - u_char hotchar; /* ldisc-specific char to be handled ASAP */ - u_char *ibuf; /* start of input buffer */ - u_char *ibufend; /* end of input buffer */ - u_char *ihighwater; /* threshold in input buffer */ - u_char *iptr; /* next free spot in input buffer */ - - u_char *obufend; /* end of output buffer */ - u_char *optr; /* next char to output */ - - Port_t data_port; /* i/o ports */ - Port_t int_id_port; - Port_t iobase; - Port_t modem_ctl_port; - Port_t line_status_port; - Port_t modem_status_port; - - struct tty *tp; /* cross reference */ - - /* Initial state. */ - struct termios it_in; /* should be in struct tty */ - struct termios it_out; - - /* Lock state. */ - struct termios lt_in; /* should be in struct tty */ - struct termios lt_out; - - bool_t do_timestamp; - struct timeval timestamp; - - u_long bytes_in; /* statistics */ - u_long bytes_out; - u_int delta_error_counts[CE_NTYPES]; - u_long error_counts[CE_NTYPES]; - - /* - * Ping-pong input buffers. The extra factor of 2 in the sizes is - * to allow for an error byte for each input byte. - */ -#define CE_INPUT_OFFSET RS_IBUFSIZE - u_char ibuf1[2 * RS_IBUFSIZE]; - u_char ibuf2[2 * RS_IBUFSIZE]; - - /* - * Output buffer. Someday we should avoid copying. Twice. - */ - u_char obuf[256]; -}; - -/* - * The public functions in the com module ought to be declared in a com-driver - * system header. - */ - -/* Interrupt handling entry points. */ -void siointr __P((int unit)); -void siopoll __P((void)); - -/* Device switch entry points. */ -int sioopen __P((dev_t dev, int oflags, int devtype, - struct proc *p)); -int sioclose __P((dev_t dev, int fflag, int devtype, - struct proc *p)); -int sioread __P((dev_t dev, struct uio *uio, int ioflag)); -int siowrite __P((dev_t dev, struct uio *uio, int ioflag)); -int sioioctl __P((dev_t dev, int cmd, caddr_t data, - int fflag, struct proc *p)); -void siostop __P((struct tty *tp, int rw)); -#define sioreset noreset -int sioselect __P((dev_t dev, int rw, struct proc *p)); -#define siommap nommap -#define siostrategy nostrategy - -/* Console device entry points. */ -int siocncheckc __P((dev_t dev)); -int siocngetc __P((dev_t dev)); -struct consdev; -void siocninit __P((struct consdev *cp)); -void siocnprobe __P((struct consdev *cp)); -void siocnputc __P((dev_t dev, int c)); - -static int sioattach __P((struct isa_device *dev)); -static timeout_t siodtrwakeup; -static void comflush __P((struct com_s *com)); -static void comhardclose __P((struct com_s *com)); -static void siointr1 __P((struct com_s *com)); -static void commctl __P((struct com_s *com, int bits, int how)); -static int comparam __P((struct tty *tp, struct termios *t)); -static int sioprobe __P((struct isa_device *dev)); -static void sioregisterdev __P((struct isa_device *id)); -static void comstart __P((struct tty *tp)); -static timeout_t comwakeup; -static int tiocm_xxx2mcr __P((int tiocm_xxx)); -static void disc_optim __P((struct tty *tp, struct termios *t, struct com_s *com)); - -#ifdef DSI_SOFT_MODEM -static int LoadSoftModem __P((int unit,int base_io, u_long size, u_char *ptr)); -#endif /* DSI_SOFT_MODEM */ - -/* table and macro for fast conversion from a unit number to its com struct */ -static struct com_s *p_com_addr[NSIO]; -#define com_addr(unit) (p_com_addr[unit]) - -static struct timeval intr_timestamp; - -struct isa_driver siodriver = { - sioprobe, sioattach, "sio" -}; - -#ifdef COMCONSOLE -#undef COMCONSOLE -#define COMCONSOLE 1 -#else -#define COMCONSOLE 0 -#endif - -static int comconsole = CONUNIT; -static speed_t comdefaultrate = TTYDEF_SPEED; -static u_int com_events; /* input chars + weighted output completions */ -static int commajor; -#if 0 /* XXX TK2.0 */ -struct tty *sio_tty[NSIO]; -#else -struct tty sio_tty[NSIO]; -#endif - -#ifdef KGDB -#include - -extern int kgdb_dev; -extern int kgdb_rate; -extern int kgdb_debug_init; -#endif - -static struct speedtab comspeedtab[] = { - 0, 0, - 50, COMBRD(50), - 75, COMBRD(75), - 110, COMBRD(110), - 134, COMBRD(134), - 150, COMBRD(150), - 200, COMBRD(200), - 300, COMBRD(300), - 600, COMBRD(600), - 1200, COMBRD(1200), - 1800, COMBRD(1800), - 2400, COMBRD(2400), - 4800, COMBRD(4800), - 9600, COMBRD(9600), - 19200, COMBRD(19200), - 38400, COMBRD(38400), - 57600, COMBRD(57600), - 115200, COMBRD(115200), - -1, -1 -}; - -/* XXX - configure this list */ -static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; - -static struct kern_devconf kdc_sio[NSIO] = { { - 0, 0, 0, /* filled in by dev_attach */ - "sio", 0, { MDDT_ISA, 0, "tty" }, - isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, - &kdc_isa0, /* parent */ - 0, /* parentdata */ - DC_UNCONFIGURED, /* state */ - "RS-232 serial port", - DC_CLS_SERIAL /* class */ -} }; -#if NCRD > 0 -/* - * PC-Card (PCMCIA) specific code. - */ -static int card_intr(struct pccard_dev *); /* Interrupt handler */ -void siounload(struct pccard_dev *); /* Disable driver */ -void siosuspend(struct pccard_dev *); /* Suspend driver */ -static int sioinit(struct pccard_dev *, int); /* init device */ - -static struct pccard_drv sio_info = - { - "sio", - card_intr, - siounload, - siosuspend, - sioinit, - 0, /* Attributes - presently unused */ - &tty_imask /* Interrupt mask for device */ - /* This should also include net_imask?? */ - }; -/* - * Called when a power down is wanted. Shuts down the - * device and configures the device as unavailable (but - * still loaded...). A resume is done by calling - * sioinit with first=0. This is called when the user suspends - * the system, or the APM code suspends the system. - */ -void -siosuspend(struct pccard_dev *dp) -{ - printf("sio%d: suspending\n", dp->isahd.id_unit); -} -/* - * Initialize the device - called from Slot manager. - * if first is set, then initially check for - * the device's existence before initialising it. - * Once initialised, the device table may be set up. - */ -int -sioinit(struct pccard_dev *dp, int first) -{ -/* - * validate unit number. - */ - if (first) - { - if (dp->isahd.id_unit >= NSIO) - return(ENODEV); -/* - * Make sure it isn't already probed. - */ - if (com_addr(dp->isahd.id_unit)) - return(EBUSY); -/* - * Probe the device. If a value is returned, the - * device was found at the location. - */ - if (sioprobe(&dp->isahd)==0) - return(ENXIO); - if (sioattach(&dp->isahd)==0) - return(ENXIO); - } -/* - * XXX TODO: - * If it was already inited before, the device structure - * should be already initialised. Here we should - * reset (and possibly restart) the hardware, but - * I am not sure of the best way to do this... - */ - return(0); -} -/* - * siounload - unload the driver and clear the table. - * XXX TODO: - * This is called usually when the card is ejected, but - * can be caused by the modunload of a controller driver. - * The idea is reset the driver's view of the device - * and ensure that any driver entry points such as - * read and write do not hang. - */ -void -siounload(struct pccard_dev *dp) -{ - printf("sio%d: unload\n", dp->isahd.id_unit); -} - -/* - * card_intr - Shared interrupt called from - * front end of PC-Card handler. - */ -static int -card_intr(struct pccard_dev *dp) -{ - siointr1(com_addr(dp->isahd.id_unit)); - return(1); -} -#endif /* NCRD > 0 */ - -static void -sioregisterdev(id) - struct isa_device *id; -{ - int unit; - - unit = id->id_unit; -/* - * If already registered, don't try to re-register. - */ - if (kdc_sio[unit].kdc_isa) - return; - if (unit != 0) - kdc_sio[unit] = kdc_sio[0]; - kdc_sio[unit].kdc_unit = unit; - kdc_sio[unit].kdc_isa = id; - dev_attach(&kdc_sio[unit]); -} - -static int -sioprobe(dev) - struct isa_device *dev; -{ - static bool_t already_init; - Port_t *com_ptr; - bool_t failures[10]; - int fn; - struct isa_device *idev; - Port_t iobase; - u_char mcr_image; - int result; - - sioregisterdev(dev); - - if (!already_init) { - /* - * Turn off MCR_IENABLE for all likely serial ports. An unused - * port with its MCR_IENABLE gate open will inhibit interrupts - * from any used port that shares the interrupt vector. - * XXX the gate enable is elsewhere for some multiports. - */ - for (com_ptr = likely_com_ports; - com_ptr < &likely_com_ports[sizeof likely_com_ports - / sizeof likely_com_ports[0]]; - ++com_ptr) - outb(*com_ptr + com_mcr, 0); -#if NCRD > 0 -/* - * If PC-Card probe required, then register driver with - * slot manager. - */ - pccard_add_driver(&sio_info); -#endif /* NCRD > 0 */ - already_init = TRUE; - } - - /* - * If the device is on a multiport card and has an AST/4 - * compatible interrupt control register, initialize this - * register and prepare to leave MCR_IENABLE clear in the mcr. - * Otherwise, prepare to set MCR_IENABLE in the mcr. - * Point idev to the device struct giving the correct id_irq. - * This is the struct for the master device if there is one. - */ - idev = dev; - mcr_image = MCR_IENABLE; -#ifdef COM_MULTIPORT - if (COM_ISMULTIPORT(dev)) { - idev = find_isadev(isa_devtab_tty, &siodriver, - COM_MPMASTER(dev)); - if (idev == NULL) { - printf("sio%d: master device %d not configured\n", - dev->id_unit, COM_MPMASTER(dev)); - return (0); - } - if (!COM_NOTAST4(dev)) { - outb(idev->id_iobase + com_scr, - idev->id_irq ? 0x80 : 0); - mcr_image = 0; - } - } -#endif /* COM_MULTIPORT */ - if (idev->id_irq == 0) - mcr_image = 0; - - bzero(failures, sizeof failures); - iobase = dev->id_iobase; - - /* - * We don't want to get actual interrupts, just masked ones. - * Interrupts from this line should already be masked in the ICU, - * but mask them in the processor as well in case there are some - * (misconfigured) shared interrupts. - */ - disable_intr(); -/* EXTRA DELAY? */ - - /* - * XXX DELAY() reenables CPU interrupts. This is a problem for - * shared interrupts after the first device using one has been - * successfully probed - config_isadev() has enabled the interrupt - * in the ICU. - */ - outb(IO_ICU1 + 1, 0xff); - - /* - * Initialize the speed and the word size and wait long enough to - * drain the maximum of 16 bytes of junk in device output queues. - * The speed is undefined after a master reset and must be set - * before relying on anything related to output. There may be - * junk after a (very fast) soft reboot and (apparently) after - * master reset. - * XXX what about the UART bug avoided by waiting in comparam()? - * We don't want to to wait long enough to drain at 2 bps. - */ - outb(iobase + com_cfcr, CFCR_DLAB); - outb(iobase + com_dlbl, COMBRD(9600) & 0xff); - outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8); - outb(iobase + com_cfcr, CFCR_8BITS); - DELAY((16 + 1) * 1000000 / (9600 / 10)); - - /* - * Enable the interrupt gate and disable device interupts. This - * should leave the device driving the interrupt line low and - * guarantee an edge trigger if an interrupt can be generated. - */ -/* EXTRA DELAY? */ - outb(iobase + com_mcr, mcr_image); - outb(iobase + com_ier, 0); - - /* - * Attempt to set loopback mode so that we can send a null byte - * without annoying any external device. - */ -/* EXTRA DELAY? */ - outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK); - - /* - * Attempt to generate an output interrupt. On 8250's, setting - * IER_ETXRDY generates an interrupt independent of the current - * setting and independent of whether the THR is empty. On 16450's, - * setting IER_ETXRDY generates an interrupt independent of the - * current setting. On 16550A's, setting IER_ETXRDY only - * generates an interrupt when IER_ETXRDY is not already set. - */ - outb(iobase + com_ier, IER_ETXRDY); - - /* - * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate - * an interrupt. They'd better generate one for actually doing - * output. Loopback may be broken on the same incompatibles but - * it's unlikely to do more than allow the null byte out. - */ - outb(iobase + com_data, 0); - DELAY((1 + 2) * 1000000 / (9600 / 10)); - - /* - * Turn off loopback mode so that the interrupt gate works again - * (MCR_IENABLE was hidden). This should leave the device driving - * an interrupt line high. It doesn't matter if the interrupt - * line oscillates while we are not looking at it, since interrupts - * are disabled. - */ -/* EXTRA DELAY? */ - outb(iobase + com_mcr, mcr_image); - - /* - * Check that - * o the CFCR, IER and MCR in UART hold the values written to them - * (the values happen to be all distinct - this is good for - * avoiding false positive tests from bus echoes). - * o an output interrupt is generated and its vector is correct. - * o the interrupt goes away when the IIR in the UART is read. - */ -/* EXTRA DELAY? */ - failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS; - failures[1] = inb(iobase + com_ier) - IER_ETXRDY; - failures[2] = inb(iobase + com_mcr) - mcr_image; - if (idev->id_irq != 0) - failures[3] = isa_irq_pending(idev) ? 0 : 1; - failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY; - if (idev->id_irq != 0) - failures[5] = isa_irq_pending(idev) ? 1 : 0; - failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; - - /* - * Turn off all device interrupts and check that they go off properly. - * Leave MCR_IENABLE alone. For ports without a master port, it gates - * the OUT2 output of the UART to - * the ICU input. Closing the gate would give a floating ICU input - * (unless there is another device driving at) and spurious interrupts. - * (On the system that this was first tested on, the input floats high - * and gives a (masked) interrupt as soon as the gate is closed.) - */ - outb(iobase + com_ier, 0); - outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */ - failures[7] = inb(iobase + com_ier); - if (idev->id_irq != 0) - failures[8] = isa_irq_pending(idev) ? 1 : 0; - failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; - - outb(IO_ICU1 + 1, imen); /* XXX */ - enable_intr(); - - result = IO_COMSIZE; - for (fn = 0; fn < sizeof failures; ++fn) - if (failures[fn]) { - outb(iobase + com_mcr, 0); - result = 0; - if (COM_VERBOSE(dev)) - printf("sio%d: probe test %d failed\n", - dev->id_unit, fn); - } - return (result); -} - -static int -sioattach(isdp) - struct isa_device *isdp; -{ - struct com_s *com; - static bool_t comwakeup_started = FALSE; - Port_t iobase; - int s; - int unit; - - isdp->id_ri_flags |= RI_FAST; - iobase = isdp->id_iobase; - unit = isdp->id_unit; - com = malloc(sizeof *com, M_TTYS, M_NOWAIT); - if (com == NULL) - return (0); - - /* - * sioprobe() has initialized the device registers as follows: - * o cfcr = CFCR_8BITS. - * It is most important that CFCR_DLAB is off, so that the - * data port is not hidden when we enable interrupts. - * o ier = 0. - * Interrupts are only enabled when the line is open. - * o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible - * interrupt control register or the config specifies no irq. - * Keeping MCR_DTR and MCR_RTS off might stop the external - * device from sending before we are ready. - */ - bzero(com, sizeof *com); - com->unit = unit; - com->cfcr_image = CFCR_8BITS; - com->dtr_wait = 3 * hz; - com->no_irq = isdp->id_irq == 0; - com->tx_fifo_size = 1; - com->iptr = com->ibuf = com->ibuf1; - com->ibufend = com->ibuf1 + RS_IBUFSIZE; - com->ihighwater = com->ibuf1 + RS_IHIGHWATER; - com->iobase = iobase; - com->data_port = iobase + com_data; - com->int_id_port = iobase + com_iir; - com->modem_ctl_port = iobase + com_mcr; - com->mcr_image = inb(com->modem_ctl_port); - com->line_status_port = iobase + com_lsr; - com->modem_status_port = iobase + com_msr; - - /* - * We don't use all the flags from since they - * are only relevant for logins. It's important to have echo off - * initially so that the line doesn't start blathering before the - * echo flag can be turned off. - */ - com->it_in.c_iflag = 0; - com->it_in.c_oflag = 0; - com->it_in.c_cflag = TTYDEF_CFLAG; - com->it_in.c_lflag = 0; - if (unit == comconsole && (COMCONSOLE || boothowto & RB_SERIAL)) { - com->it_in.c_iflag = TTYDEF_IFLAG; - com->it_in.c_oflag = TTYDEF_OFLAG; - com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL; - com->it_in.c_lflag = TTYDEF_LFLAG; - com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL; - } - termioschars(&com->it_in); - com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate; - com->it_out = com->it_in; - - /* attempt to determine UART type */ - printf("sio%d: type", unit); - -#ifdef DSI_SOFT_MODEM - if((inb(iobase+7) ^ inb(iobase+7)) & 0x80) { - printf(" Digicom Systems, Inc. SoftModem"); - kdc_sio[unit].kdc_description = - "Serial port: Digicom Systems SoftModem"; - goto determined_type; - } -#endif /* DSI_SOFT_MODEM */ - -#ifdef COM_MULTIPORT - if (!COM_ISMULTIPORT(isdp)) -#endif - { - u_char scr; - u_char scr1; - u_char scr2; - - scr = inb(iobase + com_scr); - outb(iobase + com_scr, 0xa5); - scr1 = inb(iobase + com_scr); - outb(iobase + com_scr, 0x5a); - scr2 = inb(iobase + com_scr); - outb(iobase + com_scr, scr); - if (scr1 != 0xa5 || scr2 != 0x5a) { - printf(" 8250"); - kdc_sio[unit].kdc_description = - "Serial port: National 8250 or compatible"; - goto determined_type; - } - } - outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); - DELAY(100); - switch (inb(com->int_id_port) & IIR_FIFO_MASK) { - case FIFO_TRIGGER_1: - printf(" 16450"); - kdc_sio[unit].kdc_description = - "Serial port: National 16450 or compatible"; - break; - case FIFO_TRIGGER_4: - printf(" 16450?"); - kdc_sio[unit].kdc_description = - "Serial port: maybe National 16450"; - break; - case FIFO_TRIGGER_8: - printf(" 16550?"); - kdc_sio[unit].kdc_description = - "Serial port: maybe National 16550"; - break; - case FIFO_TRIGGER_14: - printf(" 16550A"); - if (COM_NOFIFO(isdp)) { - printf(" fifo disabled"); - kdc_sio[unit].kdc_description = - "Serial port: National 16550A, FIFO disabled"; - } else { - com->hasfifo = TRUE; - com->ftl_init = FIFO_TRIGGER_14; - com->tx_fifo_size = 16; - kdc_sio[unit].kdc_description = - "Serial port: National 16550A or compatible"; - } - break; - } - outb(iobase + com_fifo, 0); -determined_type: ; - -#ifdef COM_MULTIPORT - if (COM_ISMULTIPORT(isdp)) { - com->multiport = TRUE; - printf(" (multiport"); - if (unit == COM_MPMASTER(isdp)) - printf(" master"); - printf(")"); - com->no_irq = find_isadev(isa_devtab_tty, &siodriver, - COM_MPMASTER(isdp))->id_irq == 0; - } -#endif /* COM_MULTIPORT */ - printf("\n"); - - kdc_sio[unit].kdc_state = - (unit == comconsole && (COMCONSOLE || boothowto & RB_SERIAL)) - ? DC_BUSY : DC_IDLE; - -#ifdef KGDB - if (kgdb_dev == makedev(commajor, unit)) { - if (unit == comconsole && (COMCONSOLE || boothowto & RB_SERIAL)) - kgdb_dev = -1; /* can't debug over console port */ - else { - int divisor; - - /* - * XXX now unfinished and broken. Need to do - * something more like a full open(). There's no - * suitable interrupt handler so don't enable device - * interrupts. Watch out for null tp's. - */ - outb(iobase + com_cfcr, CFCR_DLAB); - divisor = ttspeedtab(kgdb_rate, comspeedtab); - outb(iobase + com_dlbl, divisor & 0xFF); - outb(iobase + com_dlbh, (u_int) divisor >> 8); - outb(iobase + com_cfcr, CFCR_8BITS); - outb(com->modem_status_port, - com->mcr_image |= MCR_DTR | MCR_RTS); - - if (kgdb_debug_init) { - /* - * Print prefix of device name, - * let kgdb_connect print the rest. - */ - printf("sio%d: ", unit); - kgdb_connect(1); - } else - printf("sio%d: kgdb enabled\n", unit); - } - } -#endif - - s = spltty(); - com_addr(unit) = com; - splx(s); - if (!comwakeup_started) { - comwakeup((void *)NULL); - comwakeup_started = TRUE; - } - return (1); -} - -/* ARGSUSED */ -int -sioopen(dev, flag, mode, p) - dev_t dev; - int flag; - int mode; - struct proc *p; -{ - struct com_s *com; - int error; - Port_t iobase; - int mynor; - int s; - struct tty *tp; - int unit; - - mynor = minor(dev); - unit = MINOR_TO_UNIT(mynor); - if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) - return (ENXIO); - if (mynor & CONTROL_MASK) - return (0); -#if 0 /* XXX TK2.0 */ - tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]); -#else - tp = com->tp = &sio_tty[unit]; -#endif - s = spltty(); - /* - * We jump to this label after all non-interrupted sleeps to pick - * up any changes of the device state. - */ -open_top: - while (com->state & CS_DTR_OFF) { - error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0); - if (error != 0) - goto out; - } - kdc_sio[unit].kdc_state = DC_BUSY; - if (tp->t_state & TS_ISOPEN) { - /* - * The device is open, so everything has been initialized. - * Handle conflicts. - */ - if (mynor & CALLOUT_MASK) { - if (!com->active_out) { - error = EBUSY; - goto out; - } - } else { - if (com->active_out) { - if (flag & O_NONBLOCK) { - error = EBUSY; - goto out; - } - error = tsleep(&com->active_out, - TTIPRI | PCATCH, "siobi", 0); - if (error != 0) - goto out; - goto open_top; - } - } - if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { - error = EBUSY; - goto out; - } - } else { - /* - * The device isn't open, so there are no conflicts. - * Initialize it. Initialization is done twice in many - * cases: to preempt sleeping callin opens if we are - * callout, and to complete a callin open after DCD rises. - */ - tp->t_oproc = comstart; - tp->t_param = comparam; - tp->t_dev = dev; - tp->t_termios = mynor & CALLOUT_MASK - ? com->it_out : com->it_in; - commctl(com, MCR_DTR | MCR_RTS, DMSET); - com->ftl_max = com->ftl_init; - com->poll = com->no_irq; - ++com->wopeners; - error = comparam(tp, &tp->t_termios); - --com->wopeners; - if (error != 0) - goto out; - /* - * XXX we should goto open_top if comparam() slept. - */ - ttsetwater(tp); - iobase = com->iobase; - if (com->hasfifo) { - /* - * (Re)enable and drain fifos. - * - * Certain SMC chips cause problems if the fifos - * are enabled while input is ready. Turn off the - * fifo if necessary to clear the input. We test - * the input ready bit after enabling the fifos - * since we've already enabled them in comparam() - * and to handle races between enabling and fresh - * input. - */ - while (TRUE) { - outb(iobase + com_fifo, - FIFO_RCV_RST | FIFO_XMT_RST - | FIFO_ENABLE | com->ftl); - DELAY(100); - if (!(inb(com->line_status_port) & LSR_RXRDY)) - break; - outb(iobase + com_fifo, 0); - DELAY(100); - (void) inb(com->data_port); - } - } - - disable_intr(); - (void) inb(com->line_status_port); - (void) inb(com->data_port); - com->prev_modem_status = - com->last_modem_status = inb(com->modem_status_port); - outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS - | IER_EMSC); - enable_intr(); - /* - * Handle initial DCD. Callout devices get a fake initial - * DCD (trapdoor DCD). If we are callout, then any sleeping - * callin opens get woken up and resume sleeping on "siobi" - * instead of "siodcd". - */ - if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK) - (*linesw[tp->t_line].l_modem)(tp, 1); - } - /* - * Wait for DCD if necessary. - */ - if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) - && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { - ++com->wopeners; - error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0); - --com->wopeners; - if (error != 0) - goto out; - goto open_top; - } - error = (*linesw[tp->t_line].l_open)(dev, tp); - disc_optim(tp, &(tp->t_termios), com); - if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) - com->active_out = TRUE; -out: - splx(s); - if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0) - comhardclose(com); - return (error); -} - -/*ARGSUSED*/ -int -sioclose(dev, flag, mode, p) - dev_t dev; - int flag; - int mode; - struct proc *p; -{ - struct com_s *com; - int mynor; - int s; - struct tty *tp; - - mynor = minor(dev); - if (mynor & CONTROL_MASK) - return (0); - com = com_addr(MINOR_TO_UNIT(mynor)); - tp = com->tp; - s = spltty(); - (*linesw[tp->t_line].l_close)(tp, flag); - disc_optim(tp, &(tp->t_termios), com); - siostop(tp, FREAD | FWRITE); - comhardclose(com); - ttyclose(tp); - splx(s); - return (0); -} - -static void -comhardclose(com) - struct com_s *com; -{ - Port_t iobase; - int s; - struct tty *tp; - int unit; - - unit = com->unit; - iobase = com->iobase; - s = spltty(); - com->poll = FALSE; - com->do_timestamp = 0; - outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); -#ifdef KGDB - /* do not disable interrupts or hang up if debugging */ - if (kgdb_dev != makedev(commajor, unit)) -#endif - { - outb(iobase + com_ier, 0); - tp = com->tp; - if (tp->t_cflag & HUPCL - /* - * XXX we will miss any carrier drop between here and the - * next open. Perhaps we should watch DCD even when the - * port is closed; it is not sufficient to check it at - * the next open because it might go up and down while - * we're not watching. - */ - || !com->active_out - && !(com->prev_modem_status & MSR_DCD) - && !(com->it_in.c_cflag & CLOCAL) - || !(tp->t_state & TS_ISOPEN)) { - commctl(com, MCR_RTS, DMSET); - if (com->dtr_wait != 0) { - timeout(siodtrwakeup, com, com->dtr_wait); - com->state |= CS_DTR_OFF; - } - } - } - com->active_out = FALSE; - wakeup(&com->active_out); - wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ - if (!(com->state & CS_DTR_OFF) - && !(unit == comconsole && (COMCONSOLE || boothowto & RB_SERIAL))) - kdc_sio[unit].kdc_state = DC_IDLE; - splx(s); -} - -int -sioread(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; -{ - int mynor; - struct tty *tp; - - mynor = minor(dev); - if (mynor & CONTROL_MASK) - return (ENODEV); - tp = com_addr(MINOR_TO_UNIT(mynor))->tp; - return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); -} - -int -siowrite(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; -{ - int mynor; - struct tty *tp; - int unit; - - mynor = minor(dev); - if (mynor & CONTROL_MASK) - return (ENODEV); - - unit = MINOR_TO_UNIT(mynor); - tp = com_addr(unit)->tp; - /* - * (XXX) We disallow virtual consoles if the physical console is - * a serial port. This is in case there is a display attached that - * is not the console. In that situation we don't need/want the X - * server taking over the console. - */ - if (constty && unit == comconsole - && (COMCONSOLE || boothowto & RB_SERIAL)) - constty = NULL; - return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); -} - -static void -siodtrwakeup(chan) - void *chan; -{ - struct com_s *com; - - com = (struct com_s *)chan; - com->state &= ~CS_DTR_OFF; - if (!(com->unit == comconsole && (COMCONSOLE || boothowto & RB_SERIAL))) - kdc_sio[com->unit].kdc_state = DC_IDLE; - wakeup(&com->dtr_wait); -} - -/* Interrupt routine for timekeeping purposes */ -void -siointrts(unit) - int unit; -{ - /* - * XXX microtime() reenables CPU interrupts. We can't afford to - * be interrupted and don't want to slow down microtime(), so lock - * out interrupts in another way. - */ - outb(IO_ICU1 + 1, 0xff); - microtime(&intr_timestamp); - disable_intr(); - outb(IO_ICU1 + 1, imen); - - siointr(unit); -} - -void -siointr(unit) - int unit; -{ -#ifndef COM_MULTIPORT - siointr1(com_addr(unit)); -#else /* COM_MULTIPORT */ - struct com_s *com; - bool_t possibly_more_intrs; - - /* - * Loop until there is no activity on any port. This is necessary - * to get an interrupt edge more than to avoid another interrupt. - * If the IRQ signal is just an OR of the IRQ signals from several - * devices, then the edge from one may be lost because another is - * on. - */ - do { - possibly_more_intrs = FALSE; - for (unit = 0; unit < NSIO; ++unit) { - com = com_addr(unit); - if (com != NULL - && (inb(com->int_id_port) & IIR_IMASK) - != IIR_NOPEND) { - siointr1(com); - possibly_more_intrs = TRUE; - } - } - } while (possibly_more_intrs); -#endif /* COM_MULTIPORT */ -} - -static void -siointr1(com) - struct com_s *com; -{ - u_char line_status; - u_char modem_status; - u_char *ioptr; - u_char recv_data; - - if (com->do_timestamp) - /* XXX a little bloat here... */ - com->timestamp = intr_timestamp; - while (TRUE) { - line_status = inb(com->line_status_port); - - /* input event? (check first to help avoid overruns) */ - while (line_status & LSR_RCV_MASK) { - /* break/unnattached error bits or real input? */ - if (!(line_status & LSR_RXRDY)) - recv_data = 0; - else - recv_data = inb(com->data_port); - if (line_status & (LSR_PE|LSR_FE|LSR_BI)) { -#ifdef DDB -#ifdef BREAK_TO_DEBUGGER - if ( (line_status & LSR_BI) - && (COMCONSOLE || boothowto & RB_SERIAL) - && com->unit == comconsole) { - Debugger("serial console break"); - goto cont; - } -#endif -#endif - /* - Don't store PE if IGNPAR and BI if IGNBRK, - this hack allows "raw" tty optimization - works even if IGN* is set. - */ - if ( com->tp == NULL - || !(com->tp->t_state & TS_ISOPEN) - || (line_status & (LSR_PE|LSR_FE)) - && (com->tp->t_iflag & IGNPAR) - || (line_status & LSR_BI) - && (com->tp->t_iflag & IGNBRK)) - goto cont; - if ( (line_status & (LSR_PE|LSR_FE)) - && (com->tp->t_state & TS_CAN_BYPASS_L_RINT) - && ((line_status & LSR_FE) - || (line_status & LSR_PE) - && (com->tp->t_iflag & INPCK))) - recv_data = 0; - } - ++com->bytes_in; - if (com->hotchar != 0 && recv_data == com->hotchar) - setsofttty(); -#ifdef KGDB - /* trap into kgdb? (XXX - needs testing and optim) */ - if (recv_data == FRAME_END - && ( com->tp == NULL - || !(com->tp->t_state & TS_ISOPEN)) - && kgdb_dev == makedev(commajor, unit)) { - kgdb_connect(0); - continue; - } -#endif /* KGDB */ - ioptr = com->iptr; - if (ioptr >= com->ibufend) - CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); - else { - ++com_events; -#if 0 /* for testing input latency vs efficiency */ -if (com->iptr - com->ibuf == 8) - setsofttty(); -#endif - ioptr[0] = recv_data; - ioptr[CE_INPUT_OFFSET] = line_status; - com->iptr = ++ioptr; - if (ioptr == com->ihighwater - && com->state & CS_RTS_IFLOW) - outb(com->modem_ctl_port, - com->mcr_image &= ~MCR_RTS); - if (line_status & LSR_OE) - CE_RECORD(com, CE_OVERRUN); - } - cont: - /* - * "& 0x7F" is to avoid the gcc-1.40 generating a slow - * jump from the top of the loop to here - */ - line_status = inb(com->line_status_port) & 0x7F; - } - - /* modem status change? (always check before doing output) */ - modem_status = inb(com->modem_status_port); - if (modem_status != com->last_modem_status) { - /* - * Schedule high level to handle DCD changes. Note - * that we don't use the delta bits anywhere. Some - * UARTs mess them up, and it's easy to remember the - * previous bits and calculate the delta. - */ - com->last_modem_status = modem_status; - if (!(com->state & CS_CHECKMSR)) { - com_events += LOTS_OF_EVENTS; - com->state |= CS_CHECKMSR; - setsofttty(); - } - - /* handle CTS change immediately for crisp flow ctl */ - if (com->state & CS_CTS_OFLOW) { - if (modem_status & MSR_CTS) - com->state |= CS_ODEVREADY; - else - com->state &= ~CS_ODEVREADY; - } - } - - /* output queued and everything ready? */ - if (line_status & LSR_TXRDY - && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) { - ioptr = com->optr; - if (com->tx_fifo_size > 1) { - u_int ocount; - - ocount = com->obufend - ioptr; - if (ocount > com->tx_fifo_size) - ocount = com->tx_fifo_size; - com->bytes_out += ocount; - do - outb(com->data_port, *ioptr++); - while (--ocount != 0); - } else { - outb(com->data_port, *ioptr++); - ++com->bytes_out; - } - com->optr = ioptr; - if (ioptr >= com->obufend) { - /* output just completed */ - com_events += LOTS_OF_EVENTS; - com->state ^= (CS_ODONE | CS_BUSY); - setsofttty(); /* handle at high level ASAP */ - } - } - - /* finished? */ -#ifndef COM_MULTIPORT - if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) -#endif /* COM_MULTIPORT */ - return; - } -} - -static int -tiocm_xxx2mcr(tiocm_xxx) - int tiocm_xxx; -{ - int mcr; - - mcr = 0; - if (tiocm_xxx & TIOCM_DTR) - mcr |= MCR_DTR; - if (tiocm_xxx & TIOCM_RTS) - mcr |= MCR_RTS; - return (mcr); -} - -int -sioioctl(dev, cmd, data, flag, p) - dev_t dev; - int cmd; - caddr_t data; - int flag; - struct proc *p; -{ - struct com_s *com; - int error; - Port_t iobase; - int mcr; - int msr; - int mynor; - int s; - int tiocm_xxx; - struct tty *tp; -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) - int oldcmd; - struct termios term; -#endif - - mynor = minor(dev); - com = com_addr(MINOR_TO_UNIT(mynor)); - iobase = com->iobase; - if (mynor & CONTROL_MASK) { - struct termios *ct; - - switch (mynor & CONTROL_MASK) { - case CONTROL_INIT_STATE: - ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; - break; - case CONTROL_LOCK_STATE: - ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; - break; - default: - return (ENODEV); /* /dev/nodev */ - } - switch (cmd) { - case TIOCSETA: - error = suser(p->p_ucred, &p->p_acflag); - if (error != 0) - return (error); - *ct = *(struct termios *)data; - return (0); - case TIOCGETA: - *(struct termios *)data = *ct; - return (0); - case TIOCGETD: - *(int *)data = TTYDISC; - return (0); - case TIOCGWINSZ: - bzero(data, sizeof(struct winsize)); - return (0); -#ifdef DSI_SOFT_MODEM - /* - * Download micro-code to Digicom modem. - */ - case TIOCDSIMICROCODE: - { - u_long l; - u_char *p,*pi; - - pi = (u_char*)(*(caddr_t*)data); - error = copyin(pi,&l,sizeof l); - if(error) - {return error;}; - pi += sizeof l; - - p = malloc(l,M_TEMP,M_NOWAIT); - if(!p) - {return ENOBUFS;} - error = copyin(pi,p,l); - if(error) - {free(p,M_TEMP); return error;}; - if(error = LoadSoftModem( - MINOR_TO_UNIT(mynor),iobase,l,p)) - {free(p,M_TEMP); return error;} - free(p,M_TEMP); - return(0); - } -#endif /* DSI_SOFT_MODEM */ - default: - return (ENOTTY); - } - } - tp = com->tp; -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) - term = tp->t_termios; - oldcmd = cmd; - error = ttsetcompat(tp, &cmd, data, &term); - if (error != 0) - return (error); - if (cmd != oldcmd) - data = (caddr_t)&term; -#endif - if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { - int cc; - struct termios *dt = (struct termios *)data; - struct termios *lt = mynor & CALLOUT_MASK - ? &com->lt_out : &com->lt_in; - - dt->c_iflag = (tp->t_iflag & lt->c_iflag) - | (dt->c_iflag & ~lt->c_iflag); - dt->c_oflag = (tp->t_oflag & lt->c_oflag) - | (dt->c_oflag & ~lt->c_oflag); - dt->c_cflag = (tp->t_cflag & lt->c_cflag) - | (dt->c_cflag & ~lt->c_cflag); - dt->c_lflag = (tp->t_lflag & lt->c_lflag) - | (dt->c_lflag & ~lt->c_lflag); - for (cc = 0; cc < NCCS; ++cc) - if (lt->c_cc[cc] != 0) - dt->c_cc[cc] = tp->t_cc[cc]; - if (lt->c_ispeed != 0) - dt->c_ispeed = tp->t_ispeed; - if (lt->c_ospeed != 0) - dt->c_ospeed = tp->t_ospeed; - } - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (error >= 0) - return (error); - s = spltty(); - error = ttioctl(tp, cmd, data, flag); - disc_optim(tp, &(tp->t_termios), com); - if (error >= 0) { - splx(s); - return (error); - } - switch (cmd) { - case TIOCSBRK: - outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); - break; - case TIOCCBRK: - outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); - break; - case TIOCSDTR: - commctl(com, MCR_DTR, DMBIS); - break; - case TIOCCDTR: - commctl(com, MCR_DTR, DMBIC); - break; - case TIOCMSET: - commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET); - break; - case TIOCMBIS: - commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS); - break; - case TIOCMBIC: - commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC); - break; - case TIOCMGET: - tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */ - mcr = com->mcr_image; - if (mcr & MCR_DTR) - tiocm_xxx |= TIOCM_DTR; - if (mcr & MCR_RTS) - tiocm_xxx |= TIOCM_RTS; - msr = com->prev_modem_status; - if (msr & MSR_CTS) - tiocm_xxx |= TIOCM_CTS; - if (msr & MSR_DCD) - tiocm_xxx |= TIOCM_CD; - if (msr & MSR_DSR) - tiocm_xxx |= TIOCM_DSR; - /* - * XXX - MSR_RI is naturally volatile, and we make MSR_TERI - * more volatile by reading the modem status a lot. Perhaps - * we should latch both bits until the status is read here. - */ - if (msr & (MSR_RI | MSR_TERI)) - tiocm_xxx |= TIOCM_RI; - *(int *)data = tiocm_xxx; - break; - case TIOCMSDTRWAIT: - /* must be root since the wait applies to following logins */ - error = suser(p->p_ucred, &p->p_acflag); - if (error != 0) { - splx(s); - return (error); - } - com->dtr_wait = *(int *)data * hz / 100; - break; - case TIOCMGDTRWAIT: - *(int *)data = com->dtr_wait * 100 / hz; - break; - case TIOCTIMESTAMP: - com->do_timestamp = TRUE; - *(struct timeval *)data = com->timestamp; - break; - default: - splx(s); - return (ENOTTY); - } - splx(s); - return (0); -} - -/* cancel pending output */ -static void -comflush(com) - struct com_s *com; -{ - disable_intr(); - if (com->state & CS_ODONE) - com_events -= LOTS_OF_EVENTS; - com->state &= ~(CS_ODONE | CS_BUSY); - enable_intr(); - com->tp->t_state &= ~TS_BUSY; -} - -void -siopoll() -{ - int unit; - - if (com_events == 0) - return; -repeat: - for (unit = 0; unit < NSIO; ++unit) { - u_char *buf; - struct com_s *com; - u_char *ibuf; - int incc; - struct tty *tp; - - com = com_addr(unit); - if (com == NULL) - continue; - tp = com->tp; - if (tp == NULL) { - /* - * XXX forget any events related to closed devices - * (actually never opened devices) so that we don't - * loop. - */ - disable_intr(); - incc = com->iptr - com->ibuf; - com->iptr = com->ibuf; - if (com->state & CS_CHECKMSR) { - incc += LOTS_OF_EVENTS; - com->state &= ~CS_CHECKMSR; - } - com_events -= incc; - enable_intr(); - if (incc != 0) - log(LOG_DEBUG, - "sio%d: %d events for device with no tp\n", - unit, incc); - continue; - } - - /* switch the role of the low-level input buffers */ - if (com->iptr == (ibuf = com->ibuf)) { - buf = NULL; /* not used, but compiler can't tell */ - incc = 0; - } else { - buf = ibuf; - disable_intr(); - incc = com->iptr - buf; - com_events -= incc; - if (ibuf == com->ibuf1) - ibuf = com->ibuf2; - else - ibuf = com->ibuf1; - com->ibufend = ibuf + RS_IBUFSIZE; - com->ihighwater = ibuf + RS_IHIGHWATER; - com->iptr = ibuf; - - /* - * There is now room for another low-level buffer full - * of input, so enable RTS if it is now disabled and - * there is room in the high-level buffer. - */ - /* - * XXX this used not to look at CS_RTS_IFLOW. The - * change is to allow full control of MCR_RTS via - * ioctls after turning CS_RTS_IFLOW off. Check - * for races. We shouldn't allow the ioctls while - * CS_RTS_IFLOW is on. - */ - if ((com->state & CS_RTS_IFLOW) - && !(com->mcr_image & MCR_RTS) - && !(tp->t_state & TS_TBLOCK)) - outb(com->modem_ctl_port, - com->mcr_image |= MCR_RTS); - enable_intr(); - com->ibuf = ibuf; - } - - if (com->state & CS_CHECKMSR) { - u_char delta_modem_status; - - disable_intr(); - delta_modem_status = com->last_modem_status - ^ com->prev_modem_status; - com->prev_modem_status = com->last_modem_status; - com_events -= LOTS_OF_EVENTS; - com->state &= ~CS_CHECKMSR; - enable_intr(); - if (delta_modem_status & MSR_DCD) - (*linesw[tp->t_line].l_modem) - (tp, com->prev_modem_status & MSR_DCD); - } - if (com->state & CS_ODONE) { - comflush(com); - (*linesw[tp->t_line].l_start)(tp); - } - if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) - continue; - /* - * XXX only do this when we bypass ttyinput. - */ - if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER - && (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF) - && !(tp->t_state & TS_TBLOCK) - /* - * XXX - need flow control for all line disciplines. - * Only have it in standard one now. - */ - && linesw[tp->t_line].l_rint == ttyinput) { - int putc_status = FALSE; - - if ((tp->t_iflag & IXOFF - && tp->t_cc[VSTOP] != _POSIX_VDISABLE - && (putc_status = putc(tp->t_cc[VSTOP], - &tp->t_outq)) == 0) - || com->state & CS_RTS_IFLOW) { - tp->t_state |= TS_TBLOCK; - ttstart(tp); - if (putc_status != 0) - /* Try again later. */ - tp->t_state &= ~TS_TBLOCK; - } - } - /* - * Avoid the grotesquely inefficient lineswitch routine - * (ttyinput) in "raw" mode. It usually takes about 450 - * instructions (that's without canonical processing or echo!). - * slinput is reasonably fast (usually 40 instructions plus - * call overhead). - */ - if (tp->t_state & TS_CAN_BYPASS_L_RINT) { - tk_nin += incc; - tk_rawcc += incc; - tp->t_rawcc += incc; - com->delta_error_counts[CE_TTY_BUF_OVERFLOW] - += b_to_q((char *)buf, incc, &tp->t_rawq); - ttwakeup(tp); - if (tp->t_state & TS_TTSTOP - && (tp->t_iflag & IXANY - || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { - tp->t_state &= ~TS_TTSTOP; - tp->t_lflag &= ~FLUSHO; - ttstart(tp); - } - } else { - do { - u_char line_status; - int recv_data; - - line_status = (u_char) buf[CE_INPUT_OFFSET]; - recv_data = (u_char) *buf++; - if (line_status - & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { - if (line_status & LSR_BI) - recv_data |= TTY_BI; - if (line_status & LSR_FE) - recv_data |= TTY_FE; - if (line_status & LSR_OE) - recv_data |= TTY_OE; - if (line_status & LSR_PE) - recv_data |= TTY_PE; - } - (*linesw[tp->t_line].l_rint)(recv_data, tp); - } while (--incc > 0); - } - if (com_events == 0) - break; - } - if (com_events >= LOTS_OF_EVENTS) - goto repeat; -} - -static int -comparam(tp, t) - struct tty *tp; - struct termios *t; -{ - u_int cfcr; - int cflag; - struct com_s *com; - int divisor; - int error; - Port_t iobase; - int s; - int unit; - - /* check requested parameters */ - divisor = ttspeedtab(t->c_ospeed, comspeedtab); - if (t->c_ispeed == 0) - t->c_ispeed = t->c_ospeed; - if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed) - return (EINVAL); - - /* parameters are OK, convert them to the com struct and the device */ - unit = DEV_TO_UNIT(tp->t_dev); - com = com_addr(unit); - iobase = com->iobase; - s = spltty(); - if (divisor == 0) - commctl(com, MCR_DTR, DMBIC); /* hang up line */ - else - commctl(com, MCR_DTR, DMBIS); - cflag = t->c_cflag; - switch (cflag & CSIZE) { - case CS5: - cfcr = CFCR_5BITS; - break; - case CS6: - cfcr = CFCR_6BITS; - break; - case CS7: - cfcr = CFCR_7BITS; - break; - default: - cfcr = CFCR_8BITS; - break; - } - if (cflag & PARENB) { - cfcr |= CFCR_PENAB; - if (!(cflag & PARODD)) - cfcr |= CFCR_PEVEN; - } - if (cflag & CSTOPB) - cfcr |= CFCR_STOPB; - - if (com->hasfifo) { - /* - * Use a fifo trigger level low enough so that the input - * latency from the fifo is less than about 16 msec and - * the total latency is less than about 30 msec. These - * latencies are reasonable for humans. Serial comms - * protocols shouldn't expect anything better since modem - * latencies are larger. - */ - com->ftl = t->c_ospeed <= 4800 - ? FIFO_TRIGGER_1 : FIFO_TRIGGER_14; - if (com->ftl > com->ftl_max) - com->ftl = com->ftl_max; - outb(iobase + com_fifo, FIFO_ENABLE | com->ftl); - } - - /* - * Some UARTs lock up if the divisor latch registers are selected - * while the UART is doing output (they refuse to transmit anything - * more until given a hard reset). Fix this by stopping filling - * the device buffers and waiting for them to drain. Reading the - * line status port outside of siointr1() might lose some receiver - * error bits, but that is acceptable here. - */ - disable_intr(); -retry: - com->state &= ~CS_TTGO; - enable_intr(); - while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) - != (LSR_TSRE | LSR_TXRDY)) { - error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH, - "siotx", hz / 100); - if (error != 0 && error != EAGAIN) { - if (!(tp->t_state & TS_TTSTOP)) { - disable_intr(); - com->state |= CS_TTGO; - enable_intr(); - } - splx(s); - return (error); - } - } - - disable_intr(); /* very important while com_data is hidden */ - - /* - * XXX - clearing CS_TTGO is not sufficient to stop further output, - * because siopoll() calls comstart() which usually sets it again - * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be - * sufficient, for similar reasons. - */ - if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) - != (LSR_TSRE | LSR_TXRDY)) - goto retry; - - if (divisor != 0) { - outb(iobase + com_cfcr, cfcr | CFCR_DLAB); - outb(iobase + com_dlbl, divisor & 0xFF); - outb(iobase + com_dlbh, (u_int) divisor >> 8); - } - outb(iobase + com_cfcr, com->cfcr_image = cfcr); - if (!(tp->t_state & TS_TTSTOP)) - com->state |= CS_TTGO; - if (cflag & CRTS_IFLOW) - com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */ - else - com->state &= ~CS_RTS_IFLOW; - - /* - * Set up state to handle output flow control. - * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? - * Now has 10+ msec latency, while CTS flow has 50- usec latency. - */ - com->state &= ~CS_CTS_OFLOW; - com->state |= CS_ODEVREADY; - if (cflag & CCTS_OFLOW) { - com->state |= CS_CTS_OFLOW; - if (!(com->last_modem_status & MSR_CTS)) - com->state &= ~CS_ODEVREADY; - } - disc_optim(tp, t, com); - /* - * Recover from fiddling with CS_TTGO. We used to call siointr1() - * unconditionally, but that defeated the careful discarding of - * stale input in sioopen(). - */ - if (com->state >= (CS_BUSY | CS_TTGO)) - siointr1(com); - - enable_intr(); - splx(s); - return (0); -} - -static void -comstart(tp) - struct tty *tp; -{ - struct com_s *com; - int s; - int unit; - - unit = DEV_TO_UNIT(tp->t_dev); - com = com_addr(unit); - s = spltty(); - disable_intr(); - if (tp->t_state & TS_TTSTOP) - com->state &= ~CS_TTGO; - else - com->state |= CS_TTGO; - if (tp->t_state & TS_TBLOCK) { - if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) - outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); - } else { - /* - * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it - * appropriately in comparam() if RTS-flow is being changed. - * Check for races. - */ - if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) - outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); - } - enable_intr(); - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) - goto out; -#if 0 /* XXX TK2.0 */ - if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel) - ttwwakeup(tp); -#else - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state & TS_ASLEEP) { - tp->t_state &= ~TS_ASLEEP; - wakeup(TSA_OLOWAT(tp)); - } - selwakeup(&tp->t_wsel); - } -#endif - if (tp->t_state & TS_BUSY) { - disable_intr(); - siointr1(com); - enable_intr(); - } else if (tp->t_outq.c_cc != 0) { - u_int ocount; - - tp->t_state |= TS_BUSY; - ocount = q_to_b(&tp->t_outq, com->obuf, sizeof com->obuf); - disable_intr(); - com->obufend = (com->optr = com->obuf) + ocount; - com->state |= CS_BUSY; - siointr1(com); /* fake interrupt to start output */ - enable_intr(); - } -out: - splx(s); -} - -void -siostop(tp, rw) - struct tty *tp; - int rw; -{ - struct com_s *com; - - com = com_addr(DEV_TO_UNIT(tp->t_dev)); - if (rw & FWRITE) - comflush(com); - disable_intr(); - if (rw & FREAD) { - com_events -= (com->iptr - com->ibuf); - com->iptr = com->ibuf; - } - if (tp->t_state & TS_TTSTOP) - com->state &= ~CS_TTGO; - else - com->state |= CS_TTGO; - enable_intr(); -} - -struct tty * -siodevtotty(dev) - dev_t dev; -{ - int mynor; - int unit; - - mynor = minor(dev); - if (mynor & CONTROL_MASK) - return (NULL); - unit = MINOR_TO_UNIT(mynor); - if ((u_int) unit >= NSIO) - return (NULL); - return (&sio_tty[unit]); -} - -static void -commctl(com, bits, how) - struct com_s *com; - int bits; - int how; -{ - disable_intr(); - switch (how) { - case DMSET: - outb(com->modem_ctl_port, - com->mcr_image = bits | (com->mcr_image & MCR_IENABLE)); - break; - case DMBIS: - outb(com->modem_ctl_port, com->mcr_image |= bits); - break; - case DMBIC: - outb(com->modem_ctl_port, com->mcr_image &= ~bits); - break; - } - enable_intr(); -} - -static void -comwakeup(chan) - void *chan; -{ - struct com_s *com; - static int log_countdown = 1; - int unit; - - timeout(comwakeup, (caddr_t)NULL, hz > 200 ? hz / 200 : 1); - - if (com_events != 0) { - int s; - - s = splsofttty(); - siopoll(); - splx(s); - } - - /* - * Recover from lost output interrupts. - * Poll any lines that don't use interrupts. - */ - for (unit = 0; unit < NSIO; ++unit) { - com = com_addr(unit); - if (com != NULL - && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { - disable_intr(); - siointr1(com); - enable_intr(); - } - } - - /* - * Check for and log errors, but not too often. - */ - if (--log_countdown > 0) - return; - log_countdown = hz > 200 ? 200 : hz; - for (unit = 0; unit < NSIO; ++unit) { - int errnum; - - com = com_addr(unit); - if (com == NULL) - continue; - for (errnum = 0; errnum < CE_NTYPES; ++errnum) { - u_int delta; - u_long total; - - disable_intr(); - delta = com->delta_error_counts[errnum]; - com->delta_error_counts[errnum] = 0; - enable_intr(); - if (delta == 0) - continue; - total = com->error_counts[errnum] += delta; - log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n", - unit, delta, error_desc[errnum], - delta == 1 ? "" : "s", total); -#if 0 - /* - * XXX if we resurrect this then we should move - * the dropping of the ftl to somewhere with less - * latency. - */ - if (errnum == CE_OVERRUN && com->hasfifo - && com->ftl > FIFO_TRIGGER_1) { - static u_char ftl_in_bytes[] = - { 1, 4, 8, 14, }; - - com->ftl_init = FIFO_TRIGGER_8; -#define FIFO_TRIGGER_DELTA FIFO_TRIGGER_4 - com->ftl_max = - com->ftl -= FIFO_TRIGGER_DELTA; - outb(com->iobase + com_fifo, - FIFO_ENABLE | com->ftl); - log(LOG_DEBUG, - "sio%d: reduced fifo trigger level to %d\n", - unit, - ftl_in_bytes[com->ftl - / FIFO_TRIGGER_DELTA]); - } -#endif - } - } -} - -static void -disc_optim(tp, t, com) - struct tty *tp; - struct termios *t; - struct com_s *com; -{ - - if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP - | IXOFF | IXON)) - && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) - && (!(t->c_iflag & PARMRK) || - (t->c_iflag & (IGNPAR|IGNBRK)) == (IGNPAR|IGNBRK)) - && !(t->c_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG - | PENDIN)) - && linesw[tp->t_line].l_rint == ttyinput) - tp->t_state |= TS_CAN_BYPASS_L_RINT; - else - tp->t_state &= ~TS_CAN_BYPASS_L_RINT; - /* - * Prepare to reduce input latency for packet - * discplines with a end of packet character. - */ - if (tp->t_line == SLIPDISC) - com->hotchar = 0xc0; - else if (tp->t_line == PPPDISC) - com->hotchar = 0x7e; - else - com->hotchar = 0; -} - -/* - * Following are all routines needed for SIO to act as console - */ -#include - -struct siocnstate { - u_char dlbl; - u_char dlbh; - u_char ier; - u_char cfcr; - u_char mcr; -}; - -static Port_t siocniobase; - -static void siocnclose __P((struct siocnstate *sp)); -static void siocnopen __P((struct siocnstate *sp)); -static void siocntxwait __P((void)); - -static void -siocntxwait() -{ - int timo; - - /* - * Wait for any pending transmission to finish. Required to avoid - * the UART lockup bug when the speed is changed, and for normal - * transmits. - */ - timo = 100000; - while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY)) - != (LSR_TSRE | LSR_TXRDY) && --timo != 0) - ; -} - -static void -siocnopen(sp) - struct siocnstate *sp; -{ - int divisor; - Port_t iobase; - - /* - * Save all the device control registers except the fifo register - * and set our default ones (cs8 -parenb speed=comdefaultrate). - * We can't save the fifo register since it is read-only. - */ - iobase = siocniobase; - sp->ier = inb(iobase + com_ier); - outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */ - siocntxwait(); - sp->cfcr = inb(iobase + com_cfcr); - outb(iobase + com_cfcr, CFCR_DLAB); - sp->dlbl = inb(iobase + com_dlbl); - sp->dlbh = inb(iobase + com_dlbh); - divisor = ttspeedtab(comdefaultrate, comspeedtab); - outb(iobase + com_dlbl, divisor & 0xFF); - outb(iobase + com_dlbh, (u_int) divisor >> 8); - outb(iobase + com_cfcr, CFCR_8BITS); - sp->mcr = inb(iobase + com_mcr); - /* - * We don't want interrupts, but must be careful not to "disable" - * them by clearing the MCR_IENABLE bit, since that might cause - * an interrupt by floating the IRQ line. - */ - outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS); -} - -static void -siocnclose(sp) - struct siocnstate *sp; -{ - Port_t iobase; - - /* - * Restore the device control registers. - */ - siocntxwait(); - iobase = siocniobase; - outb(iobase + com_cfcr, CFCR_DLAB); - outb(iobase + com_dlbl, sp->dlbl); - outb(iobase + com_dlbh, sp->dlbh); - outb(iobase + com_cfcr, sp->cfcr); - /* - * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them. - */ - outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS); - outb(iobase + com_ier, sp->ier); -} - -void -siocnprobe(cp) - struct consdev *cp; -{ - int unit; - - /* locate the major number */ - /* XXX - should be elsewhere since KGDB uses it */ - for (commajor = 0; commajor < nchrdev; commajor++) - if (cdevsw[commajor].d_open == sioopen) - break; - - /* XXX: ick */ - unit = DEV_TO_UNIT(CONUNIT); - siocniobase = CONADDR; - - /* make sure hardware exists? XXX */ - - /* initialize required fields */ - cp->cn_dev = makedev(commajor, unit); - - if (COMCONSOLE || boothowto & RB_SERIAL) - cp->cn_pri = CN_REMOTE; /* Force a serial port console */ - else - cp->cn_pri = CN_NORMAL; - -} - -void -siocninit(cp) - struct consdev *cp; -{ - /* - * XXX can delete more comconsole stuff now that i/o routines are - * fairly reentrant. - */ - comconsole = DEV_TO_UNIT(cp->cn_dev); -} - -int -siocncheckc(dev) - dev_t dev; -{ - int c; - Port_t iobase; - int s; - struct siocnstate sp; - - iobase = siocniobase; - s = spltty(); - siocnopen(&sp); - if (inb(iobase + com_lsr) & LSR_RXRDY) - c = inb(iobase + com_data); - else - c = 0; - siocnclose(&sp); - splx(s); - return (c); -} - - -int -siocngetc(dev) - dev_t dev; -{ - int c; - Port_t iobase; - int s; - struct siocnstate sp; - - iobase = siocniobase; - s = spltty(); - siocnopen(&sp); - while (!(inb(iobase + com_lsr) & LSR_RXRDY)) - ; - c = inb(iobase + com_data); - siocnclose(&sp); - splx(s); - return (c); -} - -void -siocnputc(dev, c) - dev_t dev; - int c; -{ - int s; - struct siocnstate sp; - - s = spltty(); - siocnopen(&sp); - siocntxwait(); - outb(siocniobase + com_data, c); - siocnclose(&sp); - splx(s); -} - -#ifdef DSI_SOFT_MODEM -/* - * The magic code to download microcode to a "Connection 14.4+Fax" - * modem from Digicom Systems Inc. Very magic. - */ - -#define DSI_ERROR(str) { ptr = str; goto error; } -static int -LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr) -{ - int int_c,int_k; - int data_0188, data_0187; - - /* - * First see if it is a DSI SoftModem - */ - if(!((inb(base_io+7) ^ inb(base_io+7) & 0x80))) - return ENODEV; - - data_0188 = inb(base_io+4); - data_0187 = inb(base_io+3); - outb(base_io+3,0x80); - outb(base_io+4,0x0C); - outb(base_io+0,0x31); - outb(base_io+1,0x8C); - outb(base_io+7,0x10); - outb(base_io+7,0x19); - - if(0x18 != (inb(base_io+7) & 0x1A)) - DSI_ERROR("dsp bus not granted"); - - if(0x01 != (inb(base_io+7) & 0x01)) { - outb(base_io+7,0x18); - outb(base_io+7,0x19); - if(0x01 != (inb(base_io+7) & 0x01)) - DSI_ERROR("program mem not granted"); - } - - int_c = 0; - - while(1) { - if(int_c >= 7 || size <= 0x1800) - break; - - for(int_k = 0 ; int_k < 0x800; int_k++) { - outb(base_io+0,*ptr++); - outb(base_io+1,*ptr++); - outb(base_io+2,*ptr++); - } - - size -= 0x1800; - int_c++; - } - - if(size > 0x1800) { - outb(base_io+7,0x18); - outb(base_io+7,0x19); - if(0x00 != (inb(base_io+7) & 0x01)) - DSI_ERROR("program data not granted"); - - for(int_k = 0 ; int_k < 0x800; int_k++) { - outb(base_io+1,*ptr++); - outb(base_io+2,0); - outb(base_io+1,*ptr++); - outb(base_io+2,*ptr++); - } - - size -= 0x1800; - - while(size > 0x1800) { - for(int_k = 0 ; int_k < 0xC00; int_k++) { - outb(base_io+1,*ptr++); - outb(base_io+2,*ptr++); - } - size -= 0x1800; - } - - if(size < 0x1800) { - for(int_k=0;int_k 0) { - if(int_c == 7) { - outb(base_io+7,0x18); - outb(base_io+7,0x19); - if(0x00 != (inb(base_io+7) & 0x01)) - DSI_ERROR("program data not granted"); - for(int_k = 0 ; int_k < size/3; int_k++) { - outb(base_io+1,*ptr++); - outb(base_io+2,0); - outb(base_io+1,*ptr++); - outb(base_io+2,*ptr++); - } - } else { - for(int_k = 0 ; int_k < size/3; int_k++) { - outb(base_io+0,*ptr++); - outb(base_io+1,*ptr++); - outb(base_io+2,*ptr++); - } - } - } - outb(base_io+7,0x11); - outb(base_io+7,3); - - outb(base_io+4,data_0188 & 0xfb); - - outb(base_io+3,data_0187); - - return 0; -error: - printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",ptr); - outb(base_io+7,0x00); \ - outb(base_io+3,data_0187); \ - outb(base_io+4,data_0188); \ - return EIO; -} -#endif /* DSI_SOFT_MODEM */ - -#endif /* NSIO > 0 */