summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /sys/dev/ic
initial import of NetBSD tree
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/ad1848reg.h198
-rw-r--r--sys/dev/ic/aic7xxx.c2227
-rw-r--r--sys/dev/ic/aic7xxxvar.h168
-rw-r--r--sys/dev/ic/am7930reg.h153
-rw-r--r--sys/dev/ic/am7990.c1218
-rw-r--r--sys/dev/ic/am7990reg.h178
-rw-r--r--sys/dev/ic/am7990var.h63
-rw-r--r--sys/dev/ic/cd1400reg.h123
-rw-r--r--sys/dev/ic/com.c996
-rw-r--r--sys/dev/ic/comreg.h118
-rw-r--r--sys/dev/ic/cs4231reg.h103
-rw-r--r--sys/dev/ic/dc21040reg.h332
-rw-r--r--sys/dev/ic/dp8390reg.h550
-rw-r--r--sys/dev/ic/i8042reg.h44
-rw-r--r--sys/dev/ic/i8237reg.h13
-rw-r--r--sys/dev/ic/i82586reg.h289
-rw-r--r--sys/dev/ic/ics2101reg.h79
-rw-r--r--sys/dev/ic/mb86960reg.h320
-rw-r--r--sys/dev/ic/mc146818reg.h194
-rw-r--r--sys/dev/ic/ncr5380.c729
-rw-r--r--sys/dev/ic/ncr5380reg.h135
-rw-r--r--sys/dev/ic/ncr5380var.h115
-rw-r--r--sys/dev/ic/nec765reg.h73
-rw-r--r--sys/dev/ic/ns16450reg.h51
-rw-r--r--sys/dev/ic/ns16550reg.h53
-rw-r--r--sys/dev/ic/pdq.c1549
-rw-r--r--sys/dev/ic/pdqreg.h1061
-rw-r--r--sys/dev/ic/pdqvar.h252
-rw-r--r--sys/dev/ic/z8530reg.h432
29 files changed, 11816 insertions, 0 deletions
diff --git a/sys/dev/ic/ad1848reg.h b/sys/dev/ic/ad1848reg.h
new file mode 100644
index 00000000000..fd8de8f3a1c
--- /dev/null
+++ b/sys/dev/ic/ad1848reg.h
@@ -0,0 +1,198 @@
+/* $NetBSD: ad1848reg.h,v 1.1 1995/07/07 02:11:45 brezak Exp $ */
+
+/*
+ * Copyright (c) 1994 John Brezak
+ * Copyright (c) 1991-1993 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ *
+ */
+/*
+ * Copyright (c) 1993 Analog Devices Inc. All rights reserved
+ */
+
+/* parent driver is primarily responsible for checking this */
+#define AD1848_BASE_VALID(base) (((base) & 0x003) == 0)
+
+/* AD1848 direct registers */
+#define AD1848_IADDR 0x04
+#define AD1848_IDATA 0x05
+#define AD1848_STATUS 0x06
+#define AD1848_PIO 0x07
+
+/* Gain constants */
+#define GAIN_0 0x00
+#define GAIN_1_5 0x01
+#define GAIN_3 0x02
+#define GAIN_4_5 0x03
+#define GAIN_6 0x04
+#define GAIN_7_5 0x05
+#define GAIN_9 0x06
+#define GAIN_10_5 0x07
+#define GAIN_12 0x08
+#define GAIN_13_5 0x09
+#define GAIN_15 0x0a
+#define GAIN_16_5 0x0b
+#define GAIN_18 0x0c
+#define GAIN_19_5 0x0d
+#define GAIN_21 0x0e
+#define GAIN_22_5 0x0f
+
+/* Attenuation constants */
+
+#define ATTEN_0 0x00
+#define ATTEN_1_5 0x01
+#define ATTEN_3 0x02
+#define ATTEN_4_5 0x03
+#define ATTEN_6 0x04
+#define ATTEN_7_5 0x05
+#define ATTEN_9 0x06
+#define ATTEN_10_5 0x07
+#define ATTEN_12 0x08
+#define ATTEN_13_5 0x09
+#define ATTEN_15 0x0a
+#define ATTEN_16_5 0x0b
+#define ATTEN_18 0x0c
+#define ATTEN_19_5 0x0d
+#define ATTEN_21 0x0e
+#define ATTEN_22_5 0x0f
+
+/* AD1848 Sound Port bit defines */
+#define SP_IN_INIT 0x80
+#define MODE_CHANGE_ENABLE 0x40
+#define MODE_CHANGE_MASK 0xbf
+#define TRANSFER_DISABLE 0x20
+#define TRANSFER_DISABLE_MASK 0xdf
+#define ADDRESS_MASK 0xe0
+
+/* Status bits */
+#define INTERRUPT_STATUS 0x01
+#define PLAYBACK_READY 0x02
+#define PLAYBACK_LEFT 0x04
+/* pbright is not left */
+#define PLAYBACK_UPPER 0x08
+/* bplower is not upper */
+
+#define SAMPLE_ERROR 0x10
+#define CAPTURE_READY 0x20
+#define CAPTURE_LEFT 0x40
+/* cpright is not left */
+#define CAPTURE_UPPER 0x08
+/* cplower is not upper */
+
+/* Input & Output regs bits */
+#define LINE_INPUT 0x00
+#define AUX_INPUT 0x40
+#define MIC_INPUT 0x80
+#define MIXED_DAC_INPUT 0xC0
+#define INPUT_GAIN_MASK 0xf0
+#define INPUT_MIC_GAIN_ENABLE 0x20
+#define INPUT_MIC_GAIN_MASK 0xdf
+#define INPUT_SOURCE_MASK 0x3f
+#define AUX_INPUT_ATTEN_BITS 0x1f
+#define AUX_INPUT_ATTEN_MASK 0xe0
+#define AUX_INPUT_MUTE 0x80
+#define AUX_INPUT_MUTE_MASK 0x7f
+#define OUTPUT_MUTE 0x80
+#define OUTPUT_MUTE_MASK 0x7f
+#define OUTPUT_ATTEN_BITS 0x3f
+#define OUTPUT_ATTEN_MASK 0xc0
+
+/* Clock and Data format reg bits (some also Capture Data format) */
+#define CLOCK_SELECT_MASK 0xfe
+#define CLOCK_XTAL2 0x01
+#define CLOCK_XTAL1 0x00
+#define CLOCK_FREQ_MASK 0xf1
+#define STEREO_MONO_MASK 0xef
+#define FMT_STEREO 0x10
+#define FMT_MONO 0x00
+#define FORMAT_MASK 0x1f
+#define FMT_PCM8 0x00 /* 8-bit unsigned */
+#define FMT_ULAW 0x20 /* 8-bit mu-law */
+#define FMT_TWOS_COMP 0x40 /* 16-bit signed */
+#define FMT_ALAW 0x60 /* 8-bit alaw */
+#define FMT_TWOS_COMP_BE 0xC0 /* 16-bit signed, big endian */
+
+/* Interface Configuration reg bits */
+#define PLAYBACK_ENABLE 0x01
+#define PLAYBACK_ENABLE_MASK 0xfe
+#define CAPTURE_ENABLE 0x02
+#define CAPTURE_ENABLE_MASK 0xfd
+#define SINGLE_DMA 0x04
+#define SINGLE_DMA_MASK 0xfb
+#define DUAL_DMA 0x00
+#define AUTO_CAL_ENABLE 0x08
+#define AUTO_CAL_DISABLE_MASK 0xf7
+#define PLAYBACK_PIO_ENABLE 0x40
+#define PLAYBACK_DMA_MASK 0xbf
+#define CAPTURE_PIO_ENABLE 0x80
+#define CAPTURE_DMA_MASK 0x7f
+
+/* Pin control bits */
+#define INTERRUPT_ENABLE 0x02
+#define INTERRUPT_MASK 0xfd
+#define XCTL0_ENABLE 0x40
+#define XCTL1_ENABLE 0x80
+
+/* Test and init reg bits */
+#define OVERRANGE_LEFT_MASK 0xfc
+#define OVERRANGE_RIGHT_MASK 0xf3
+#define DATA_REQUEST_STATUS 0x10
+#define AUTO_CAL_IN_PROG 0x20
+#define PLAYBACK_UNDERRUN 0x40
+#define CAPTURE_OVERRUN 0x80
+
+/* Miscellaneous Control reg bits */
+#define ID_MASK 0x70
+#define MODE2 0x40
+
+/* Digital Mix Control reg bits */
+#define DIGITAL_MIX1_MUTE_MASK 0xfe
+#define DIGITAL_MIX1_ENABLE 0x01
+#define MIX_ATTEN_MASK 0xfc
+
+/* AD1848 Sound Port reg defines */
+#define SP_LEFT_INPUT_CONTROL 0x00
+#define SP_RIGHT_INPUT_CONTROL 0x01
+#define SP_LEFT_AUX1_CONTROL 0x02
+#define SP_RIGHT_AUX1_CONTROL 0x03
+#define SP_LEFT_AUX2_CONTROL 0x04
+#define SP_RIGHT_AUX2_CONTROL 0x05
+#define SP_LEFT_OUTPUT_CONTROL 0x06
+#define SP_RIGHT_OUTPUT_CONTROL 0x07
+#define SP_CLOCK_DATA_FORMAT 0x08
+#define SP_INTERFACE_CONFIG 0x09
+#define SP_PIN_CONTROL 0x0A
+#define SP_TEST_AND_INIT 0x0B
+#define SP_MISC_INFO 0x0C
+#define SP_DIGITAL_MIX 0x0D
+#define SP_UPPER_BASE_COUNT 0x0E
+#define SP_LOWER_BASE_COUNT 0x0F
+
diff --git a/sys/dev/ic/aic7xxx.c b/sys/dev/ic/aic7xxx.c
new file mode 100644
index 00000000000..dd2ddf0a9fc
--- /dev/null
+++ b/sys/dev/ic/aic7xxx.c
@@ -0,0 +1,2227 @@
+/* $NetBSD: aic7xxx.c,v 1.1 1995/10/09 09:49:30 mycroft Exp $ */
+
+/*
+ * Generic driver for the aic7xxx based adaptec SCSI controllers
+ * Copyright (c) 1994, 1995 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Product specific probe and attach routines can be found in:
+ * i386/isa/aic7770.c 27/284X and aic7770 motherboard controllers
+ * /pci/aic7870.c 294x and aic7870 motherboard controllers
+ *
+ * Portions of this driver are based on the FreeBSD 1742 Driver:
+ *
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * commenced: Sun Sep 27 18:14:01 PDT 1992
+ */
+/*
+ * TODO:
+ * Add target reset capabilities
+ * Implement Target Mode
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <machine/pio.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_debug.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/aic7xxxvar.h>
+
+int ahc_init __P((struct ahc_softc *));
+void ahc_loadseq __P((int));
+int ahc_scsi_cmd __P((struct scsi_xfer *));
+void ahc_timeout __P((void *));
+void ahc_done __P((struct ahc_softc *, struct ahc_scb *));
+struct ahc_scb *ahc_get_scb __P((struct ahc_softc *, int));
+void ahc_free_scb __P((struct ahc_softc *, struct ahc_scb *, int));
+void ahc_abort_scb __P((struct ahc_softc *, struct ahc_scb *));
+void ahcminphys __P((struct buf *));
+int ahc_poll __P((struct ahc_softc *, struct scsi_xfer *, int));
+
+/* Different debugging levels */
+#define AHC_SHOWMISC 0x0001
+#define AHC_SHOWCMDS 0x0002
+#define AHC_SHOWSCBS 0x0004
+/*#define AHC_DEBUG /**/
+int ahc_debug = AHC_SHOWMISC;
+
+/*#define AHC_MORE_DEBUG /**/
+
+#ifdef AHC_MORE_DEBUG
+#define DEBUGLEVEL -1
+#define DEBUGTARGET 0x0
+#endif
+
+/**** bit definitions for SCSIDEF ****/
+#define HSCSIID 0x07 /* our SCSI ID */
+#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */
+
+struct scsi_adapter ahc_switch = {
+ ahc_scsi_cmd,
+ ahcminphys,
+ 0,
+ 0,
+};
+
+
+/* the below structure is so we have a default dev struct for our link struct */
+struct scsi_device ahc_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+
+/*
+ * All of these should be in a separate header file shared by the sequencer
+ * code and the kernel level driver. The only catch is that we would need to
+ * add an additional 0xc00 offset when using them in the kernel driver. The
+ * aic7770 assembler must be modified to allow include files as well. All
+ * page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/* -------------------- AIC-7770 offset definitions ----------------------- */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+#define SCSISEQ 0xc00ul
+#define TEMODEO 0x80
+#define ENSELO 0x40
+#define ENSELI 0x20
+#define ENRSELI 0x10
+#define ENAUTOATNO 0x08
+#define ENAUTOATNI 0x04
+#define ENAUTOATNP 0x02
+#define SCSIRSTO 0x01
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+#define SXFRCTL1 0xc02ul
+#define BITBUCKET 0x80
+#define SWRAPEN 0x40
+#define ENSPCHK 0x20
+#define STIMESEL 0x18
+#define ENSTIMER 0x04
+#define ACTNEGEN 0x02
+#define STPWEN 0x01 /* Powered Termination */
+
+/*
+ * SCSI Interrrupt Mode 1 (pp. 3-28,29).
+ * Set bits in this register enable the corresponding
+ * interrupt source.
+ */
+#define SIMODE1 0xc11ul
+#define ENSELTIMO 0x80
+#define ENATNTARG 0x40
+#define ENSCSIRST 0x20
+#define ENPHASEMIS 0x10
+#define ENBUSFREE 0x08
+#define ENSCSIPERR 0x04
+#define ENPHASECHG 0x02
+#define ENREQINIT 0x01
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+#define SCSISIGI 0xc03ul
+#define CDI 0x80
+#define IOI 0x40
+#define MSGI 0x20
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
+
+/*
+ * SCSI Contol Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus. Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+#define SCSISIGO 0xc03ul
+#define CDO 0x80
+#define IOO 0x40
+#define MSGO 0x20
+#define ATNO 0x10
+#define SELO 0x08
+#define BSYO 0x04
+#define REQO 0x02
+#define ACKO 0x01
+
+/* XXX document this thing */
+#define SCSIRATE 0xc04ul
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel
+ */
+#define SCSIID 0xc05ul
+#define TID 0xf0 /* Target ID mask */
+#define OID 0x0f /* Our ID mask */
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+#define SSTAT0 0xc0bul
+#define TARGET 0x80 /* Board is a target */
+#define SELDO 0x40 /* Selection Done */
+#define SELDI 0x20 /* Board has been selected */
+#define SELINGO 0x10 /* Selection In Progress */
+#define SWRAP 0x08 /* 24bit counter wrap */
+#define SDONE 0x04 /* STCNT = 0x000000 */
+#define SPIORDY 0x02 /* SCSI PIO Ready */
+#define DMADONE 0x01 /* DMA transfer completed */
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+#define CLRSINT1 0xc0cul
+#define CLRSELTIMEO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+/* UNUSED 0x10 */
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRPHASECHG 0x02
+#define CLRREQINIT 0x01
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ * These interrupt bits are of interest to the kernel driver
+ */
+#define SSTAT1 0xc0cul
+#define SELTO 0x80
+#define ATNTARG 0x40
+#define SCSIRSTI 0x20
+#define PHASEMIS 0x10
+#define BUSFREE 0x08
+#define SCSIPERR 0x04
+#define PHASECHG 0x02
+#define REQINIT 0x01
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id. The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+#define SELID 0xc19ul
+#define SELID_MASK 0xf0
+#define ONEBIT 0x08
+/* UNUSED 0x07 */
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection. In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+#define SBLKCTL 0xc1ful
+/* UNUSED 0xc0 */
+#define AUTOFLUSHDIS 0x20
+/* UNUSED 0x10 */
+#define SELBUSB 0x08
+/* UNUSED 0x04 */
+#define SELWIDE 0x02
+/* UNUSED 0x01 */
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+#define SEQCTL 0xc60ul
+#define PERRORDIS 0x80
+#define PAUSEDIS 0x40
+#define FAILDIS 0x20
+#define FASTMODE 0x10
+#define BRKADRINTEN 0x08
+#define STEP 0x04
+#define SEQRESET 0x02
+#define LOADRAM 0x01
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
+ * four bytes in sucessesion. The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+#define SEQRAM 0xc61ul
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+#define SEQADDR0 0xc62ul
+#define SEQADDR1 0xc63ul
+#define SEQADDR1_MASK 0x01
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+#define ACCUM 0xc64ul
+
+#define SINDEX 0xc65ul
+
+/*
+ * Board Control (p. 3-43)
+ */
+#define BCTL 0xc84ul
+/* RSVD 0xf0 */
+#define ACE 0x08 /* Support for external processors */
+/* RSVD 0x06 */
+#define ENABLE 0x01
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overal host control of the device.
+ */
+#define HCNTRL 0xc87ul
+/* UNUSED 0x80 */
+#define POWRDN 0x40
+/* UNUSED 0x20 */
+#define SWINT 0x10
+#define IRQMS 0x08
+#define PAUSE 0x04
+#define INTEN 0x02
+#define CHIPRST 0x01
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+#define SCBPTR 0xc90ul
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+#define INTSTAT 0xc91ul
+#define SEQINT_MASK 0xf0 /* SEQINT Status Codes */
+#define BAD_PHASE 0x00
+#define SEND_REJECT 0x10
+#define NO_IDENT 0x20
+#define NO_MATCH 0x30
+#define MSG_SDTR 0x40
+#define MSG_WDTR 0x50
+#define MSG_REJECT 0x60
+#define BAD_STATUS 0x70
+#define RESIDUAL 0x80
+#define ABORT_TAG 0x90
+#define BRKADRINT 0x08
+#define SCSIINT 0x04
+#define CMDCMPLT 0x02
+#define SEQINT 0x01
+#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors. You usually cannot recover from
+ * these without a full board reset.
+ */
+#define ERROR 0xc92ul
+/* UNUSED 0xf0 */
+#define PARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+#define CLRINT 0xc92ul
+#define CLRBRKADRINT 0x08
+#define CLRSCSIINT 0x04
+#define CLRCMDINT 0x02
+#define CLRSEQINT 0x01
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+#define SCBCNT 0xc9aul
+#define SCBAUTO 0x80
+#define SCBCNT_MASK 0x1f
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+#define QINFIFO 0xc9bul
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+#define QINCNT 0xc9cul
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+#define QOUTFIFO 0xc9dul
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+#define QOUTCNT 0xc9eul
+
+#define SCBARRAY 0xca0ul
+
+/* ---------------- END AIC-7770 Register Definitions ----------------- */
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+#define DSPCISTATUS 0xc86ul
+
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the Linux sequencer code. If I can figure out
+ * how to read the EISA configuration info at probe time, the cards could
+ * be run without BIOS support installed
+ */
+
+/*
+ * 1 byte per target starting at this address for configuration values
+ */
+#define HA_TARG_SCRATCH 0xc20ul
+
+/*
+ * The sequencer will stick the frist byte of any rejected message here so
+ * we can see what is getting thrown away.
+ */
+#define HA_REJBYTE 0xc31ul
+
+/*
+ * Length of pending message
+ */
+#define HA_MSG_LEN 0xc34ul
+
+/*
+ * message body
+ */
+#define HA_MSG_START 0xc35ul /* outgoing message body */
+
+/*
+ * These are offsets into the card's scratch ram. Some of the values are
+ * specified in the AHA2742 technical reference manual and are initialized
+ * by the BIOS at boot time.
+ */
+#define HA_ARG_1 0xc4aul
+#define HA_RETURN_1 0xc4aul
+#define SEND_SENSE 0x80
+#define SEND_WDTR 0x80
+#define SEND_SDTR 0x80
+#define SEND_REJ 0x40
+
+#define HA_SIGSTATE 0xc4bul
+
+#define HA_SCBCOUNT 0xc52ul
+#define HA_FLAGS 0xc53ul
+#define SINGLE_BUS 0x00
+#define TWIN_BUS 0x01
+#define WIDE_BUS 0x02
+#define ACTIVE_MSG 0x20
+#define IDENTIFY_SEEN 0x40
+#define RESELECTING 0x80
+
+#define HA_ACTIVE0 0xc54ul
+#define HA_ACTIVE1 0xc55ul
+#define SAVED_TCL 0xc56ul
+#define WAITING_SCBH 0xc57ul
+#define WAITING_SCBT 0xc58ul
+
+#define HA_SCSICONF 0xc5aul
+#define INTDEF 0xc5cul
+#define HA_HOSTCONF 0xc5dul
+
+#define MSG_ABORT 0x06
+#define BUS_8_BIT 0x00
+#define BUS_16_BIT 0x01
+#define BUS_32_BIT 0x02
+
+/*
+ * Since the sequencer can disable pausing in a critical section, we
+ * must loop until it actually stops.
+ * XXX Should add a timeout in here??
+ */
+#define PAUSE_SEQUENCER(ahc) \
+ do { \
+ outb(HCNTRL + ahc->sc_iobase, ahc->pause); \
+ while ((inb(HCNTRL + ahc->sc_iobase) & PAUSE) == 0) \
+ ; \
+ } while (0)
+
+#define UNPAUSE_SEQUENCER(ahc) \
+ do { \
+ outb(HCNTRL + ahc->sc_iobase, ahc->unpause); \
+ } while (0)
+
+/*
+ * Restart the sequencer program from address zero
+ * XXX Should add a timeout in here??
+ */
+#define RESET_SEQUENCER(ahc) \
+ do { \
+ do { \
+ outb(SEQCTL + ahc->sc_iobase, SEQRESET|FASTMODE); \
+ } while (inb(SEQADDR0 + ahc->sc_iobase) != 0 && \
+ inb(SEQADDR1 + ahc->sc_iobase) != 0); \
+ } while (0)
+
+#define RESTART_SEQUENCER(ahc) \
+ do { \
+ RESET_SEQUENCER(ahc); \
+ UNPAUSE_SEQUENCER(ahc); \
+ } while (0)
+
+#ifdef AHC_DEBUG
+void
+ahc_print_scb(scb)
+ struct ahc_scb *scb;
+{
+
+ printf("scb:0x%x control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%x\n",
+ scb,
+ scb->control,
+ scb->target_channel_lun,
+ scb->cmdlen,
+ scb->cmdpointer);
+ printf("\tdatlen:%d data:0x%x res:0x%x segs:0x%x segp:0x%x\n",
+ scb->datalen[2] << 16 | scb->datalen[1] << 8 | scb->datalen[0],
+ scb->data,
+ scb->RESERVED[1] << 8 | scb->RESERVED[0],
+ scb->SG_segment_count,
+ scb->SG_list_pointer);
+ printf("\tsg_addr:%x sg_len:%d\n",
+ scb->ahc_dma[0].addr,
+ scb->ahc_dma[0].len);
+ printf(" size:%d\n",
+ (int)&scb->next - (int)scb);
+}
+
+void
+ahc_print_active_scb(ahc)
+ struct ahc_softc *ahc;
+{
+ int iobase = ahc->sc_iobase;
+ int scb_index;
+
+ PAUSE_SEQUENCER(ahc);
+ scb_index = inb(SCBPTR + iobase);
+ UNPAUSE_SEQUENCER(ahc);
+
+ ahc_print_scb(ahc->scbarray[scb_index]);
+}
+#endif
+
+#define PARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
+
+static struct {
+ u_char errno;
+ char *errmesg;
+} hard_error[] = {
+ { ILLHADDR, "Illegal Host Access" },
+ { ILLSADDR, "Illegal Sequencer Address referrenced" },
+ { ILLOPCODE, "Illegal Opcode in sequencer program" },
+ { PARERR, "Sequencer Ram Parity Error" }
+};
+
+
+/*
+ * Valid SCSIRATE values. (p. 3-17)
+ * Provides a mapping of tranfer periods in ns to the proper value to
+ * stick in the scsiscfr reg to use that transfer rate.
+ */
+static struct {
+ u_char sxfr;
+ int period; /* in ns */
+ char *rate;
+} ahc_syncrates[] = {
+ { 0x00, 100, "10.0" },
+ { 0x10, 125, "8.0" },
+ { 0x20, 150, "6.67" },
+ { 0x30, 175, "5.7" },
+ { 0x40, 200, "5.0" },
+ { 0x50, 225, "4.4" },
+ { 0x60, 250, "4.0" },
+ { 0x70, 275, "3.6" }
+};
+
+static int ahc_num_syncrates =
+ sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]);
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, determine configuration and set it up for further work.
+ */
+
+int
+ahcprobe(ahc, iobase)
+ struct ahc_softc *ahc;
+ int iobase;
+{
+
+ ahc->sc_iobase = iobase;
+
+ /*
+ * Try to initialize a unit at this location
+ * reset the AIC-7770, read its registers,
+ * and fill in the dev structure accordingly
+ */
+
+ if (ahc_init(ahc) != 0)
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * Look up the valid period to SCSIRATE conversion in our table.
+ */
+static u_char
+ahc_scsirate(offset, period, ahc, target)
+ u_char offset;
+ int period;
+ struct ahc_softc *ahc;
+ int target;
+{
+ u_char scsirate;
+ int i;
+
+ for (i = 0; i < ahc_num_syncrates; i++) {
+ if ((ahc_syncrates[i].period - period) >= 0) {
+ printf("%s: target %d synchronous at %sMB/s, "
+ "offset = %d\n",
+ ahc->sc_dev.dv_xname, target,
+ ahc_syncrates[i].rate, offset);
+#ifdef AHC_DEBUG
+#endif /* AHC_DEBUG */
+ return ((ahc_syncrates[i].sxfr) | (offset & 0x0f));
+ }
+ }
+
+ /* Default to asyncronous transfers. Also reject this SDTR request. */
+ printf("%s: target %d using asyncronous transfers\n",
+ ahc->sc_dev.dv_xname, target);
+ return (0);
+#ifdef AHC_DEBUG
+#endif /* AHC_DEBUG */
+}
+
+ahcprint()
+{
+
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+ahcattach(ahc)
+ struct ahc_softc *ahc;
+{
+
+ TAILQ_INIT(&ahc->free_scb);
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ ahc->sc_link.adapter_softc = ahc;
+ ahc->sc_link.adapter_target = ahc->ahc_scsi_dev;
+ ahc->sc_link.adapter = &ahc_switch;
+ ahc->sc_link.device = &ahc_dev;
+ ahc->sc_link.openings = 1;
+ ahc->sc_link.flags = DEBUGLEVEL;
+ ahc->sc_link.quirks = 0;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ printf("%s: Probing channel A\n", ahc->sc_dev.dv_xname);
+ config_found((void *)ahc, &ahc->sc_link, ahcprint);
+ if (ahc->type & AHC_TWIN) {
+ /* Configure the second scsi bus */
+ ahc->sc_link_b = ahc->sc_link;
+ /* XXXX Didn't do this before. */
+ ahc->sc_link_b.adapter_target = ahc->ahc_scsi_dev_b;
+ ahc->sc_link_b.quirks = 0x0008; /**/
+ printf("%s: Probing channel B\n", ahc->sc_dev.dv_xname);
+ config_found((void *)ahc, &ahc->sc_link_b, ahcprint);
+ }
+
+ return 1;
+}
+
+void
+ahc_send_scb(ahc, scb)
+ struct ahc_softc *ahc;
+ struct ahc_scb *scb;
+{
+ int iobase = ahc->sc_iobase;
+
+ PAUSE_SEQUENCER(ahc);
+ outb(QINFIFO + iobase, scb->position);
+ UNPAUSE_SEQUENCER(ahc);
+}
+
+static void
+ahc_getscb(iobase, scb)
+ int iobase;
+ struct ahc_scb *scb;
+{
+
+ outb(SCBCNT + iobase, SCBAUTO);
+ insb(SCBARRAY + iobase, scb, SCB_UP_SIZE);
+ outb(SCBCNT + iobase, 0);
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+ahcintr(ahc)
+ struct ahc_softc *ahc;
+{
+ int iobase = ahc->sc_iobase;
+ u_char intstat = inb(INTSTAT + iobase);
+ u_char status;
+ struct ahc_scb *scb = NULL;
+ struct scsi_xfer *xs = NULL;
+
+ /*
+ * Is this interrupt for me? or for
+ * someone who is sharing my interrupt
+ */
+ if ((intstat & INT_PEND) == 0)
+ return 0;
+
+ if (intstat & BRKADRINT) {
+ /* We upset the sequencer :-( */
+
+ /* Lookup the error message */
+ int i, error = inb(ERROR + iobase);
+ int num_errors = sizeof(hard_error)/sizeof(hard_error[0]);
+ for (i = 0; error != 1 && i < num_errors; i++)
+ error >>= 1;
+ panic("%s: brkadrint, %s at seqaddr = 0x%x\n",
+ ahc->sc_dev.dv_xname, hard_error[i].errmesg,
+ (inb(SEQADDR1 + iobase) << 8) |
+ (inb(SEQADDR0 + iobase) << 0));
+ }
+
+ if (intstat & SEQINT) {
+ switch (intstat & SEQINT_MASK) {
+ case BAD_PHASE:
+ panic("%s: unknown scsi bus phase. "
+ "Attempting to continue\n",
+ ahc->sc_dev.dv_xname);
+ break;
+ case SEND_REJECT:
+ printf("%s: Warning - "
+ "message reject, message type: 0x%x\n",
+ ahc->sc_dev.dv_xname,
+ inb(HA_REJBYTE + iobase));
+ break;
+ case NO_IDENT:
+ panic("%s: No IDENTIFY message from reconnecting "
+ "target %d at seqaddr = 0x%lx "
+ "SAVED_TCL == 0x%x\n",
+ ahc->sc_dev.dv_xname,
+ (inb(SELID + iobase) >> 4) & 0xf,
+ (inb(SEQADDR1 + iobase) << 8) |
+ (inb(SEQADDR0 + iobase) << 0),
+ inb(SAVED_TCL + iobase));
+ break;
+ case NO_MATCH: {
+ u_char active;
+ int active_port = HA_ACTIVE0 + iobase;
+ int tcl = inb(SCBARRAY+1 + iobase);
+ int target = (tcl >> 4) & 0x0f;
+ printf("%s: no active SCB for reconnecting "
+ "target %d, channel %c - issuing ABORT\n",
+ ahc->sc_dev.dv_xname,
+ target, tcl & 0x08 ? 'B' : 'A');
+ printf("SAVED_TCL == 0x%x\n", inb(SAVED_TCL + iobase));
+ if (tcl & 0x88) {
+ /* Second channel stores its info
+ * in byte two of HA_ACTIVE
+ */
+ active_port++;
+ }
+ active = inb(active_port);
+ active &= ~(0x01 << (target & 0x07));
+ outb(SCBARRAY + iobase, SCB_NEEDDMA);
+ outb(active_port, active);
+ outb(CLRSINT1 + iobase, CLRSELTIMEO);
+ RESTART_SEQUENCER(ahc);
+ break;
+ }
+ case MSG_SDTR: {
+ u_char scsi_id =
+ (inb(SCSIID + iobase) >> 0x4) |
+ (inb(SBLKCTL + iobase) & 0x08);
+ u_char scratch, offset;
+ int period;
+
+ /*
+ * Help the sequencer to translate the
+ * negotiated transfer rate. Transfer is
+ * 1/4 the period in ns as is returned by
+ * the sync negotiation message. So, we must
+ * multiply by four
+ */
+ period = inb(HA_ARG_1 + iobase) << 2;
+ /* The bottom half of SCSIXFER */
+ offset = inb(ACCUM + iobase);
+
+ printf("%s: SDTR, target %d period %d offset %d\n",
+ ahc->sc_dev.dv_xname, scsi_id, period, offset);
+ scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id);
+ scratch &= 0x80;
+ scratch |= ahc_scsirate(offset, period, ahc, scsi_id);
+
+ if ((scratch & 0x7f) == 0) {
+ /*
+ * The requested rate was so low
+ * that asyncronous transfers are
+ * faster (not to mention the
+ * controller won't support them),
+ * so we issue a message reject to
+ * ensure we go to asyncronous
+ * transfers.
+ */
+ outb(HA_RETURN_1 + iobase, SEND_REJ);
+ } else if (ahc->sdtrpending & (0x01 << scsi_id)) {
+ /*
+ * Don't send an SDTR back to the
+ * target, since we asked first.
+ */
+ outb(HA_RETURN_1 + iobase, 0);
+ } else {
+ /*
+ * Send our own SDTR in reply
+ */
+#ifdef AHC_DEBUG
+ if (ahc_debug & AHC_SHOWMISC)
+ printf("Sending SDTR!!\n");
+#endif
+ outb(HA_RETURN_1 + iobase, SEND_SDTR);
+ }
+ /*
+ * Negate the flags
+ */
+ ahc->needsdtr &= ~(0x01 << scsi_id);
+ ahc->sdtrpending &= ~(0x01 << scsi_id);
+
+ outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch);
+ outb(SCSIRATE + iobase, scratch);
+ break;
+ }
+ case MSG_WDTR: {
+ u_char scsi_id =
+ (inb(SCSIID + iobase) >> 0x4) |
+ (inb(SBLKCTL + iobase) & 0x08);
+ u_char scratch, width;
+
+ width = inb(ACCUM + iobase);
+
+ scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id);
+
+ if (ahc->wdtrpending & (0x01 << scsi_id)) {
+ /*
+ * Don't send a WDTR back to the
+ * target, since we asked first.
+ */
+ outb(HA_RETURN_1 + iobase, 0);
+ switch (width) {
+ case BUS_8_BIT:
+ scratch &= 0x7f;
+ break;
+ case BUS_16_BIT:
+ printf("%s: target %d using 16Bit "
+ "transfers\n",
+ ahc->sc_dev.dv_xname, scsi_id);
+ scratch &= 0xf8;
+ scratch |= 0x88;
+ break;
+ case BUS_32_BIT:
+ /* XXXX */
+ }
+ } else {
+ /*
+ * Send our own WDTR in reply
+ */
+ switch (width) {
+ case BUS_8_BIT:
+ scratch &= 0x7f;
+ break;
+ case BUS_32_BIT:
+ /* Negotiate 16_BITS */
+ width = BUS_16_BIT;
+ case BUS_16_BIT:
+ printf("%s: target %d using 16Bit "
+ "transfers\n",
+ ahc->sc_dev.dv_xname, scsi_id);
+ scratch &= 0xf8;
+ scratch |= 0x88;
+ break;
+ }
+ outb(HA_RETURN_1 + iobase,
+ width | SEND_WDTR);
+ }
+ ahc->needwdtr &= ~(0x01 << scsi_id);
+ ahc->wdtrpending &= ~(0x01 << scsi_id);
+
+ outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch);
+ outb(SCSIRATE + iobase, scratch);
+ break;
+ }
+ case MSG_REJECT: {
+ /*
+ * What we care about here is if we had an
+ * outstanding SDTR or WDTR message for this
+ * target. If we did, this is a signal that
+ * the target is refusing negotiation.
+ */
+
+ u_char scsi_id =
+ (inb(SCSIID + iobase) >> 0x4) |
+ (inb(SBLKCTL + iobase) & 0x08);
+ u_char scratch;
+ u_short mask;
+
+ scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id);
+
+ mask = (0x01 << scsi_id);
+ if (ahc->wdtrpending & mask) {
+ /* note 8bit xfers and clear flag */
+ scratch &= 0x7f;
+ ahc->needwdtr &= ~mask;
+ ahc->wdtrpending &= ~mask;
+ printf("%s: target %d refusing "
+ "WIDE negotiation. Using "
+ "8bit transfers\n",
+ ahc->sc_dev.dv_xname, scsi_id);
+ } else if (ahc->sdtrpending & mask) {
+ /* note asynch xfers and clear flag */
+ scratch &= 0xf0;
+ ahc->needsdtr &= ~mask;
+ ahc->sdtrpending &= ~mask;
+ printf("%s: target %d refusing "
+ "syncronous negotiation; using "
+ "asyncronous transfers\n",
+ ahc->sc_dev.dv_xname, scsi_id);
+ } else {
+ /*
+ * Otherwise, we ignore it.
+ */
+#ifdef AHC_DEBUG
+ if (ahc_debug & AHC_SHOWMISC)
+ printf("Message reject -- ignored\n");
+#endif
+ break;
+ }
+
+ outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch);
+ outb(SCSIRATE + iobase, scratch);
+ break;
+ }
+ case BAD_STATUS: {
+ int scb_index = inb(SCBPTR + iobase);
+ scb = ahc->scbarray[scb_index];
+
+ /*
+ * The sequencer will notify us when a command
+ * has an error that would be of interest to
+ * the kernel. This allows us to leave the sequencer
+ * running in the common case of command completes
+ * without error.
+ */
+
+ /*
+ * Set the default return value to 0 (don't
+ * send sense). The sense code with change
+ * this if needed and this reduces code
+ * duplication.
+ */
+ outb(HA_RETURN_1 + iobase, 0);
+ if (!scb || scb->flags == SCB_FREE) {
+ printf("%s: ahcintr: referenced scb not "
+ "valid during seqint 0x%x scb(%d)\n",
+ ahc->sc_dev.dv_xname, intstat, scb_index);
+ goto clear;
+ }
+
+ xs = scb->xs;
+
+ ahc_getscb(iobase, scb);
+
+#ifdef AHC_DEBUG
+ if (xs->sc_link->target == DEBUGTARGET)
+ ahc_print_scb(scb);
+#endif
+ xs->status = scb->target_status;
+ switch (scb->target_status) {
+ case SCSI_OK:
+ printf("%s: Interrupted for status of 0???\n",
+ ahc->sc_dev.dv_xname);
+ break;
+ case SCSI_CHECK:
+#ifdef AHC_DEBUG
+ sc_print_addr(xs->sc_link);
+ printf("requests Check Status\n");
+#endif
+
+ if (xs->error == XS_NOERROR &&
+ scb->flags != SCB_CHKSENSE) {
+ u_char flags;
+ u_char head;
+ u_char tail;
+ struct ahc_dma_seg *sg = scb->ahc_dma;
+ struct scsi_sense *sc = &(scb->sense_cmd);
+ u_char control = scb->control;
+ u_char tcl = scb->target_channel_lun;
+#ifdef AHC_DEBUG
+ sc_print_addr(xs->sc_link);
+ printf("Sending Sense\n");
+#endif
+ bzero(scb, SCB_DOWN_SIZE);
+ scb->flags = SCB_CHKSENSE;
+ scb->control = (control & SCB_TE);
+ sc->opcode = REQUEST_SENSE;
+ sc->byte2 = xs->sc_link->lun << 5;
+ sc->length = sizeof(struct scsi_sense_data);
+ sc->control = 0;
+
+ sg->seg_addr = vtophys(&xs->sense);
+ sg->seg_len = sizeof(struct scsi_sense_data);
+
+ scb->target_channel_lun = tcl;
+ scb->SG_segment_count = 1;
+ scb->SG_list_pointer = vtophys(sg);
+ scb->cmdpointer = vtophys(sc);
+ scb->cmdlen = sizeof(*sc);
+
+ outb(SCBCNT + iobase, SCBAUTO);
+ outsb(SCBARRAY + iobase, scb,
+ SCB_DOWN_SIZE);
+ outb(SCBCNT + iobase, 0);
+ outb(SCBARRAY + iobase + 30,
+ SCB_LIST_NULL);
+
+ /*
+ * Add this SCB to the "waiting for
+ * selection" list.
+ */
+ head = inb(WAITING_SCBH + iobase);
+ tail = inb(WAITING_SCBT + iobase);
+ if (head & SCB_LIST_NULL) {
+ /* List was empty */
+ head = scb->position;
+ tail = SCB_LIST_NULL;
+ } else if (tail & SCB_LIST_NULL) {
+ /* List had one element */
+ tail = scb->position;
+ outb(SCBPTR + iobase, head);
+ outb(SCBARRAY + iobase + 30,
+ tail);
+ } else {
+ outb(SCBPTR + iobase, tail);
+ tail = scb->position;
+ outb(SCBARRAY + iobase + 30,
+ tail);
+ }
+ outb(WAITING_SCBH + iobase, head);
+ outb(WAITING_SCBT + iobase, tail);
+ outb(HA_RETURN_1 + iobase, SEND_SENSE);
+ break;
+ }
+ /*
+ * Have the sequencer do a normal command
+ * complete with either a "DRIVER_STUFFUP"
+ * error or whatever other error condition
+ * we already had.
+ */
+ if (xs->error == XS_NOERROR)
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ case SCSI_BUSY:
+ sc_print_addr(xs->sc_link);
+ printf("Target Busy\n");
+ xs->error = XS_BUSY;
+ break;
+#if 0
+ case SCSI_QUEUE_FULL:
+ /*
+ * The upper level SCSI code will eventually
+ * handle this properly.
+ */
+ sc_print_addr(xs->sc_link);
+ printf("Queue Full\n");
+ xs->error = XS_BUSY;
+ break;
+#endif
+ default:
+ sc_print_addr(xs->sc_link);
+ printf("unexpected targ_status: %x\n",
+ scb->target_status);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ break;
+ }
+ case RESIDUAL: {
+ int scb_index = inb(SCBPTR + iobase);
+ scb = ahc->scbarray[scb_index];
+
+ /*
+ * Don't clobber valid resid info with
+ * a resid coming from a check sense
+ * operation.
+ */
+ if (scb->flags != SCB_CHKSENSE)
+ scb->xs->resid =
+ (inb(iobase + SCBARRAY + 17) << 16) |
+ (inb(iobase + SCBARRAY + 16) << 8) |
+ (inb(iobase + SCBARRAY + 15) << 0);
+#ifdef AHC_MORE_DEBUG
+ printf("ahc: Handled Residual\n");
+#endif
+ break;
+ }
+ case ABORT_TAG: {
+ int scb_index = inb(SCBPTR + iobase);
+ scb = ahc->scbarray[scb_index];
+
+ /*
+ * We didn't recieve a valid tag back from
+ * the target on a reconnect.
+ */
+ sc_print_addr(xs->sc_link);
+ printf("invalid tag recieved on channel %c "
+ "-- sending ABORT_TAG\n",
+ (xs->sc_link->quirks & 0x08) ? 'B' : 'A');
+ scb->xs->error = XS_DRIVER_STUFFUP;
+ untimeout(ahc_timeout, scb);
+ ahc_done(ahc, scb);
+ break;
+ }
+ default:
+ printf("%s: seqint, intstat == 0x%x, scsisigi = 0x%x\n",
+ ahc->sc_dev.dv_xname,
+ intstat, inb(SCSISIGI + iobase));
+ break;
+ }
+
+ clear:
+ /*
+ * Clear the upper byte that holds SEQINT status
+ * codes and clear the SEQINT bit.
+ */
+ outb(CLRINT + iobase, CLRSEQINT);
+
+ /*
+ * The sequencer is paused immediately on
+ * a SEQINT, so we should restart it when
+ * we leave this section.
+ */
+ UNPAUSE_SEQUENCER(ahc);
+ }
+
+ if (intstat & SCSIINT) {
+ int scb_index = inb(SCBPTR + iobase);
+ scb = ahc->scbarray[scb_index];
+
+ status = inb(SSTAT1 + iobase);
+
+ if (!scb || scb->flags == SCB_FREE) {
+ printf("%s: ahcintr - referenced scb not "
+ "valid during scsiint 0x%x scb(%d)\n",
+ ahc->sc_dev.dv_xname, status, scb_index);
+ outb(CLRSINT1 + iobase, status);
+ UNPAUSE_SEQUENCER(ahc);
+ outb(CLRINT + iobase, CLRSCSIINT);
+ scb = NULL;
+ goto cmdcomplete;
+ }
+ xs = scb->xs;
+
+#ifdef AHC_MORE_DEBUG
+ if ((xs->sc_link->target & 0xf) == DEBUGTARGET)
+ printf("Intr status %x\n", status);
+#endif
+
+ if (status & SELTO) {
+ u_char active;
+ u_char waiting;
+ u_char flags;
+ int active_port = HA_ACTIVE0 + iobase;
+
+ outb(SCSISEQ + iobase, ENRSELI);
+ xs->error = XS_SELTIMEOUT;
+ /*
+ * Clear any pending messages for the timed out
+ * target, and mark the target as free
+ */
+ flags = inb(HA_FLAGS + iobase);
+ outb(HA_FLAGS + iobase, flags & ~ACTIVE_MSG);
+
+ if (scb->target_channel_lun & 0x88)
+ active_port++;
+
+ active = inb(active_port) &
+ ~(0x01 << (xs->sc_link->target & 0x07));
+ outb(active_port, active);
+
+ outb(SCBARRAY + iobase, SCB_NEEDDMA);
+
+ outb(CLRSINT1 + iobase, CLRSELTIMEO);
+
+ outb(CLRINT + iobase, CLRSCSIINT);
+
+ /* Shift the waiting for selection queue forward */
+ waiting = inb(WAITING_SCBH + iobase);
+ outb(SCBPTR + iobase, waiting);
+ waiting = inb(SCBARRAY + iobase + 30);
+ outb(WAITING_SCBH + iobase, waiting);
+
+ RESTART_SEQUENCER(ahc);
+ }
+
+ if (status & SCSIPERR) {
+ sc_print_addr(xs->sc_link);
+ printf("parity error on channel %c\n",
+ (xs->sc_link->quirks & 0x08) ? 'B' : 'A');
+ xs->error = XS_DRIVER_STUFFUP;
+
+ outb(CLRSINT1 + iobase, CLRSCSIPERR);
+ UNPAUSE_SEQUENCER(ahc);
+
+ outb(CLRINT + iobase, CLRSCSIINT);
+ scb = NULL;
+ }
+ if (status & BUSFREE) {
+#if 0
+ /*
+ * Has seen busfree since selection, i.e.
+ * a "spurious" selection. Shouldn't happen.
+ */
+ printf("ahc: unexpected busfree\n");
+#if 0
+ xs->error = XS_DRIVER_STUFFUP;
+ outb(CLRSINT1 + iobase, BUSFREE); /* CLRBUSFREE */
+#endif
+#endif
+ } else {
+ printf("%s: Unknown SCSIINT. Status = 0x%x\n",
+ ahc->sc_dev.dv_xname, status);
+ outb(CLRSINT1 + iobase, status);
+ UNPAUSE_SEQUENCER(ahc);
+ outb(CLRINT + iobase, CLRSCSIINT);
+ scb = NULL;
+ }
+ if (scb != NULL) {
+ /* We want to process the command */
+ untimeout(ahc_timeout, scb);
+ ahc_done(ahc, scb);
+ }
+ }
+
+cmdcomplete:
+ if (intstat & CMDCMPLT) {
+ int scb_index;
+
+ do {
+ scb_index = inb(QOUTFIFO + iobase);
+ scb = ahc->scbarray[scb_index];
+
+ if (!scb || scb->flags == SCB_FREE) {
+ printf("%s: WARNING "
+ "no command for scb %d (cmdcmplt)\n"
+ "QOUTCNT == %d\n",
+ ahc->sc_dev.dv_xname,
+ scb_index, inb(QOUTCNT + iobase));
+ outb(CLRINT + iobase, CLRCMDINT);
+ continue;
+ }
+
+ /* XXXX Should do this before reading FIFO? */
+ outb(CLRINT + iobase, CLRCMDINT);
+ untimeout(ahc_timeout, scb);
+ ahc_done(ahc, scb);
+ } while (inb(QOUTCNT + iobase));
+ }
+
+ return 1;
+}
+
+/*
+ * We have a scb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went.
+ */
+void
+ahc_done(ahc, scb)
+ struct ahc_softc *ahc;
+ struct ahc_scb *scb;
+{
+ struct scsi_xfer *xs = scb->xs;
+
+#ifdef AHC_MORE_DEBUG
+ if ((xs->sc_link->target & 0xf) == DEBUGTARGET) {
+ xs->sc_link->flags |= 0xf0;
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n"));
+ printf("%x %x %x %x\n",
+ scb->flags,
+ scb->target_status,
+ xs->flags,
+ xs->error);
+ }
+#endif
+
+ /*
+ * Put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if (xs->error == XS_NOERROR) {
+ if (scb->flags == SCB_ABORTED)
+ xs->error = XS_DRIVER_STUFFUP;
+ else if (scb->flags == SCB_CHKSENSE)
+ xs->error = XS_SENSE;
+ }
+
+ xs->flags |= ITSDONE;
+
+#ifdef AHC_TAGENABLE
+ if (xs->cmd->opcode == 0x12 && xs->error == XS_NOERROR) {
+ struct scsi_inquiry_data *inq_data;
+ u_short mask = 0x01 << (xs->sc_link->target |
+ (scb->target_channel_lun & 0x08));
+ /*
+ * Sneak a look at the results of the SCSI Inquiry
+ * command and see if we can do Tagged queing. XXX This
+ * should really be done by the higher level drivers.
+ */
+ inq_data = (struct scsi_inquiry_data *)xs->data;
+ if (((inq_data->device & SID_TYPE) == 0)
+ && (inq_data->flags & SID_CmdQue)
+ && !(ahc->tagenable & mask)) {
+ /*
+ * Disk type device and can tag
+ */
+ sc_print_addr(xs->sc_link);
+ printf("Tagged Queuing Device\n");
+ ahc->tagenable |= mask;
+#ifdef QUEUE_FULL_SUPPORTED
+ xs->sc_link->openings += 2; */
+#endif
+ }
+ }
+#endif
+
+ ahc_free_scb(ahc, scb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+/* XXXX clean */
+int
+ahc_init(ahc)
+ struct ahc_softc *ahc;
+{
+ int iobase = ahc->sc_iobase;
+ u_char scsi_conf, sblkctl, i;
+ int intdef, max_targ = 16, wait;
+
+ /*
+ * Assume we have a board at this stage
+ * Find out the configured interupt and the card type.
+ */
+
+#ifdef AHC_DEBUG
+ printf("%s: scb %d bytes; SCB_SIZE %d bytes, ahc_dma %d bytes\n",
+ ahc->sc_dev.dv_xname, sizeof(struct ahc_scb), SCB_DOWN_SIZE,
+ sizeof(struct ahc_dma_seg));
+#endif /* AHC_DEBUG */
+ /*printf("%s: reading board settings\n", ahc->sc_dev.dv_xname);/**/
+
+ /* Save the IRQ type before we do a chip reset */
+
+ ahc->unpause = (inb(HCNTRL + iobase) & IRQMS) | INTEN;
+ ahc->pause = ahc->unpause | PAUSE;
+ outb(HCNTRL + iobase, CHIPRST | ahc->pause);
+
+ /*
+ * Ensure that the reset has finished
+ */
+ wait = 1000;
+ while (wait--) {
+ delay(1000);
+ if (!(inb(HCNTRL + iobase) & CHIPRST))
+ break;
+ }
+ if (wait == 0) {
+ printf("\n%s: WARNING - Failed chip reset! "
+ "Trying to initialize anyway.\n", ahc->sc_dev.dv_xname);
+ /* Forcibly clear CHIPRST */
+ outb(HCNTRL + iobase, ahc->pause);
+ }
+
+ switch (ahc->type) {
+ case AHC_274:
+ printf(": 274x ", ahc->sc_dev.dv_xname);
+ ahc->maxscbs = 0x4;
+ break;
+ case AHC_284:
+ printf(": 284x ", ahc->sc_dev.dv_xname);
+ ahc->maxscbs = 0x4;
+ break;
+ case AHC_AIC7870:
+ case AHC_294:
+ if (ahc->type == AHC_AIC7870)
+ printf(": aic7870 ", ahc->sc_dev.dv_xname);
+ else
+ printf(": 294x ", ahc->sc_dev.dv_xname);
+ ahc->maxscbs = 0x10;
+ #define DFTHRESH 3
+ outb(DSPCISTATUS + iobase, DFTHRESH << 6);
+ /*
+ * XXX Hard coded SCSI ID until we can read it from the
+ * SEEPROM or NVRAM.
+ */
+ outb(HA_SCSICONF + iobase, 0x07 | (DFTHRESH << 6));
+ /* In case we are a wide card */
+ outb(HA_SCSICONF + 1 + iobase, 0x07);
+ break;
+ }
+
+ /* Determine channel configuration and who we are on the scsi bus. */
+ switch ((sblkctl = inb(SBLKCTL + iobase) & 0x0f)) {
+ case 0:
+ ahc->ahc_scsi_dev = (inb(HA_SCSICONF + iobase) & HSCSIID);
+ printf("Single Channel, SCSI Id=%d, ", ahc->ahc_scsi_dev);
+ outb(HA_FLAGS + iobase, SINGLE_BUS);
+ break;
+ case 2:
+ ahc->ahc_scsi_dev = (inb(HA_SCSICONF + 1 + iobase) & HWSCSIID);
+ printf("Wide Channel, SCSI Id=%d, ", ahc->ahc_scsi_dev);
+ ahc->type |= AHC_WIDE;
+ outb(HA_FLAGS + iobase, WIDE_BUS);
+ break;
+ case 8:
+ ahc->ahc_scsi_dev = (inb(HA_SCSICONF + iobase) & HSCSIID);
+ ahc->ahc_scsi_dev_b = (inb(HA_SCSICONF + 1 + iobase) & HSCSIID);
+ printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ",
+ ahc->ahc_scsi_dev, ahc->ahc_scsi_dev_b);
+ ahc->type |= AHC_TWIN;
+ outb(HA_FLAGS + iobase, TWIN_BUS);
+ break;
+ default:
+ printf(" Unsupported adapter type. %x Ignoring\n",sblkctl);
+ return(-1);
+ }
+
+ /*
+ * Take the bus led out of diagnostic mode
+ */
+ outb(SBLKCTL + iobase, sblkctl);
+
+ /*
+ * Number of SCBs that will be used. Rev E aic7770s and
+ * aic7870s have 16. The rest have 4.
+ */
+ if (!(ahc->type & AHC_AIC7870)) {
+ /*
+ * See if we have a Rev E or higher
+ * aic7770. Anything below a Rev E will
+ * have a R/O autoflush disable configuration
+ * bit.
+ */
+ u_char sblkctl_orig;
+ sblkctl_orig = inb(SBLKCTL + iobase);
+ sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
+ outb(SBLKCTL + iobase, sblkctl);
+ sblkctl = inb(SBLKCTL + iobase);
+ if (sblkctl != sblkctl_orig) {
+ printf("aic7770 >= Rev E, ");
+ /*
+ * Ensure autoflush is enabled
+ */
+ sblkctl &= ~AUTOFLUSHDIS;
+ outb(SBLKCTL + iobase, sblkctl);
+ } else
+ printf("aic7770 <= Rev C, ");
+ } else
+ printf("aic7870, ");
+ printf("%d SCBs\n", ahc->maxscbs);
+
+ if (ahc->pause & IRQMS)
+ printf("%s: Using Level Sensitive Interrupts\n",
+ ahc->sc_dev.dv_xname);
+ else
+ printf("%s: Using Edge Triggered Interrupts\n",
+ ahc->sc_dev.dv_xname);
+
+ if (!(ahc->type & AHC_AIC7870)) {
+ /*
+ * The 294x cards are PCI, so we get their interrupt from the
+ * PCI BIOS.
+ */
+
+ intdef = inb(INTDEF + iobase);
+ switch (intdef & 0xf) {
+ case 9:
+ ahc->sc_irq = 9;
+ break;
+ case 10:
+ ahc->sc_irq = 10;
+ break;
+ case 11:
+ ahc->sc_irq = 11;
+ break;
+ case 12:
+ ahc->sc_irq = 12;
+ break;
+ case 14:
+ ahc->sc_irq = 14;
+ break;
+ case 15:
+ ahc->sc_irq = 15;
+ break;
+ default:
+ printf("illegal irq setting\n");
+ return (EIO);
+ }
+ }
+
+ /* Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels */
+ if (ahc->type & AHC_TWIN) {
+ /*
+ * The device is gated to channel B after a chip reset,
+ * so set those values first
+ */
+ outb(SCSIID + iobase, ahc->ahc_scsi_dev_b);
+ scsi_conf = inb(HA_SCSICONF + 1 + iobase) & (ENSPCHK|STIMESEL);
+ outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
+ outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIPERR);
+ /* Select Channel A */
+ outb(SBLKCTL + iobase, 0);
+ }
+ outb(SCSIID + iobase, ahc->ahc_scsi_dev);
+ scsi_conf = inb(HA_SCSICONF + iobase) & (ENSPCHK|STIMESEL);
+ outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
+ outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIPERR);
+
+ /*
+ * Look at the information that board initialization or
+ * the board bios has left us. In the lower four bits of each
+ * target's scratch space any value other than 0 indicates
+ * that we should initiate syncronous transfers. If it's zero,
+ * the user or the BIOS has decided to disable syncronous
+ * negotiation to that target so we don't activate the needsdr
+ * flag.
+ */
+ ahc->needsdtr_orig = 0;
+ ahc->needwdtr_orig = 0;
+ if (!(ahc->type & AHC_WIDE))
+ max_targ = 8;
+
+ for (i = 0; i < max_targ; i++) {
+ u_char target_settings = inb(HA_TARG_SCRATCH + i + iobase);
+#if 0 /* XXXX */
+ target_settings |= 0x8f;
+#endif
+ if (target_settings & 0x0f) {
+ ahc->needsdtr_orig |= (0x01 << i);
+ /* Default to a asyncronous transfers (0 offset) */
+ target_settings &= 0xf0;
+ }
+ if (target_settings & 0x80) {
+ ahc->needwdtr_orig |= (0x01 << i);
+ /*
+ * We'll set the Wide flag when we
+ * are successful with Wide negotiation,
+ * so turn it off for now so we aren't
+ * confused.
+ */
+ target_settings &= 0x7f;
+ }
+ outb(HA_TARG_SCRATCH + i + iobase, target_settings);
+ }
+ /*
+ * If we are not a WIDE device, forget WDTR. This
+ * makes the driver work on some cards that don't
+ * leave these fields cleared when the BIOS is not
+ * installed.
+ */
+ if (!(ahc->type & AHC_WIDE))
+ ahc->needwdtr_orig = 0;
+ ahc->needsdtr = ahc->needsdtr_orig;
+ ahc->needwdtr = ahc->needwdtr_orig;
+ ahc->sdtrpending = 0;
+ ahc->wdtrpending = 0;
+ ahc->tagenable = 0;
+
+ /*
+ * Clear the control byte for every SCB so that the sequencer
+ * doesn't get confused and think that one of them is valid
+ */
+ for (i = 0; i < ahc->maxscbs; i++) {
+ outb(SCBPTR + iobase, i);
+ outb(SCBARRAY + iobase, 0);
+ }
+
+#ifdef AHC_DEBUG
+ printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n", ahc->needsdtr,
+ ahc->needwdtr);
+#endif
+
+ /*
+ * Set the number of availible SCBs
+ */
+ outb(HA_SCBCOUNT + iobase, ahc->maxscbs);
+
+ /* We don't have any busy targets right now */
+ outb(HA_ACTIVE0 + iobase, 0);
+ outb(HA_ACTIVE1 + iobase, 0);
+
+ /* We don't have any waiting selections */
+ outb(WAITING_SCBH + iobase, SCB_LIST_NULL);
+ outb(WAITING_SCBT + iobase, SCB_LIST_NULL);
+ /*
+ * Load the Sequencer program and Enable the adapter.
+ * Place the aic7770 in fastmode which makes a big
+ * difference when doing many small block transfers.
+ */
+
+ printf("%s: Downloading Sequencer Program...", ahc->sc_dev.dv_xname);
+ ahc_loadseq(iobase);
+ printf("Done\n");
+
+ if (!(ahc->type & AHC_AIC7870))
+ outb(BCTL + iobase, ENABLE);
+
+ /* Reset the bus */
+ outb(SCSISEQ + iobase, SCSIRSTO);
+ delay(1000);
+ outb(SCSISEQ + iobase, 0);
+
+ RESTART_SEQUENCER(ahc);
+
+ return (0);
+}
+
+void
+ahcminphys(bp)
+ struct buf *bp;
+{
+
+ if (bp->b_bcount > ((AHC_NSEG - 1) << PGSHIFT))
+ bp->b_bcount = ((AHC_NSEG - 1) << PGSHIFT);
+ minphys(bp);
+}
+
+/*
+ * start a scsi operation given the command and
+ * the data address, target, and lun all of which
+ * are stored in the scsi_xfer struct
+ */
+int
+ahc_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct ahc_softc *ahc = sc_link->adapter_softc;
+ struct ahc_scb *scb;
+ struct ahc_dma_seg *sg;
+ int seg; /* scatter gather seg being worked on */
+ u_long thiskv, thisphys, nextphys;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ int s;
+ u_short mask = (0x01 << (sc_link->target | (sc_link->quirks & 0x08)));
+
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ printf("ahc ahc_scsi_cmd for %x\n", sc_link->target);
+ sc_link->flags = 0xf0;
+ SC_DEBUG(sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
+ }
+#endif
+
+ /*
+ * get a scb to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if ((flags & (ITSDONE|INUSE)) != INUSE) {
+ printf("%s: done or not in use?\n", ahc->sc_dev.dv_xname);
+ xs->flags &= ~ITSDONE;
+ xs->flags |= INUSE;
+ }
+ if ((scb = ahc_get_scb(ahc, flags)) == NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ scb->xs = xs;
+
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUG(sc_link, SDEV_DB3, ("start scb(%x)\n", scb));
+ }
+#endif
+
+ if (flags & SCSI_RESET) {
+ /* XXX: Needs Implementation */
+ printf("ahc: SCSI_RESET called.\n");
+ }
+
+ /*
+ * Put all the arguments for the xfer in the scb
+ */
+ scb->control = 0;
+ if (ahc->tagenable & mask)
+ scb->control |= SCB_TE;
+ if ((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask)) {
+ scb->control |= SCB_NEEDWDTR;
+ ahc->wdtrpending |= mask;
+ }
+ if ((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) {
+ scb->control |= SCB_NEEDSDTR;
+ ahc->sdtrpending |= mask;
+ }
+ scb->target_channel_lun = ((sc_link->target << 4) & 0xF0) |
+ (sc_link->quirks & 0x08) | (sc_link->lun & 0x07);
+ scb->cmdlen = xs->cmdlen;
+ scb->cmdpointer = vtophys(xs->cmd);
+
+ xs->resid = 0;
+ if (xs->datalen) {
+ scb->SG_list_pointer = vtophys(scb->ahc_dma);
+ sg = scb->ahc_dma;
+ seg = 0;
+ {
+ /*
+ * Set up the scatter gather block
+ */
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUG(sc_link, SDEV_DB4,
+ ("%ld @%x:- ", xs->datalen, xs->data));
+ }
+#endif
+ datalen = xs->datalen;
+ thiskv = (long) xs->data;
+ thisphys = vtophys(thiskv);
+
+ while (datalen && seg < AHC_NSEG) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->seg_addr = thisphys;
+
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUGN(sc_link, SDEV_DB4, ("0x%lx",
+ thisphys));
+ }
+#endif
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while (datalen && thisphys == nextphys) {
+ /*
+ * This page is contiguous (physically)
+ * with the the last, just extend the
+ * length
+ */
+ /* how far to the end of the page */
+ nextphys = (thisphys & ~PGOFSET) + NBPG;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page,
+ datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & ~PGOFSET) + NBPG;
+ if (datalen)
+ thisphys = vtophys(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x)",
+ bytes_this_seg));
+ }
+#endif
+ sg->seg_len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ }
+ /*end of iov/kv decision */
+ scb->SG_segment_count = seg;
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
+ }
+#endif
+ if (datalen) {
+ /*
+ * there's still data, must have run out of segs!
+ */
+ printf("%s: ahc_scsi_cmd: more than %d dma segs\n",
+ ahc->sc_dev.dv_xname, AHC_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ ahc_free_scb(ahc, scb, flags);
+ return (COMPLETE);
+ }
+ } else {
+ scb->SG_list_pointer = (physaddr)0;
+ scb->SG_segment_count = 0;
+ }
+
+#ifdef AHC_DEBUG
+ if (sc_link->target == DEBUGTARGET)
+ ahc_print_scb(scb);
+#endif
+
+ s = splbio();
+
+ ahc_send_scb(ahc, scb);
+
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if ((flags & SCSI_POLL) == 0) {
+ timeout(ahc_timeout, scb, (xs->timeout * hz) / 1000);
+ splx(s);
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
+ }
+#endif
+ return (SUCCESSFULLY_QUEUED);
+ }
+
+ splx(s);
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+#ifdef AHC_MORE_DEBUG
+ if ((sc_link->target & 0xf) == DEBUGTARGET) {
+ sc_link->flags = 0xf0;
+ SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n"));
+ }
+#endif
+ if (ahc_poll(ahc, xs, xs->timeout)) {
+ ahc_timeout(scb);
+ if (ahc_poll(ahc, xs, 2000))
+ ahc_timeout(scb);
+ }
+ return (COMPLETE);
+}
+
+
+/*
+ * A scb (and hence an scb entry on the board is put onto the
+ * free list.
+ */
+void
+ahc_free_scb(ahc, scb, flags)
+ struct ahc_softc *ahc;
+ struct ahc_scb *scb;
+ int flags;
+{
+ int s;
+
+ s = splbio();
+
+ scb->flags = SCB_FREE;
+ TAILQ_INSERT_TAIL(&ahc->free_scb, scb, chain);
+#ifdef AHC_DEBUG
+ ahc->activescbs--;
+#endif
+
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if (scb->chain.tqe_next == 0)
+ wakeup(&ahc->free_scb);
+
+ splx(s);
+}
+
+/* XXXX check */
+static inline void
+ahc_init_scb(ahc, scb)
+ struct ahc_softc *ahc;
+ struct ahc_scb *scb;
+{
+ int iobase = ahc->sc_iobase;
+ u_char scb_index;
+
+ bzero(scb, sizeof(struct ahc_scb));
+ scb->position = ahc->numscbs;
+ /*
+ * Place in the scbarray
+ * Never is removed. Position
+ * in ahc->scbarray is the scbarray
+ * position on the board we will
+ * load it into.
+ */
+ ahc->scbarray[scb->position] = scb;
+
+ /*
+ * Initialize the host memory location
+ * of this SCB down on the board and
+ * flag that it should be DMA's before
+ * reference. Also set its psuedo
+ * next pointer (for use in the psuedo
+ * list of SCBs waiting for selection)
+ * to SCB_LIST_NULL.
+ */
+ scb->control = SCB_NEEDDMA;
+ scb->host_scb = vtophys(scb);
+ scb->next_waiting = SCB_LIST_NULL;
+ PAUSE_SEQUENCER(ahc);
+ scb_index = inb(SCBPTR + iobase);
+ outb(SCBPTR + iobase, scb->position);
+ outb(SCBCNT + iobase, SCBAUTO);
+ outsb(SCBARRAY + iobase, scb, 31);
+ outb(SCBCNT + iobase, 0);
+ outb(SCBPTR + iobase, scb_index);
+ UNPAUSE_SEQUENCER(ahc);
+ scb->control = 0;
+}
+
+static inline void
+ahc_reset_scb(ahc, scb)
+ struct ahc_softc *ahc;
+ struct ahc_scb *scb;
+{
+
+ bzero(scb, SCB_BZERO_SIZE);
+}
+
+/*
+ * Get a free scb
+ *
+ * If there are none, see if we can allocate a new one.
+ */
+struct ahc_scb *
+ahc_get_scb(ahc, flags)
+ struct ahc_softc *ahc;
+ int flags;
+{
+ struct ahc_scb *scb;
+ int s;
+
+ s = splbio();
+
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ for (;;) {
+ scb = ahc->free_scb.tqh_first;
+ if (scb) {
+ TAILQ_REMOVE(&ahc->free_scb, scb, chain);
+ break;
+ }
+ if (ahc->numscbs < ahc->maxscbs) {
+ if (scb = (struct ahc_scb *) malloc(sizeof(struct ahc_scb),
+ M_TEMP, M_NOWAIT)) {
+ ahc_init_scb(ahc, scb);
+ ahc->numscbs++;
+ } else {
+ printf("%s: can't malloc scb\n",
+ ahc->sc_dev.dv_xname);
+ goto out;
+ }
+ break;
+ }
+ if ((flags & SCSI_NOSLEEP) != 0)
+ goto out;
+ tsleep(&ahc->free_scb, PRIBIO, "ahcscb", 0);
+ }
+
+ ahc_reset_scb(ahc, scb);
+ scb->flags = SCB_ACTIVE;
+#ifdef AHC_DEBUG
+ ahc->activescbs++;
+ if (ahc->activescbs == ahc->maxscbs)
+ printf("%s: Max SCBs active\n", ahc->sc_dev.dv_xname);
+#endif
+
+out:
+ splx(s);
+ return (scb);
+}
+
+/* XXXX check */
+void
+ahc_loadseq(iobase)
+ int iobase;
+{
+ static u_char seqprog[] = {
+# include "aic7xxx_seq.h"
+ };
+
+ outb(SEQCTL + iobase, PERRORDIS|SEQRESET|LOADRAM);
+ outsb(SEQRAM + iobase, seqprog, sizeof(seqprog));
+ outb(SEQCTL + iobase, FASTMODE|SEQRESET);
+}
+
+/*
+ * Function to poll for command completion when in poll mode
+ */
+int
+ahc_poll(ahc, xs, count)
+ struct ahc_softc *ahc;
+ struct scsi_xfer *xs;
+ int count;
+{ /* in msec */
+ int iobase = ahc->sc_iobase;
+ int stport = INTSTAT + iobase;
+
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ if (inb(stport) & INT_PEND)
+ ahcintr(ahc);
+ if (xs->flags & ITSDONE)
+ return 0;
+ delay(1000);
+ count--;
+ }
+ return 1;
+}
+
+/* XXXX check */
+void
+ahc_abort_scb(ahc, scb)
+ struct ahc_softc *ahc;
+ struct ahc_scb *scb;
+{
+ int iobase = ahc->sc_iobase;
+ int found = 0;
+ int scb_index;
+ u_char flags;
+ u_char scb_control;
+
+ PAUSE_SEQUENCER(ahc);
+ /*
+ * Case 1: In the QINFIFO
+ */
+ {
+ int saved_queue[AHC_SCB_MAX];
+ int i;
+ int queued = inb(QINCNT + iobase);
+
+ for (i = 0; i < (queued - found); i++) {
+ saved_queue[i] = inb(QINFIFO + iobase);
+ if (saved_queue[i] == scb->position) {
+ i--;
+ found = 1;
+ }
+ }
+ /* Re-insert entries back into the queue */
+ for (queued = 0; queued < i; queued++)
+ outb(QINFIFO + iobase, saved_queue[queued]);
+
+ if (found)
+ goto done;
+ }
+
+ scb_index = inb(SCBPTR + iobase);
+ /*
+ * Case 2: Not the active command
+ */
+ if (scb_index != scb->position) {
+ /*
+ * Select the SCB we want to abort
+ * and turn off the disconnected bit.
+ * the driver will then abort the command
+ * and notify us of the abort.
+ */
+ outb(SCBPTR + iobase, scb->position);
+ scb_control = inb(SCBARRAY + iobase);
+ scb_control &= ~SCB_DIS;
+ outb(SCBARRAY + iobase, scb_control);
+ outb(SCBPTR + iobase, scb_index);
+ goto done;
+ }
+ scb_control = inb(SCBARRAY + iobase);
+ if (scb_control & SCB_DIS) {
+ scb_control &= ~SCB_DIS;
+ outb(SCBARRAY + iobase, scb_control);
+ goto done;
+ }
+ /*
+ * Case 3: Currently active command
+ */
+ if ((flags = inb(HA_FLAGS + iobase)) & ACTIVE_MSG) {
+ /*
+ * If there's a message in progress,
+ * reset the bus and have all devices renegotiate.
+ */
+ if (scb->target_channel_lun & 0x08) {
+ ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00);
+ ahc->sdtrpending &= 0x00ff;
+ outb(HA_ACTIVE1, 0);
+ } else if (ahc->type & AHC_WIDE) {
+ ahc->needsdtr = ahc->needsdtr_orig;
+ ahc->needwdtr = ahc->needwdtr_orig;
+ ahc->sdtrpending = 0;
+ ahc->wdtrpending = 0;
+ outb(HA_ACTIVE0, 0);
+ outb(HA_ACTIVE1, 0);
+ } else {
+ ahc->needsdtr |= (ahc->needsdtr_orig & 0x00ff);
+ ahc->sdtrpending &= 0xff00;
+ outb(HA_ACTIVE0, 0);
+ }
+
+ /* Reset the bus */
+ outb(SCSISEQ + iobase, SCSIRSTO);
+ delay(1000);
+ outb(SCSISEQ + iobase, 0);
+ goto done;
+ }
+
+ /*
+ * Otherwise, set up an abort message and have the sequencer
+ * clean up
+ */
+ outb(HA_FLAGS + iobase, flags | ACTIVE_MSG);
+ outb(HA_MSG_LEN + iobase, 1);
+ outb(HA_MSG_START + iobase, MSG_ABORT);
+
+ outb(SCSISIGO + iobase, inb(HA_SIGSTATE + iobase) | 0x10);
+
+done:
+ scb->flags = SCB_ABORTED;
+ UNPAUSE_SEQUENCER(ahc);
+ ahc_done(ahc, scb);
+ return;
+}
+
+void
+ahc_timeout(arg)
+ void *arg;
+{
+ struct ahc_scb *scb = arg;
+ struct scsi_xfer *xs = scb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct ahc_softc *ahc = sc_link->adapter_softc;
+ int s;
+
+ sc_print_addr(sc_link);
+ printf("timed out");
+
+ s = splbio();
+
+#ifdef SCSIDEBUG
+ show_scsi_cmd(scb->xs);
+#endif
+#ifdef AHC_DEBUG
+ if (ahc_debug & AHC_SHOWSCBS)
+ ahc_print_active_scb(ahc);
+#endif /*AHC_DEBUG */
+
+ if (scb->flags & SCB_IMMED) {
+ printf("\n");
+ scb->xs->retries = 0; /* I MEAN IT ! */
+ scb->flags |= SCB_IMMED_FAIL;
+ ahc_done(ahc, scb);
+ splx(s);
+ return;
+ }
+
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (scb->flags == SCB_ABORTED) {
+ /* abort timed out */
+ printf(" AGAIN\n");
+ scb->xs->retries = 0; /* I MEAN IT ! */
+ ahc_done(ahc, scb);
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ scb->xs->error = XS_TIMEOUT;
+ scb->flags = SCB_ABORTED;
+ ahc_abort_scb(ahc, scb);
+ /* 2 secs for the abort */
+ if ((xs->flags & SCSI_POLL) == 0)
+ timeout(ahc_timeout, scb, 2 * hz);
+ }
+
+ splx(s);
+}
diff --git a/sys/dev/ic/aic7xxxvar.h b/sys/dev/ic/aic7xxxvar.h
new file mode 100644
index 00000000000..1ba2546a0a6
--- /dev/null
+++ b/sys/dev/ic/aic7xxxvar.h
@@ -0,0 +1,168 @@
+/*
+ * Interface to the generic driver for the aic7xxx based adaptec
+ * SCSI controllers. This is used to implement product specific
+ * probe and attach routines.
+ *
+ * Copyright (c) 1994, 1995 Justin T. Gibbs.
+ * 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 immediately at the beginning of the file, without modification,
+ * 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. Absolutely no warranty of function or purpose is made by the author
+ * Justin T. Gibbs.
+ * 4. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ * $Id: aic7xxxvar.h,v 1.1 1995/10/18 08:52:30 deraadt Exp $
+ */
+
+#ifndef _AIC7XXX_H_
+#define _AIC7XXX_H_
+
+/*#include "ahc.h" /* for NAHC from config */
+
+#define AHC_NSEG 256 /* number of dma segments supported */
+
+#define AHC_SCB_MAX 16 /*
+ * Up to 16 SCBs on some types of aic7xxx based
+ * boards. The aic7770 family only have 4
+ */
+
+/* #define AHCDEBUG */
+
+typedef u_long physaddr;
+typedef u_long physlen;
+
+struct ahc_dma_seg {
+ physaddr seg_addr;
+ physlen seg_len;
+};
+
+typedef u_char ahc_type;
+#define AHC_NONE 0x00
+#define AHC_WIDE 0x02 /* Wide Channel */
+#define AHC_TWIN 0x08 /* Twin Channel */
+#define AHC_274 0x10 /* EISA Based Controller */
+#define AHC_284 0x20 /* VL/ISA Based Controller */
+#define AHC_AIC7870 0x40 /* PCI Based Controller */
+#define AHC_294 0xc0 /* PCI Based Controller */
+
+/*
+ * The driver keeps up to MAX_SCB scb structures per card in memory. Only the
+ * first 26 bytes of the structure are valid for the hardware, the rest used
+ * for driver level bookeeping. The "__attribute ((packed))" tags ensure that
+ * gcc does not attempt to pad the long ints in the structure to word
+ * boundaries since the first 26 bytes of this structure must have the correct
+ * offsets for the hardware to find them. The driver is further optimized
+ * so that we only have to download the first 19 bytes since as long
+ * as we always use S/G, the last fields should be zero anyway.
+ */
+#if __GNUC__ >= 2
+#if __GNUC_MINOR__ <5
+#pragma pack(1)
+#endif
+#endif
+
+struct ahc_scb {
+/* ------------ Begin hardware supported fields ---------------- */
+/*1*/ u_char control;
+#define SCB_NEEDWDTR 0x80 /* Initiate Wide Negotiation */
+#define SCB_NEEDSDTR 0x40 /* Initiate Sync Negotiation */
+#define SCB_TE 0x20 /* Tag enable */
+#define SCB_NEEDDMA 0x08 /* Refresh SCB from host ram */
+#define SCB_DIS 0x04
+#define SCB_TAG_TYPE 0x3
+#define SIMPLE_QUEUE 0x0
+#define HEAD_QUEUE 0x1
+#define OR_QUEUE 0x2
+/*2*/ u_char target_channel_lun; /* 4/1/3 bits */
+/*3*/ u_char SG_segment_count;
+/*7*/ physaddr SG_list_pointer __attribute__ ((packed));
+/*11*/ physaddr cmdpointer __attribute__ ((packed));
+/*12*/ u_char cmdlen;
+/*14*/ u_char RESERVED[2]; /* must be zero */
+/*15*/ u_char target_status;
+/*18*/ u_char residual_data_count[3];
+/*19*/ u_char residual_SG_segment_count;
+#define SCB_DOWN_SIZE 19 /* amount to actually download */
+#define SCB_BZERO_SIZE 19 /*
+ * amount we need to clear between
+ * commands
+ */
+/*23*/ physaddr data __attribute__ ((packed));
+/*26*/ u_char datalen[3];
+#define SCB_UP_SIZE 26 /*
+ * amount we need to upload to perform
+ * a request sense.
+ */
+/*30*/ physaddr host_scb __attribute__ ((packed));
+/*31*/ u_char next_waiting; /* Used to thread SCBs awaiting
+ * selection
+ */
+#define SCB_LIST_NULL 0x10 /* SCB list equivelent to NULL */
+#if 0
+ /*
+ * No real point in transferring this to the
+ * SCB registers.
+ */
+ unsigned char RESERVED[1];
+#endif
+ /*-----------------end of hardware supported fields----------------*/
+ TAILQ_ENTRY(ahc_scb) chain;
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ int flags;
+#define SCB_FREE 0
+#define SCB_ACTIVE 1
+#define SCB_ABORTED 2
+#define SCB_CHKSENSE 3
+#define SCB_IMMED 4
+#define SCB_IMMED_FAIL 8
+ int position; /* Position in scbarray */
+ struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed));
+ struct scsi_sense sense_cmd; /* SCSI command block */
+};
+
+#if __GNUC__ >= 2
+#if __GNUC_MINOR__ <5
+#pragma pack(4)
+#endif
+#endif
+
+struct ahc_softc {
+ struct device sc_dev;
+ void *sc_ih;
+
+ int sc_iobase;
+ int sc_irq;
+
+ ahc_type type;
+
+ struct ahc_scb *scbarray[AHC_SCB_MAX]; /* Mirror boards scbarray */
+ TAILQ_HEAD(, ahc_scb) free_scb;
+ int ahc_scsi_dev; /* our scsi id */
+ int ahc_scsi_dev_b; /* B channel scsi id */
+ struct ahc_scb *immed_ecb; /* an outstanding immediete command */
+ struct scsi_link sc_link;
+ struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
+ u_short needsdtr_orig; /* Targets we initiate sync neg with */
+ u_short needwdtr_orig; /* Targets we initiate wide neg with */
+ u_short needsdtr; /* Current list of negotiated targets */
+ u_short needwdtr; /* Current list of negotiated targets */
+ u_short sdtrpending; /* Pending SDTR to these targets */
+ u_short wdtrpending; /* Pending WDTR to these targets */
+ u_short tagenable; /* Targets that can handle tagqueing */
+ int numscbs;
+ int activescbs;
+ u_char maxscbs;
+ u_char unpause;
+ u_char pause;
+};
+
+#endif /* _AIC7XXX_H_ */
diff --git a/sys/dev/ic/am7930reg.h b/sys/dev/ic/am7930reg.h
new file mode 100644
index 00000000000..192dffe0c6d
--- /dev/null
+++ b/sys/dev/ic/am7930reg.h
@@ -0,0 +1,153 @@
+/* $NetBSD: am7930reg.h,v 1.1 1995/04/24 19:17:17 pk Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * @(#)bsd_audioreg.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Bit encodings for chip commands from "Microprocessor Access Guide for
+ * Indirect Registers", p.19 Am79C30A/32A Advanced Micro Devices spec
+ * sheet (preliminary).
+ *
+ * Indirect register numbers (the value written into cr to select a given
+ * chip registers) have the form AMDR_*. Register fields look like AMD_*.
+ */
+
+struct amd7930 {
+ u_char cr; /* command register (wo) */
+#define ir cr /* interrupt register (ro) */
+ u_char dr; /* data register (rw) */
+ u_char dsr1; /* D-channel status register 1 (ro) */
+ u_char der; /* D-channel error register (ro) */
+ u_char dctb; /* D-channel transmit register (wo) */
+#define dcrb dctb /* D-channel receive register (ro) */
+ u_char bbtb; /* Bb-channel transmit register (wo) */
+#define bbrb bbtb /* Bb-channel receive register (ro) */
+ u_char bctb; /* Bc-channel transmit register (wo) */
+#define bcrb bctb /* Bc-channel receive register (ro) */
+ u_char dsr2; /* D-channel status register 2 (ro) */
+};
+
+#define AMDR_INIT 0x21
+#define AMD_INIT_PMS_IDLE 0x00
+#define AMD_INIT_PMS_ACTIVE 0x01
+#define AMD_INIT_PMS_ACTIVE_DATA 0x02
+#define AMD_INIT_INT_DISABLE (0x01 << 2)
+#define AMD_INIT_CDS_DIV2 (0x00 << 3)
+#define AMD_INIT_CDS_DIV1 (0x01 << 3)
+#define AMD_INIT_CDS_DIV4 (0x02 << 3)
+#define AMD_INIT_AS_RX (0x01 << 6)
+#define AMD_INIT_AS_TX (0x01 << 7)
+
+#define AMDR_LIU_LSR 0xa1
+#define AMDR_LIU_LPR 0xa2
+#define AMDR_LIU_LMR1 0xa3
+#define AMDR_LIU_LMR2 0xa4
+#define AMDR_LIU_2_4 0xa5
+#define AMDR_LIU_MF 0xa6
+#define AMDR_LIU_MFSB 0xa7
+#define AMDR_LIU_MFQB 0xa8
+
+#define AMDR_MUX_MCR1 0x41
+#define AMDR_MUX_MCR2 0x42
+#define AMDR_MUX_MCR3 0x43
+#define AMD_MCRCHAN_NC 0x00
+#define AMD_MCRCHAN_B1 0x01
+#define AMD_MCRCHAN_B2 0x02
+#define AMD_MCRCHAN_BA 0x03
+#define AMD_MCRCHAN_BB 0x04
+#define AMD_MCRCHAN_BC 0x05
+#define AMD_MCRCHAN_BD 0x06
+#define AMD_MCRCHAN_BE 0x07
+#define AMD_MCRCHAN_BF 0x08
+#define AMDR_MUX_MCR4 0x44
+#define AMD_MCR4_INT_ENABLE (1 << 3)
+#define AMD_MCR4_SWAPBB (1 << 4)
+#define AMD_MCR4_SWAPBC (1 << 5)
+
+#define AMDR_MUX_1_4 0x45
+
+#define AMDR_MAP_X 0x61
+#define AMDR_MAP_R 0x62
+#define AMDR_MAP_GX 0x63
+#define AMDR_MAP_GR 0x64
+#define AMDR_MAP_GER 0x65
+#define AMDR_MAP_STG 0x66
+#define AMDR_MAP_FTGR 0x67
+#define AMDR_MAP_ATGR 0x68
+#define AMDR_MAP_MMR1 0x69
+#define AMD_MMR1_ALAW 0x01
+#define AMD_MMR1_GX 0x02
+#define AMD_MMR1_GR 0x04
+#define AMD_MMR1_GER 0x08
+#define AMD_MMR1_X 0x10
+#define AMD_MMR1_R 0x20
+#define AMD_MMR1_STG 0x40
+#define AMD_MMR1_LOOP 0x80
+#define AMDR_MAP_MMR2 0x6a
+#define AMD_MMR2_AINB 0x01
+#define AMD_MMR2_LS 0x02
+#define AMD_MMR2_DTMF 0x04
+#define AMD_MMR2_GEN 0x08
+#define AMD_MMR2_RNG 0x10
+#define AMD_MMR2_DIS_HPF 0x20
+#define AMD_MMR2_DIS_AZ 0x40
+#define AMDR_MAP_1_10 0x6b
+
+#define AMDR_DLC_FRAR123 0x81
+#define AMDR_DLC_SRAR123 0x82
+#define AMDR_DLC_TAR 0x83
+#define AMDR_DLC_DRLR 0x84
+#define AMDR_DLC_DTCR 0x85
+#define AMDR_DLC_DMR1 0x86
+#define AMDR_DLC_DMR2 0x87
+#define AMDR_DLC_1_7 0x88
+#define AMDR_DLC_DRCR 0x89
+#define AMDR_DLC_RNGR1 0x8a
+#define AMDR_DLC_RNGR2 0x8b
+#define AMDR_DLC_FRAR4 0x8c
+#define AMDR_DLC_SRAR4 0x8d
+#define AMDR_DLC_DMR3 0x8e
+#define AMDR_DLC_DMR4 0x8f
+#define AMDR_DLC_12_15 0x90
+#define AMDR_DLC_ASR 0x91
diff --git a/sys/dev/ic/am7990.c b/sys/dev/ic/am7990.c
new file mode 100644
index 00000000000..d1a8ef3d68d
--- /dev/null
+++ b/sys/dev/ic/am7990.c
@@ -0,0 +1,1218 @@
+/* $NetBSD: am7990.c,v 1.3 1995/07/24 04:34:51 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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.
+ *
+ * @(#)if_le.c 8.2 (Berkeley) 11/16/93
+ */
+
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+
+#ifdef INET
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if defined(CCITT) && defined(LLC)
+#include <sys/socketvar.h>
+#include <netccitt/x25.h>
+extern llc_ctlinput(), cons_rtrequest();
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#ifdef LEDEBUG
+void recv_print __P((struct le_softc *, int));
+void xmit_print __P((struct le_softc *, int));
+#endif
+
+void
+leconfig(sc)
+ struct le_softc *sc;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ int mem;
+
+ /* Make sure the chip is stopped. */
+ lestop(sc);
+
+ /* Initialize ifnet structure. */
+ ifp->if_unit = sc->sc_dev.dv_unit;
+ ifp->if_start = lestart;
+ ifp->if_ioctl = leioctl;
+ ifp->if_watchdog = lewatchdog;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
+
+ /* Attach the interface. */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ switch (sc->sc_memsize) {
+ case 8192:
+ sc->sc_nrbuf = 4;
+ sc->sc_ntbuf = 1;
+ break;
+ case 16384:
+ sc->sc_nrbuf = 8;
+ sc->sc_ntbuf = 2;
+ break;
+ case 32768:
+ sc->sc_nrbuf = 16;
+ sc->sc_ntbuf = 4;
+ break;
+ case 65536:
+ sc->sc_nrbuf = 32;
+ sc->sc_ntbuf = 8;
+ break;
+ default:
+ panic("leconfig: weird memory size");
+ }
+
+ printf(": address %s, %d receive buffers, %d transmit buffers\n",
+ ether_sprintf(sc->sc_arpcom.ac_enaddr),
+ sc->sc_nrbuf, sc->sc_ntbuf);
+
+ mem = 0;
+ sc->sc_initaddr = mem;
+ mem += sizeof(struct leinit);
+ sc->sc_rmdaddr = mem;
+ mem += sizeof(struct lermd) * sc->sc_nrbuf;
+ sc->sc_tmdaddr = mem;
+ mem += sizeof(struct letmd) * sc->sc_ntbuf;
+ sc->sc_rbufaddr = mem;
+ mem += LEBLEN * sc->sc_nrbuf;
+ sc->sc_tbufaddr = mem;
+ mem += LEBLEN * sc->sc_ntbuf;
+#ifdef notyet
+ if (mem > ...)
+ panic(...);
+#endif
+}
+
+void
+lereset(sc)
+ struct le_softc *sc;
+{
+ int s;
+
+ s = splimp();
+ leinit(sc);
+ splx(s);
+}
+
+void
+lewatchdog(unit)
+ short unit;
+{
+ struct le_softc *sc = LE_SOFTC(unit);
+
+ log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
+ ++sc->sc_arpcom.ac_if.if_oerrors;
+
+ lereset(sc);
+}
+
+/*
+ * Set up the initialization block and the descriptor rings.
+ */
+void
+lememinit(sc)
+ register struct le_softc *sc;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ u_long a;
+ int bix;
+ struct leinit init;
+ struct lermd rmd;
+ struct letmd tmd;
+
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC)
+ init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
+ else
+#endif
+ init.init_mode = LE_MODE_NORMAL;
+ init.init_padr[0] =
+ (sc->sc_arpcom.ac_enaddr[1] << 8) | sc->sc_arpcom.ac_enaddr[0];
+ init.init_padr[1] =
+ (sc->sc_arpcom.ac_enaddr[3] << 8) | sc->sc_arpcom.ac_enaddr[2];
+ init.init_padr[2] =
+ (sc->sc_arpcom.ac_enaddr[5] << 8) | sc->sc_arpcom.ac_enaddr[4];
+ lesetladrf(&sc->sc_arpcom, init.init_ladrf);
+
+ sc->sc_last_rd = 0;
+ sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
+
+ a = sc->sc_addr + LE_RMDADDR(sc, 0);
+ init.init_rdra = a;
+ init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
+
+ a = sc->sc_addr + LE_TMDADDR(sc, 0);
+ init.init_tdra = a;
+ init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
+
+ (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
+
+ /*
+ * Set up receive ring descriptors.
+ */
+ for (bix = 0; bix < sc->sc_nrbuf; bix++) {
+ a = sc->sc_addr + LE_RBUFADDR(sc, bix);
+ rmd.rmd0 = a;
+ rmd.rmd1_hadr = a >> 16;
+ rmd.rmd1_bits = LE_R1_OWN;
+ rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
+ rmd.rmd3 = 0;
+ (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
+ sizeof(rmd));
+ }
+
+ /*
+ * Set up transmit ring descriptors.
+ */
+ for (bix = 0; bix < sc->sc_ntbuf; bix++) {
+ a = sc->sc_addr + LE_TBUFADDR(sc, bix);
+ tmd.tmd0 = a;
+ tmd.tmd1_hadr = a >> 16;
+ tmd.tmd1_bits = 0;
+ tmd.tmd2 = 0 | LE_XMD2_ONES;
+ tmd.tmd3 = 0;
+ (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
+ sizeof(tmd));
+ }
+}
+
+void
+lestop(sc)
+ struct le_softc *sc;
+{
+
+ lewrcsr(sc, LE_CSR0, LE_C0_STOP);
+}
+
+/*
+ * Initialization of interface; set up initialization block
+ * and transmit/receive descriptor rings.
+ */
+void
+leinit(sc)
+ register struct le_softc *sc;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ register int timo;
+ u_long a;
+
+ lewrcsr(sc, LE_CSR0, LE_C0_STOP);
+ LE_DELAY(100);
+
+ /* Set the correct byte swapping mode, etc. */
+ lewrcsr(sc, LE_CSR3, sc->sc_conf3);
+
+ /* Set up LANCE init block. */
+ lememinit(sc);
+
+ /* Give LANCE the physical address of its init block. */
+ a = sc->sc_addr + LE_INITADDR(sc);
+ lewrcsr(sc, LE_CSR1, a);
+ lewrcsr(sc, LE_CSR2, a >> 16);
+
+ /* Try to initialize the LANCE. */
+ LE_DELAY(100);
+ lewrcsr(sc, LE_CSR0, LE_C0_INIT);
+
+ /* Wait for initialization to finish. */
+ for (timo = 100000; timo; timo--)
+ if (lerdcsr(sc, LE_CSR0) & LE_C0_IDON)
+ break;
+
+ if (lerdcsr(sc, LE_CSR0) & LE_C0_IDON) {
+ /* Start the LANCE. */
+ lewrcsr(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT | LE_C0_IDON);
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_timer = 0;
+ lestart(ifp);
+ } else
+ printf("%s: card failed to initialize\n", sc->sc_dev.dv_xname);
+}
+
+/*
+ * Routine to copy from mbuf chain to transmit buffer in
+ * network buffer memory.
+ */
+integrate int
+leput(sc, boff, m)
+ struct le_softc *sc;
+ int boff;
+ register struct mbuf *m;
+{
+ register struct mbuf *n;
+ register int len, tlen = 0;
+
+ for (; m; m = n) {
+ len = m->m_len;
+ if (len == 0) {
+ MFREE(m, n);
+ continue;
+ }
+ (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
+ boff += len;
+ tlen += len;
+ MFREE(m, n);
+ }
+ if (tlen < LEMINSIZE) {
+ (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
+ tlen = LEMINSIZE;
+ }
+ return (tlen);
+}
+
+/*
+ * Pull data off an interface.
+ * Len is length of data, with local net header stripped.
+ * We copy the data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+integrate struct mbuf *
+leget(sc, boff, totlen)
+ struct le_softc *sc;
+ int boff, totlen;
+{
+ register struct mbuf *m;
+ struct mbuf *top, **mp;
+ int len, pad;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
+ m->m_pkthdr.len = totlen;
+ pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
+ m->m_data += pad;
+ len = MHLEN - pad;
+ top = 0;
+ mp = &top;
+
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return 0;
+ }
+ len = MLEN;
+ }
+ if (top && totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ len = MCLBYTES;
+ }
+ m->m_len = len = min(totlen, len);
+ (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
+ boff += len;
+ totlen -= len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+
+ return (top);
+}
+
+/*
+ * Pass a packet to the higher levels.
+ */
+integrate void
+leread(sc, boff, len)
+ register struct le_softc *sc;
+ int boff, len;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct mbuf *m;
+ struct ether_header *eh;
+
+ if (len <= sizeof(struct ether_header) ||
+ len > ETHERMTU + sizeof(struct ether_header)) {
+ printf("%s: invalid packet size %d; dropping\n",
+ sc->sc_dev.dv_xname, len);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /* Pull packet off interface. */
+ m = leget(sc, boff, len);
+ if (m == 0) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ ifp->if_ipackets++;
+
+ /* We assume that the header fit entirely in one mbuf. */
+ eh = mtod(m, struct ether_header *);
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to BPF.
+ */
+ if (ifp->if_bpf) {
+ bpf_mtap(ifp->if_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 ((ifp->if_flags & IFF_PROMISC) != 0 &&
+ (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
+ bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+ m_freem(m);
+ return;
+ }
+ }
+#endif
+
+ /* Pass the packet up, with the ether header sort-of removed. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+}
+
+integrate void
+lerint(sc)
+ struct le_softc *sc;
+{
+ register int bix;
+ int rp;
+ struct lermd rmd;
+
+ bix = sc->sc_last_rd;
+
+ /* Process all buffers with valid data. */
+ for (;;) {
+ rp = LE_RMDADDR(sc, bix);
+ (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
+
+ if (rmd.rmd1_bits & LE_R1_OWN)
+ break;
+
+ if (rmd.rmd1_bits & LE_R1_ERR) {
+ if (rmd.rmd1_bits & LE_R1_ENP) {
+ if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
+ if (rmd.rmd1_bits & LE_R1_FRAM)
+ printf("%s: framing error\n",
+ sc->sc_dev.dv_xname);
+ if (rmd.rmd1_bits & LE_R1_CRC)
+ printf("%s: crc mismatch\n",
+ sc->sc_dev.dv_xname);
+ }
+ } else {
+ if (rmd.rmd1_bits & LE_R1_OFLO)
+ printf("%s: overflow\n",
+ sc->sc_dev.dv_xname);
+ }
+ if (rmd.rmd1_bits & LE_R1_BUFF)
+ printf("%s: receive buffer error\n",
+ sc->sc_dev.dv_xname);
+ } else if (rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP) !=
+ (LE_R1_STP | LE_R1_ENP)) {
+ printf("%s: dropping chained buffer\n",
+ sc->sc_dev.dv_xname);
+ } else {
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ recv_print(sc, sc->sc_last_rd);
+#endif
+ leread(sc, LE_RBUFADDR(sc, bix), (int)rmd.rmd3 - 4);
+ }
+
+ rmd.rmd1_bits = LE_R1_OWN;
+ rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
+ rmd.rmd3 = 0;
+ (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
+
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ printf("sc->sc_last_rd = %x, rmd = %x\n",
+ sc->sc_last_rd, rmd);
+#endif
+
+ if (++bix == sc->sc_nrbuf)
+ bix = 0;
+ }
+
+ sc->sc_last_rd = bix;
+}
+
+integrate void
+letint(sc)
+ register struct le_softc *sc;
+{
+ register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ register int bix;
+ struct letmd tmd;
+
+ bix = sc->sc_first_td;
+
+ for (;;) {
+ if (sc->sc_no_td <= 0)
+ break;
+
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ printf("trans tmd = %x\n", tmd);
+#endif
+
+ (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
+ sizeof(tmd));
+
+ if (tmd.tmd1_bits & LE_T1_OWN)
+ break;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (tmd.tmd1_bits & LE_T1_ERR) {
+ if (tmd.tmd3 & LE_T3_BUFF)
+ printf("%s: transmit buffer error\n", sc->sc_dev.dv_xname);
+ else if (tmd.tmd3 & LE_T3_UFLO)
+ printf("%s: underflow\n", sc->sc_dev.dv_xname);
+ if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
+ lereset(sc);
+ return;
+ }
+ if (tmd.tmd3 & LE_T3_LCAR)
+ printf("%s: lost carrier\n", sc->sc_dev.dv_xname);
+ if (tmd.tmd3 & LE_T3_LCOL)
+ ifp->if_collisions++;
+ if (tmd.tmd3 & LE_T3_RTRY) {
+ printf("%s: excessive collisions, tdr %d\n",
+ sc->sc_dev.dv_xname, tmd.tmd3 & LE_T3_TDR_MASK);
+ ifp->if_collisions += 16;
+ }
+ ifp->if_oerrors++;
+ } else {
+ if (tmd.tmd1_bits & LE_T1_ONE)
+ ifp->if_collisions++;
+ else if (tmd.tmd1_bits & LE_T1_MORE)
+ /* Real number is unknown. */
+ ifp->if_collisions += 2;
+ ifp->if_opackets++;
+ }
+
+ if (++bix == sc->sc_ntbuf)
+ bix = 0;
+
+ --sc->sc_no_td;
+ }
+
+ sc->sc_first_td = bix;
+
+ lestart(ifp);
+
+ if (sc->sc_no_td == 0)
+ ifp->if_timer = 0;
+}
+
+/*
+ * Controller interrupt.
+ */
+#ifdef LEINTR_UNIT
+int
+leintr(unit)
+ int unit;
+{
+ register struct le_softc *sc = LE_SOFTC(unit);
+#else
+int
+leintr(arg)
+ register void *arg;
+{
+ register struct le_softc *sc = arg;
+#endif
+ register u_int16_t isr;
+
+ isr = lerdcsr(sc, LE_CSR0);
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ printf("%s: leintr entering with isr=%04x\n",
+ sc->sc_dev.dv_xname, isr);
+#endif
+ if ((isr & LE_C0_INTR) == 0)
+ return (0);
+
+ lewrcsr(sc, LE_CSR0,
+ isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
+ LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
+ if (isr & LE_C0_ERR) {
+ if (isr & LE_C0_BABL) {
+ printf("%s: babble\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ }
+#if 0
+ if (isr & LE_C0_CERR) {
+ printf("%s: collision error\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_collisions++;
+ }
+#endif
+ if (isr & LE_C0_MISS)
+ sc->sc_arpcom.ac_if.if_ierrors++;
+ if (isr & LE_C0_MERR) {
+ printf("%s: memory error\n", sc->sc_dev.dv_xname);
+ lereset(sc);
+ return (1);
+ }
+ }
+
+ if ((isr & LE_C0_RXON) == 0) {
+ printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_ierrors++;
+ lereset(sc);
+ return (1);
+ }
+ if ((isr & LE_C0_TXON) == 0) {
+ printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ lereset(sc);
+ return (1);
+ }
+
+ if (isr & LE_C0_RINT)
+ lerint(sc);
+ if (isr & LE_C0_TINT)
+ letint(sc);
+
+ return (1);
+}
+
+/*
+ * Setup output on interface.
+ * Get another datagram to send off of the interface queue, and map it to the
+ * interface before starting the output.
+ * Called only at splimp or interrupt level.
+ */
+void
+lestart(ifp)
+ register struct ifnet *ifp;
+{
+ register struct le_softc *sc = LE_SOFTC(ifp->if_unit);
+ register int bix;
+ register struct mbuf *m;
+ struct letmd tmd;
+ int rp;
+ int len;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ bix = sc->sc_last_td;
+
+ for (;;) {
+ rp = LE_TMDADDR(sc, bix);
+ (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
+
+ if (tmd.tmd1_bits & LE_T1_OWN) {
+ ifp->if_flags |= IFF_OACTIVE;
+ printf("missing buffer, no_td = %d, last_td = %d\n",
+ sc->sc_no_td, sc->sc_last_td);
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ break;
+
+#if NBPFILTER > 0
+ /*
+ * If BPF is listening on this interface, let it see the packet
+ * before we commit it to the wire.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ /*
+ * Copy the mbuf chain into the transmit buffer.
+ */
+ len = leput(sc, LE_TBUFADDR(sc, bix), m);
+
+#ifdef LEDEBUG
+ if (len > ETHERMTU + sizeof(struct ether_header))
+ printf("packet length %d\n", len);
+#endif
+
+ ifp->if_timer = 5;
+
+ /*
+ * Init transmit registers, and set transmit start flag.
+ */
+ tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
+ tmd.tmd2 = -len | LE_XMD2_ONES;
+ tmd.tmd3 = 0;
+
+ (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
+
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ xmit_print(sc, sc->sc_last_td);
+#endif
+
+ lewrcsr(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
+
+ if (++bix == sc->sc_ntbuf)
+ bix = 0;
+
+ if (++sc->sc_no_td == sc->sc_ntbuf) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ }
+
+ sc->sc_last_td = bix;
+}
+
+/*
+ * Process an ioctl request.
+ */
+int
+leioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct le_softc *sc = LE_SOFTC(ifp->if_unit);
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ leinit(sc);
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
+ else
+ bcopy(ina->x_host.c_host,
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+ /* Set new address. */
+ leinit(sc);
+ break;
+ }
+#endif
+ default:
+ leinit(sc);
+ break;
+ }
+ break;
+
+#if defined(CCITT) && defined(LLC)
+ case SIOCSIFCONF_X25:
+ ifp->if_flags |= IFF_UP;
+ ifa->ifa_rtrequest = (void (*)())cons_rtrequest; /* XXX */
+ error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
+ if (error == 0)
+ leinit(sc);
+ break;
+#endif /* CCITT && LLC */
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ lestop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ leinit(sc);
+ } else {
+ /*
+ * Reset the interface to pick up changes in any other
+ * flags that affect hardware registers.
+ */
+ /*lestop(sc);*/
+ leinit(sc);
+ }
+#ifdef LEDEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ sc->sc_debug = 1;
+ else
+ sc->sc_debug = 0;
+#endif
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_arpcom) :
+ ether_delmulti(ifr, &sc->sc_arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ lereset(sc);
+ error = 0;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ splx(s);
+ return (error);
+}
+
+#ifdef LEDEBUG
+void
+recv_print(sc, no)
+ struct le_softc *sc;
+ int no;
+{
+ struct lermd rmd;
+ u_int16_t len;
+ struct ether_header eh;
+
+ (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
+ len = rmd.rmd3;
+ printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
+ len);
+ printf("%s: status %04x\n", sc->sc_dev.dv_xname, lerdcsr(sc, LE_CSR0));
+ printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
+ sc->sc_dev.dv_xname,
+ rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
+ if (len >= sizeof(eh)) {
+ (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
+ printf("%s: dst %s", ether_sprintf(eh.ether_dhost));
+ printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
+ ntohs(eh.ether_type));
+ }
+}
+
+void
+xmit_print(sc, no)
+ struct le_softc *sc;
+ int no;
+{
+ struct letmd tmd;
+ u_int16_t len;
+ struct ether_header eh;
+
+ (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
+ len = -tmd.tmd2;
+ printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
+ len);
+ printf("%s: status %04x\n", sc->sc_dev.dv_xname, lerdcsr(sc, LE_CSR0));
+ printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
+ sc->sc_dev.dv_xname,
+ tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
+ if (len >= sizeof(eh)) {
+ (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
+ printf("%s: dst %s", ether_sprintf(eh.ether_dhost));
+ printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
+ ntohs(eh.ether_type));
+ }
+}
+#endif /* LEDEBUG */
+
+/*
+ * Set up the logical address filter.
+ */
+void
+lesetladrf(ac, af)
+ struct arpcom *ac;
+ u_int16_t *af;
+{
+ struct ifnet *ifp = &ac->ac_if;
+ struct ether_multi *enm;
+ register u_char *cp, c;
+ register u_int32_t crc;
+ register int i, len;
+ struct ether_multistep step;
+
+ /*
+ * Set up multicast address filter by passing all multicast addresses
+ * through a crc generator, and then using the high order 6 bits as an
+ * index into the 64 bit logical address filter. The high order bit
+ * selects the word, while the rest of the bits select the bit within
+ * the word.
+ */
+
+ if (ifp->if_flags & IFF_PROMISC)
+ goto allmulti;
+
+ af[0] = af[1] = af[2] = af[3] = 0x0000;
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
+ sizeof(enm->enm_addrlo)) != 0) {
+ /*
+ * We must listen to a range of multicast addresses.
+ * For now, just accept all multicasts, rather than
+ * trying to set only those filter bits needed to match
+ * the range. (At this time, the only use of address
+ * ranges is for IP multicast routing, for which the
+ * range is big enough to require all bits set.)
+ */
+ goto allmulti;
+ }
+
+ cp = enm->enm_addrlo;
+ crc = 0xffffffff;
+ for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
+ c = *cp++;
+ for (i = 8; --i >= 0;) {
+ if ((crc & 0x01) ^ (c & 0x01)) {
+ crc >>= 1;
+ crc ^= 0xedb88320;
+ } else
+ crc >>= 1;
+ c >>= 1;
+ }
+ }
+ /* Just want the 6 most significant bits. */
+ crc >>= 26;
+
+ /* Set the corresponding bit in the filter. */
+ af[crc >> 4] |= 1 << (crc & 0xf);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ return;
+
+allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ af[0] = af[1] = af[2] = af[3] = 0xffff;
+}
+
+
+#if 0 /* USE OF THE FOLLOWING IS MACHINE-SPECIFIC */
+/*
+ * Routines for accessing the transmit and receive buffers. Unfortunately,
+ * CPU addressing of these buffers is done in one of 3 ways:
+ * - contiguous (for the 3max and turbochannel option card)
+ * - gap2, which means shorts (2 bytes) interspersed with short (2 byte)
+ * spaces (for the pmax)
+ * - gap16, which means 16bytes interspersed with 16byte spaces
+ * for buffers which must begin on a 32byte boundary (for 3min and maxine)
+ * The buffer offset is the logical byte offset, assuming contiguous storage.
+ */
+void
+copytodesc_contig(sc, from, boff, len)
+ struct le_softc *sc;
+ caddr_t from;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just call bcopy() to do the work.
+ */
+ bcopy(from, buf + boff, len);
+}
+
+void
+copyfromdesc_contig(sc, to, boff, len)
+ struct le_softc *sc;
+ caddr_t to;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just call bcopy() to do the work.
+ */
+ bcopy(buf + boff, to, len);
+}
+
+void
+copytobuf_contig(sc, from, boff, len)
+ struct le_softc *sc;
+ caddr_t from;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just call bcopy() to do the work.
+ */
+ bcopy(from, buf + boff, len);
+}
+
+void
+copyfrombuf_contig(sc, to, boff, len)
+ struct le_softc *sc;
+ caddr_t to;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just call bcopy() to do the work.
+ */
+ bcopy(buf + boff, to, len);
+}
+
+void
+zerobuf_contig(sc, boff, len)
+ struct le_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just let bzero() do the work
+ */
+ bzero(buf + boff, len);
+}
+
+/*
+ * For the pmax the buffer consists of shorts (2 bytes) interspersed with
+ * short (2 byte) spaces and must be accessed with halfword load/stores.
+ * (don't worry about doing an extra byte)
+ */
+void
+copytobuf_gap2(sc, from, boff, len)
+ struct le_softc *sc;
+ register caddr_t from;
+ int boff;
+ register int len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register volatile u_short *bptr;
+ register int xfer;
+
+ if (boff & 0x1) {
+ /* handle unaligned first byte */
+ bptr = ((volatile u_short *)buf) + (boff - 1);
+ *bptr = (*from++ << 8) | (*bptr & 0xff);
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_short *)buf) + boff;
+ if ((unsigned)from & 0x1) {
+ while (len > 1) {
+ *bptr = (from[1] << 8) | (from[0] & 0xff);
+ bptr += 2;
+ from += 2;
+ len -= 2;
+ }
+ } else {
+ /* optimize for aligned transfers */
+ xfer = (int)((unsigned)len & ~0x1);
+ CopyToBuffer((u_short *)from, bptr, xfer);
+ bptr += xfer;
+ from += xfer;
+ len -= xfer;
+ }
+ if (len == 1)
+ *bptr = (u_short)*from;
+}
+
+void
+copyfrombuf_gap2(sc, to, boff, len)
+ struct le_softc *sc;
+ register caddr_t to;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register volatile u_short *bptr;
+ register u_short tmp;
+ register int xfer;
+
+ if (boff & 0x1) {
+ /* handle unaligned first byte */
+ bptr = ((volatile u_short *)buf) + (boff - 1);
+ *to++ = (*bptr >> 8) & 0xff;
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_short *)buf) + boff;
+ if ((unsigned)to & 0x1) {
+ while (len > 1) {
+ tmp = *bptr;
+ *to++ = tmp & 0xff;
+ *to++ = (tmp >> 8) & 0xff;
+ bptr += 2;
+ len -= 2;
+ }
+ } else {
+ /* optimize for aligned transfers */
+ xfer = (int)((unsigned)len & ~0x1);
+ CopyFromBuffer(bptr, to, xfer);
+ bptr += xfer;
+ to += xfer;
+ len -= xfer;
+ }
+ if (len == 1)
+ *to = *bptr & 0xff;
+}
+
+void
+zerobuf_gap2(sc, boff, len)
+ struct le_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register volatile u_short *bptr;
+
+ if ((unsigned)boff & 0x1) {
+ bptr = ((volatile u_short *)buf) + (boff - 1);
+ *bptr &= 0xff;
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_short *)buf) + boff;
+ while (len > 0) {
+ *bptr = 0;
+ bptr += 2;
+ len -= 2;
+ }
+}
+
+/*
+ * For the 3min and maxine, the buffers are in main memory filled in with
+ * 16byte blocks interspersed with 16byte spaces.
+ */
+void
+copytobuf_gap16(sc, from, boff, len)
+ struct le_softc *sc;
+ register caddr_t from;
+ int boff;
+ register int len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bcopy(from, bptr + boff, xfer);
+ from += xfer;
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+
+void
+copyfrombuf_gap16(sc, to, boff, len)
+ struct le_softc *sc;
+ register caddr_t to;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bcopy(bptr + boff, to, xfer);
+ to += xfer;
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+
+void
+zerobuf_gap16(sc, boff, len)
+ struct le_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bzero(bptr + boff, xfer);
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+#endif
diff --git a/sys/dev/ic/am7990reg.h b/sys/dev/ic/am7990reg.h
new file mode 100644
index 00000000000..2e563efc20c
--- /dev/null
+++ b/sys/dev/ic/am7990reg.h
@@ -0,0 +1,178 @@
+/* $NetBSD: am7990reg.h,v 1.1 1995/04/11 04:17:50 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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.
+ *
+ * @(#)if_lereg.h 8.1 (Berkeley) 6/10/93
+ */
+
+#define LEBLEN 1536 /* ETHERMTU + header + CRC */
+#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */
+
+/*
+ * Receive message descriptor
+ */
+struct lermd {
+ u_int16_t rmd0;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t rmd1_bits;
+ u_int8_t rmd1_hadr;
+#else
+ u_int8_t rmd1_hadr;
+ u_int8_t rmd1_bits;
+#endif
+ int16_t rmd2;
+ u_int16_t rmd3;
+};
+
+/*
+ * Transmit message descriptor
+ */
+struct letmd {
+ u_int16_t tmd0;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t tmd1_bits;
+ u_int8_t tmd1_hadr;
+#else
+ u_int8_t tmd1_hadr;
+ u_int8_t tmd1_bits;
+#endif
+ int16_t tmd2;
+ u_int16_t tmd3;
+};
+
+/*
+ * Initialization block
+ */
+struct leinit {
+ u_int16_t init_mode; /* +0x0000 */
+ u_int16_t init_padr[3]; /* +0x0002 */
+ u_int16_t init_ladrf[4]; /* +0x0008 */
+ u_int16_t init_rdra; /* +0x0010 */
+ u_int16_t init_rlen; /* +0x0012 */
+ u_int16_t init_tdra; /* +0x0014 */
+ u_int16_t init_tlen; /* +0x0016 */
+ int16_t pad0[4]; /* Pad to 16 shorts */
+};
+
+#define LE_INITADDR(sc) (sc->sc_initaddr)
+#define LE_RMDADDR(sc, bix) (sc->sc_rmdaddr + sizeof(struct lermd) * (bix))
+#define LE_TMDADDR(sc, bix) (sc->sc_tmdaddr + sizeof(struct letmd) * (bix))
+#define LE_RBUFADDR(sc, bix) (sc->sc_rbufaddr + LEBLEN * (bix))
+#define LE_TBUFADDR(sc, bix) (sc->sc_tbufaddr + LEBLEN * (bix))
+
+/* register addresses */
+#define LE_CSR0 0x0000 /* Control and status register */
+#define LE_CSR1 0x0001 /* low address of init block */
+#define LE_CSR2 0x0002 /* high address of init block */
+#define LE_CSR3 0x0003 /* Bus master and control */
+
+/* Control and status register 0 (csr0) */
+#define LE_C0_ERR 0x8000 /* error summary */
+#define LE_C0_BABL 0x4000 /* transmitter timeout error */
+#define LE_C0_CERR 0x2000 /* collision */
+#define LE_C0_MISS 0x1000 /* missed a packet */
+#define LE_C0_MERR 0x0800 /* memory error */
+#define LE_C0_RINT 0x0400 /* receiver interrupt */
+#define LE_C0_TINT 0x0200 /* transmitter interrupt */
+#define LE_C0_IDON 0x0100 /* initalization done */
+#define LE_C0_INTR 0x0080 /* interrupt condition */
+#define LE_C0_INEA 0x0040 /* interrupt enable */
+#define LE_C0_RXON 0x0020 /* receiver on */
+#define LE_C0_TXON 0x0010 /* transmitter on */
+#define LE_C0_TDMD 0x0008 /* transmit demand */
+#define LE_C0_STOP 0x0004 /* disable all external activity */
+#define LE_C0_STRT 0x0002 /* enable external activity */
+#define LE_C0_INIT 0x0001 /* begin initalization */
+
+#define LE_C0_BITS \
+ "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\
+\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"
+
+/* Control and status register 3 (csr3) */
+#define LE_C3_BSWP 0x0004 /* byte swap */
+#define LE_C3_ACON 0x0002 /* ALE control, eh? */
+#define LE_C3_BCON 0x0001 /* byte control */
+
+/* Initialzation block (mode) */
+#define LE_MODE_PROM 0x8000 /* promiscuous mode */
+/* 0x7f80 reserved, must be zero */
+#define LE_MODE_INTL 0x0040 /* internal loopback */
+#define LE_MODE_DRTY 0x0020 /* disable retry */
+#define LE_MODE_COLL 0x0010 /* force a collision */
+#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */
+#define LE_MODE_LOOP 0x0004 /* loopback mode */
+#define LE_MODE_DTX 0x0002 /* disable transmitter */
+#define LE_MODE_DRX 0x0001 /* disable receiver */
+#define LE_MODE_NORMAL 0 /* none of the above */
+
+/* Receive message descriptor 1 (rmd1_bits) */
+#define LE_R1_OWN 0x80 /* LANCE owns the packet */
+#define LE_R1_ERR 0x40 /* error summary */
+#define LE_R1_FRAM 0x20 /* framing error */
+#define LE_R1_OFLO 0x10 /* overflow error */
+#define LE_R1_CRC 0x08 /* CRC error */
+#define LE_R1_BUFF 0x04 /* buffer error */
+#define LE_R1_STP 0x02 /* start of packet */
+#define LE_R1_ENP 0x01 /* end of packet */
+
+#define LE_R1_BITS \
+ "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP"
+
+/* Transmit message descriptor 1 (tmd1_bits) */
+#define LE_T1_OWN 0x80 /* LANCE owns the packet */
+#define LE_T1_ERR 0x40 /* error summary */
+#define LE_T1_MORE 0x10 /* multiple collisions */
+#define LE_T1_ONE 0x08 /* single collision */
+#define LE_T1_DEF 0x04 /* defferred transmit */
+#define LE_T1_STP 0x02 /* start of packet */
+#define LE_T1_ENP 0x01 /* end of packet */
+
+#define LE_T1_BITS \
+ "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP"
+
+/* Transmit message descriptor 3 (tmd3) */
+#define LE_T3_BUFF 0x8000 /* buffer error */
+#define LE_T3_UFLO 0x4000 /* underflow error */
+#define LE_T3_LCOL 0x1000 /* late collision */
+#define LE_T3_LCAR 0x0800 /* loss of carrier */
+#define LE_T3_RTRY 0x0400 /* retry error */
+#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */
+
+#define LE_XMD2_ONES 0xf000
+
+#define LE_T3_BITS \
+ "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"
diff --git a/sys/dev/ic/am7990var.h b/sys/dev/ic/am7990var.h
new file mode 100644
index 00000000000..b1f86584a42
--- /dev/null
+++ b/sys/dev/ic/am7990var.h
@@ -0,0 +1,63 @@
+/* $NetBSD: am7990var.h,v 1.1 1995/06/28 02:24:56 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 Charles M. Hannum. 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 Charles M. Hannum.
+ * 4. 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.
+ */
+
+#ifdef DDB
+#define integrate
+#else
+#define integrate static inline
+#endif
+
+void leconfig __P((struct le_softc *));
+void leinit __P((struct le_softc *));
+int leioctl __P((struct ifnet *, u_long, caddr_t));
+void lememinit __P((struct le_softc *));
+void lereset __P((struct le_softc *));
+void lesetladrf __P((struct arpcom *, u_int16_t *));
+void lestart __P((struct ifnet *));
+void lestop __P((struct le_softc *));
+void lewatchdog __P((/* short */));
+
+integrate u_int16_t lerdcsr __P((/* struct le_softc *, u_int16_t */));
+integrate void lewrcsr __P((/* struct le_softc *, u_int16_t, u_int16_t */));
+
+integrate void lerint __P((struct le_softc *));
+integrate void letint __P((struct le_softc *));
+
+integrate int leput __P((struct le_softc *, int, struct mbuf *));
+integrate struct mbuf *leget __P((struct le_softc *, int, int));
+integrate void leread __P((struct le_softc *, int, int));
+
+void copytodesc_contig(), copyfromdesc_contig();
+void copytobuf_contig(), copyfrombuf_contig(), zerobuf_contig();
+#ifdef 0
+void copytobuf_gap2(), copyfrombuf_gap2(), zerobuf_gap2();
+void copytobuf_gap16(), copyfrombuf_gap16(), zerobuf_gap16();
+#endif
diff --git a/sys/dev/ic/cd1400reg.h b/sys/dev/ic/cd1400reg.h
new file mode 100644
index 00000000000..9481f71f004
--- /dev/null
+++ b/sys/dev/ic/cd1400reg.h
@@ -0,0 +1,123 @@
+/* $NetBSD: cd1400reg.h,v 1.2 1994/10/27 04:18:37 cgd Exp $ */
+
+/*
+ * cyclades cyclom-y serial driver
+ * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993
+ *
+ * Copyright (c) 1993 Andrew Herbert.
+ * 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 Andrew Herbert may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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.
+ */
+
+#define CD1400_NO_OF_CHANNELS 4 /* four serial channels per chip */
+#define CD1400_FIFOSIZE 12 /* 12 chars */
+
+/* register definitions */
+
+#define CD1400_CCR 2*0x05 /* channel control */
+#define CD1400_CMD_RESET 0x81 /* full reset */
+
+#define CD1400_SRER 2*0x06 /* service request enable */
+
+#define CD1400_GFRCR 2*0x40 /* global firmware revision code */
+
+#define CD1400_LIVR 2*0x18 /* local intr vector */
+#define CD1400_MIVR 2*0x41 /* modem intr vector */
+#define CD1400_TIVR 2*0x42 /* transmit intr vector */
+#define CD1400_RIVR 2*0x43 /* receive intr vector */
+#define CD1400_RIVR_EXCEPTION (1<<2) /* receive exception bit */
+
+#define CD1400_RICR 2*0x44 /* receive intr channel */
+#define CD1400_TICR 2*0x45 /* transmit intr channel */
+#define CD1400_MICR 2*0x46 /* modem intr channel */
+
+#define CD1400_RDCR 2*0x0e /* rx data count */
+
+#define CD1400_EOSRR 2*0x60 /* end of service request */
+#define CD1400_RDSR 2*0x62 /* rx data/status */
+#define CD1400_RDSR_OVERRUN (1<<0) /* rx overrun error */
+#define CD1400_RDSR_FRAMING (1<<1) /* rx framing error */
+#define CD1400_RDSR_PARITY (1<<2) /* rx parity error */
+#define CD1400_RDSR_BREAK (1<<3) /* rx break */
+#define CD1400_RDSR_SPECIAL (7<<4) /* rx special char */
+#define CD1400_RDSR_SPECIAL_SHIFT 4 /* rx special char shift */
+#define CD1400_RDSR_TIMEOUT (1<<7) /* rx timeout */
+
+#define CD1400_TDR 2*0x63 /* tx data */
+
+#define CD1400_MISR 2*0x4c /* modem intr status */
+#define CD1400_MISR_DSRd (1<<7) /* DSR delta */
+#define CD1400_MISR_CTSd (1<<6) /* CTS delta */
+#define CD1400_MISR_RId (1<<5) /* RI delta */
+#define CD1400_MISR_CDd (1<<4) /* CD delta */
+
+#define CD1400_MSVR 2*0x6d /* modem signals */
+#define CD1400_MSVR_DSR (1<<7) /* !DSR line */
+#define CD1400_MSVR_CTS (1<<6) /* !CTS line */
+#define CD1400_MSVR_RI (1<<5) /* !RI line */
+#define CD1400_MSVR_CD (1<<4) /* !CD line */
+#define CD1400_MSVR_DTR (1<<1) /* DTR line */
+
+#define CD1400_DTR 2*0x6d /* dtr control */
+#define CD1400_DTR_CLEAR 0
+#define CD1400_DTR_SET (1<<1)
+
+#define CD1400_PPR 2*0x7e
+#define CD1400_CLOCK_25_1MS 0x31
+
+#define CD1400_CAR 2*0x68 /* channel access */
+
+#define CD1400_RIR 2*0x6B /* receive interrupt status */
+#define CD1400_TIR 2*0x6A /* transmit interrupt status */
+#define CD1400_MIR 2*0x69 /* modem interrupt status */
+
+#define CD1400_RBPR 2*0x78 /* receive baud rate period */
+#define CD1400_RCOR 2*0x7C /* receive clock option */
+#define CD1400_TBPR 2*0x72 /* transmit baud rate period */
+#define CD1400_TCOR 2*0x76 /* transmit clock option */
+
+#define CD1400_COR1 2*0x08 /* channel option 1 */
+#define CD1400_COR2 2*0x09 /* channel option 2 */
+#define CD1400_COR3 2*0x0A /* channel option 3 */
+#define CD1400_COR4 2*0x1E /* channel option 4 */
+#define CD1400_COR5 2*0x1F /* channel option 5 */
+
+#define CD1400_SCHR1 2*0x1A /* special character 1 */
+#define CD1400_SCHR2 2*0x1B /* special character 2 */
+#define CD1400_SCHR3 2*0x1C /* special character 3 */
+#define CD1400_SCHR4 2*0x1D /* special character 4 */
+
+#define CD1400_MCOR1 2*0x15 /* modem change 1 */
+#define CD1400_MCOR2 2*0x16 /* modem change 2 */
+#define CD1400_RTPR 2*0x21 /* receive timeout period */
+
+#define CD1400_SVRR 2*0x67 /* service request */
+#define CD1400_SVRR_RX (1<<0)
+#define CD1400_SVRR_TX (1<<1)
+#define CD1400_SVRR_MDM (1<<2)
+
+/* hardware SVCACK addresses, for use in interrupt handlers */
+#define CD1400_SVCACKR 0x100
+#define CD1400_SVCACKT 0x200
+#define CD1400_SVCACKM 0x300
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c
new file mode 100644
index 00000000000..8c5c5480544
--- /dev/null
+++ b/sys/dev/ic/com.c
@@ -0,0 +1,996 @@
+/* $NetBSD: com.c,v 1.61 1995/07/04 06:47:18 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
+ * 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.
+ *
+ * @(#)com.c 7.5 (Berkeley) 5/16/91
+ */
+
+/*
+ * COM driver, based on HP dca driver
+ * uses National Semiconductor NS16450/NS16550AF UART
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/types.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/pio.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/comreg.h>
+#include <dev/ic/ns16550reg.h>
+
+#define COM_IBUFSIZE (2 * 256)
+#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
+
+struct com_softc {
+ struct device sc_dev;
+ void *sc_ih;
+ struct tty *sc_tty;
+
+ int sc_overflows;
+ int sc_floods;
+ int sc_errors;
+
+ int sc_iobase;
+ u_char sc_hwflags;
+#define COM_HW_NOIEN 0x01
+#define COM_HW_FIFO 0x02
+#define COM_HW_CONSOLE 0x40
+ u_char sc_swflags;
+#define COM_SW_SOFTCAR 0x01
+#define COM_SW_CLOCAL 0x02
+#define COM_SW_CRTSCTS 0x04
+#define COM_SW_MDMBUF 0x08
+ u_char sc_msr, sc_mcr;
+ u_char sc_dtr;
+
+ u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+ u_char sc_ibufs[2][COM_IBUFSIZE];
+};
+
+int comprobe __P((struct device *, void *, void *));
+void comattach __P((struct device *, struct device *, void *));
+int comopen __P((dev_t, int, int, struct proc *));
+int comclose __P((dev_t, int, int, struct proc *));
+void comdiag __P((void *));
+int comintr __P((void *));
+void compoll __P((void *));
+int comparam __P((struct tty *, struct termios *));
+void comstart __P((struct tty *));
+
+struct cfdriver comcd = {
+ NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc)
+};
+
+int comdefaultrate = TTYDEF_SPEED;
+#ifdef COMCONSOLE
+int comconsole = COMCONSOLE;
+#else
+int comconsole = -1;
+#endif
+int comconsinit;
+int commajor;
+int comsopen = 0;
+int comevents = 0;
+
+#ifdef KGDB
+#include <machine/remote-sl.h>
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+#define COMUNIT(x) (minor(x))
+
+#define bis(c, b) do { const register int com_ad = (c); \
+ outb(com_ad, inb(com_ad) | (b)); } while(0)
+#define bic(c, b) do { const register int com_ad = (c); \
+ outb(com_ad, inb(com_ad) & ~(b)); } while(0)
+
+int
+comspeed(speed)
+ long speed;
+{
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+
+ int x, err;
+
+ if (speed == 0)
+ return 0;
+ if (speed < 0)
+ return -1;
+ x = divrnd((COM_FREQ / 16), speed);
+ if (x <= 0)
+ return -1;
+ err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > COM_TOLERANCE)
+ return -1;
+ return x;
+
+#undef divrnd(n, q)
+}
+
+int
+comprobe1(iobase)
+ int iobase;
+{
+
+ /* force access to id reg */
+ outb(iobase + com_cfcr, 0);
+ outb(iobase + com_iir, 0);
+ if (inb(iobase + com_iir) & 0x38)
+ return 0;
+
+ return 1;
+}
+
+int
+comprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct isa_attach_args *ia = aux;
+ int iobase = ia->ia_iobase;
+
+ if (!comprobe1(iobase))
+ return 0;
+
+ ia->ia_iosize = COM_NPORTS;
+ ia->ia_msize = 0;
+ return 1;
+}
+
+void
+comattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct com_softc *sc = (void *)self;
+ struct isa_attach_args *ia = aux;
+ struct cfdata *cf = sc->sc_dev.dv_cfdata;
+ int iobase = ia->ia_iobase;
+ struct tty *tp;
+
+ sc->sc_iobase = iobase;
+ sc->sc_hwflags = cf->cf_flags & COM_HW_NOIEN;
+ sc->sc_swflags = 0;
+
+ if (sc->sc_dev.dv_unit == comconsole)
+ delay(1000);
+
+ /* look for a NS 16550AF UART with FIFOs */
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ delay(100);
+ if ((inb(iobase + com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK)
+ if ((inb(iobase + com_fifo) & FIFO_TRIGGER_14) == FIFO_TRIGGER_14) {
+ sc->sc_hwflags |= COM_HW_FIFO;
+ printf(": ns16550a, working fifo\n");
+ } else
+ printf(": ns16550, broken fifo\n");
+ else
+ printf(": ns8250 or ns16450, no fifo\n");
+ outb(iobase + com_fifo, 0);
+
+ /* disable interrupts */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, 0);
+
+ if (ia->ia_irq != IRQUNK)
+ sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE,
+ ISA_IPL_TTY, comintr, sc);
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ (void) cominit(unit, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("%s: ", sc->sc_dev.dv_xname);
+ kgdb_connect(1);
+ } else
+ printf("%s: kgdb enabled\n",
+ sc->sc_dev.dv_xname);
+ }
+ }
+#endif
+
+ if (sc->sc_dev.dv_unit == comconsole) {
+ /*
+ * Need to reset baud rate, etc. of next print so reset
+ * comconsinit. Also make sure console is always "hardwired".
+ */
+ comconsinit = 0;
+ sc->sc_hwflags |= COM_HW_CONSOLE;
+ sc->sc_swflags |= COM_SW_SOFTCAR;
+ }
+}
+
+int
+comopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = COMUNIT(dev);
+ struct com_softc *sc;
+ int iobase;
+ struct tty *tp;
+ int s;
+ int error = 0;
+
+ if (unit >= comcd.cd_ndevs)
+ return ENXIO;
+ sc = comcd.cd_devs[unit];
+ if (!sc)
+ return ENXIO;
+
+ if (!sc->sc_tty)
+ tp = sc->sc_tty = ttymalloc();
+ else
+ tp = sc->sc_tty;
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ if (sc->sc_swflags & COM_SW_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (sc->sc_swflags & COM_SW_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (sc->sc_swflags & COM_SW_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+
+ s = spltty();
+
+ comparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ if (comsopen++ == 0)
+ timeout(compoll, NULL, 1);
+
+ sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ iobase = sc->sc_iobase;
+ /* Set the FIFO threshold based on the receive speed. */
+ if (sc->sc_hwflags & COM_HW_FIFO)
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
+ (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+ /* flush any pending I/O */
+ while (inb(iobase + com_lsr) & LSR_RXRDY)
+ (void) inb(iobase + com_data);
+ /* you turn me on, baby */
+ sc->sc_mcr = MCR_DTR | MCR_RTS;
+ if ((sc->sc_hwflags & COM_HW_NOIEN) == 0)
+ sc->sc_mcr |= MCR_IENABLE;
+ outb(iobase + com_mcr, sc->sc_mcr);
+ outb(iobase + com_ier,
+ IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
+
+ sc->sc_msr = inb(iobase + com_msr);
+ if (sc->sc_swflags & COM_SW_SOFTCAR || sc->sc_msr & MSR_DCD ||
+ tp->t_cflag & MDMBUF)
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+ } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ return EBUSY;
+ } else
+ s = spltty();
+
+ /* wait for carrier if necessary */
+ if ((flag & O_NONBLOCK) == 0)
+ while ((tp->t_cflag & CLOCAL) == 0 &&
+ (tp->t_state & TS_CARR_ON) == 0) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)&tp->t_rawq,
+ TTIPRI | PCATCH, ttopen, 0);
+ if (error) {
+ /* XXX should turn off chip if we're the
+ only waiter */
+ splx(s);
+ return error;
+ }
+ }
+ splx(s);
+
+ return (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+int
+comclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = COMUNIT(dev);
+ struct com_softc *sc = comcd.cd_devs[unit];
+ struct tty *tp = sc->sc_tty;
+ int iobase = sc->sc_iobase;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ s = spltty();
+ bic(iobase + com_cfcr, CFCR_SBREAK);
+ outb(iobase + com_ier, 0);
+ if (tp->t_cflag & HUPCL &&
+ (sc->sc_swflags & COM_SW_SOFTCAR) == 0) {
+ /* XXX perhaps only clear DTR */
+ outb(iobase + com_mcr, 0);
+ }
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (--comsopen == 0)
+ untimeout(compoll, NULL);
+ splx(s);
+ ttyclose(tp);
+#ifdef notyet /* XXXX */
+ if (unit != comconsole) {
+ ttyfree(tp);
+ sc->sc_tty = 0;
+ }
+#endif
+ return 0;
+}
+
+int
+comread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+comwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+struct tty *
+comtty(dev)
+ dev_t dev;
+{
+ struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (tp);
+}
+
+static u_char
+tiocm_xxx2mcr(data)
+ int data;
+{
+ u_char m = 0;
+
+ if (data & TIOCM_DTR)
+ m |= MCR_DTR;
+ if (data & TIOCM_RTS)
+ m |= MCR_RTS;
+ return m;
+}
+
+int
+comioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int unit = COMUNIT(dev);
+ struct com_softc *sc = comcd.cd_devs[unit];
+ struct tty *tp = sc->sc_tty;
+ int iobase = sc->sc_iobase;
+ int error;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ switch (cmd) {
+ case TIOCSBRK:
+ bis(iobase + com_cfcr, CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ bic(iobase + com_cfcr, CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ outb(iobase + com_mcr, sc->sc_mcr |= sc->sc_dtr);
+ break;
+ case TIOCCDTR:
+ outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
+ break;
+ case TIOCMSET:
+ sc->sc_mcr &= ~(MCR_DTR | MCR_RTS);
+ case TIOCMBIS:
+ outb(iobase + com_mcr,
+ sc->sc_mcr |= tiocm_xxx2mcr(*(int *)data));
+ break;
+ case TIOCMBIC:
+ outb(iobase + com_mcr,
+ sc->sc_mcr &= ~tiocm_xxx2mcr(*(int *)data));
+ break;
+ case TIOCMGET: {
+ u_char m;
+ int bits = 0;
+
+ m = sc->sc_mcr;
+ if (m & MCR_DTR)
+ bits |= TIOCM_DTR;
+ if (m & MCR_RTS)
+ bits |= TIOCM_RTS;
+ m = sc->sc_msr;
+ if (m & MSR_DCD)
+ bits |= TIOCM_CD;
+ if (m & MSR_CTS)
+ bits |= TIOCM_CTS;
+ if (m & MSR_DSR)
+ bits |= TIOCM_DSR;
+ if (m & (MSR_RI | MSR_TERI))
+ bits |= TIOCM_RI;
+ if (inb(iobase + com_ier))
+ bits |= TIOCM_LE;
+ *(int *)data = bits;
+ break;
+ }
+ case TIOCGFLAGS: {
+ int bits = 0;
+
+ if (sc->sc_swflags & COM_SW_SOFTCAR)
+ bits |= TIOCFLAG_SOFTCAR;
+ if (sc->sc_swflags & COM_SW_CLOCAL)
+ bits |= TIOCFLAG_CLOCAL;
+ if (sc->sc_swflags & COM_SW_CRTSCTS)
+ bits |= TIOCFLAG_CRTSCTS;
+ if (sc->sc_swflags & COM_SW_MDMBUF)
+ bits |= TIOCFLAG_MDMBUF;
+
+ *(int *)data = bits;
+ break;
+ }
+ case TIOCSFLAGS: {
+ int userbits, driverbits = 0;
+
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return(EPERM);
+
+ userbits = *(int *)data;
+ if ((userbits & TIOCFLAG_SOFTCAR) ||
+ (sc->sc_hwflags & COM_HW_CONSOLE))
+ driverbits |= COM_SW_SOFTCAR;
+ if (userbits & TIOCFLAG_CLOCAL)
+ driverbits |= COM_SW_CLOCAL;
+ if (userbits & TIOCFLAG_CRTSCTS)
+ driverbits |= COM_SW_CRTSCTS;
+ if (userbits & TIOCFLAG_MDMBUF)
+ driverbits |= COM_SW_MDMBUF;
+
+ sc->sc_swflags = driverbits;
+ break;
+ }
+ default:
+ return ENOTTY;
+ }
+
+ return 0;
+}
+
+int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)];
+ int iobase = sc->sc_iobase;
+ int ospeed = comspeed(t->c_ospeed);
+ u_char cfcr;
+ tcflag_t oldcflag;
+ int s;
+
+ /* check requested parameters */
+ if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+ return EINVAL;
+
+ switch (t->c_cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ case CS8:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (t->c_cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if ((t->c_cflag & PARODD) == 0)
+ cfcr |= CFCR_PEVEN;
+ }
+ if (t->c_cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ s = spltty();
+
+ if (ospeed == 0)
+ outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_DTR);
+
+ /*
+ * Set the FIFO threshold based on the receive speed, if we are
+ * changing it.
+ */
+ if (tp->t_ispeed != t->c_ispeed) {
+ if (sc->sc_hwflags & COM_HW_FIFO)
+ outb(iobase + com_fifo,
+ FIFO_ENABLE |
+ (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+ }
+
+ if (ospeed != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, ospeed);
+ outb(iobase + com_dlbh, ospeed >> 8);
+ outb(iobase + com_cfcr, cfcr);
+ outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR);
+ } else
+ outb(iobase + com_cfcr, cfcr);
+
+ /* When not using CRTSCTS, RTS follows DTR. */
+ if ((t->c_cflag & CRTSCTS) == 0) {
+ if (sc->sc_mcr & MCR_DTR) {
+ if ((sc->sc_mcr & MCR_RTS) == 0)
+ outb(iobase + com_mcr, sc->sc_mcr |= MCR_RTS);
+ } else {
+ if (sc->sc_mcr & MCR_RTS)
+ outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_RTS);
+ }
+ sc->sc_dtr = MCR_DTR | MCR_RTS;
+ } else
+ sc->sc_dtr = MCR_DTR;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ oldcflag = tp->t_cflag;
+ tp->t_cflag = t->c_cflag;
+
+ /*
+ * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+ * stop the device.
+ */
+ if ((sc->sc_msr & MSR_DCD) == 0 &&
+ (sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
+ (oldcflag & MDMBUF) != (tp->t_cflag & MDMBUF) &&
+ (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
+ outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
+ }
+
+ splx(s);
+ return 0;
+}
+
+void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)];
+ int iobase = sc->sc_iobase;
+ int s;
+
+ s = spltty();
+ if (tp->t_state & (TS_TTSTOP | TS_BUSY))
+ goto out;
+ if ((tp->t_cflag & CRTSCTS) != 0 &&
+ (sc->sc_msr & MSR_CTS) == 0)
+ goto out;
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+ selwakeup(&tp->t_wsel);
+ }
+ tp->t_state |= TS_BUSY;
+ if (sc->sc_hwflags & COM_HW_FIFO) {
+ u_char buffer[16], *cp = buffer;
+ int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
+ do {
+ outb(iobase + com_data, *cp++);
+ } while (--n);
+ } else
+ outb(iobase + com_data, getc(&tp->t_outq));
+out:
+ splx(s);
+}
+
+/*
+ * Stop output on a line.
+ */
+void
+comstop(tp, flag)
+ struct tty *tp;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY)
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ splx(s);
+}
+
+void
+comdiag(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ int overflows, floods;
+ int s;
+
+ s = spltty();
+ sc->sc_errors = 0;
+ overflows = sc->sc_overflows;
+ sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+compoll(arg)
+ void *arg;
+{
+ int unit;
+ struct com_softc *sc;
+ struct tty *tp;
+ register u_char *ibufp;
+ u_char *ibufend;
+ register int c;
+ int s;
+ static int lsrmap[8] = {
+ 0, TTY_PE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE
+ };
+
+ s = spltty();
+ if (comevents == 0) {
+ splx(s);
+ goto out;
+ }
+ comevents = 0;
+ splx(s);
+
+ for (unit = 0; unit < comcd.cd_ndevs; unit++) {
+ sc = comcd.cd_devs[unit];
+ if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf)
+ continue;
+
+ tp = sc->sc_tty;
+
+ s = spltty();
+
+ ibufp = sc->sc_ibuf;
+ ibufend = sc->sc_ibufp;
+
+ if (ibufp == ibufend) {
+ splx(s);
+ continue;
+ }
+
+ sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+ sc->sc_ibufs[1] : sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ if (tp == 0 || (tp->t_state & TS_ISOPEN) == 0) {
+ splx(s);
+ continue;
+ }
+
+ if ((tp->t_cflag & CRTSCTS) != 0 &&
+ (sc->sc_mcr & MCR_RTS) == 0)
+ outb(sc->sc_iobase + com_mcr, sc->sc_mcr |= MCR_RTS);
+
+ splx(s);
+
+ while (ibufp < ibufend) {
+ c = *ibufp++;
+ if (*ibufp & LSR_OE) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ }
+ /* This is ugly, but fast. */
+ c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+
+out:
+ timeout(compoll, NULL, 1);
+}
+
+int
+comintr(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ int iobase = sc->sc_iobase;
+ struct tty *tp;
+ u_char lsr, data, msr, delta;
+
+ if (inb(iobase + com_iir) & IIR_NOPEND)
+ return (0);
+
+ tp = sc->sc_tty;
+
+ for (;;) {
+ lsr = inb(iobase + com_lsr);
+
+ if (lsr & LSR_RCV_MASK) {
+ register u_char *p = sc->sc_ibufp;
+
+ comevents = 1;
+ do {
+ if ((lsr & LSR_BI) != 0) {
+#ifdef DDB
+ if (sc->sc_dev.dv_unit == comconsole) {
+ Debugger();
+ goto next;
+ }
+#endif
+ data = '\0';
+ } else
+ data = inb(iobase + com_data);
+ if (p >= sc->sc_ibufend) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ } else {
+ *p++ = data;
+ *p++ = lsr;
+ if (p == sc->sc_ibufhigh &&
+ (tp->t_cflag & CRTSCTS) != 0)
+ outb(iobase + com_mcr,
+ sc->sc_mcr &= ~MCR_RTS);
+ }
+ next:
+ lsr = inb(iobase + com_lsr);
+ } while (lsr & LSR_RCV_MASK);
+
+ sc->sc_ibufp = p;
+ }
+
+ if (lsr & LSR_TXRDY && (tp->t_state & TS_BUSY) != 0) {
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_state & TS_FLUSH)
+ tp->t_state &= ~TS_FLUSH;
+ else
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+
+ msr = inb(iobase + com_msr);
+
+ if (msr != sc->sc_msr) {
+ delta = msr ^ sc->sc_msr;
+ sc->sc_msr = msr;
+ if ((delta & MSR_DCD) != 0 &&
+ (sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
+ (*linesw[tp->t_line].l_modem)(tp, (msr & MSR_DCD) != 0) == 0) {
+ outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
+ }
+ if ((delta & msr & MSR_CTS) != 0 &&
+ (tp->t_cflag & CRTSCTS) != 0) {
+ /* the line is up and we want to do rts/cts flow control */
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+ }
+
+ if (inb(iobase + com_iir) & IIR_NOPEND)
+ return (1);
+ }
+}
+
+/*
+ * Following are all routines needed for COM to act as console
+ */
+#include <dev/cons.h>
+
+void
+comcnprobe(cp)
+ struct consdev *cp;
+{
+
+ if (!comprobe1(CONADDR)) {
+ cp->cn_pri = CN_DEAD;
+ return;
+ }
+
+ /* locate the major number */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == comopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, CONUNIT);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+comcninit(cp)
+ struct consdev *cp;
+{
+
+ cominit(CONUNIT, comdefaultrate);
+ comconsole = CONUNIT;
+ comconsinit = 0;
+}
+
+cominit(unit, rate)
+ int unit, rate;
+{
+ int s = splhigh();
+ int iobase = CONADDR;
+ u_char stat;
+
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ rate = comspeed(comdefaultrate);
+ outb(iobase + com_dlbl, rate);
+ outb(iobase + com_dlbh, rate >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY);
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
+ stat = inb(iobase + com_iir);
+ splx(s);
+}
+
+comcngetc(dev)
+ dev_t dev;
+{
+ int s = splhigh();
+ int iobase = CONADDR;
+ u_char stat, c;
+
+ while (((stat = inb(iobase + com_lsr)) & LSR_RXRDY) == 0)
+ ;
+ c = inb(iobase + com_data);
+ stat = inb(iobase + com_iir);
+ splx(s);
+ return c;
+}
+
+/*
+ * Console kernel output character routine.
+ */
+void
+comcnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s = splhigh();
+ int iobase = CONADDR;
+ u_char stat;
+ register int timo;
+
+#ifdef KGDB
+ if (dev != kgdb_dev)
+#endif
+ if (comconsinit == 0) {
+ (void) cominit(COMUNIT(dev), comdefaultrate);
+ comconsinit = 1;
+ }
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo)
+ ;
+ outb(iobase + com_data, c);
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo)
+ ;
+ /* clear any interrupts generated by this transmission */
+ stat = inb(iobase + com_iir);
+ splx(s);
+}
+
+void
+comcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+
+}
diff --git a/sys/dev/ic/comreg.h b/sys/dev/ic/comreg.h
new file mode 100644
index 00000000000..4a4f0e90c25
--- /dev/null
+++ b/sys/dev/ic/comreg.h
@@ -0,0 +1,118 @@
+/* $NetBSD: comreg.h,v 1.6 1995/06/28 04:31:30 cgd Exp $ */
+
+/*-
+ * 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.
+ *
+ * @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ */
+
+#include <dev/ic/ns16550reg.h>
+
+#define COM_FREQ 1843200 /* 16-bit baud rate divisor */
+#define COM_TOLERANCE 30 /* baud rate tolerance, in 0.1% units */
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+#define COM_NPORTS 8
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/dev/ic/cs4231reg.h b/sys/dev/ic/cs4231reg.h
new file mode 100644
index 00000000000..7ad90f03999
--- /dev/null
+++ b/sys/dev/ic/cs4231reg.h
@@ -0,0 +1,103 @@
+/* $NetBSD: cs4231reg.h,v 1.1 1995/07/07 02:11:46 brezak Exp $ */
+/*
+ * Copyright (c) 1995 John T. Kohl
+ * 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.
+ *
+ */
+
+/*
+ * Register defs for Crystal Semiconductor CS4231 Audio Codec/mixer
+ * chip, used on Gravis UltraSound MAX cards.
+ *
+ * Block diagram:
+ * +----------------------------------------------------+
+ * | |
+ * | +----------------------------------------------+ |
+ * | |mixed in +-+ | |
+ * | +------------>--| | | |
+ * | mic in | | | |
+ * Mic --+-->| --------- GAIN ->-| | | |
+ * | | AUX 1 in |M| | |
+ * GF1 --)-->| -------------+-->-|U| | |
+ * | | Line in | |X|---- GAIN ----------+ | |
+ * Line --)-->| ---------+---)-->-| | | | |
+ * | | | | | | | | |
+ * | | | | +-+ ADC | |
+ * | | | | | | |
+ * | | | | | | |
+ * | | | +--- L/M --\ | | | AMP-->
+ * | | | \ | | | |
+ * | | | \ | | | |
+ * | | +---- L/M -------O-->--+--------)-------+-|--+-> line
+ * | | mono in /| | | |
+ * +---|-->------------ L/M -----/ | | | |
+ * | AUX 2 in | | | |
+ * CD --------|-->------------ L/M -------+ L/M | |
+ * | | v |
+ * | | | |
+ * | DAC | |
+ * | | | |
+ * +----------------------------------------------------+
+ * | |
+ * | |
+ * v v
+ * Pc BUS (DISK) ???
+ *
+ */
+
+
+/*
+ * The CS4231 mixer is write-only--it cannot be queried for current
+ * settings. Drivers must keep track of current values themselves.
+ */
+
+/* CS4231/AD1845 mode2 registers; added to AD1848 registers */
+#define CS_ALT_FEATURE1 0x10
+#define CS_ALT_FEATURE2 0x11
+#define CS_LEFT_LINE_CONTROL 0x12
+#define CS_RIGHT_LINE_CONTROL 0x13
+#define CS_TIMER_LOW 0x14
+#define CS_TIMER_HIGH 0x15
+#define CS_UPPER_FREQUENCY_SEL 0x16
+#define CS_LOWER_FREQUENCY_SEL 0x17
+#define CS_IRQ_STATUS 0x18
+#define CS_VERSION_ID 0x19
+#define CS_MONO_IO_CONTROL 0x1A
+#define CS_POWERDOWN_CONTROL 0x1B
+#define CS_REC_FORMAT 0x1C
+#define CS_XTAL_SELECT 0x1D
+#define CS_UPPER_REC_CNT 0x1E
+#define CS_LOWER_REC_CNT 0x1F
+
+#define MONO_INPUT_ATTEN_BITS 0x0f
+#define MONO_INPUT_ATTEN_MASK 0xf0
+#define MONO_INPUT_MUTE 0x80
+#define MONO_INPUT_MUTE_MASK 0x7f
+
+#define LINE_INPUT_ATTEN_BITS 0x1f
+#define LINE_INPUT_ATTEN_MASK 0xe0
+#define LINE_INPUT_MUTE 0x80
+#define LINE_INPUT_MUTE_MASK 0x7f
diff --git a/sys/dev/ic/dc21040reg.h b/sys/dev/ic/dc21040reg.h
new file mode 100644
index 00000000000..a330c09d4f9
--- /dev/null
+++ b/sys/dev/ic/dc21040reg.h
@@ -0,0 +1,332 @@
+/* $NetBSD: dc21040reg.h,v 1.6 1995/08/19 04:15:29 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1994, 1995 Matt Thomas (thomas@lkg.dec.com)
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough 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.
+ */
+
+#if !defined(_DC21040_H)
+#define _DC21040_H
+
+typedef u_int16_t tulip_uint16_t;
+typedef u_int32_t tulip_uint32_t;
+
+#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+#define TULIP_BITFIELD2(a, b) b, a
+#define TULIP_BITFIELD3(a, b, c) c, b, a
+#define TULIP_BITFIELD4(a, b, c, d) d, c, b, a
+#else
+#define TULIP_BITFIELD2(a, b) a, b
+#define TULIP_BITFIELD3(a, b, c) a, b, c
+#define TULIP_BITFIELD4(a, b, c, d) a, b, c, d
+#endif
+
+typedef struct {
+ tulip_uint32_t d_status;
+ tulip_uint32_t TULIP_BITFIELD3(d_length1 : 11,
+ d_length2 : 11,
+ d_flag : 10);
+ tulip_uint32_t d_addr1;
+ tulip_uint32_t d_addr2;
+} tulip_desc_t;
+
+#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = DC21040) */
+#define TULIP_DSTS_ERRSUM 0x00008000 /* Error Summary */
+/*
+ * Transmit Status
+ */
+#define TULIP_DSTS_TxBABBLE 0x00004000 /* Transmitter Babbled */
+#define TULIP_DSTS_TxCARRLOSS 0x00000800 /* Carrier Loss */
+#define TULIP_DSTS_TxNOCARR 0x00000400 /* No Carrier */
+#define TULIP_DSTS_TxLATECOLL 0x00000200 /* Late Collision */
+#define TULIP_DSTS_TxEXCCOLL 0x00000100 /* Excessive Collisions */
+#define TULIP_DSTS_TxNOHRTBT 0x00000080 /* No Heartbeat */
+#define TULIP_DSTS_TxCOLLMASK 0x00000078 /* Collision Count (mask) */
+#define TULIP_DSTS_V_TxCOLLCNT 0x00000003 /* Collision Count (bit) */
+#define TULIP_DSTS_TxLINKFAIL 0x00000004 /* Link Failure */
+#define TULIP_DSTS_TxUNDERFLOW 0x00000002 /* Underflow Error */
+#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */
+/*
+ * Receive Status
+ */
+#define TULIP_DSTS_RxBADLENGTH 0x00004000 /* Length Error */
+#define TULIP_DSTS_RxDATATYPE 0x00003000 /* Data Type */
+#define TULIP_DSTS_RxRUNT 0x00000800 /* Runt Frame */
+#define TULIP_DSTS_RxMULTICAST 0x00000400 /* Multicast Frame */
+#define TULIP_DSTS_RxFIRSTDESC 0x00000200 /* First Descriptor */
+#define TULIP_DSTS_RxLASTDESC 0x00000100 /* Last Descriptor */
+#define TULIP_DSTS_RxTOOLONG 0x00000080 /* Frame Too Long */
+#define TULIP_DSTS_RxCOLLSEEN 0x00000040 /* Collision Seen */
+#define TULIP_DSTS_RxFRAMETYPE 0x00000020 /* Frame Type */
+#define TULIP_DSTS_RxWATCHDOG 0x00000010 /* Receive Watchdog */
+#define TULIP_DSTS_RxDRBBLBIT 0x00000004 /* Dribble Bit */
+#define TULIP_DSTS_RxBADCRC 0x00000002 /* CRC Error */
+#define TULIP_DSTS_RxOVERFLOW 0x00000001 /* Overflow */
+
+
+#define TULIP_DFLAG_ENDRING 0x0008 /* End of Transmit Ring */
+#define TULIP_DFLAG_CHAIN 0x0004 /* Chain using d_addr2 */
+
+#define TULIP_DFLAG_TxWANTINTR 0x0200 /* Signal Interrupt on Completion */
+#define TULIP_DFLAG_TxLASTSEG 0x0100 /* Last Segment */
+#define TULIP_DFLAG_TxFIRSTSEG 0x0080 /* First Segment */
+#define TULIP_DFLAG_TxINVRSFILT 0x0040 /* Inverse Filtering */
+#define TULIP_DFLAG_TxSETUPPKT 0x0020 /* Setup Packet */
+#define TULIP_DFLAG_TxHASCRC 0x0010 /* Don't Append the CRC */
+#define TULIP_DFLAG_TxNOPADDING 0x0002 /* Don't AutoPad */
+#define TULIP_DFLAG_TxHASHFILT 0x0001 /* Hash/Perfect Filtering */
+
+/*
+ * The DC21040 Registers (IO Space Addresses)
+ */
+#define TULIP_REG_BUSMODE 0x00 /* CSR0 -- Bus Mode */
+#define TULIP_REG_TXPOLL 0x08 /* CSR1 -- Transmit Poll Demand */
+#define TULIP_REG_RXPOLL 0x10 /* CSR2 -- Receive Poll Demand */
+#define TULIP_REG_RXLIST 0x18 /* CSR3 -- Receive List Base Addr */
+#define TULIP_REG_TXLIST 0x20 /* CSR4 -- Transmit List Base Addr */
+#define TULIP_REG_STATUS 0x28 /* CSR5 -- Status */
+#define TULIP_REG_CMD 0x30 /* CSR6 -- Command */
+#define TULIP_REG_INTR 0x38 /* CSR7 -- Interrupt Control */
+#define TULIP_REG_MISSES 0x40 /* CSR8 -- Missed Frame Counter */
+#define TULIP_REG_ADDRROM 0x48 /* CSR9 -- ENET ROM Register */
+#define TULIP_REG_RSRVD 0x50 /* CSR10 -- Reserved */
+#define TULIP_REG_FULL_DUPLEX 0x58 /* CSR11 -- Full Duplex */
+#define TULIP_REG_SIA_STATUS 0x60 /* CSR12 -- SIA Status */
+#define TULIP_REG_SIA_CONN 0x68 /* CSR13 -- SIA Connectivity */
+#define TULIP_REG_SIA_TXRX 0x70 /* CSR14 -- SIA Tx Rx */
+#define TULIP_REG_SIA_GEN 0x78 /* CSR15 -- SIA General */
+
+/*
+ * CSR5 -- Status Register
+ * CSR7 -- Interrupt Control
+ */
+#define TULIP_STS_ERRORMASK 0x03800000L /* ( R) Error Bits (Valid when SYSERROR is set) */
+#define TULIP_STS_ERR_PARITY 0x00000000L /* 000 - Parity Error (Perform Reset) */
+#define TULIP_STS_ERR_MASTER 0x00800000L /* 001 - Master Abort */
+#define TULIP_STS_ERR_TARGET 0x01000000L /* 010 - Target Abort */
+#define TULIP_STS_TXSTATEMASK 0x00700000L /* ( R) Transmission Process State */
+#define TULIP_STS_TXS_RESET 0x00000000L /* 000 - Rset or transmit jabber expired */
+#define TULIP_STS_TXS_FETCH 0x00100000L /* 001 - Fetching transmit descriptor */
+#define TULIP_STS_TXS_WAITEND 0x00200000L /* 010 - Wait for end of transmission */
+#define TULIP_STS_TXS_READING 0x00300000L /* 011 - Read buffer and enqueue data */
+#define TULIP_STS_TXS_RSRVD 0x00400000L /* 100 - Reserved */
+#define TULIP_STS_TXS_SETUP 0x00500000L /* 101 - Setup Packet */
+#define TULIP_STS_TXS_SUSPEND 0x00600000L /* 110 - Transmit FIFO underflow or an
+ unavailable transmit descriptor */
+#define TULIP_STS_TXS_CLOSE 0x00700000L /* 111 - Close transmit descriptor */
+#define TULIP_STS_RXSTATEMASK 0x000E0000L /* ( R) Receive Process State*/
+#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */
+#define TULIP_STS_RXS_FETCH 0x00020000L /* 001 - Running -- Fetch receive descriptor */
+#define TULIP_STS_RXS_ENDCHECK 0x00040000L /* 010 - Running -- Check for end of receive
+ packet before prefetch of next descriptor */
+#define TULIP_STS_RXS_WAIT 0x00060000L /* 011 - Running -- Wait for receive packet */
+#define TULIP_STS_RXS_SUSPEND 0x00080000L /* 100 - Suspended -- As a result of
+ unavailable receive buffers */
+#define TULIP_STS_RXS_CLOSE 0x000A0000L /* 101 - Running -- Close receive descriptor */
+#define TULIP_STS_RXS_FLUSH 0x000C0000L /* 110 - Running -- Flush the current frame
+ from the receive FIFO as a result of
+ an unavailable receive buffer */
+#define TULIP_STS_RXS_DEQUEUE 0x000E0000L /* 111 - Running -- Dequeue the receive frame
+ from the receive FIFO into the receive
+ buffer. */
+#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */
+#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */
+#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */
+#define TULIP_STS_LINKFAIL 0x00001000L /* (RW) Link Failure (DC21040) */
+#define TULIP_STS_FULDPLXSHRT 0x00000800L /* (RW) Full Duplex Short Fram Rcvd (DC21040) */
+#define TULIP_STS_GPTIMEOUT 0x00000800L /* (RW) General Purpose Timeout (DC21140) */
+#define TULIP_STS_AUI 0x00000400L /* (RW) AUI/TP Switch (DC21040) */
+#define TULIP_STS_RXTIMEOUT 0x00000200L /* (RW) Receive Watchbog Timeout */
+#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */
+#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buffer Unavailable */
+#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */
+#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */
+#define TULIP_STS_LINKPASS 0x00000010L /* (RW) LinkPass (DC21041) */
+#define TULIP_STS_TXBABBLE 0x00000008L /* (RW) Transmit Jabber Timeout */
+#define TULIP_STS_TXNOBUF 0x00000004L /* (RW) Transmit Buffer Unavailable */
+#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */
+#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */
+
+/*
+ * CSR6 -- Command (Operation Mode) Register
+ */
+#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (DC21140) */
+#define TULIP_CMD_SCRAMBLER 0x01000000L /* (RW) Scrambler Mode (DC21140) */
+#define TULIP_CMD_PCSFUNCTION 0x00800000L /* (RW) PCS Function (DC21140) */
+#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (DC21140) */
+#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (DC21140) */
+#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (DC21140) */
+#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (DC21140) */
+#define TULIP_CMD_ENHCAPTEFFCT 0x00040000L /* (RW) Enhanced Capture Effecty (DC21041) */
+#define TULIP_CMD_CAPTREFFCT 0x00020000L /* (RW) Capture Effect (!802.3) */
+#define TULIP_CMD_BACKPRESSURE 0x00010000L /* (RW) Back Pressure (!802.3) (DC21040) */
+#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */
+#define TULIP_CMD_THRSHLD72 0x00000000L /* 00 - 72 Bytes */
+#define TULIP_CMD_THRSHLD96 0x00004000L /* 01 - 96 Bytes */
+#define TULIP_CMD_THRSHLD128 0x00008000L /* 10 - 128 bytes */
+#define TULIP_CMD_THRSHLD160 0x0000C000L /* 11 - 160 Bytes */
+#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */
+#define TULIP_CMD_FORCECOLL 0x00001000L /* (RW) Force Collisions */
+#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */
+#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */
+#define TULIP_CMD_FLAKYOSCDIS 0x00000100L /* (RW) Flakey Oscillator Disable */
+#define TULIP_CMD_ALLMULTI 0x00000080L /* (RW) Pass All Multicasts */
+#define TULIP_CMD_PROMISCUOUS 0x00000040L /* (RW) Promiscuous Mode */
+#define TULIP_CMD_BACKOFFCTR 0x00000020L /* (RW) Start/Stop Backoff Counter (!802.3) */
+#define TULIP_CMD_INVFILTER 0x00000010L /* (R ) Inverse Filtering */
+#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */
+#define TULIP_CMD_HASHONLYFLTR 0x00000004L /* (R ) Hash Only Filtering */
+#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */
+#define TULIP_CMD_HASHPRFCTFLTR 0x00000001L /* (R ) Hash/Perfect Receive Filtering */
+
+
+#define TULIP_SIASTS_OTHERRXACTIVITY 0x00000200L
+#define TULIP_SIASTS_RXACTIVITY 0x00000100L
+#define TULIP_SIASTS_LINKFAIL 0x00000004L
+#define TULIP_SIACONN_RESET 0x00000000L
+
+#define TULIP_SIACONN_AUI 0x0000000DL
+#define TULIP_SIACONN_10BASET 0x00000005L
+
+#define TULIP_DC21041_SIACONN_10BASET 0x0000EF01L
+#define TULIP_DC21041_SIATXRX_10BASET 0x0000FF3FL
+#define TULIP_DC21041_SIAGEN_10BASET 0x00000000L
+
+#define TULIP_DC21041_SIACONN_AUI 0x0000EF09L
+#define TULIP_DC21041_SIATXRX_AUI 0x0000F73DL
+#define TULIP_DC21041_SIAGEN_AUI 0x0000000EL
+
+#define TULIP_DC21041_SIACONN_BNC 0x0000EF09L
+#define TULIP_DC21041_SIATXRX_BNC 0x0000F73DL
+#define TULIP_DC21041_SIAGEN_BNC 0x00000006L
+
+#define TULIP_BUSMODE_SWRESET 0x00000001L
+#define TULIP_BUSMODE_DESCSKIPLEN_MASK 0x0000007CL
+#define TULIP_BUSMODE_BIGENDIAN 0x00000080L
+#define TULIP_BUSMODE_BURSTLEN_MASK 0x00003F00L
+#define TULIP_BUSMODE_BURSTLEN_DEFAULT 0x00000000L
+#define TULIP_BUSMODE_BURSTLEN_1LW 0x00000100L
+#define TULIP_BUSMODE_BURSTLEN_2LW 0x00000200L
+#define TULIP_BUSMODE_BURSTLEN_4LW 0x00000400L
+#define TULIP_BUSMODE_BURSTLEN_8LW 0x00000800L
+#define TULIP_BUSMODE_BURSTLEN_16LW 0x00001000L
+#define TULIP_BUSMODE_BURSTLEN_32LW 0x00002000L
+#define TULIP_BUSMODE_CACHE_NOALIGN 0x00000000L
+#define TULIP_BUSMODE_CACHE_ALIGN8 0x00004000L
+#define TULIP_BUSMODE_CACHE_ALIGN16 0x00008000L
+#define TULIP_BUSMODE_CACHE_ALIGN32 0x0000C000L
+#define TULIP_BUSMODE_TXPOLL_NEVER 0x00000000L
+#define TULIP_BUSMODE_TXPOLL_200000ns 0x00020000L
+#define TULIP_BUSMODE_TXPOLL_800000ns 0x00040000L
+#define TULIP_BUSMODE_TXPOLL_1600000ns 0x00060000L
+#define TULIP_BUSMODE_TXPOLL_12800ns 0x00080000L /* DC21041 only */
+#define TULIP_BUSMODE_TXPOLL_25600ns 0x000A0000L /* DC21041 only */
+#define TULIP_BUSMODE_TXPOLL_51200ns 0x000C0000L /* DC21041 only */
+#define TULIP_BUSMODE_TXPOLL_102400ns 0x000E0000L /* DC21041 only */
+#define TULIP_BUSMODE_DESC_BIGENDIAN 0x00100000L /* DC21041 only */
+
+/*
+ * These are the defintitions used for the DEC DC21140
+ * evaluation board.
+ */
+#define TULIP_GP_EB_PINS 0x0000011F /* General Purpose Pin directions */
+#define TULIP_GP_EB_OK10 0x00000080 /* 10 Mb/sec Signal Detect gep<7> */
+#define TULIP_GP_EB_OK100 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */
+#define TULIP_GP_EB_INIT 0x0000000B /* No loopback --- point-to-point */
+
+/*
+ * There are the definitions used for the DEC DE500-XA
+ * 10/100 board
+ */
+#define TULIP_GP_DE500_PINS 0x0000010FL
+#define TULIP_GP_DE500_NOTOK_10 0x00000080L
+#define TULIP_GP_DE500_NOTOK_100 0x00000040L
+#define TULIP_GP_DE500_HALFDUPLEX 0x00000008L
+#define TULIP_GP_DE500_FORCE_100 0x00000001L
+
+/*
+ * These are the defintitions used for the Cogent EM100
+ * DC21140 board.
+ */
+#define TULIP_GP_EM100_PINS 0x0000013F /* General Purpose Pin directions */
+#define TULIP_GP_EM100_INIT 0x00000009 /* No loopback --- point-to-point */
+#define TULIP_OUI_COGENT_0 0x00
+#define TULIP_OUI_COGENT_1 0x00
+#define TULIP_OUI_COGENT_2 0x94
+#define TULIP_COGENT_EM100_ID 0x12
+
+
+/*
+ * These are the defintitions used for the Znyx ZX342
+ * 10/100 board
+ */
+#define TULIP_GP_ZX34X_PINS 0x0000011F /* General Purpose Pin directions */
+#define TULIP_GP_ZX34X_OK10 0x00000080 /* 10 Mb/sec Signal Detect gep<7> */
+#define TULIP_GP_ZX34X_OK100 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */
+#define TULIP_GP_ZX34X_INIT 0x00000009
+#define TULIP_OUI_ZNYX_0 0x00
+#define TULIP_OUI_ZNYX_1 0xC0
+#define TULIP_OUI_ZNYX_2 0x95
+
+
+/*
+ * SROM definitions for the DC21140 and DC21041.
+ */
+#define SROMSEL 0x0800
+#define SROMRD 0x4000
+#define SROMWR 0x2000
+#define SROMDIN 0x0008
+#define SROMDOUT 0x0004
+#define SROMDOUTON 0x0004
+#define SROMDOUTOFF 0x0004
+#define SROMCLKON 0x0002
+#define SROMCLKOFF 0x0002
+#define SROMCSON 0x0001
+#define SROMCSOFF 0x0001
+#define SROMCS 0x0001
+
+#define SROMCMD_MODE 4
+#define SROMCMD_WR 5
+#define SROMCMD_RD 6
+
+#define SROM_BITWIDTH 6
+
+/*
+ * Definitions for the DE425.
+ */
+#define DE425_CFID 0x08 /* Configuration Id */
+#define DE425_CFCS 0x0C /* Configuration Command-Status */
+#define DE425_CFRV 0x18 /* Configuration Revision */
+#define DE425_CFLT 0x1C /* Configuration Latency Timer */
+#define DE425_CBIO 0x28 /* Configuration Base IO Address */
+#define DE425_CFDA 0x2C /* Configuration Driver Area */
+#define DE425_ENETROM_OFFSET 0xC90 /* Offset in I/O space for ENETROM */
+#define DE425_CFG0 0xC88 /* IRQ register */
+
+#define DEC_VENDORID 0x1011
+#define DC21040_CHIPID 0x0002
+#define DC21140_CHIPID 0x0009
+#define DC21041_CHIPID 0x0014
+#define PCI_VENDORID(x) ((x) & 0xFFFF)
+#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
+
+#endif /* !defined(_DC21040_H) */
diff --git a/sys/dev/ic/dp8390reg.h b/sys/dev/ic/dp8390reg.h
new file mode 100644
index 00000000000..ba7aad30bda
--- /dev/null
+++ b/sys/dev/ic/dp8390reg.h
@@ -0,0 +1,550 @@
+/* $NetBSD: dp8390reg.h,v 1.2 1995/04/12 16:12:42 mycroft Exp $ */
+
+/*
+ * National Semiconductor DS8390 NIC register definitions.
+ *
+ * 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.
+ */
+
+/*
+ * 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 boundary 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 Tally
+ * 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 boundary 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 boundary 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 boundary and the CRC did not match at the last byte boundary.
+ */
+#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
+ * boundary 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 {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char next_packet; /* pointer to next packet */
+ u_char rsr; /* receiver status */
+#else
+ u_char rsr; /* receiver status */
+ u_char next_packet; /* pointer to next packet */
+#endif
+ u_short count; /* bytes in packet (length + 4) */
+};
+
+/*
+ * Common constants
+ */
+#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */
+#define ED_PAGE_MASK 255
+#define ED_PAGE_SHIFT 8
+
+#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */
diff --git a/sys/dev/ic/i8042reg.h b/sys/dev/ic/i8042reg.h
new file mode 100644
index 00000000000..b2fc306d4d5
--- /dev/null
+++ b/sys/dev/ic/i8042reg.h
@@ -0,0 +1,44 @@
+/* $NetBSD: i8042reg.h,v 1.6 1995/04/21 09:16:16 mycroft Exp $ */
+
+#define KBSTATP 0x64 /* kbd controller status port (I) */
+#define KBS_DIB 0x01 /* kbd data in buffer */
+#define KBS_IBF 0x02 /* kbd input buffer low */
+#define KBS_WARM 0x04 /* kbd input buffer low */
+#define KBS_OCMD 0x08 /* kbd output buffer has command */
+#define KBS_NOSEC 0x10 /* kbd security lock not engaged */
+#define KBS_TERR 0x20 /* kbd transmission error */
+#define KBS_RERR 0x40 /* kbd receive error */
+#define KBS_PERR 0x80 /* kbd parity error */
+
+#define KBCMDP 0x64 /* kbd controller port (O) */
+#define KBC_RAMREAD 0x20 /* read from RAM */
+#define KBC_RAMWRITE 0x60 /* write to RAM */
+#define KBC_AUXDISABLE 0xa7 /* disable auxiliary port */
+#define KBC_AUXENABLE 0xa8 /* enable auxiliary port */
+#define KBC_AUXTEST 0xa9 /* test auxiliary port */
+#define KBC_KBDECHO 0xd2 /* echo to keyboard port */
+#define KBC_AUXECHO 0xd3 /* echo to auxiliary port */
+#define KBC_AUXWRITE 0xd4 /* write to auxiliary port */
+#define KBC_SELFTEST 0xaa /* start self-test */
+#define KBC_KBDTEST 0xab /* test keyboard port */
+#define KBC_KBDDISABLE 0xad /* disable keyboard port */
+#define KBC_KBDENABLE 0xae /* enable keyboard port */
+#define KBC_PULSE0 0xfe /* pulse output bit 0 */
+#define KBC_PULSE1 0xfd /* pulse output bit 1 */
+#define KBC_PULSE2 0xfb /* pulse output bit 2 */
+#define KBC_PULSE3 0xf7 /* pulse output bit 3 */
+
+#define KBDATAP 0x60 /* kbd data port (I) */
+#define KBOUTP 0x60 /* kbd data port (O) */
+
+#define K_RDCMDBYTE 0x20
+#define K_LDCMDBYTE 0x60
+
+#define KC8_TRANS 0x40 /* convert to old scan codes */
+#define KC8_MDISABLE 0x20 /* disable mouse */
+#define KC8_KDISABLE 0x10 /* disable keyboard */
+#define KC8_IGNSEC 0x08 /* ignore security lock */
+#define KC8_CPU 0x04 /* exit from protected mode reset */
+#define KC8_MENABLE 0x02 /* enable mouse interrupt */
+#define KC8_KENABLE 0x01 /* enable keyboard interrupt */
+#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE)
diff --git a/sys/dev/ic/i8237reg.h b/sys/dev/ic/i8237reg.h
new file mode 100644
index 00000000000..68a4e767930
--- /dev/null
+++ b/sys/dev/ic/i8237reg.h
@@ -0,0 +1,13 @@
+/* $NetBSD: i8237reg.h,v 1.4 1994/10/27 04:18:39 cgd Exp $ */
+
+/*
+ * Intel 8237 DMA Controller
+ */
+
+#define DMA37MD_SINGLE 0x40 /* single pass mode */
+#define DMA37MD_CASCADE 0xc0 /* cascade mode */
+#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */
+#define DMA37MD_READ 0x08 /* write the device, read memory operation */
+
+#define DMA37SM_CLEAR 0x00 /* clear mask bit */
+#define DMA37SM_SET 0x04 /* set mask bit */
diff --git a/sys/dev/ic/i82586reg.h b/sys/dev/ic/i82586reg.h
new file mode 100644
index 00000000000..fefaed3e346
--- /dev/null
+++ b/sys/dev/ic/i82586reg.h
@@ -0,0 +1,289 @@
+/* $NetBSD: i82586reg.h,v 1.5 1995/04/04 01:59:34 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * 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
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * 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 UNIVERSITY OR 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+
+/*
+ * This is the master configuration block. It tells the hardware where all
+ * the rest of the stuff is.
+ */
+struct ie_sys_conf_ptr {
+ u_short mbz; /* must be zero */
+ u_char ie_bus_use; /* true if 8-bit only */
+ u_char mbz2[5]; /* must be zero */
+ caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
+};
+
+/*
+ * Note that this is wired in hardware; the SCP is always located here, no
+ * matter what.
+ */
+#define IE_SCP_ADDR 0xfffff4
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_int_sys_conf_ptr {
+ u_char ie_busy; /* zeroed after init */
+ u_char mbz;
+ u_short ie_scb_offset; /* 16-bit physaddr of next struct */
+ caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */
+};
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_sys_ctl_block {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list; /* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource; /* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+
+/* Command values */
+#define IE_RU_COMMAND 0x0070 /* mask for RU command */
+#define IE_RU_NOP 0 /* for completeness */
+#define IE_RU_START 0x0010 /* start receive unit command */
+#define IE_RU_ENABLE 0x0020 /* enable receiver command */
+#define IE_RU_DISABLE 0x0030 /* disable receiver command */
+#define IE_RU_ABORT 0x0040 /* abort current receive operation */
+
+#define IE_CU_COMMAND 0x0700 /* mask for CU command */
+#define IE_CU_NOP 0 /* included for completeness */
+#define IE_CU_START 0x0100 /* do-command command */
+#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */
+#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */
+#define IE_CU_ABORT 0x0400 /* abort current command */
+
+#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
+#define IE_ACK_CX 0x8000 /* ack IE_ST_CX */
+#define IE_ACK_FR 0x4000 /* ack IE_ST_FR */
+#define IE_ACK_CNA 0x2000 /* ack IE_ST_CNA */
+#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
+#define IE_ST_CX 0x8000 /* command with I bit completed */
+#define IE_ST_FR 0x4000 /* frame received */
+#define IE_ST_CNA 0x2000 /* all commands completed */
+#define IE_ST_RNR 0x1000 /* receive not ready */
+
+#define IE_CU_STATUS 0x700 /* mask for command unit status */
+#define IE_CU_ACTIVE 0x200 /* command unit is active */
+#define IE_CU_SUSPEND 0x100 /* command unit is suspended */
+
+#define IE_RU_STATUS 0x70 /* mask for receiver unit status */
+#define IE_RU_SUSPEND 0x10 /* receiver is suspended */
+#define IE_RU_NOSPACE 0x20 /* receiver has no resources */
+#define IE_RU_READY 0x40 /* reveiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_FD_LAST 0x8000 /* last rfd in list */
+#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE 0x8000 /* frame is complete */
+#define IE_FD_BUSY 0x4000 /* frame is busy */
+#define IE_FD_OK 0x2000 /* frame is bad */
+#define IE_FD_RNR 0x0200 /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_RBD_LAST 0x8000 /* last buffer */
+#define IE_RBD_USED 0x4000 /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+
+#define IE_STAT_COMPL 0x8000 /* command is completed */
+#define IE_STAT_BUSY 0x4000 /* command is running now */
+#define IE_STAT_OK 0x2000 /* command completed successfully */
+#define IE_STAT_ABORT 0x1000 /* command was aborted */
+
+#define IE_CMD_NOP 0x0000 /* NOP */
+#define IE_CMD_IASETUP 0x0001 /* initial address setup */
+#define IE_CMD_CONFIG 0x0002 /* configure command */
+#define IE_CMD_MCAST 0x0003 /* multicast setup command */
+#define IE_CMD_XMIT 0x0004 /* transmit command */
+#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
+#define IE_CMD_DUMP 0x0006 /* dump command */
+#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
+
+#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
+#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
+#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+
+#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
+#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
+#define IE_XS_SQE 0x0040 /* SQE positive */
+#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
+#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
+#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
+#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
+#define IE_XS_LATECOLL 0x0800 /* Late collision */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */
+};
+
+#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 250 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+
+#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
+#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
+#define IE_TDR_OPEN 0x2000 /* detected an open */
+#define IE_TDR_SHORT 0x1000 /* TDR detected a short */
+#define IE_TDR_TIME 0x07ff /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count; /* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
diff --git a/sys/dev/ic/ics2101reg.h b/sys/dev/ic/ics2101reg.h
new file mode 100644
index 00000000000..12d944af910
--- /dev/null
+++ b/sys/dev/ic/ics2101reg.h
@@ -0,0 +1,79 @@
+/* $NetBSD: ics2101reg.h,v 1.1 1995/07/19 19:58:33 brezak Exp $ */
+/*
+ * Copyright (c) 1994, 1995 Ken Hornstein. All rights reserved.
+ * Copyright (c) 1995 John T. Kohl. 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 Ken Hornstein.
+ * 4. The name of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
+ *
+ * $Id: ics2101reg.h,v 1.1 1995/10/18 08:52:31 deraadt Exp $
+ */
+
+/*
+ * Register defs for Integrated Circuit Systems, Inc. ICS-2101 mixer
+ * chip, used on Gravis UltraSound cards.
+ *
+ * Block diagram:
+ * port #
+ * 0 +----+
+ * Mic in (Right/Left) -->--->---| |
+ * 1 | | amp --->---- amp out
+ * Line in (Right/Left) -->--->---| | |
+ * 2 | | |
+ * CD in (Right/Left) -->--->---| |--->---+---+----->---- line out
+ * 3 | | |
+ * GF1 Out (Right/Left) -->--->---| | |
+ * 4 | | |
+ * Unused (Right/Left) -->--->---| | |
+ * +----+ v
+ * ICS 2101 |
+ * |
+ * To GF1 Sample Input ---<---------------+
+ *
+ * Master output volume: mixer channel #5
+ */
+
+/*
+ * ICS Mixer registers
+ */
+
+#define ICSMIX_CTRL_LEFT 0x00 /* Control left channel */
+#define ICSMIX_CTRL_RIGHT 0x01 /* Control right channel */
+#define ICSMIX_ATTN_LEFT 0x02 /* Attenuate left channel */
+#define ICSMIX_ATTN_RIGHT 0x03 /* Attenutate right channel */
+#define ICSMIX_PAEN 0x04 /* Panning control */
+#define ICSMIX_CHAN_0 0 /* Values for mixer channels */
+#define ICSMIX_CHAN_1 1
+#define ICSMIX_CHAN_2 2
+#define ICSMIX_CHAN_3 3
+#define ICSMIX_CHAN_4 4
+#define ICSMIX_CHAN_5 5
+
+#define ICSMIX_MIN_ATTN 0x7f
+#define ICSMIX_MAX_ATTN 0x00
+/*
+ * The ICS mixer is write-only--it cannot be queried for current settings.
+ * Drivers must keep track of current values themselves.
+ */
diff --git a/sys/dev/ic/mb86960reg.h b/sys/dev/ic/mb86960reg.h
new file mode 100644
index 00000000000..ebbb0ea70aa
--- /dev/null
+++ b/sys/dev/ic/mb86960reg.h
@@ -0,0 +1,320 @@
+/*
+ * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
+ *
+ * This software may be used, modified, copied, distributed, and sold, in
+ * both source and binary form provided that the above copyright, these
+ * terms and the following disclaimer are retained. The name of the author
+ * and/or the contributor 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 AND THE CONTRIBUTOR ``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 OR THE CONTRIBUTOR 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.
+ */
+
+#define FE_MB86960_H_VERSION "mb86960.h ver. 0.8"
+
+/*
+ * Registers of Fujitsu MB86960A/MB86965A Ethernet controller.
+ * Written and contributed by M.S. <seki@sysrap.cs.fujitsu.co.jp>
+ */
+
+/*
+ * Notes on register naming:
+ *
+ * Fujitsu documents for MB86960A/MB86965A uses no mnemorable names
+ * for their registers. They defined only three names for 32
+ * registers and appended numbers to distinguish registers of
+ * same name. Surprisingly, the numbers represent I/O address
+ * offsets of the registers from the base addresses, and their
+ * names correspond to the "bank" the registers are allocated.
+ * All this means that, for example, to say "read DLCR8" has no more
+ * than to say "read a register at offset 8 on bank DLCR."
+ *
+ * The following definitions may look silly, but that's what Fujitsu
+ * did, and it is necessary to know these names to read Fujitsu
+ * documents..
+ */
+
+/* Data Link Control Registrs, on invaliant port addresses. */
+#define FE_DLCR0 0
+#define FE_DLCR1 1
+#define FE_DLCR2 2
+#define FE_DLCR3 3
+#define FE_DLCR4 4
+#define FE_DLCR5 5
+#define FE_DLCR6 6
+#define FE_DLCR7 7
+
+/* More DLCRs, on register bank #0. */
+#define FE_DLCR8 8
+#define FE_DLCR9 9
+#define FE_DLCR10 10
+#define FE_DLCR11 11
+#define FE_DLCR12 12
+#define FE_DLCR13 13
+#define FE_DLCR14 14
+#define FE_DLCR15 15
+
+/* Malticast Address Registers. On register bank #1. */
+#define FE_MAR8 8
+#define FE_MAR9 9
+#define FE_MAR10 10
+#define FE_MAR11 11
+#define FE_MAR12 12
+#define FE_MAR13 13
+#define FE_MAR14 14
+#define FE_MAR15 15
+
+/* Buffer Memory Port Registers. On register back #2. */
+#define FE_BMPR8 8
+#define FE_BMPR9 9
+#define FE_BMPR10 10
+#define FE_BMPR11 11
+#define FE_BMPR12 12
+#define FE_BMPR13 13
+#define FE_BMPR14 14
+#define FE_BMPR15 15
+
+/* More BMPRs, only on MB86965A, accessible only when JLI mode. */
+#define FE_BMPR16 16
+#define FE_BMPR17 17
+#define FE_BMPR18 18
+#define FE_BMPR19 19
+
+#define FE_RESET 31
+
+/*
+ * Definitions of registers.
+ * I don't have Fujitsu documents of MB86960A/MB86965A, so I don't
+ * know the official names for each flags and fields. The following
+ * names are assigned by me (the author of this file,) since I cannot
+ * mnemorize hexadecimal constants for all of these functions.
+ * Comments? FIXME.
+ */
+
+/* DLCR0 -- transmitter status */
+#define FE_D0_BUSERR 0x01 /* Bus write error */
+#define FE_D0_COLL16 0x02 /* Collision limit (16) encountered */
+#define FE_D0_COLLID 0x04 /* Collision on last transmission */
+#define FE_D0_JABBER 0x08 /* Jabber */
+#define FE_D0_CRLOST 0x10 /* Carrier lost on last transmission */
+#define FE_D0_PKTRCD 0x20 /* No corrision on last transmission */
+#define FE_D0_NETBSY 0x40 /* Network Busy (Carrier Detected) */
+#define FE_D0_TXDONE 0x80 /* Transmission complete */
+
+/* DLCR1 -- receiver status */
+#define FE_D1_OVRFLO 0x01 /* Receiver buffer overflow */
+#define FE_D1_CRCERR 0x02 /* CRC error on last packet */
+#define FE_D1_ALGERR 0x04 /* Alignment error on last packet */
+#define FE_D1_SRTPKT 0x08 /* Short (RUNT) packet is received */
+#define FE_D1_RMTRST 0x10 /* Remote reset packet (type = 0x0900) */
+#define FE_D1_DMAEOP 0x20 /* Host asserted End of DMA OPeration */
+#define FE_D1_BUSERR 0x40 /* Bus read error */
+#define FE_D1_PKTRDY 0x80 /* Packet(s) ready on receive buffer */
+
+#define FE_D1_ERRBITS "\20\4SRTPKT\3ALGERR\2CRCERR\1OVRFLO"
+
+/* DLCR2 -- transmitter interrupt control; same layout as DLCR0 */
+#define FE_D2_BUSERR FE_D0_BUSERR
+#define FE_D2_COLL16 FE_D0_COLL16
+#define FE_D2_COLLID FE_D0_COLLID
+#define FE_D2_JABBER FE_D0_JABBER
+#define FE_D2_TXDONE FE_D0_TXDONE
+
+#define FE_D2_RESERVED 0x70
+
+/* DLCR3 -- receiver interrupt control; same layout as DLCR1 */
+#define FE_D3_OVRFLO FE_D1_OVRFLO
+#define FE_D3_CRCERR FE_D1_CRCERR
+#define FE_D3_ALGERR FE_D1_ALGERR
+#define FE_D3_SRTPKT FE_D1_SRTPKT
+#define FE_D3_RMTRST FE_D1_RMTRST
+#define FE_D3_DMAEOP FE_D1_DMAEOP
+#define FE_D3_BUSERR FE_D1_BUSERR
+#define FE_D3_PKTRDY FE_D1_PKTRDY
+
+/* DLCR4 -- transmitter operation mode */
+#define FE_D4_DSC 0x01 /* Disable carrier sense on trans. */
+#define FE_D4_LBC 0x02 /* Loop back test control */
+#define FE_D4_CNTRL 0x04 /* - ??? */
+#define FE_D4_TEST1 0x08 /* Test output #1 */
+#define FE_D4_COL 0xF0 /* Collision counter */
+
+#define FE_D4_LBC_ENABLE 0x00 /* Perform loop back test */
+#define FE_D4_LBC_DISABLE 0x02 /* Normal operation */
+
+#define FE_D4_COL_SHIFT 4
+
+/* DLCR5 -- receiver operation mode */
+#define FE_D5_AFM0 0x01 /* Receive packets for other stations */
+#define FE_D5_AFM1 0x02 /* Receive packets for this station */
+#define FE_D5_RMTRST 0x04 /* Enable remote reset operation */
+#define FE_D5_SRTPKT 0x08 /* Accept short (RUNT) packets */
+#define FE_D5_SRTADR 0x10 /* Short (16 bits?) MAC address */
+#define FE_D5_BADPKT 0x20 /* Accept packets with error */
+#define FE_D5_BUFEMP 0x40 /* Receive buffer is empty */
+#define FE_D5_TEST2 0x80 /* Test output #2 */
+
+/* DLCR6 -- hardware configuration #0 */
+#define FE_D6_BUFSIZ 0x03 /* Size of NIC buffer SRAM */
+#define FE_D6_TXBSIZ 0x0C /* Size (and config)of trans. buffer */
+#define FE_D6_BBW 0x10 /* Buffer SRAM bus width */
+#define FE_D6_SBW 0x20 /* System bus width */
+#define FE_D6_SRAM 0x40 /* Buffer SRAM access time */
+#define FE_D6_DLC 0x80 /* Disable DLC (recever/transmitter) */
+
+#define FE_D6_BUFSIZ_8KB 0x00 /* The board has 8KB SRAM */
+#define FE_D6_BUFSIZ_16KB 0x01 /* The board has 16KB SRAM */
+#define FE_D6_BUFSIZ_32KB 0x02 /* The board has 32KB SRAM */
+#define FE_D6_BUFSIZ_64KB 0x03 /* The board has 64KB SRAM */
+
+#define FE_D6_TXBSIZ_1x2KB 0x00 /* Single 2KB buffer for trans. */
+#define FE_D6_TXBSIZ_2x2KB 0x04 /* Double 2KB buffers */
+#define FE_D6_TXBSIZ_2x4KB 0x08 /* Double 4KB buffers */
+#define FE_D6_TXBSIZ_2x8KB 0x0C /* Double 8KB buffers */
+
+#define FE_D6_BBW_WORD 0x00 /* SRAM has 16 bit data line */
+#define FE_D6_BBW_BYTE 0x10 /* SRAM has 8 bit data line */
+
+#define FE_D6_SBW_WORD 0x00 /* Access with 16 bit (AT) bus */
+#define FE_D6_SBW_BYTE 0x20 /* Access with 8 bit (XT) bus */
+
+#define FE_D6_SRAM_150ns 0x00 /* The board has slow SRAM */
+#define FE_D6_SRAM_100ns 0x40 /* The board has fast SRAM */
+
+#define FE_D6_DLC_ENABLE 0x00 /* Normal operation */
+#define FE_D6_DLC_DISABLE 0x80 /* Stop sending/receiving */
+
+/* DLC7 -- hardware configuration #1 */
+#define FE_D7_BYTSWP 0x01 /* Host byte order control */
+#define FE_D7_EOPPOL 0x02 /* Polarity of DMA EOP signal */
+#define FE_D7_RBS 0x0C /* Register bank select */
+#define FE_D7_RDYPNS 0x10 /* Senses RDYPNSEL input signal */
+#define FE_D7_POWER 0x20 /* Stand-by (power down) mode control */
+#define FE_D7_IDENT 0xC0 /* Chip identification */
+
+#define FE_D7_BYTSWP_LH 0x00 /* DEC/Intel byte order */
+#define FE_D7_BYTSWP_HL 0x01 /* IBM/Motorolla byte order */
+
+#define FE_D7_RBS_DLCR 0x00 /* Select DLCR8-15 */
+#define FE_D7_RBS_MAR 0x04 /* Select MAR8-15 */
+#define FE_D7_RBS_BMPR 0x08 /* Select BMPR8-15 */
+
+#define FE_D7_POWER_DOWN 0x00 /* Power down (stand-by) mode */
+#define FE_D7_POWER_UP 0x20 /* Normal operation */
+
+#define FE_D7_IDENT_NICE 0x80
+#define FE_D7_IDENT_EC 0xC0
+
+/* DLCR8 thru DLCR13 are for Ethernet station address. */
+
+/* DLCR14 and DLCR15 are for TDR. (BTW, what is TDR? FIXME.) */
+
+/* MAR8 thru MAR15 are for Multicast address filter. */
+
+/* BMPR8 and BMPR9 are for packet data. */
+
+/* BMPR10 -- transmitter start trigger */
+#define FE_B10_START 0x80 /* Start transmitter */
+#define FE_B10_COUNT 0x7F /* Packet count */
+
+/* BMPR11 -- 16 collisions control */
+#define FE_B11_CTRL 0x01 /* Skip or resend errored packets */
+#define FE_B11_MODE1 0x02 /* Restart transmitter after COLL16 */
+#define FE_B11_MODE2 0x04 /* Automatic restart enable */
+
+#define FE_B11_CTRL_RESEND 0x00 /* Re-send the collided packet */
+#define FE_B11_CTRL_SKIP 0x01 /* Skip the collided packet */
+
+/* BMPR12 -- DMA enable */
+#define FE_B12_TXDMA 0x01 /* Enable transmitter DMA */
+#define FE_B12_RXDMA 0x02 /* Enable receiver DMA */
+
+/* BMPR13 -- DMA control */
+#define FE_B13_BSTCTL 0x03 /* DMA burst mode control */
+#define FE_B13_TPTYPE 0x04 /* Twisted pair cable impedance */
+#define FE_B13_PORT 0x18 /* Port (TP/AUI) selection */
+#define FE_B13_LNKTST 0x20 /* Link test enable */
+#define FE_B13_SQTHLD 0x40 /* Lower squelch threshold */
+#define FE_B13_IOUNLK 0x80 /* Change I/O base address */
+
+#define FE_B13_BSTCTL_1 0x00
+#define FE_B13_BSTCTL_4 0x01
+#define FE_B13_BSTCTL_8 0x02
+#define FE_B13_BSTCLT_12 0x03
+
+#define FE_B13_TPTYPE_UTP 0x00 /* Unshielded (standard) cable */
+#define FE_B13_TPTYPE_STP 0x04 /* Shielded (IBM) cable */
+
+#define FE_B13_PORT_AUTO 0x00 /* Auto detected */
+#define FE_B13_PORT_TP 0x08 /* Force TP */
+#define FE_B13_PORT_AUI 0x18 /* Force AUI */
+
+/* BMPR14 -- More receiver control and more transmission interrupts */
+#define FE_B14_FILTER 0x01 /* Filter out self-originated packets */
+#define FE_B14_SQE 0x02 /* SQE interrupt enable */
+#define FE_B14_SKIP 0x04 /* Skip a received packet */
+#define FE_B14_RJAB 0x20 /* RJAB interrupt enable */
+#define FE_B14_LLD 0x40 /* Local-link-down interrupt enable */
+#define FE_B14_RLD 0x80 /* Remote-link-down interrupt enable */
+
+/* BMPR15 -- More transmitter status; basically same layout as BMPR14 */
+#define FE_B15_SQE FE_B14_SQE
+#define FE_B15_RCVPOL 0x08 /* Reversed receive line polarity */
+#define FE_B15_RMTPRT 0x10 /* ??? */
+#define FE_B15_RAJB FE_B14_RJAB
+#define FE_B15_LLD FE_B14_LLD
+#define FE_B15_RLD FE_B14_RLD
+
+/* BMPR16 -- EEPROM control */
+#define FE_B16_DOUT 0x04 /* EEPROM Data in (CPU to EEPROM) */
+#define FE_B16_SELECT 0x20 /* EEPROM chip select */
+#define FE_B16_CLOCK 0x40 /* EEPROM shift clock */
+#define FE_B16_DIN 0x80 /* EEPROM data out (EEPROM to CPU) */
+
+/* BMPR17 -- EEPROM data */
+#define FE_B17_DATA 0x80 /* EEPROM data bit */
+
+/* BMPR18 ??? */
+
+/* BMPR19 -- ISA interface configuration */
+#define FE_B19_IRQ 0xC0
+#define FE_B19_IRQ_SHIFT 6
+
+#define FE_B19_ROM 0x38
+#define FE_B19_ROM_SHIFT 3
+
+#define FE_B19_ADDR 0x07
+#define FE_B19_ADDR_SHIFT 0
+
+/*
+ * EEPROM specification (of JLI mode).
+ */
+
+/* Number of bytes in an EEPROM accessible through 86965. */
+#define FE_EEPROM_SIZE 32
+
+/* Offset for JLI config; automatically copied into BMPR19 at startup. */
+#define FE_EEPROM_CONF 0
+
+/*
+ * Some 86960 specific constants.
+ */
+
+/* Length (in bytes) of a Multicast Address Filter. */
+#define FE_FILTER_LEN 8
+
+/* How many packets we can put in the transmission buffer on NIC memory. */
+#define FE_QUEUEING_MAX 127
+
+/* Length (in bytes) of a "packet length" word in transmission buffer. */
+#define FE_DATA_LEN_LEN 2
diff --git a/sys/dev/ic/mc146818reg.h b/sys/dev/ic/mc146818reg.h
new file mode 100644
index 00000000000..27a3ba20e6a
--- /dev/null
+++ b/sys/dev/ic/mc146818reg.h
@@ -0,0 +1,194 @@
+/* $NetBSD: mc146818reg.h,v 1.1 1995/05/04 19:31:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Definitions for the Motorola MC146818A Real Time Clock.
+ * They also apply for the (compatible) Dallas Semicontuctor DS1287A RTC.
+ *
+ * Though there are undoubtedly other (better) sources, this material was
+ * culled from the DEC "KN121 System Module Programmer's Reference
+ * Information."
+ *
+ * The MC146818A has 16 registers. The first 10 contain time-of-year
+ * and alarm data. The rest contain various control and status bits.
+ *
+ * To read or write the registers, one writes the register number to
+ * the RTC's control port, then either reads from or writes the new
+ * data to the RTC's data port. Since the locations of these ports
+ * and the method used to access them can be machine-dependent, the
+ * low-level details of reading and writing the RTC's registers are
+ * handled by machine-specific functions.
+ *
+ * The time-of-year and alarm data can be expressed in either binary
+ * or BCD, and they are selected by a bit in register B.
+ *
+ * The "hour" time-of-year and alarm fields can either be expressed in
+ * AM/PM format, or in 24-hour format. If AM/PM format is chosen, the
+ * hour fields can have the values: 1-12 and 81-92 (the latter being
+ * PM). If the 24-hour format is chosen, they can have the values
+ * 0-24. The hour format is selectable by a bit in register B.
+ * (XXX IS AM/PM MODE DESCRIPTION CORRECT?)
+ *
+ * It is assumed the if systems are going to use BCD (rather than
+ * binary) mode, or AM/PM hour format, they'll do the appropriate
+ * conversions in machine-dependent code. Also, if the clock is
+ * switched between BCD and binary mode, or between AM/PM mode and
+ * 24-hour mode, the time-of-day and alarm registers are NOT
+ * automatically reset; they must be reprogrammed with correct values.
+ */
+
+/*
+ * The registers, and the bits within each register.
+ */
+
+#define MC_SEC 0x0 /* Time of year: seconds (0-59) */
+#define MC_ASEC 0x1 /* Alarm: seconds */
+#define MC_MIN 0x2 /* Time of year: minutes (0-59) */
+#define MC_AMIN 0x3 /* Alarm: minutes */
+#define MC_HOUR 0x4 /* Time of year: hour (see above) */
+#define MC_AHOUR 0x5 /* Alarm: hour */
+#define MC_DOW 0x6 /* Time of year: day of week (1-7) */
+#define MC_DOM 0x7 /* Time of year: day of month (1-31) */
+#define MC_MONTH 0x8 /* Time of year: month (1-12) */
+#define MC_YEAR 0x9 /* Time of year: year in century (0-99) */
+
+#define MC_REGA 0xa /* Control register A */
+
+#define MC_REGA_RSMASK 0x0f /* Interrupt rate select mask (see below) */
+#define MC_REGA_DVMASK 0x70 /* Divisor select mask (see below) */
+#define MC_REGA_UIP 0x80 /* Update in progress; read only. */
+
+#define MC_REGB 0xb /* Control register B */
+
+#define MC_REGB_DSE 0x01 /* Daylight Savings Enable */
+#define MC_REGB_24HR 0x02 /* 24-hour mode (AM/PM mode when clear) */
+#define MC_REGB_BINARY 0x04 /* Binary mode (BCD mode when clear) */
+/* MC_REGB_UNUSED 0x08 UNUSED */
+#define MC_REGB_UIE 0x10 /* Update End interrupt enable */
+#define MC_REGB_AIE 0x20 /* Alarm interrupt enable */
+#define MC_REGB_PIE 0x40 /* Periodic interrupt enable */
+#define MC_REGB_SET 0x80 /* Allow time to be set; stops updates */
+
+#define MC_REGC 0xc /* Control register C */
+
+/* MC_REGC_UNUSED 0x0f UNUSED */
+#define MC_REGC_UF 0x10 /* Update End interrupt flag */
+#define MC_REGC_AF 0x20 /* Alarm interrupt flag */
+#define MC_REGC_PF 0x40 /* Periodic interrupt flag */
+#define MC_REGC_IRQF 0x80 /* Interrupt request pending flag */
+
+#define MC_REGD 0xd /* Control register D */
+
+/* MC_REGD_UNUSED 0x7f UNUSED */
+#define MC_REGD_VRT 0x80 /* Valid RAM and Time bit */
+
+
+#define MC_NREGS 0xe /* 14 registers; CMOS follows */
+#define MC_NTODREGS 0xa /* 10 of those regs are for TOD and alarm */
+
+#define MC_NVRAM_START 0xe /* start of NVRAM: offset 14 */
+#define MC_NVRAM_SIZE 50 /* 50 bytes of NVRAM */
+
+/*
+ * Periodic Interrupt Rate Select constants (Control register A)
+ */
+#define MC_RATE_NONE 0x0 /* No periodic interrupt */
+#define MC_RATE_1 0x1 /* 256 Hz if MC_BASE_32_KHz, else 32768 Hz */
+#define MC_RATE_2 0x2 /* 128 Hz if MC_BASE_32_KHz, else 16384 Hz */
+#define MC_RATE_8192_Hz 0x3 /* 122.070 us period */
+#define MC_RATE_4096_Hz 0x4 /* 244.141 us period */
+#define MC_RATE_2048_Hz 0x5 /* 488.281 us period */
+#define MC_RATE_1024_Hz 0x6 /* 976.562 us period */
+#define MC_RATE_512_Hz 0x7 /* 1.953125 ms period */
+#define MC_RATE_256_Hz 0x8 /* 3.90625 ms period */
+#define MC_RATE_128_Hz 0x9 /* 7.8125 ms period */
+#define MC_RATE_64_Hz 0xa /* 15.625 ms period */
+#define MC_RATE_32_Hz 0xb /* 31.25 ms period */
+#define MC_RATE_16_Hz 0xc /* 62.5 ms period */
+#define MC_RATE_8_Hz 0xd /* 125 ms period */
+#define MC_RATE_4_Hz 0xe /* 250 ms period */
+#define MC_RATE_2_Hz 0xf /* 500 ms period */
+
+/*
+ * Time base (divisor select) constants (Control register A)
+ */
+#define MC_BASE_4_MHz 0x00 /* 4MHz crystal */
+#define MC_BASE_1_MHz 0x10 /* 1MHz crystal */
+#define MC_BASE_32_KHz 0x20 /* 32KHz crystal */
+#define MC_BASE_NONE 0x60 /* actually, both of these reset */
+#define MC_BASE_RESET 0x70
+
+
+/*
+ * RTC register/NVRAM read and write functions -- machine-dependent.
+ * Appropriately manipulate RTC registers to get/put data values.
+ */
+u_int mc146818_read __P((void *sc, u_int reg));
+void mc146818_write __P((void *sc, u_int reg, u_int datum));
+
+/*
+ * A collection of TOD/Alarm registers.
+ */
+typedef u_int mc_todregs[MC_NTODREGS];
+
+/*
+ * Get all of the TOD/Alarm registers
+ * Must be called at splhigh(), and with the RTC properly set up.
+ */
+#define MC146818_GETTOD(sc, regs) \
+ do { \
+ int i; \
+ \
+ /* update in progress; spin loop */ \
+ while (mc146818_read(sc, MC_REGA) & MC_REGA_UIP) \
+ ; \
+ \
+ /* read all of the tod/alarm regs */ \
+ for (i = 0; i < MC_NTODREGS; i++) \
+ (*regs)[i] = mc146818_read(sc, i); \
+ } while (0);
+
+/*
+ * Set all of the TOD/Alarm registers
+ * Must be called at splhigh(), and with the RTC properly set up.
+ */
+#define MC146818_PUTTOD(sc, regs) \
+ do { \
+ int i; \
+ \
+ /* stop updates while setting */ \
+ mc146818_write(sc, MC_REGB, \
+ mc146818_read(sc, MC_REGB) | MC_REGB_SET); \
+ \
+ /* write all of the tod/alarm regs */ \
+ for (i = 0; i < MC_NTODREGS; i++) \
+ mc146818_write(sc, i, (*regs)[i]); \
+ \
+ /* reenable updates */ \
+ mc146818_write(sc, MC_REGB, \
+ mc146818_read(sc, MC_REGB) & ~MC_REGB_SET); \
+ } while (0);
diff --git a/sys/dev/ic/ncr5380.c b/sys/dev/ic/ncr5380.c
new file mode 100644
index 00000000000..bbc68d483f4
--- /dev/null
+++ b/sys/dev/ic/ncr5380.c
@@ -0,0 +1,729 @@
+/* $NetBSD: ncr5380.c,v 1.3 1995/09/26 21:04:27 pk Exp $ */
+
+/*
+ * Copyright (C) 1994 Adam Glass, Gordon W. Ross
+ * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
+ * Michael L. Finch, Bradley A. Grantham, and
+ * Lawrence A. Kesteloot
+ * 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 Alice Group.
+ * 4. The names of the Alice Group or any of its members may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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.
+ */
+
+/*
+ * NOTE: This is 99% Sun 3 `si' driver. I've made the probe and attach
+ * routines a little minimalistic, and adjusted them slightly for the Sun 4.
+ * Also, fixed some logic in ncr5380_select_target().
+ * Jason R. Thorpe <thorpej@nas.nasa.gov>
+ */
+
+static int
+ncr5380_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ int flags, s, r;
+
+ flags = xs->flags;
+ if (xs->bp) flags |= (SCSI_NOSLEEP);
+ if ( flags & ITSDONE ) {
+ printf("Already done?");
+ xs->flags &= ~ITSDONE;
+ }
+ if ( ! ( flags & INUSE ) ) {
+ printf("Not in use?");
+ xs->flags |= INUSE;
+ }
+
+ s = splbio();
+
+ if ( flags & SCSI_RESET ) {
+ printf("flags & SCSIRESET.\n");
+ ncr5380_reset_scsibus(xs->sc_link->adapter_softc);
+ r = COMPLETE;
+ } else {
+ r = ncr5380_send_cmd(xs);
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ }
+
+ splx(s);
+
+ switch(r) {
+ case COMPLETE:
+ case SUCCESSFULLY_QUEUED:
+ r = SUCCESSFULLY_QUEUED;
+ if (xs->flags & SCSI_POLL)
+ r = COMPLETE;
+ break;
+ default:
+ break;
+ }
+ return r;
+}
+
+#ifdef DEBUG
+static int
+ncr5380_show_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ u_char *b = (u_char *) xs->cmd;
+ int i = 0;
+
+ if ( ! ( xs->flags & SCSI_RESET ) ) {
+ printf("si(%d:%d:%d)-",
+ xs->sc_link->scsibus,
+ xs->sc_link->target,
+ xs->sc_link->lun);
+ while (i < xs->cmdlen) {
+ if (i) printf(",");
+ printf("%x",b[i++]);
+ }
+ printf("-\n");
+ } else {
+ printf("si(%d:%d:%d)-RESET-\n",
+ xs->sc_link->scsibus,
+ xs->sc_link->target,
+ xs->sc_link->lun);
+ }
+}
+#endif
+
+/*
+ * Actual chip control.
+ */
+
+static void
+ncr5380_sbc_intr(ncr5380)
+ struct ncr5380_softc *ncr5380;
+{
+ volatile sci_regmap_t *regs = ncr5380->sc_regs;
+
+ if ((regs->sci_csr & SCI_CSR_INT) == 0) {
+#ifdef DEBUG
+ printf (" ncr5380_sbc_intr: spurious\n");
+#endif
+ return;
+ }
+
+ SCI_CLR_INTR(regs);
+#ifdef DEBUG
+ printf (" ncr5380_sbc_intr\n");
+#endif
+}
+
+static int
+ncr5380_reset_scsibus(ncr5380)
+ struct ncr5380_softc *ncr5380;
+{
+ volatile sci_regmap_t *regs = ncr5380->sc_regs;
+
+#ifdef DEBUG
+ if (ncr5380_debug) {
+ printf("ncr5380_reset_scsibus\n");
+ }
+#endif
+
+ regs->sci_icmd = SCI_ICMD_RST;
+ delay(100);
+ regs->sci_icmd = 0;
+
+ regs->sci_mode = 0;
+ regs->sci_tcmd = SCI_PHASE_DISC;
+ regs->sci_sel_enb = 0;
+
+ SCI_CLR_INTR(regs);
+ /* XXX - Need long delay here! */
+}
+
+static int
+ncr5380_poll(adapter, timeout)
+ int adapter, timeout;
+{
+}
+
+static int
+ncr5380_send_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ int sense;
+
+#ifdef DEBUG
+ if (ncr5380_debug & 2)
+ ncr5380_show_scsi_cmd(xs);
+#endif
+
+ sense = ncr5380_generic( xs->sc_link->adapter_softc,
+ xs->sc_link->target, xs->sc_link->lun, xs->cmd,
+ xs->cmdlen, xs->data, xs->datalen );
+
+ switch (sense) {
+ case 0: /* success */
+ xs->resid = 0;
+ xs->error = XS_NOERROR;
+ break;
+
+ case 0x02: /* Check condition */
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf("check cond. target %d.\n",
+ xs->sc_link->target);
+#endif
+ delay(10); /* Phil's fix for slow devices. */
+ ncr5380_group0(xs->sc_link->adapter_softc,
+ xs->sc_link->target,
+ xs->sc_link->lun,
+ 0x3, 0x0,
+ sizeof(struct scsi_sense_data),
+ 0, (caddr_t) &(xs->sense),
+ sizeof(struct scsi_sense_data));
+ xs->error = XS_SENSE;
+ break;
+ case 0x08: /* Busy - common code will delay, retry. */
+ xs->error = XS_BUSY;
+ break;
+ default: /* Dead - tell common code to give up. */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ }
+ return (COMPLETE);
+}
+
+static int
+ncr5380_select_target(regs, myid, tid, with_atn)
+ register volatile sci_regmap_t *regs;
+ u_char myid, tid;
+ int with_atn;
+{
+ register u_char bid, icmd;
+ int ret = SCSI_RET_RETRY;
+ int arb_retries, arb_wait;
+ int i;
+
+ /* for our purposes.. */
+ myid = 1 << myid;
+ tid = 1 << tid;
+
+ regs->sci_sel_enb = 0; /* we don't want any interrupts. */
+ regs->sci_tcmd = 0; /* get into a harmless state */
+
+ arb_retries = ARBITRATION_RETRIES;
+
+retry_arbitration:
+ regs->sci_mode = 0; /* get into a harmless state */
+wait_for_bus_free:
+ if (--arb_retries <= 0) {
+#ifdef DEBUG
+ if (ncr5380_debug) {
+ printf("ncr5380_select: arb_retries expended; resetting...\n");
+ }
+#endif
+ ret = SCSI_RET_NEED_RESET;
+ goto nosel;
+ }
+
+ icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
+
+ if (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) {
+ /* Something is sitting on the SCSI bus... */
+#ifdef DEBUG
+ /* Only complain once (the last time through). */
+ if (ncr5380_debug && (arb_retries <= 1)) {
+ printf("si_select_target: still BSY+SEL\n");
+ }
+#endif
+ /* Give it a little time, then try again. */
+ delay(10);
+ goto wait_for_bus_free;
+ }
+
+ regs->sci_odata = myid;
+ regs->sci_mode = SCI_MODE_ARB;
+/* regs->sci_mode |= SCI_MODE_ARB; XXX? */
+
+ /* AIP might not set if BSY went true after we checked */
+ /* Wait up to about 100 usec. for it to appear. */
+ arb_wait = 50; /* X2 */
+ do {
+ if (regs->sci_icmd & SCI_ICMD_AIP)
+ goto got_aip;
+ delay(2);
+ } while (--arb_wait > 0);
+ /* XXX - Could have missed it? */
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf("ncr5380_select_target: API did not appear\n");
+#endif
+ goto retry_arbitration;
+
+ got_aip:
+#ifdef DEBUG
+ if (ncr5380_debug & 4) {
+ printf("ncr5380_select_target: API after %d tries (last wait %d)\n",
+ ARBITRATION_RETRIES - arb_retries,
+ (50 - arb_wait));
+ }
+#endif
+
+ delay(3); /* 2.2 uSec. arbitration delay */
+
+ if (regs->sci_icmd & SCI_ICMD_LST) {
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf ("lost 1\n");
+#endif
+ goto retry_arbitration; /* XXX */
+ }
+
+ regs->sci_mode &= ~SCI_MODE_PAR_CHK;
+ bid = regs->sci_data;
+
+ if ((bid & ~myid) > myid) {
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf ("lost 2\n");
+#endif
+ /* Trying again will not help. */
+ goto lost;
+ }
+ if (regs->sci_icmd & SCI_ICMD_LST) {
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf ("lost 3\n");
+#endif
+ goto lost;
+ }
+
+ /* Won arbitration, enter selection phase now */
+ icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
+ icmd |= (with_atn ? (SCI_ICMD_SEL|SCI_ICMD_ATN) : SCI_ICMD_SEL);
+ regs->sci_icmd = icmd;
+
+ if (regs->sci_icmd & SCI_ICMD_LST) {
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf ("nosel\n");
+#endif
+ goto nosel;
+ }
+
+ /* XXX a target that violates specs might still drive the bus XXX */
+ /* XXX should put our id out, and after the delay check nothi XXX */
+ /* XXX ng else is out there. XXX */
+
+ delay(3);
+
+ regs->sci_sel_enb = 0;
+
+ regs->sci_odata = myid | tid;
+
+ icmd |= SCI_ICMD_BSY|SCI_ICMD_DATA;
+ regs->sci_icmd = icmd;
+
+/* regs->sci_mode &= ~SCI_MODE_ARB; 2 deskew delays, too */
+ regs->sci_mode = 0; /* 2 deskew delays, too */
+
+ icmd &= ~SCI_ICMD_BSY;
+ regs->sci_icmd = icmd;
+
+ /* bus settle delay, 400ns */
+ delay(3);
+
+ regs->sci_mode |= SCI_MODE_PAR_CHK;
+
+ {
+ register int timeo = 2500;/* 250 msecs in 100 usecs chunks */
+ while ((regs->sci_bus_csr & SCI_BUS_BSY) == 0) {
+ if (--timeo > 0) {
+ delay(100);
+ } else {
+ /* This is the "normal" no-such-device select error. */
+#ifdef DEBUG
+ if (ncr5380_debug)
+ printf("ncr5380_select: not BSY (nothing there)\n");
+#endif
+ goto nodev;
+ }
+ }
+ }
+
+ icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL);
+ regs->sci_icmd = icmd;
+/* regs->sci_sel_enb = myid;*/ /* looks like we should NOT have it */
+ /* XXX - SCI_MODE_PAR_CHK ? */
+ return SCSI_RET_SUCCESS;
+
+nodev:
+ ret = SCSI_RET_DEVICE_DOWN;
+ regs->sci_sel_enb = myid;
+nosel:
+ regs->sci_icmd = 0;
+ regs->sci_mode = 0;
+ return ret;
+
+lost:
+ regs->sci_icmd = 0;
+ regs->sci_mode = 0;
+#ifdef DEBUG
+ if (ncr5380_debug) {
+ printf("ncr5380_select: lost arbitration\n");
+ }
+#endif
+ return ret;
+}
+
+sci_data_out(regs, phase, count, data)
+ register volatile sci_regmap_t *regs;
+ unsigned char *data;
+{
+ register unsigned char icmd;
+ register int cnt=0;
+
+ /* ..checks.. */
+
+ icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
+loop:
+ /* SCSI bus phase not valid until REQ is true. */
+ WAIT_FOR_REQ(regs);
+ if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
+ return cnt;
+
+ icmd |= SCI_ICMD_DATA;
+ regs->sci_icmd = icmd;
+ regs->sci_odata = *data++;
+ icmd |= SCI_ICMD_ACK;
+ regs->sci_icmd = icmd;
+
+ icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_ACK);
+ WAIT_FOR_NOT_REQ(regs);
+ regs->sci_icmd = icmd;
+ ++cnt;
+ if (--count > 0)
+ goto loop;
+scsi_timeout_error:
+ return cnt;
+}
+
+static int
+sci_data_in(regs, phase, count, data)
+ register volatile sci_regmap_t *regs;
+ unsigned char *data;
+{
+ register unsigned char icmd;
+ register int cnt=0;
+
+ /* ..checks.. */
+
+ icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
+
+loop:
+ /* SCSI bus phase not valid until REQ is true. */
+ WAIT_FOR_REQ(regs);
+ if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
+ return cnt;
+
+ *data++ = regs->sci_data;
+ icmd |= SCI_ICMD_ACK;
+ regs->sci_icmd = icmd;
+
+ icmd &= ~SCI_ICMD_ACK;
+ WAIT_FOR_NOT_REQ(regs);
+ regs->sci_icmd = icmd;
+ ++cnt;
+ if (--count > 0)
+ goto loop;
+
+scsi_timeout_error:
+ return cnt;
+}
+
+/*
+ * Return -1 (error) or number of bytes sent (>=0).
+ */
+static int
+ncr5380_command_transfer(regs, maxlen, data, status, msg)
+ register volatile sci_regmap_t *regs;
+ int maxlen;
+ u_char *data;
+ u_char *status;
+ u_char *msg;
+{
+ int xfer, phase;
+
+ xfer = 0;
+ regs->sci_icmd = 0;
+
+ while (1) {
+
+ WAIT_FOR_REQ(regs);
+
+ phase = SCI_CUR_PHASE(regs->sci_bus_csr);
+
+ switch (phase) {
+ case SCSI_PHASE_CMD:
+ SCI_ACK(regs,SCSI_PHASE_CMD);
+ xfer += sci_data_out(regs, SCSI_PHASE_CMD,
+ maxlen, data);
+ goto out;
+
+ case SCSI_PHASE_DATA_IN:
+ printf("command_transfer: Data in phase?\n");
+ goto err;
+
+ case SCSI_PHASE_DATA_OUT:
+ printf("command_transfer: Data out phase?\n");
+ goto err;
+
+ case SCSI_PHASE_STATUS:
+ SCI_ACK(regs,SCSI_PHASE_STATUS);
+ printf("command_transfer: status in...\n");
+ sci_data_in(regs, SCSI_PHASE_STATUS,
+ 1, status);
+ printf("command_transfer: status=0x%x\n", *status);
+ goto err;
+
+ case SCSI_PHASE_MESSAGE_IN:
+ SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN);
+ printf("command_transfer: msg in?\n");
+ sci_data_in(regs, SCSI_PHASE_MESSAGE_IN,
+ 1, msg);
+ break;
+
+ case SCSI_PHASE_MESSAGE_OUT:
+ SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT);
+ sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT,
+ 1, msg);
+ break;
+
+ default:
+ printf("command_transfer: Unexpected phase 0x%x\n", phase);
+ goto err;
+ }
+ }
+scsi_timeout_error:
+err:
+ xfer = -1;
+out:
+ return xfer;
+}
+
+static int
+ncr5380_data_transfer(regs, maxlen, data, status, msg)
+ register volatile sci_regmap_t *regs;
+ int maxlen;
+ u_char *data, *status, *msg;
+{
+ int retlen = 0, xfer, phase;
+
+ regs->sci_icmd = 0;
+
+ *status = 0;
+
+ while (1) {
+
+ WAIT_FOR_REQ(regs);
+
+ phase = SCI_CUR_PHASE(regs->sci_bus_csr);
+
+ switch (phase) {
+ case SCSI_PHASE_CMD:
+ printf("Command phase in data_transfer().\n");
+ return retlen;
+ case SCSI_PHASE_DATA_IN:
+ SCI_ACK(regs,SCSI_PHASE_DATA_IN);
+#if PSEUDO_DMA
+ xfer = sci_pdma_in(regs, SCSI_PHASE_DATA_IN,
+ maxlen, data);
+#else
+ xfer = sci_data_in(regs, SCSI_PHASE_DATA_IN,
+ maxlen, data);
+#endif
+ retlen += xfer;
+ maxlen -= xfer;
+ break;
+ case SCSI_PHASE_DATA_OUT:
+ SCI_ACK(regs,SCSI_PHASE_DATA_OUT);
+#if PSEUDO_DMA
+ xfer = sci_pdma_out(regs, SCSI_PHASE_DATA_OUT,
+ maxlen, data);
+#else
+ xfer = sci_data_out(regs, SCSI_PHASE_DATA_OUT,
+ maxlen, data);
+#endif
+ retlen += xfer;
+ maxlen -= xfer;
+ break;
+ case SCSI_PHASE_STATUS:
+ SCI_ACK(regs,SCSI_PHASE_STATUS);
+ sci_data_in(regs, SCSI_PHASE_STATUS,
+ 1, status);
+ break;
+ case SCSI_PHASE_MESSAGE_IN:
+ SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN);
+ sci_data_in(regs, SCSI_PHASE_MESSAGE_IN,
+ 1, msg);
+ if (*msg == 0) {
+ return retlen;
+ } else {
+ printf( "message 0x%x in "
+ "data_transfer.\n", *msg);
+ }
+ break;
+ case SCSI_PHASE_MESSAGE_OUT:
+ SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT);
+ sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT,
+ 1, msg);
+ break;
+ default:
+ printf( "Unexpected phase 0x%x in "
+ "data_transfer().\n", phase);
+scsi_timeout_error:
+ return retlen;
+ break;
+ }
+ }
+}
+
+/*
+ * Returns 0 on success, -1 on internal error, or the status byte
+ */
+static int
+ncr5380_dorequest(sc, target, lun, cmd, cmdlen, databuf, datalen, sent)
+ struct ncr5380_softc *sc;
+ int target, lun;
+ u_char *cmd;
+ int cmdlen;
+ char *databuf;
+ int datalen, *sent;
+{
+ register volatile sci_regmap_t *regs = sc->sc_regs;
+ int cmd_bytes_sent, r;
+ u_char stat, msg, c;
+
+#ifdef DEBUG
+ if (ncr5380_debug) {
+ printf("ncr5380_dorequest: target=%d, lun=%d\n", target, lun);
+ }
+#endif
+
+ *sent = 0;
+
+ if ( ( r = ncr5380_select_target(regs, 7, target, 1) ) != SCSI_RET_SUCCESS) {
+#ifdef DEBUG
+ if (ncr5380_debug) {
+ printf("ncr5380_dorequest: select returned %d\n", r);
+ }
+#endif
+
+ SCI_CLR_INTR(regs);
+ switch (r) {
+
+ case SCSI_RET_NEED_RESET:
+ printf("ncr5380_dorequest: target=%d, lun=%d, r=%d resetting...\n",
+ target, lun, r);
+ reset_adapter(sc);
+ ncr5380_reset_scsibus(sc);
+ /* fall through */
+ case SCSI_RET_RETRY:
+ return 0x08; /* Busy - tell common code to retry. */
+
+ default:
+ printf("ncr5380_dorequest: target=%d, lun=%d, error=%d.\n",
+ target, lun, r);
+ /* fall through */
+ case SCSI_RET_DEVICE_DOWN:
+ return -1; /* Dead - tell common code to give up. */
+ }
+ }
+
+ c = 0x80 | lun;
+
+ if ((cmd_bytes_sent = ncr5380_command_transfer(regs, cmdlen,
+ (u_char *) cmd, &stat, &c)) != cmdlen)
+ {
+ SCI_CLR_INTR(regs);
+ if (cmd_bytes_sent >= 0) {
+ printf("Data underrun sending CCB (%d bytes of %d, sent).\n",
+ cmd_bytes_sent, cmdlen);
+ }
+ return -1;
+ }
+
+ *sent = ncr5380_data_transfer(regs, datalen, (u_char *)databuf,
+ &stat, &msg);
+#ifdef DEBUG
+ if (ncr5380_debug) {
+ printf("ncr5380_dorequest: data transfered = %d\n", *sent);
+ }
+#endif
+
+ return stat;
+}
+
+static int
+ncr5380_generic(adapter, id, lun, cmd, cmdlen, databuf, datalen)
+ void *adapter;
+ int id, lun;
+ struct scsi_generic *cmd;
+ int cmdlen;
+ void *databuf;
+ int datalen;
+{
+ register struct ncr5380_softc *sc = adapter;
+ int i, j, sent;
+
+ if (cmd->opcode == TEST_UNIT_READY) /* XXX */
+ cmd->bytes[0] = ((u_char) lun << 5);
+
+ i = ncr5380_dorequest(sc, id, lun, (u_char *) cmd, cmdlen,
+ databuf, datalen, &sent);
+
+ return i;
+}
+
+static int
+ncr5380_group0(adapter, id, lun, opcode, addr, len, flags, databuf, datalen)
+ void *adapter;
+ int id, lun, opcode, addr, len, flags;
+ caddr_t databuf;
+ int datalen;
+{
+ register struct ncr5380_softc *sc = adapter;
+ unsigned char cmd[6];
+ int i, j, sent;
+
+ cmd[0] = opcode; /* Operation code */
+ cmd[1] = (lun << 5) | ((addr >> 16) & 0x1F); /* Lun & MSB of addr */
+ cmd[2] = (addr >> 8) & 0xFF; /* addr */
+ cmd[3] = addr & 0xFF; /* LSB of addr */
+ cmd[4] = len; /* Allocation length */
+ cmd[5] = flags; /* Link/Flag */
+
+ i = ncr5380_dorequest(sc, id, lun, cmd, 6, databuf, datalen, &sent);
+
+ return i;
+}
diff --git a/sys/dev/ic/ncr5380reg.h b/sys/dev/ic/ncr5380reg.h
new file mode 100644
index 00000000000..600a26f9b3b
--- /dev/null
+++ b/sys/dev/ic/ncr5380reg.h
@@ -0,0 +1,135 @@
+/* $NetBSD: ncr5380reg.h,v 1.1 1995/07/08 21:30:43 pk Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY (mach3)
+ * Revision 2.3 91/08/24 12:25:10 af
+ * Moved padding of regmap in impl file.
+ * [91/08/02 04:22:39 af]
+ *
+ * Revision 2.2 91/06/19 16:28:35 rvb
+ * From the NCR data sheets
+ * "NCR 5380 Family, SCSI Protocol Controller Data Manual"
+ * NCR Microelectronics Division, Colorado Spring, 6/98 T01891L
+ * [91/04/21 af]
+ *
+ */
+
+/*
+ * File: scsi_5380.h
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 5/91
+ *
+ * Defines for the NCR 5380 (SCSI chip), aka Am5380
+ */
+
+/*
+ * Register map
+ */
+typedef struct {
+ volatile unsigned char sci_data; /* r: Current data */
+#define sci_odata sci_data /* w: Out data */
+ volatile unsigned char sci_icmd; /* rw: Initiator command */
+ volatile unsigned char sci_mode; /* rw: Mode */
+ volatile unsigned char sci_tcmd; /* rw: Target command */
+ volatile unsigned char sci_bus_csr; /* r: Bus Status */
+#define sci_sel_enb sci_bus_csr /* w: Select enable */
+ volatile unsigned char sci_csr; /* r: Status */
+#define sci_dma_send sci_csr /* w: Start dma send data */
+ volatile unsigned char sci_idata; /* r: Input data */
+#define sci_trecv sci_idata /* w: Start dma receive, target */
+ volatile unsigned char sci_iack; /* r: Interrupt Acknowledge */
+#define sci_irecv sci_iack /* w: Start dma receive, initiator */
+} sci_regmap_t;
+
+
+/*
+ * Initiator command register
+ */
+#define SCI_ICMD_DATA 0x01 /* rw: Assert data bus */
+#define SCI_ICMD_ATN 0x02 /* rw: Assert ATN signal */
+#define SCI_ICMD_SEL 0x04 /* rw: Assert SEL signal */
+#define SCI_ICMD_BSY 0x08 /* rw: Assert BSY signal */
+#define SCI_ICMD_ACK 0x10 /* rw: Assert ACK signal */
+#define SCI_ICMD_LST 0x20 /* r: Lost arbitration */
+#define SCI_ICMD_DIFF SCI_ICMD_LST /* w: Differential cable */
+#define SCI_ICMD_AIP 0x40 /* r: Arbitration in progress */
+#define SCI_ICMD_TEST SCI_ICMD_AIP /* w: Test mode */
+#define SCI_ICMD_RST 0x80 /* rw: Assert RST signal */
+
+
+/*
+ * Mode register
+ */
+#define SCI_MODE_ARB 0x01 /* rw: Start arbitration */
+#define SCI_MODE_DMA 0x02 /* rw: Enable DMA xfers */
+#define SCI_MODE_MONBSY 0x04 /* rw: Monitor BSY signal */
+#define SCI_MODE_DMA_IE 0x08 /* rw: Enable DMA complete interrupt */
+#define SCI_MODE_PERR_IE 0x10 /* rw: Interrupt on parity errors */
+#define SCI_MODE_PAR_CHK 0x20 /* rw: Check parity */
+#define SCI_MODE_TARGET 0x40 /* rw: Target mode (Initiator if 0) */
+#define SCI_MODE_BLOCKDMA 0x80 /* rw: Block-mode DMA handshake (MBZ) */
+
+
+/*
+ * Target command register
+ */
+#define SCI_TCMD_IO 0x01 /* rw: Assert I/O signal */
+#define SCI_TCMD_CD 0x02 /* rw: Assert C/D signal */
+#define SCI_TCMD_MSG 0x04 /* rw: Assert MSG signal */
+#define SCI_TCMD_PHASE_MASK 0x07 /* r: Mask for current bus phase */
+#define SCI_TCMD_REQ 0x08 /* rw: Assert REQ signal */
+#define SCI_TCMD_LAST_SENT 0x80 /* ro: Last byte was xferred
+ * (not on 5380/1) */
+
+#define SCI_PHASE(x) ((x)&0x7)
+
+/*
+ * Current (SCSI) Bus status
+ */
+#define SCI_BUS_DBP 0x01 /* r: Data Bus parity */
+#define SCI_BUS_SEL 0x02 /* r: SEL signal */
+#define SCI_BUS_IO 0x04 /* r: I/O signal */
+#define SCI_BUS_CD 0x08 /* r: C/D signal */
+#define SCI_BUS_MSG 0x10 /* r: MSG signal */
+#define SCI_BUS_REQ 0x20 /* r: REQ signal */
+#define SCI_BUS_BSY 0x40 /* r: BSY signal */
+#define SCI_BUS_RST 0x80 /* r: RST signal */
+
+#define SCI_CUR_PHASE(x) SCI_PHASE((x)>>2)
+
+/*
+ * Bus and Status register
+ */
+#define SCI_CSR_ACK 0x01 /* r: ACK signal */
+#define SCI_CSR_ATN 0x02 /* r: ATN signal */
+#define SCI_CSR_DISC 0x04 /* r: Disconnected (BSY==0) */
+#define SCI_CSR_PHASE_MATCH 0x08 /* r: Bus and SCI_TCMD match */
+#define SCI_CSR_INT 0x10 /* r: Interrupt request */
+#define SCI_CSR_PERR 0x20 /* r: Parity error */
+#define SCI_CSR_DREQ 0x40 /* r: DMA request */
+#define SCI_CSR_DONE 0x80 /* r: DMA count is zero */
diff --git a/sys/dev/ic/ncr5380var.h b/sys/dev/ic/ncr5380var.h
new file mode 100644
index 00000000000..df0cb788df8
--- /dev/null
+++ b/sys/dev/ic/ncr5380var.h
@@ -0,0 +1,115 @@
+/* $NetBSD: ncr5380var.h,v 1.3 1995/09/26 19:24:26 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1994 Adam Glass, Gordon W. Ross
+ * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
+ * Michael L. Finch, Bradley A. Grantham, and
+ * Lawrence A. Kesteloot
+ * 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 Alice Group.
+ * 4. The names of the Alice Group or any of its members may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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.
+ */
+
+#define SCI_PHASE_DISC 0 /* sort of ... */
+#define SCI_CLR_INTR(regs) ((volatile)(regs->sci_iack))
+#define SCI_ACK(ptr,phase) (ptr)->sci_tcmd = (phase)
+#define SCSI_TIMEOUT_VAL 1000000
+#define WAIT_FOR_NOT_REQ(ptr) { \
+ int scsi_timeout = SCSI_TIMEOUT_VAL; \
+ while ( ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \
+ ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \
+ ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \
+ (--scsi_timeout) ); \
+ if (!scsi_timeout) { \
+ printf("scsi timeout--WAIT_FOR_NOT_REQ---%s, line %d.\n", \
+ __FILE__, __LINE__); \
+ goto scsi_timeout_error; \
+ } \
+ }
+#define WAIT_FOR_REQ(ptr) { \
+ int scsi_timeout = SCSI_TIMEOUT_VAL; \
+ while ( (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \
+ (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \
+ (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \
+ (--scsi_timeout) ); \
+ if (!scsi_timeout) { \
+ printf("scsi timeout--WAIT_FOR_REQ---%s, line %d.\n", \
+ __FILE__, __LINE__); \
+ goto scsi_timeout_error; \
+ } \
+ }
+#define WAIT_FOR_BSY(ptr) { \
+ int scsi_timeout = SCSI_TIMEOUT_VAL; \
+ while ( (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \
+ (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \
+ (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \
+ (--scsi_timeout) ); \
+ if (!scsi_timeout) { \
+ printf("scsi timeout--WAIT_FOR_BSY---%s, line %d.\n", \
+ __FILE__, __LINE__); \
+ goto scsi_timeout_error; \
+ } \
+ }
+
+#define ARBITRATION_RETRIES 1000
+
+#ifndef DDB
+#define Debugger() panic("Should call Debugger here %s:%d", \
+ __FILE__, __LINE__)
+#endif /* ! DDB */
+
+struct ncr5380_softc {
+ struct device sc_dev;
+ struct intrhand sc_ih; /* interrupt info */
+ volatile void *sc_regs;
+ int sc_adapter_type;
+ int sc_adapter_iv_am; /* int. vec + address modifier */
+ struct scsi_link sc_link;
+};
+
+static int ncr5380_reset_scsibus __P((struct ncr5380_softc *));
+static int ncr5380_poll __P((int, int));
+static void ncr5380_sbc_intr __P((struct ncr5380_softc *));
+static int ncr5380_send_cmd __P((struct scsi_xfer *));
+static int ncr5380_scsi_cmd __P((struct scsi_xfer *));
+static int ncr5380_data_in __P((sci_regmap_t *, int, int, u_char *));
+static int ncr5380_data_out __P((sci_regmap_t *, int, int, u_char *));
+static int ncr5380_select_target __P((volatile sci_regmap_t *, u_char,
+ u_char, int));
+static int ncr5380_command_transfer __P((volatile sci_regmap_t *, int,
+ u_char *, u_char *, u_char *));
+static int ncr5380_data_transfer __P((volatile sci_regmap_t *, int,
+ u_char *, u_char *, u_char *));
+static int ncr5380_dorequest __P((struct ncr5380_softc *, int, int,
+ u_char *, int, char *, int, int *));
+
+static int ncr5380_generic __P((void *, int, int, struct scsi_generic *,
+ int, void *, int));
+static int ncr5380_group0 __P((void *, int, int, int, int, int,
+ int, caddr_t, int));
+
+
diff --git a/sys/dev/ic/nec765reg.h b/sys/dev/ic/nec765reg.h
new file mode 100644
index 00000000000..670117f43db
--- /dev/null
+++ b/sys/dev/ic/nec765reg.h
@@ -0,0 +1,73 @@
+/* $NetBSD: nec765reg.h,v 1.3 1994/10/27 04:18:41 cgd Exp $ */
+
+/*-
+ * 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.
+ *
+ * @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/dev/ic/ns16450reg.h b/sys/dev/ic/ns16450reg.h
new file mode 100644
index 00000000000..3b6372c994d
--- /dev/null
+++ b/sys/dev/ic/ns16450reg.h
@@ -0,0 +1,51 @@
+/* $NetBSD: ns16450reg.h,v 1.3 1994/10/27 04:18:42 cgd Exp $ */
+
+/*-
+ * 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.
+ *
+ * @(#)ns16450.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16450 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/dev/ic/ns16550reg.h b/sys/dev/ic/ns16550reg.h
new file mode 100644
index 00000000000..b9cf9726851
--- /dev/null
+++ b/sys/dev/ic/ns16550reg.h
@@ -0,0 +1,53 @@
+/* $NetBSD: ns16550reg.h,v 1.4 1994/10/27 04:18:43 cgd Exp $ */
+
+/*-
+ * 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.
+ *
+ * @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
+#define com_scratch 7 /* scratch register (R/W) */
diff --git a/sys/dev/ic/pdq.c b/sys/dev/ic/pdq.c
new file mode 100644
index 00000000000..27001b0890a
--- /dev/null
+++ b/sys/dev/ic/pdq.c
@@ -0,0 +1,1549 @@
+/* $NetBSD: pdq.c,v 1.2 1995/08/19 04:35:18 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1995 Matt Thomas (matt@lkg.dec.com)
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough 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.
+ */
+
+/*
+ * DEC PDQ FDDI Controller O/S independent code
+ *
+ * Written by Matt Thomas <matt@lkg.dec.com>
+ *
+ * This module should work any PDQ based board. Note that changes for
+ * MIPS and Alpha architectures (or any other architecture which requires
+ * a flushing of memory or write buffers and/or has incoherent caches)
+ * have yet to be made.
+ */
+
+#define PDQ_HWSUPPORT /* for pdq.h */
+
+#include "pdqreg.h"
+#ifndef __NetBSD__
+#include "pdq_os.h"
+#else
+#include "pdqvar.h"
+#endif
+
+#define PDQ_ROUNDUP(n, x) (((n) + ((x) - 1)) & ~((x) - 1))
+#define PDQ_CMD_RX_ALIGNMENT 16
+
+#if defined(PDQTEST) && !defined(PDQ_NOPRINTF)
+#define PDQ_PRINTF(x) printf x
+#else
+#define PDQ_PRINTF(x) do { } while (0)
+#endif
+
+const char * const pdq_halt_codes[] = {
+ "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault",
+ "Software Fault", "Hardware Fault", "PC Trace Path Test",
+ "DMA Error", "Image CRC Error", "Adapter Processer Error"
+};
+
+const char * const pdq_adapter_states[] = {
+ "Reset", "Upgrade", "DMA Unavailable", "DMA Available",
+ "Link Available", "Link Unavailable", "Halted", "Ring Member"
+};
+
+/*
+ * The following are used in conjunction with
+ * unsolicited events
+ */
+const char * const pdq_entities[] = {
+ "Station", "Link", "Phy Port"
+};
+
+const char * const pdq_station_events[] = {
+ "Trace Received"
+};
+
+const char * const pdq_station_arguments[] = {
+ "Reason"
+};
+
+const char * const pdq_link_events[] = {
+ "Transmit Underrun",
+ "Transmit Failed",
+ "Block Check Error (CRC)",
+ "Frame Status Error",
+ "PDU Length Error",
+ NULL,
+ NULL,
+ "Receive Data Overrun",
+ NULL,
+ "No User Buffer",
+ "Ring Initialization Initiated",
+ "Ring Initialization Received",
+ "Ring Beacon Initiated",
+ "Duplicate Address Failure",
+ "Duplicate Token Detected",
+ "Ring Purger Error",
+ "FCI Strip Error",
+ "Trace Initiated",
+ "Directed Beacon Received",
+};
+
+const char * const pdq_link_arguments[] = {
+ "Reason",
+ "Data Link Header",
+ "Source",
+ "Upstream Neighbor"
+};
+
+const char * const pdq_phy_events[] = {
+ "LEM Error Monitor Reject",
+ "Elasticy Buffer Error",
+ "Link Confidence Test Reject"
+};
+
+const char * const pdq_phy_arguments[] = {
+ "Direction"
+};
+
+const char * const * const pdq_event_arguments[] = {
+ pdq_station_arguments,
+ pdq_link_arguments,
+ pdq_phy_arguments
+};
+
+const char * const * const pdq_event_codes[] = {
+ pdq_station_events,
+ pdq_link_events,
+ pdq_phy_events
+};
+
+const char * const pdq_station_types[] = {
+ "SAS", "DAC", "SAC", "NAC", "DAS"
+};
+
+const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" };
+
+const char pdq_phy_types[] = "ABSM";
+
+const char * const pdq_pmd_types0[] = {
+ "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2",
+ "ANSI Sonet"
+};
+
+const char * const pdq_pmd_types100[] = {
+ "Low Power", "Thin Wire", "Shielded Twisted Pair",
+ "Unshielded Twisted Pair"
+};
+
+const char * const * const pdq_pmd_types[] = {
+ pdq_pmd_types0, pdq_pmd_types100
+};
+
+const char * const pdq_descriptions[] = {
+ "DEFPA PCI",
+ "DEFEA EISA",
+};
+
+void
+pdq_print_fddi_chars(
+ pdq_t *pdq,
+ const pdq_response_status_chars_get_t *rsp)
+{
+ const char hexchars[] = "0123456789abcdef";
+
+ printf(
+#if !defined(__bsdi__) && !defined(__NetBSD__)
+ PDQ_OS_PREFIX
+#else
+ ": "
+#endif
+ "DEC %s FDDI %s Controller\n",
+#if !defined(__bsdi__) && !defined(__NetBSD__)
+ PDQ_OS_PREFIX_ARGS,
+#endif
+ pdq_descriptions[pdq->pdq_type],
+ pdq_station_types[rsp->status_chars_get.station_type]);
+
+ printf(PDQ_OS_PREFIX "FDDI address %c%c:%c%c:%c%c:%c%c:%c%c:%c%c, FW=%c%c%c%c, HW=%c",
+ PDQ_OS_PREFIX_ARGS,
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F],
+ pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
+ pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3],
+ rsp->status_chars_get.module_rev.fwrev_bytes[0]);
+
+ if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) {
+ printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]);
+ }
+
+ printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)",
+ PDQ_OS_PREFIX_ARGS,
+ rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "",
+ pdq_phy_types[rsp->status_chars_get.phy_type[0]],
+ pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]);
+
+ if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
+ printf(", FDDI Port[B] = %c (PMD = %s)",
+ pdq_phy_types[rsp->status_chars_get.phy_type[1]],
+ pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]);
+
+ printf("\n");
+}
+
+void
+pdq_init_csrs(
+ pdq_csrs_t *csrs,
+ void *csr_va,
+ size_t csrsize)
+{
+ volatile pdq_uint32_t *csr_base = (volatile pdq_uint32_t *) csr_va;
+
+ csrs->csr_port_reset = &csr_base[0 * csrsize];
+ csrs->csr_host_data = &csr_base[1 * csrsize];
+ csrs->csr_port_control = &csr_base[2 * csrsize];
+ csrs->csr_port_data_a = &csr_base[3 * csrsize];
+ csrs->csr_port_data_b = &csr_base[4 * csrsize];
+ csrs->csr_port_status = &csr_base[5 * csrsize];
+ csrs->csr_host_int_type_0 = &csr_base[6 * csrsize];
+ csrs->csr_host_int_enable = &csr_base[7 * csrsize];
+ csrs->csr_type_2_producer = &csr_base[8 * csrsize];
+ csrs->csr_cmd_response_producer = &csr_base[10 * csrsize];
+ csrs->csr_cmd_request_producer = &csr_base[11 * csrsize];
+ csrs->csr_host_smt_producer = &csr_base[12 * csrsize];
+ csrs->csr_unsolicited_producer = &csr_base[13 * csrsize];
+}
+
+void
+pdq_init_pci_csrs(
+ pdq_pci_csrs_t *csrs,
+ void *csr_va,
+ size_t csrsize)
+{
+ volatile pdq_uint32_t *csr_base = (volatile pdq_uint32_t *) csr_va;
+
+ csrs->csr_pfi_mode_control = &csr_base[16 * csrsize];
+ csrs->csr_pfi_status = &csr_base[17 * csrsize];
+ csrs->csr_fifo_write = &csr_base[18 * csrsize];
+ csrs->csr_fifo_read = &csr_base[19 * csrsize];
+}
+
+void
+pdq_flush_databuf_queue(
+ pdq_databuf_queue_t *q)
+{
+ PDQ_OS_DATABUF_T *pdu;
+ for (;;) {
+ PDQ_OS_DATABUF_DEQUEUE(q, pdu);
+ if (pdu == NULL)
+ return;
+ PDQ_OS_DATABUF_FREE(pdu);
+ }
+}
+
+pdq_boolean_t
+pdq_do_port_control(
+ const pdq_csrs_t * const csrs,
+ pdq_uint32_t cmd)
+{
+ int cnt = 0;
+ *csrs->csr_host_int_type_0 = PDQ_HOST_INT_CSR_CMD_DONE;
+ *csrs->csr_port_control = PDQ_PCTL_CMD_ERROR | cmd;
+ while ((*csrs->csr_host_int_type_0 & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000)
+ cnt++;
+ PDQ_PRINTF(("CSR cmd spun %d times\n", cnt));
+ if (*csrs->csr_host_int_type_0 & PDQ_HOST_INT_CSR_CMD_DONE) {
+ *csrs->csr_host_int_type_0 = PDQ_HOST_INT_CSR_CMD_DONE;
+ return (*csrs->csr_port_control & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE;
+ }
+ /* adapter failure */
+ PDQ_ASSERT(0);
+ return PDQ_FALSE;
+}
+
+void
+pdq_read_mla(
+ const pdq_csrs_t * const csrs,
+ pdq_lanaddr_t *hwaddr)
+{
+ pdq_uint32_t data;
+
+ *csrs->csr_port_data_a = 0;
+ pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
+ data = *csrs->csr_host_data;
+
+ hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF;
+ hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF;
+ hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF;
+ hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF;
+
+ *csrs->csr_port_data_a = 1;
+ pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
+ data = *csrs->csr_host_data;
+
+ hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF;
+ hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF;
+}
+
+void
+pdq_read_fwrev(
+ const pdq_csrs_t * const csrs,
+ pdq_fwrev_t *fwrev)
+{
+ pdq_uint32_t data;
+
+ pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ);
+ data = *csrs->csr_host_data;
+
+ fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF;
+ fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF;
+ fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF;
+ fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF;
+}
+
+pdq_boolean_t
+pdq_read_error_log(
+ pdq_t *pdq,
+ pdq_response_error_log_get_t *log_entry)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry;
+
+ pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START);
+
+ while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) {
+ *ptr++ = *csrs->csr_host_data;
+ if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry))
+ break;
+ }
+ return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE;
+}
+
+pdq_chip_rev_t
+pdq_read_chiprev(
+ const pdq_csrs_t * const csrs)
+{
+ pdq_uint32_t data;
+
+ *csrs->csr_port_data_a = PDQ_SUB_CMD_PDQ_REV_GET;
+ pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
+ data = *csrs->csr_host_data;
+
+ return (pdq_chip_rev_t) data;
+}
+
+static const struct {
+ size_t cmd_len;
+ size_t rsp_len;
+ const char *cmd_name;
+} pdq_cmd_info[] = {
+ { sizeof(pdq_cmd_generic_t), /* 0 - PDQC_START */
+ sizeof(pdq_response_generic_t),
+ "Start"
+ },
+ { sizeof(pdq_cmd_filter_set_t), /* 1 - PDQC_FILTER_SET */
+ sizeof(pdq_response_generic_t),
+ "Filter Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 2 - PDQC_FILTER_GET */
+ sizeof(pdq_response_filter_get_t),
+ "Filter Get"
+ },
+ { sizeof(pdq_cmd_chars_set_t), /* 3 - PDQC_CHARS_SET */
+ sizeof(pdq_response_generic_t),
+ "Chars Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 4 - PDQC_STATUS_CHARS_GET */
+ sizeof(pdq_response_status_chars_get_t),
+ "Status Chars Get"
+ },
+#if 0
+ { sizeof(pdq_cmd_generic_t), /* 5 - PDQC_COUNTERS_GET */
+ sizeof(pdq_response_counters_get_t),
+ "Counters Get"
+ },
+ { sizeof(pdq_cmd_counters_set_t), /* 6 - PDQC_COUNTERS_SET */
+ sizeof(pdq_response_generic_t),
+ "Counters Set"
+ },
+#else
+ { 0, 0, "Counters Get" },
+ { 0, 0, "Counters Set" },
+#endif
+ { sizeof(pdq_cmd_addr_filter_set_t), /* 7 - PDQC_ADDR_FILTER_SET */
+ sizeof(pdq_response_generic_t),
+ "Addr Filter Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 8 - PDQC_ADDR_FILTER_GET */
+ sizeof(pdq_response_addr_filter_get_t),
+ "Addr Filter Get"
+ },
+#if 0
+ { sizeof(pdq_cmd_generic_t), /* 9 - PDQC_ERROR_LOG_CLEAR */
+ sizeof(pdq_response_generic_t),
+ "Error Log Clear"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 10 - PDQC_ERROR_LOG_SET */
+ sizeof(pdq_response_generic_t),
+ "Error Log Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 11 - PDQC_FDDI_MIB_GET */
+ sizeof(pdq_response_generic_t),
+ "FDDI MIB Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 12 - PDQC_DEC_EXT_MIB_GET */
+ sizeof(pdq_response_generic_t),
+ "DEC Ext MIB Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 13 - PDQC_DEC_SPECIFIC_GET */
+ sizeof(pdq_response_generic_t),
+ "DEC Specific Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 14 - PDQC_SNMP_SET */
+ sizeof(pdq_response_generic_t),
+ "SNMP Set"
+ },
+ { 0, 0, "N/A" },
+ { sizeof(pdq_cmd_generic_t), /* 16 - PDQC_SMT_MIB_GET */
+ sizeof(pdq_response_generic_t),
+ "SMT MIB Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 17 - PDQC_SMT_MIB_SET */
+ sizeof(pdq_response_generic_t),
+ "SMT MIB Set",
+ },
+#endif
+};
+
+void
+pdq_queue_commands(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_command_info_t * const ci = &pdq->pdq_command_info;
+ pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
+ pdq_cmd_code_t op;
+ pdq_uint32_t cmdlen, rsplen, mask;
+
+ /*
+ * If there are commands or responses active or there aren't
+ * any pending commands, then don't queue any more.
+ */
+ if (ci->ci_command_active || ci->ci_pending_commands == 0)
+ return;
+
+ /*
+ * Determine which command needs to be queued.
+ */
+ op = PDQC_SMT_MIB_SET;
+ for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1)
+ op = (pdq_cmd_code_t) ((int) op - 1);
+ /*
+ * Obtain the sizes needed for the command and response.
+ * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is
+ * always properly aligned.
+ */
+ cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT);
+ rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT);
+ if (cmdlen < rsplen)
+ cmdlen = rsplen;
+ /*
+ * Since only one command at a time will be queued, there will always
+ * be enough space.
+ */
+
+ /*
+ * Obtain and fill in the descriptor for the command (descriptor is
+ * pre-initialized)
+ */
+ dbp->pdqdb_command_requests[ci->ci_request_producer].txd_seg_len = cmdlen;
+ PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
+
+ /*
+ * Obtain and fill in the descriptor for the response (descriptor is
+ * pre-initialized)
+ */
+ dbp->pdqdb_command_responses[ci->ci_response_producer].rxd_seg_len_hi = cmdlen / 16;
+ PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
+
+ /*
+ * Clear the command area, set the opcode, and the command from the pending
+ * mask.
+ */
+
+ PDQ_OS_MEMZERO(ci->ci_bufstart, cmdlen);
+ *(pdq_cmd_code_t *) ci->ci_bufstart = op;
+ ci->ci_pending_commands &= ~mask;
+
+ /*
+ * Fill in the command area, if needed.
+ */
+ switch (op) {
+ case PDQC_FILTER_SET: {
+ pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_bufstart;
+ unsigned idx = 0;
+ filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM;
+ filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM;
+ filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM;
+ filter_set->filter_set_items[idx].filter_state = ((pdq->pdq_flags & (PDQ_PROMISC|PDQ_PASS_SMT)) == (PDQ_PROMISC|PDQ_PASS_SMT) ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER;
+ filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_EOL;
+ break;
+ }
+ case PDQC_ADDR_FILTER_SET: {
+ pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_bufstart;
+ pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses;
+ addr->lanaddr_bytes[0] = 0xFF;
+ addr->lanaddr_bytes[1] = 0xFF;
+ addr->lanaddr_bytes[2] = 0xFF;
+ addr->lanaddr_bytes[3] = 0xFF;
+ addr->lanaddr_bytes[4] = 0xFF;
+ addr->lanaddr_bytes[5] = 0xFF;
+ addr++;
+ pdq_os_addr_fill(pdq, addr, 61);
+ break;
+ }
+ }
+ /*
+ * At this point the command is done. All that needs to be done is to
+ * produce it to the PDQ.
+ */
+ PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n",
+ pdq_cmd_info[op].cmd_name));
+
+ ci->ci_command_active++;
+ *csrs->csr_cmd_response_producer = ci->ci_response_producer | (ci->ci_response_completion << 8);
+ *csrs->csr_cmd_request_producer = ci->ci_request_producer | (ci->ci_request_completion << 8);
+}
+
+void
+pdq_process_command_responses(
+ pdq_t * const pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_command_info_t * const ci = &pdq->pdq_command_info;
+ volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp;
+ pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
+ pdq_txdesc_t *txd;
+ pdq_rxdesc_t *rxd;
+ const pdq_response_generic_t *rspgen;
+
+ /*
+ * We have to process the command and response in tandem so
+ * just wait for the response to be consumed. If it has been
+ * consumed then the command must have been as well.
+ */
+
+ if (cbp->pdqcb_command_response == ci->ci_response_completion)
+ return;
+
+ PDQ_ASSERT (cbp->pdqcb_command_request != ci->ci_request_completion);
+
+ txd = &dbp->pdqdb_command_requests[ci->ci_request_completion];
+ rxd = &dbp->pdqdb_command_responses[ci->ci_response_completion];
+
+ rspgen = (const pdq_response_generic_t *) ci->ci_bufstart;
+ PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS);
+ PDQ_PRINTF(("PDQ Process Command Response: %s completed\n",
+ pdq_cmd_info[rspgen->generic_op].cmd_name));
+
+ if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) {
+ pdq->pdq_flags &= ~PDQ_PRINTCHARS;
+ pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen);
+ }
+
+ PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
+ PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
+ ci->ci_command_active = 0;
+
+ if (ci->ci_pending_commands != 0) {
+ pdq_queue_commands(pdq);
+ } else {
+ *csrs->csr_cmd_response_producer = ci->ci_response_producer | (ci->ci_response_completion << 8);
+ *csrs->csr_cmd_request_producer = ci->ci_request_producer | (ci->ci_request_completion << 8);
+ }
+}
+
+/*
+ * This following routine processes unsolicited events.
+ * In addition, it also fills the unsolicited queue with
+ * event buffers so it can be used to initialize the queue
+ * as well.
+ */
+void
+pdq_process_unsolicited_events(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info;
+ volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
+ pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
+ const pdq_unsolicited_event_t *event;
+ pdq_rxdesc_t *rxd;
+
+ /*
+ * Process each unsolicited event (if any).
+ */
+
+ while (cbp->pdqcb_unsolicited_event != ui->ui_completion) {
+ rxd = &dbp->pdqdb_unsolicited_events[ui->ui_completion];
+ event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
+
+ switch (event->event_type) {
+ case PDQ_UNSOLICITED_EVENT: {
+ printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s",
+ PDQ_OS_PREFIX_ARGS,
+ pdq_entities[event->event_entity],
+ pdq_event_codes[event->event_entity][event->event_code.value]);
+ if (event->event_type == PDQ_ENTITY_PHY_PORT)
+ printf("[%d]", event->event_index);
+ printf("\n");
+ break;
+ }
+ case PDQ_UNSOLICITED_COUNTERS: {
+ break;
+ }
+ }
+ PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
+ ui->ui_free++;
+ }
+
+ /*
+ * Now give back the event buffers back to the PDQ.
+ */
+ PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
+ ui->ui_free = 0;
+
+ *csrs->csr_unsolicited_producer = ui->ui_producer | (ui->ui_completion << 8);
+}
+
+void
+pdq_process_received_data(
+ pdq_t *pdq,
+ pdq_rx_info_t *rx,
+ pdq_rxdesc_t *receives,
+ pdq_uint32_t completion_goal,
+ pdq_uint32_t ring_mask)
+{
+ pdq_uint32_t completion = rx->rx_completion;
+ pdq_uint32_t producer = rx->rx_producer;
+ PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers;
+ pdq_rxdesc_t *rxd;
+ pdq_uint32_t idx;
+
+ while (completion != completion_goal) {
+ PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu;
+ pdq_uint8_t *dataptr;
+ pdq_uint32_t fc, datalen, pdulen, segcnt;
+ pdq_rxstatus_t status;
+
+ fpdu = lpdu = buffers[completion];
+ PDQ_ASSERT(fpdu != NULL);
+
+ dataptr = PDQ_OS_DATABUF_PTR(fpdu);
+ status = *(pdq_rxstatus_t *) dataptr;
+ if ((status.rxs_status & 0x200000) == 0) {
+ datalen = status.rxs_status & 0x1FFF;
+ fc = dataptr[PDQ_RX_FC_OFFSET];
+ switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) {
+ case PDQ_FDDI_LLC_ASYNC:
+ case PDQ_FDDI_LLC_SYNC:
+ case PDQ_FDDI_IMP_ASYNC:
+ case PDQ_FDDI_IMP_SYNC: {
+ if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) {
+ PDQ_PRINTF(("discard: bad length %d\n", datalen));
+ goto discard_frame;
+ }
+ break;
+ }
+ case PDQ_FDDI_SMT: {
+ if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN)
+ goto discard_frame;
+ break;
+ }
+ default: {
+ PDQ_PRINTF(("discard: bad fc 0x%x\n", fc));
+ goto discard_frame;
+ }
+ }
+ /*
+ * Update the lengths of the data buffers now that we know
+ * the real length.
+ */
+ pdulen = datalen - 4 /* CRC */;
+ segcnt = (pdulen + PDQ_RX_FC_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE;
+ PDQ_OS_DATABUF_ALLOC(npdu);
+ if (npdu == NULL) {
+ PDQ_PRINTF(("discard: no databuf #0\n"));
+ goto discard_frame;
+ }
+ buffers[completion] = npdu;
+ for (idx = 1; idx < segcnt; idx++) {
+ PDQ_OS_DATABUF_ALLOC(npdu);
+ if (npdu == NULL) {
+ PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
+ PDQ_OS_DATABUF_FREE(fpdu);
+ goto discard_frame;
+ }
+ PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]);
+ lpdu = PDQ_OS_DATABUF_NEXT(lpdu);
+ buffers[(completion + idx) & ring_mask] = npdu;
+ }
+ PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
+ for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
+ buffers[(producer + idx) & ring_mask] =
+ buffers[(completion + idx) & ring_mask];
+ buffers[(completion + idx) & ring_mask] = NULL;
+ }
+ PDQ_OS_DATABUF_ADJ(fpdu, PDQ_RX_FC_OFFSET);
+ if (segcnt == 1) {
+ PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen);
+ } else {
+ PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_RX_FC_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE);
+ }
+ pdq_os_receive_pdu(pdq, fpdu, pdulen);
+ rx->rx_free += PDQ_RX_SEGCNT;
+ PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask);
+ PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask);
+ continue;
+ } else {
+ PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status,
+ status.rxs_rcc_badpdu, status.rxs_rcc_badcrc,
+ status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e));
+ if (status.rxs_rcc_reason == 7)
+ goto discard_frame;
+ if (status.rxs_rcc_reason != 0)
+ /* hardware fault */
+ if (status.rxs_rcc_badcrc) {
+ printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n",
+ PDQ_OS_PREFIX_ARGS,
+ dataptr[PDQ_RX_FC_OFFSET+1],
+ dataptr[PDQ_RX_FC_OFFSET+2],
+ dataptr[PDQ_RX_FC_OFFSET+3],
+ dataptr[PDQ_RX_FC_OFFSET+4],
+ dataptr[PDQ_RX_FC_OFFSET+5],
+ dataptr[PDQ_RX_FC_OFFSET+6]);
+ /* rx->rx_badcrc++; */
+ } else if (status.rxs_fsc == 0 | status.rxs_fsb_e == 1) {
+ /* rx->rx_frame_status_errors++; */
+ } else {
+ /* hardware fault */
+ }
+ }
+ discard_frame:
+ /*
+ * Discarded frames go right back on the queue; therefore
+ * ring entries were freed.
+ */
+ for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
+ buffers[producer] = buffers[completion];
+ buffers[completion] = NULL;
+ rxd = &receives[rx->rx_producer];
+ if (idx == 0) {
+ rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
+ } else {
+ rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
+ }
+ rxd->rxd_pa_hi = 0;
+ rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
+ rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(PDQ_OS_DATABUF_PTR(buffers[rx->rx_producer]));
+ PDQ_ADVANCE(rx->rx_producer, 1, ring_mask);
+ PDQ_ADVANCE(producer, 1, ring_mask);
+ PDQ_ADVANCE(completion, 1, ring_mask);
+ }
+ }
+ rx->rx_completion = completion;
+
+ while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) {
+ PDQ_OS_DATABUF_T *pdu;
+ /*
+ * Allocate the needed number of data buffers.
+ * Try to obtain them from our free queue before
+ * asking the system for more.
+ */
+ for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
+ if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) {
+ PDQ_OS_DATABUF_ALLOC(pdu);
+ if (pdu == NULL)
+ break;
+ buffers[(rx->rx_producer + idx) & ring_mask] = pdu;
+ }
+ rxd = &receives[(rx->rx_producer + idx) & ring_mask];
+ if (idx == 0) {
+ rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
+ } else {
+ rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
+ }
+ rxd->rxd_pa_hi = 0;
+ rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
+ rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(PDQ_OS_DATABUF_PTR(pdu));
+ }
+ if (idx < PDQ_RX_SEGCNT) {
+ /*
+ * We didn't get all databufs required to complete a new
+ * receive buffer. Keep the ones we got and retry a bit
+ * later for the rest.
+ */
+ break;
+ }
+ PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask);
+ rx->rx_free -= PDQ_RX_SEGCNT;
+ }
+}
+
+pdq_boolean_t
+pdq_queue_transmit_data(
+ pdq_t *pdq,
+ PDQ_OS_DATABUF_T *pdu)
+{
+ pdq_tx_info_t *tx = &pdq->pdq_tx_info;
+ pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
+ pdq_uint32_t producer = tx->tx_producer;
+ pdq_txdesc_t *eop = NULL;
+ PDQ_OS_DATABUF_T *pdu0;
+ pdq_uint32_t freecnt;
+
+ if (tx->tx_free < 1)
+ return PDQ_FALSE;
+
+ dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc;
+ PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
+
+ for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) {
+ pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0);
+ const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0);
+
+ /*
+ * The first segment is limited to the space remaining in
+ * page. All segments after that can be up to a full page
+ * in size.
+ */
+ fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1));
+ while (datalen > 0 && freecnt > 0) {
+ pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen);
+
+ /*
+ * Initialize the transmit descriptor
+ */
+ eop = &dbp->pdqdb_transmits[producer];
+ eop->txd_seg_len = seglen;
+ eop->txd_pa_lo = PDQ_OS_VA_TO_PA(dataptr);
+ eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0;
+
+ datalen -= seglen;
+ dataptr += seglen;
+ fraglen = PDQ_OS_PAGESIZE;
+ freecnt--;
+ PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
+ }
+ pdu0 = PDQ_OS_DATABUF_NEXT(pdu0);
+ }
+ if (pdu0 != NULL) {
+ PDQ_ASSERT(freecnt == 0);
+ /*
+ * If we still have data to process then the ring was too full
+ * to store the PDU. Return FALSE so the caller will requeue
+ * the PDU for later.
+ */
+ return PDQ_FALSE;
+ }
+ /*
+ * Everything went fine. Finish it up.
+ */
+ tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt;
+ eop->txd_eop = 1;
+ PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu);
+ tx->tx_producer = producer;
+ tx->tx_free = freecnt;
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+ return PDQ_TRUE;
+}
+
+void
+pdq_process_transmitted_data(
+ pdq_t *pdq)
+{
+ pdq_tx_info_t *tx = &pdq->pdq_tx_info;
+ volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
+ pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
+ pdq_uint32_t completion = tx->tx_completion;
+
+ while (completion != cbp->pdqcb_transmits) {
+ PDQ_OS_DATABUF_T *pdu;
+ pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion];
+ PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1);
+ PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1);
+ PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
+ pdq_os_transmit_done(pdq, pdu);
+ tx->tx_free += descriptor_count;
+
+ PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits));
+ }
+ if (tx->tx_completion != completion) {
+ tx->tx_completion = completion;
+ pdq_os_restart_transmitter(pdq);
+ }
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+}
+
+void
+pdq_flush_transmitter(
+ pdq_t *pdq)
+{
+ volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp;
+ pdq_tx_info_t *tx = &pdq->pdq_tx_info;
+
+ for (;;) {
+ PDQ_OS_DATABUF_T *pdu;
+ PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
+ if (pdu == NULL)
+ break;
+ /*
+ * Don't call transmit done since the packet never made it
+ * out on the wire.
+ */
+ PDQ_OS_DATABUF_FREE(pdu);
+ }
+
+ tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
+ tx->tx_completion = cbp->pdqcb_transmits = tx->tx_producer;
+
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+}
+
+void
+pdq_hwreset(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_state_t state;
+ int cnt;
+
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ if (state == PDQS_DMA_UNAVAILABLE)
+ return;
+ *csrs->csr_port_data_a = (state == PDQS_HALTED) ? 0 : PDQ_PRESET_SKIP_SELFTEST;
+ *csrs->csr_port_reset = 1;
+ PDQ_OS_USEC_DELAY(100);
+ *csrs->csr_port_reset = 0;
+ for (cnt = 45000;;cnt--) {
+ PDQ_OS_USEC_DELAY(1000);
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ if (state == PDQS_DMA_UNAVAILABLE || cnt == 0)
+ break;
+ }
+ PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 45000 - cnt));
+ PDQ_OS_USEC_DELAY(10000);
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
+ PDQ_ASSERT(cnt > 0);
+}
+
+/*
+ * The following routine brings the PDQ from whatever state it is
+ * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET).
+ */
+pdq_state_t
+pdq_stop(
+ pdq_t *pdq)
+{
+ pdq_state_t state;
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ int cnt, pass = 0, idx;
+ PDQ_OS_DATABUF_T **buffers;
+
+ restart:
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ if (state != PDQS_DMA_UNAVAILABLE) {
+ pdq_hwreset(pdq);
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
+ }
+#if 0
+ switch (state) {
+ case PDQS_RING_MEMBER:
+ case PDQS_LINK_UNAVAILABLE:
+ case PDQS_LINK_AVAILABLE: {
+ *csrs->csr_port_data_a = PDQ_SUB_CMD_LINK_UNINIT;
+ *csrs->csr_port_data_b = 0;
+ pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
+ /* FALL THROUGH */
+ }
+ case PDQS_DMA_AVAILABLE: {
+ *csrs->csr_port_data_a = 0;
+ *csrs->csr_port_data_b = 0;
+ pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT);
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
+ /* FALL THROUGH */
+ }
+ case PDQS_DMA_UNAVAILABLE: {
+ break;
+ }
+ }
+#endif
+ /*
+ * Now we should be in DMA_UNAVAILABLE. So bring the PDQ into
+ * DMA_AVAILABLE.
+ */
+
+ /*
+ * Obtain the hardware address and firmware revisions
+ * (MLA = my long address which is FDDI speak for hardware address)
+ */
+ pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr);
+ pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev);
+ pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs);
+
+ if (pdq->pdq_type == PDQ_DEFPA) {
+ /*
+ * Disable interrupts and DMA.
+ */
+ *pdq->pdq_pci_csrs.csr_pfi_mode_control = 0;
+ *pdq->pdq_pci_csrs.csr_pfi_status = 0x10;
+ }
+
+ /*
+ * Flush all the databuf queues.
+ */
+ pdq_flush_databuf_queue(&pdq->pdq_tx_info.tx_txq);
+ buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers;
+ for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) {
+ if (buffers[idx] != NULL) {
+ PDQ_OS_DATABUF_FREE(buffers[idx]);
+ buffers[idx] = NULL;
+ }
+ }
+ pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
+ buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers;
+ for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) {
+ if (buffers[idx] != NULL) {
+ PDQ_OS_DATABUF_FREE(buffers[idx]);
+ buffers[idx] = NULL;
+ }
+ }
+ pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
+
+ /*
+ * Reset the consumer indexes to 0.
+ */
+ pdq->pdq_cbp->pdqcb_receives = 0;
+ pdq->pdq_cbp->pdqcb_transmits = 0;
+ pdq->pdq_cbp->pdqcb_host_smt = 0;
+ pdq->pdq_cbp->pdqcb_unsolicited_event = 0;
+ pdq->pdq_cbp->pdqcb_command_response = 0;
+ pdq->pdq_cbp->pdqcb_command_request = 0;
+
+ /*
+ * Reset the producer and completion indexes to 0.
+ */
+ pdq->pdq_command_info.ci_request_producer = 0;
+ pdq->pdq_command_info.ci_response_producer = 0;
+ pdq->pdq_command_info.ci_request_completion = 0;
+ pdq->pdq_command_info.ci_response_completion = 0;
+ pdq->pdq_unsolicited_info.ui_producer = 0;
+ pdq->pdq_unsolicited_info.ui_completion = 0;
+ pdq->pdq_rx_info.rx_producer = 0;
+ pdq->pdq_rx_info.rx_completion = 0;
+ pdq->pdq_tx_info.tx_producer = 0;
+ pdq->pdq_tx_info.tx_completion = 0;
+ pdq->pdq_host_smt_info.rx_producer = 0;
+ pdq->pdq_host_smt_info.rx_completion = 0;
+
+ pdq->pdq_command_info.ci_command_active = 0;
+ pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
+ pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
+
+ /*
+ * Allow the DEFPA to do DMA. Then program the physical
+ * addresses of the consumer and descriptor blocks.
+ */
+ if (pdq->pdq_type == PDQ_DEFPA) {
+#ifdef PDQTEST
+ *pdq->pdq_pci_csrs.csr_pfi_mode_control = PDQ_PFI_MODE_DMA_ENABLE;
+#else
+ *pdq->pdq_pci_csrs.csr_pfi_mode_control = PDQ_PFI_MODE_DMA_ENABLE
+ |PDQ_PFI_MODE_PFI_PCI_INTR|PDQ_PFI_MODE_PDQ_PCI_INTR;
+#endif
+ }
+
+ /*
+ * Make the unsolicited queue has events ...
+ */
+ pdq_process_unsolicited_events(pdq);
+
+ *csrs->csr_port_data_b = PDQ_DMA_BURST_8LW;
+ *csrs->csr_port_data_a = PDQ_SUB_CMD_DMA_BURST_SIZE_SET;
+ pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
+
+ *csrs->csr_port_data_b = 0;
+ *csrs->csr_port_data_a = PDQ_OS_VA_TO_PA(pdq->pdq_cbp);
+ pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK);
+
+ *csrs->csr_port_data_b = 0;
+ *csrs->csr_port_data_a = PDQ_OS_VA_TO_PA(pdq->pdq_dbp) | PDQ_DMA_INIT_LW_BSWAP_DATA;
+ pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT);
+
+ for (cnt = 0; cnt < 1000; cnt++) {
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ if (state == PDQS_HALTED) {
+ if (pass > 0)
+ return PDQS_HALTED;
+ pass = 1;
+ goto restart;
+ }
+ if (state == PDQS_DMA_AVAILABLE) {
+ PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt));
+ break;
+ }
+ PDQ_OS_USEC_DELAY(1000);
+ }
+ PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
+
+ *csrs->csr_host_int_type_0 = 0xFF;
+ *csrs->csr_host_int_enable = 0 /* PDQ_HOST_INT_STATE_CHANGE
+ |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE
+ |PDQ_HOST_INT_UNSOL_ENABLE */;
+
+ /*
+ * Any other command but START should be valid.
+ */
+ pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START));
+ if (pdq->pdq_flags & PDQ_PRINTCHARS)
+ pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
+ pdq_queue_commands(pdq);
+
+ if (pdq->pdq_flags & PDQ_PRINTCHARS) {
+ /*
+ * Now wait (up to 100ms) for the command(s) to finish.
+ */
+ for (cnt = 0; cnt < 1000; cnt++) {
+ pdq_process_command_responses(pdq);
+ if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion)
+ break;
+ PDQ_OS_USEC_DELAY(1000);
+ }
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ }
+
+ return state;
+}
+
+void
+pdq_run(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_state_t state;
+
+ state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE);
+ PDQ_ASSERT(state != PDQS_RESET);
+ PDQ_ASSERT(state != PDQS_HALTED);
+ PDQ_ASSERT(state != PDQS_UPGRADE);
+ PDQ_ASSERT(state != PDQS_RING_MEMBER);
+ switch (state) {
+ case PDQS_DMA_AVAILABLE: {
+ /*
+ * The PDQ after being reset screws up some of its state.
+ * So we need to clear all the errors/interrupts so the real
+ * ones will get through.
+ */
+ *csrs->csr_host_int_type_0 = 0xFF;
+ *csrs->csr_host_int_enable = PDQ_HOST_INT_STATE_CHANGE|PDQ_HOST_INT_XMT_DATA_FLUSH
+ |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE
+ |PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_TX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE;
+ /*
+ * Set the MAC and address filters and start up the PDQ.
+ */
+ pdq_process_unsolicited_events(pdq);
+ pdq_process_received_data(pdq, &pdq->pdq_rx_info,
+ pdq->pdq_dbp->pdqdb_receives,
+ pdq->pdq_cbp->pdqcb_receives,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+ if (pdq->pdq_flags & PDQ_PASS_SMT) {
+ pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
+ pdq->pdq_dbp->pdqdb_host_smt,
+ pdq->pdq_cbp->pdqcb_host_smt,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
+ *csrs->csr_host_smt_producer = pdq->pdq_host_smt_info.rx_producer | (pdq->pdq_host_smt_info.rx_completion << 8);
+ }
+ pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
+ | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) | PDQ_BITMASK(PDQC_START);
+ if (pdq->pdq_flags & PDQ_PRINTCHARS)
+ pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
+ pdq_queue_commands(pdq);
+ break;
+ }
+ case PDQS_LINK_UNAVAILABLE:
+ case PDQS_LINK_AVAILABLE: {
+ pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
+ | PDQ_BITMASK(PDQC_ADDR_FILTER_SET);
+ if (pdq->pdq_flags & PDQ_PRINTCHARS)
+ pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
+ if (pdq->pdq_flags & PDQ_PASS_SMT) {
+ pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
+ pdq->pdq_dbp->pdqdb_host_smt,
+ pdq->pdq_cbp->pdqcb_host_smt,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
+ *csrs->csr_host_smt_producer = pdq->pdq_host_smt_info.rx_producer | (pdq->pdq_host_smt_info.rx_completion << 8);
+ }
+ pdq_process_unsolicited_events(pdq);
+ pdq_queue_commands(pdq);
+ break;
+ }
+ case PDQS_RING_MEMBER: {
+ }
+ }
+}
+
+int
+pdq_interrupt(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_uint32_t data;
+ int progress = 0;
+
+ if (pdq->pdq_type == PDQ_DEFPA)
+ if (*pdq->pdq_pci_csrs.csr_pfi_status & 0x10)
+ *pdq->pdq_pci_csrs.csr_pfi_status = 0x10;
+
+ while ((data = *csrs->csr_port_status) & PDQ_PSTS_INTR_PENDING) {
+ progress = 1;
+ PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data));
+ if (data & PDQ_PSTS_RCV_DATA_PENDING) {
+ pdq_process_received_data(pdq, &pdq->pdq_rx_info,
+ pdq->pdq_dbp->pdqdb_receives,
+ pdq->pdq_cbp->pdqcb_receives,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+ }
+ if (data & PDQ_PSTS_HOST_SMT_PENDING) {
+ pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
+ pdq->pdq_dbp->pdqdb_host_smt,
+ pdq->pdq_cbp->pdqcb_host_smt,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
+ *csrs->csr_host_smt_producer = pdq->pdq_host_smt_info.rx_producer | (pdq->pdq_host_smt_info.rx_completion << 8);
+ }
+ if (data & PDQ_PSTS_XMT_DATA_PENDING)
+ pdq_process_transmitted_data(pdq);
+ if (data & PDQ_PSTS_UNSOL_PENDING)
+ pdq_process_unsolicited_events(pdq);
+ if (data & PDQ_PSTS_CMD_RSP_PENDING)
+ pdq_process_command_responses(pdq);
+ if (data & PDQ_PSTS_TYPE_0_PENDING) {
+ data = *csrs->csr_host_int_type_0;
+ if (data & PDQ_HOST_INT_STATE_CHANGE) {
+ pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status);
+ printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]);
+ if (state == PDQS_LINK_UNAVAILABLE) {
+ pdq->pdq_flags &= ~PDQ_TXOK;
+ } else if (state == PDQS_LINK_AVAILABLE) {
+ pdq->pdq_flags |= PDQ_TXOK;
+ pdq_os_restart_transmitter(pdq);
+ } else if (state == PDQS_HALTED) {
+ pdq_response_error_log_get_t log_entry;
+ pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(*csrs->csr_port_status);
+ printf(": halt code = %d (%s)\n",
+ halt_code, pdq_halt_codes[halt_code]);
+ if (halt_code == PDQH_DMA_ERROR) {
+ PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
+ *pdq->pdq_pci_csrs.csr_pfi_status,
+ data & PDQ_HOST_INT_FATAL_ERROR));
+ }
+ pdq_read_error_log(pdq, &log_entry);
+ pdq_stop(pdq);
+ if (pdq->pdq_flags & PDQ_RUNNING)
+ pdq_run(pdq);
+ return 1;
+ }
+ printf("\n");
+ *csrs->csr_host_int_type_0 = PDQ_HOST_INT_STATE_CHANGE;
+ }
+ if (data & PDQ_HOST_INT_FATAL_ERROR) {
+ pdq_stop(pdq);
+ if (pdq->pdq_flags & PDQ_RUNNING)
+ pdq_run(pdq);
+ return 1;
+ }
+ if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) {
+ printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS);
+ pdq->pdq_flags &= ~PDQ_TXOK;
+ pdq_flush_transmitter(pdq);
+ pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE);
+ *csrs->csr_host_int_type_0 = PDQ_HOST_INT_XMT_DATA_FLUSH;
+ }
+ }
+ if (pdq->pdq_type == PDQ_DEFPA)
+ if (*pdq->pdq_pci_csrs.csr_pfi_status & 0x10)
+ *pdq->pdq_pci_csrs.csr_pfi_status = 0x10;
+ }
+ return progress;
+}
+
+pdq_t *
+pdq_initialize(
+ void *csr_va,
+ const char *name,
+ int unit,
+ void *ctx,
+ pdq_type_t type)
+{
+ pdq_t *pdq;
+ pdq_state_t state;
+ const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE;
+ pdq_uint8_t *p;
+ int idx;
+
+ PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192);
+ PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64);
+ PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET);
+ PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET);
+ PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET);
+ PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET);
+ PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET);
+ PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET);
+ PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512);
+
+ pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t));
+ if (pdq == NULL) {
+ PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq)));
+ return NULL;
+ }
+ PDQ_OS_MEMZERO(pdq, sizeof(pdq_t));
+ pdq->pdq_type = type;
+ pdq->pdq_unit = unit;
+ pdq->pdq_os_ctx = (void *) ctx;
+ pdq->pdq_os_name = name;
+ pdq->pdq_flags = PDQ_PRINTCHARS;
+ /*
+ * Allocate the additional data structures required by
+ * the PDQ driver. Allocate a contiguous region of memory
+ * for the descriptor block. We need to allocated enough
+ * to guarantee that we will a get 8KB block of memory aligned
+ * on a 8KB boundary. This turns to require that we allocate
+ * (N*2 - 1 page) pages of memory. On machine with less than
+ * a 8KB page size, it mean we will allocate more memory than
+ * we need. The extra will be used for the unsolicited event
+ * buffers (though on machines with 8KB pages we will to allocate
+ * them separately since there will be nothing left overs.)
+ */
+ p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes);
+ if (p != NULL) {
+ pdq_physaddr_t physaddr = PDQ_OS_VA_TO_PA(p) & 0x1FFF;
+ if (physaddr) {
+ pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p;
+ pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - physaddr];
+ } else {
+ pdq->pdq_dbp = (pdq_descriptor_block_t *) p;
+ pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000];
+ }
+ }
+ if (contig_bytes == sizeof(pdq_descriptor_block_t)) {
+ pdq->pdq_unsolicited_info.ui_events =
+ (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC(
+ PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
+ }
+
+ /*
+ * Make sure everything got allocated. If not, free what did
+ * get allocated and return.
+ */
+ if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) {
+ cleanup_and_return:
+ if (pdq->pdq_dbp != NULL)
+ PDQ_OS_MEMFREE_CONTIG(pdq->pdq_dbp, contig_bytes);
+ if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL)
+ PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events,
+ PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
+ PDQ_OS_MEMFREE(pdq, sizeof(pdq_t));
+ return NULL;
+ }
+
+ pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer;
+ pdq->pdq_command_info.ci_bufstart = (pdq_uint8_t *) pdq->pdq_dbp->pdqdb_command_pool;
+ pdq->pdq_rx_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_receive_buffers;
+
+ pdq->pdq_host_smt_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_host_smt_buffers;
+
+ PDQ_PRINTF(("PDQ Descriptor Block = %x\n", pdq->pdq_dbp));
+ PDQ_PRINTF((" Recieve Queue = %x\n", pdq->pdq_dbp->pdqdb_receives));
+ PDQ_PRINTF((" Transmit Queue = %x\n", pdq->pdq_dbp->pdqdb_transmits));
+ PDQ_PRINTF((" Host SMT Queue = %x\n", pdq->pdq_dbp->pdqdb_host_smt));
+ PDQ_PRINTF((" Command Response Queue = %x\n", pdq->pdq_dbp->pdqdb_command_responses));
+ PDQ_PRINTF((" Command Request Queue = %x\n", pdq->pdq_dbp->pdqdb_command_requests));
+ PDQ_PRINTF(("PDQ Consumer Block = %x\n", pdq->pdq_cbp));
+
+ /*
+ * Zero out the descriptor block. Not really required but
+ * it pays to be neat. This will also zero out the consumer
+ * block, command pool, and buffer pointers for the receive
+ * host_smt rings.
+ */
+ PDQ_OS_MEMZERO(pdq->pdq_dbp, sizeof(*pdq->pdq_dbp));
+
+ /*
+ * Initialize the CSR references.
+ */
+ pdq_init_csrs(&pdq->pdq_csrs, csr_va, 1);
+ switch (pdq->pdq_type) {
+ case PDQ_DEFPA: pdq_init_pci_csrs(&pdq->pdq_pci_csrs, csr_va, 1); break;
+#ifdef PDQ_DO_EISA
+ case PDQ_DEFEA: pdq_init_esia_csrs(&pdq->pdq_eisa_csrs, csr_va, 1); break;
+#endif
+ }
+
+ PDQ_PRINTF(("PDQ CSRs:\n"));
+ PDQ_PRINTF((" Port Reset = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_reset, *pdq->pdq_csrs.csr_port_reset));
+ PDQ_PRINTF((" Host Data = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_data, *pdq->pdq_csrs.csr_host_data));
+ PDQ_PRINTF((" Port Control = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_control, *pdq->pdq_csrs.csr_port_control));
+ PDQ_PRINTF((" Port Data A = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_data_a, *pdq->pdq_csrs.csr_port_data_a));
+ PDQ_PRINTF((" Port Data B = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_data_b, *pdq->pdq_csrs.csr_port_data_b));
+ PDQ_PRINTF((" Port Status = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_status, *pdq->pdq_csrs.csr_port_status));
+ PDQ_PRINTF((" Host Int Type 0 = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_int_type_0, *pdq->pdq_csrs.csr_host_int_type_0));
+ PDQ_PRINTF((" Host Int Enable = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_int_enable, *pdq->pdq_csrs.csr_host_int_enable));
+ PDQ_PRINTF((" Type 2 Producer = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_type_2_producer, *pdq->pdq_csrs.csr_type_2_producer));
+ PDQ_PRINTF((" Command Response Producer = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_cmd_response_producer, *pdq->pdq_csrs.csr_cmd_response_producer));
+ PDQ_PRINTF((" Command Request Producer = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_cmd_request_producer, *pdq->pdq_csrs.csr_cmd_request_producer));
+ PDQ_PRINTF((" Host SMT Producer = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_smt_producer, *pdq->pdq_csrs.csr_host_smt_producer));
+ PDQ_PRINTF((" Unsolicited Producer = %x [0x%08x]\n",
+ pdq->pdq_csrs.csr_unsolicited_producer, *pdq->pdq_csrs.csr_unsolicited_producer));
+
+ /*
+ * Initialize the command information block
+ */
+ pdq->pdq_command_info.ci_pa_bufstart = PDQ_OS_VA_TO_PA(pdq->pdq_command_info.ci_bufstart);
+ for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_requests)/sizeof(pdq->pdq_dbp->pdqdb_command_requests[0]); idx++) {
+ pdq_txdesc_t *txd = &pdq->pdq_dbp->pdqdb_command_requests[idx];
+
+ txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
+ txd->txd_eop = txd->txd_sop = 1;
+ txd->txd_pa_hi = 0;
+ }
+ for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_responses)/sizeof(pdq->pdq_dbp->pdqdb_command_responses[0]); idx++) {
+ pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_command_responses[idx];
+
+ rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
+ rxd->rxd_sop = 1;
+ rxd->rxd_seg_cnt = 0;
+ rxd->rxd_seg_len_lo = 0;
+ }
+
+ /*
+ * Initialize the unsolicited event information block
+ */
+ pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
+ pdq->pdq_unsolicited_info.ui_pa_bufstart = PDQ_OS_VA_TO_PA(pdq->pdq_unsolicited_info.ui_events);
+ for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events)/sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events[0]); idx++) {
+ pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_unsolicited_events[idx];
+ pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
+
+ rxd->rxd_sop = 1;
+ rxd->rxd_seg_cnt = 0;
+ rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16;
+ rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event
+ - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events;
+ rxd->rxd_pa_hi = 0;
+ }
+ /*
+ * Initialize the receive information blocks (normal and SMT).
+ */
+ pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
+ pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8;
+
+ pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
+ pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3;
+
+ /*
+ * Initialize the transmit information block.
+ */
+ pdq->pdq_tx_hdr[0] = PDQ_FDDI_PH0;
+ pdq->pdq_tx_hdr[1] = PDQ_FDDI_PH1;
+ pdq->pdq_tx_hdr[2] = PDQ_FDDI_PH2;
+ pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
+ pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = sizeof(pdq->pdq_tx_hdr);
+ pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1;
+ pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_OS_VA_TO_PA(pdq->pdq_tx_hdr);
+
+ state = PDQ_PSTS_ADAPTER_STATE(*pdq->pdq_csrs.csr_port_status);
+ PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
+
+ /*
+ * Stop the PDQ if it is running and put it into a known state.
+ */
+ state = pdq_stop(pdq);
+
+ /* state = PDQ_PSTS_ADAPTER_STATE(*pdq->pdq_csrs.csr_port_status); */
+ PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
+ PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
+ /*
+ * If the adapter is not the state we expect, then the initialization
+ * failed. Cleanup and exit.
+ */
+ if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE)
+ goto cleanup_and_return;
+
+ PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1],
+ pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3],
+ pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5]));
+ PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n",
+ pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
+ pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3]));
+ PDQ_PRINTF(("PDQ Chip Revision = "));
+ switch (pdq->pdq_chip_rev) {
+ case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break;
+ case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break;
+ case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break;
+ default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev));
+ }
+ PDQ_PRINTF(("\n"));
+
+ return pdq;
+}
diff --git a/sys/dev/ic/pdqreg.h b/sys/dev/ic/pdqreg.h
new file mode 100644
index 00000000000..71ce819e348
--- /dev/null
+++ b/sys/dev/ic/pdqreg.h
@@ -0,0 +1,1061 @@
+/* $NetBSD: pdqreg.h,v 1.2 1995/08/19 04:35:21 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1995 Matt Thomas (thomas@lkg.dec.com)
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough 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.
+ */
+
+/*
+ * DEC PDQ FDDI Controller; PDQ port driver definitions
+ *
+ * Written by Matt Thomas
+ */
+
+#ifndef _PDQREG_H
+#define _PDQREG_H
+
+#include <stddef.h>
+#if defined(PDQTEST) && !defined(PDQ_NDEBUG)
+#include <assert.h>
+#define PDQ_ASSERT assert
+#else
+#define PDQ_ASSERT(x) do { } while(0)
+#endif
+
+#define PDQ_RING_SIZE(array) ((sizeof(array) / sizeof(array[0])))
+#define PDQ_ARRAY_SIZE(array) ((sizeof(array) / sizeof(array[0])))
+#define PDQ_RING_MASK(array) (PDQ_RING_SIZE(array) - 1)
+#define PDQ_BITMASK(n) (1L << (pdq_uint32_t) (n))
+
+#define PDQ_FDDI_MAX 4495
+#define PDQ_FDDI_LLC_MIN 20
+#define PDQ_FDDI_SMT_MIN 37
+
+#define PDQ_FDDI_SMT 0x40
+#define PDQ_FDDI_LLC_ASYNC 0x50
+#define PDQ_FDDI_LLC_SYNC 0xD0
+#define PDQ_FDDI_IMP_ASYNC 0x60
+#define PDQ_FDDI_IMP_SYNC 0xE0
+
+#define PDQ_FDDIFC_C 0x80
+#define PDQ_FDDIFC_L 0x40
+#define PDQ_FDDIFC_F 0x30
+#define PDQ_FDDIFC_Z 0x0F
+
+#define PDQ_FDDI_PH0 0x20
+#define PDQ_FDDI_PH1 0x38
+#define PDQ_FDDI_PH2 0x00
+
+typedef unsigned int pdq_uint32_t;
+typedef unsigned short pdq_uint16_t;
+typedef unsigned char pdq_uint8_t;
+
+typedef pdq_uint32_t pdq_physaddr_t;
+
+typedef struct {
+ pdq_uint8_t lanaddr_bytes[8];
+} pdq_lanaddr_t;
+
+typedef struct {
+ pdq_uint8_t fwrev_bytes[4];
+} pdq_fwrev_t;
+
+typedef enum {
+ PDQS_RESET=0,
+ PDQS_UPGRADE=1,
+ PDQS_DMA_UNAVAILABLE=2,
+ PDQS_DMA_AVAILABLE=3,
+ PDQS_LINK_AVAILABLE=4,
+ PDQS_LINK_UNAVAILABLE=5,
+ PDQS_HALTED=6,
+ PDQS_RING_MEMBER=7
+} pdq_state_t;
+
+typedef struct {
+ volatile pdq_uint32_t *csr_port_reset; /* 0x00 [RW] */
+ volatile pdq_uint32_t *csr_host_data; /* 0x04 [R] */
+ volatile pdq_uint32_t *csr_port_control; /* 0x08 [RW] */
+ volatile pdq_uint32_t *csr_port_data_a; /* 0x0C [RW] */
+ volatile pdq_uint32_t *csr_port_data_b; /* 0x10 [RW] */
+ volatile pdq_uint32_t *csr_port_status; /* 0x14 [R] */
+ volatile pdq_uint32_t *csr_host_int_type_0; /* 0x18 [RW] */
+ volatile pdq_uint32_t *csr_host_int_enable; /* 0x1C [RW] */
+ volatile pdq_uint32_t *csr_type_2_producer; /* 0x20 [RW] */
+ volatile pdq_uint32_t *csr_cmd_response_producer; /* 0x28 [RW] */
+ volatile pdq_uint32_t *csr_cmd_request_producer; /* 0x2C [RW] */
+ volatile pdq_uint32_t *csr_host_smt_producer; /* 0x30 [RW] */
+ volatile pdq_uint32_t *csr_unsolicited_producer; /* 0x34 [RW] */
+} pdq_csrs_t;
+
+typedef struct {
+ volatile pdq_uint32_t *csr_pfi_mode_control; /* 0x40 [RW] */
+ volatile pdq_uint32_t *csr_pfi_status; /* 0x44 [RW] */
+ volatile pdq_uint32_t *csr_fifo_write; /* 0x48 [RW] */
+ volatile pdq_uint32_t *csr_fifo_read; /* 0x4C [RW] */
+} pdq_pci_csrs_t;
+
+#define PDQ_PFI_MODE_DMA_ENABLE 0x01 /* DMA Enable */
+#define PDQ_PFI_MODE_PFI_PCI_INTR 0x02 /* PFI-to-PCI Int Enable */
+#define PDQ_PFI_MODE_PDQ_PCI_INTR 0x04 /* PDQ-to-PCI Int Enable */
+
+#define PDQ_PFI_STATUS_PDQ_INTR 0x10 /* PDQ Int received */
+#define PDQ_PFI_STATUS_DMA_ABORT 0x08 /* PDQ DMA Abort asserted */
+
+#define PDQ_EISA_BURST_HOLDOFF 0x0040
+#define PDQ_EISA_SLOT_ID 0x0C80
+#define PDQ_EISA_SLOT_CTRL 0x0C84
+#define PDQ_EISA_MEM_ADD_CMP_0 0x0C85
+#define PDQ_EISA_MEM_ADD_CMP_1 0x0C86
+#define PDQ_EISA_MEM_ADD_CMP_2 0x0C87
+#define PDQ_EISA_MEM_ADD_HI_CMP_0 0x0C88
+#define PDQ_EISA_MEM_ADD_HI_CMP_1 0x0C89
+#define PDQ_EISA_MEM_ADD_HI_CMP_2 0x0C8A
+#define PDQ_EISA_MEM_ADD_MASK_0 0x0C8B
+#define PDQ_EISA_MEM_ADD_MASK_1 0x0C8C
+#define PDQ_EISA_MEM_ADD_MASK_2 0x0C8D
+#define PDQ_EISA_MEM_ADD_LO_CMP_0 0x0C8E
+#define PDQ_EISA_MEM_ADD_LO_CMP_1 0x0C8F
+#define PDQ_EISA_MEM_ADD_LO_CMP_2 0x0C90
+#define PDQ_EISA_IO_CMP_0_0 0x0C91
+#define PDQ_EISA_IO_CMP_0_1 0x0C92
+#define PDQ_EISA_IO_CMP_1_0 0x0C93
+#define PDQ_EISA_IO_CMP_1_1 0x0C94
+#define PDQ_EISA_IO_CMP_2_0 0x0C95
+#define PDQ_EISA_IO_CMP_2_1 0x0C96
+#define PDQ_EISA_IO_CMP_3_0 0x0C97
+#define PDQ_EISA_IO_CMP_3_1 0x0C98
+#define PDQ_EISA_IO_ADD_MASK_0_0 0x0C99
+#define PDQ_EISA_IO_ADD_MASK_0_1 0x0C9A
+#define PDQ_EISA_IO_ADD_MASK_1_0 0x0C9B
+#define PDQ_EISA_IO_ADD_MASK_1_1 0x0C9C
+#define PDQ_EISA_IO_ADD_MASK_2_0 0x0C9D
+#define PDQ_EISA_IO_ADD_MASK_2_1 0x0C9E
+#define PDQ_EISA_IO_ADD_MASK_3_0 0x0C9F
+#define PDQ_EISA_IO_ADD_MASK_3_1 0x0CA0
+#define PDQ_EISA_MOD_CONFIG_1 0x0CA1
+#define PDQ_EISA_MOD_CONFIG_2 0x0CA2
+#define PDQ_EISA_MOD_CONFIG_3 0x0CA3
+#define PDQ_EISA_MOD_CONFIG_4 0x0CA4
+#define PDQ_EISA_MOD_CONFIG_5 0x0CA5
+#define PDQ_EISA_MOD_CONFIG_6 0x0CA6
+#define PDQ_EISA_MOD_CONFIG_7 0x0CA7
+#define PDQ_EISA_DIP_SWITCH 0x0CA8
+#define PDQ_EISA_IO_CONFIG_STAT_0 0x0CA9
+#define PDQ_EISA_IO_CONFIG_STAT_1 0x0CAA
+#define PDQ_EISA_DMA_CONFIG 0x0CAB
+#define PDQ_EISA_INPUT_PORT 0x0CAC
+#define PDQ_EISA_OUTPUT_PORT 0x0CAD
+#define PDQ_EISA_FUNCTION_CTRL 0x0CAE
+
+/*
+ * Port Reset Data A Definitions
+ */
+#define PDQ_PRESET_SKIP_SELFTEST 0x0004
+#define PDQ_PRESET_SOFT_RESET 0x0002
+#define PDQ_PRESET_UPGRADE 0x0001
+/*
+ * Port Control Register Definitions
+ */
+#define PDQ_PCTL_CMD_ERROR 0x8000
+#define PDQ_PCTL_FLASH_BLAST 0x4000
+#define PDQ_PCTL_HALT 0x2000
+#define PDQ_PCTL_COPY_DATA 0x1000
+#define PDQ_PCTL_ERROR_LOG_START 0x0800
+#define PDQ_PCTL_ERROR_LOG_READ 0x0400
+#define PDQ_PCTL_XMT_DATA_FLUSH_DONE 0x0200
+#define PDQ_PCTL_DMA_INIT 0x0100
+#define PDQ_DMA_INIT_LW_BSWAP_DATA 0x02
+#define PDQ_DMA_INIT_LW_BSWAP_LITERAL 0x01
+#define PDQ_PCTL_INIT_START 0x0080
+#define PDQ_PCTL_CONSUMER_BLOCK 0x0040
+#define PDQ_PCTL_DMA_UNINIT 0x0020
+#define PDQ_PCTL_RING_MEMBER 0x0010
+#define PDQ_PCTL_MLA_READ 0x0008
+#define PDQ_PCTL_FW_REV_READ 0x0004
+#define PDQ_PCTL_DEVICE_SPECIFIC 0x0002
+#define PDQ_PCTL_SUB_CMD 0x0001
+
+typedef enum {
+ PDQ_SUB_CMD_LINK_UNINIT=1,
+ PDQ_SUB_CMD_DMA_BURST_SIZE_SET=2,
+ PDQ_SUB_CMD_PDQ_REV_GET=4
+} pdq_sub_cmd_t;
+
+typedef enum {
+ PDQ_DMA_BURST_4LW=0,
+ PDQ_DMA_BURST_8LW=1,
+ PDQ_DMA_BURST_16LW=2,
+ PDQ_DMA_BURST_32LW=3
+} pdq_dma_burst_size_t;
+
+typedef enum {
+ PDQ_CHIP_REV_A_B_OR_C=0,
+ PDQ_CHIP_REV_D=2,
+ PDQ_CHIP_REV_E=4
+} pdq_chip_rev_t;
+/*
+ * Port Status Register Definitions
+ */
+#define PDQ_PSTS_RCV_DATA_PENDING 0x80000000ul
+#define PDQ_PSTS_XMT_DATA_PENDING 0x40000000ul
+#define PDQ_PSTS_HOST_SMT_PENDING 0x20000000ul
+#define PDQ_PSTS_UNSOL_PENDING 0x10000000ul
+#define PDQ_PSTS_CMD_RSP_PENDING 0x08000000ul
+#define PDQ_PSTS_CMD_REQ_PENDING 0x04000000ul
+#define PDQ_PSTS_TYPE_0_PENDING 0x02000000ul
+#define PDQ_PSTS_INTR_PENDING 0xFE000000ul
+#define PDQ_PSTS_ADAPTER_STATE(sts) ((pdq_state_t) (((sts) >> 8) & 0x07))
+#define PDQ_PSTS_HALT_ID(sts) ((pdq_halt_code_t) ((sts) & 0xFF))
+/*
+ * Host Interrupt Register Definitions
+ */
+#define PDQ_HOST_INT_TX_ENABLE 0x80000000ul
+#define PDQ_HOST_INT_RX_ENABLE 0x40000000ul
+#define PDQ_HOST_INT_UNSOL_ENABLE 0x20000000ul
+#define PDQ_HOST_INT_HOST_SMT_ENABLE 0x10000000ul
+#define PDQ_HOST_INT_CMD_RSP_ENABLE 0x08000000ul
+#define PDQ_HOST_INT_CMD_RQST_ENABLE 0x04000000ul
+
+#define PDQ_HOST_INT_1MS 0x80
+#define PDQ_HOST_INT_20MS 0x40
+#define PDQ_HOST_INT_CSR_CMD_DONE 0x20
+#define PDQ_HOST_INT_STATE_CHANGE 0x10
+#define PDQ_HOST_INT_XMT_DATA_FLUSH 0x08
+#define PDQ_HOST_INT_NXM 0x04
+#define PDQ_HOST_INT_PM_PARITY_ERROR 0x02
+#define PDQ_HOST_INT_HOST_BUS_PARITY_ERROR 0x01
+#define PDQ_HOST_INT_FATAL_ERROR 0x07
+
+typedef enum {
+ PDQH_SELFTEST_TIMEOUT=0,
+ PDQH_HOST_BUS_PARITY_ERROR=1,
+ PDQH_HOST_DIRECTED_HALT=2,
+ PDQH_SOFTWARE_FAULT=3,
+ PDQH_HARDWARE_FAULT=4,
+ PDQH_PC_TRACE_PATH_TEST=5,
+ PDQH_DMA_ERROR=6,
+ PDQH_IMAGE_CRC_ERROR=7,
+ PDQH_ADAPTER_PROCESSOR_ERROR=8,
+ PDQH_MAX=9
+} pdq_halt_code_t;
+
+typedef struct {
+ pdq_uint16_t pdqcb_receives;
+ pdq_uint16_t pdqcb_transmits;
+ pdq_uint32_t pdqcb__filler1;
+ pdq_uint32_t pdqcb_host_smt;
+ pdq_uint32_t pdqcb__filler2;
+ pdq_uint32_t pdqcb_unsolicited_event;
+ pdq_uint32_t pdqcb__filler3;
+ pdq_uint32_t pdqcb_command_response;
+ pdq_uint32_t pdqcb__filler4;
+ pdq_uint32_t pdqcb_command_request;
+ pdq_uint32_t pdqcb__filler5[7];
+} pdq_consumer_block_t;
+
+#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+#define PDQ_BITFIELD2(a, b) b, a
+#define PDQ_BITFIELD3(a, b, c) c, b, a
+#define PDQ_BITFIELD4(a, b, c, d) d, c, b, a
+#define PDQ_BITFIELD5(a, b, c, d, e) e, d, c, b, a
+#define PDQ_BITFIELD12(a, b, c, d, e, f, g, h, i, j, k, l) \
+ l, k, j, i, h, g, f, e, d, c, b, a
+#else
+#define PDQ_BITFIELD2(a, b) a, b
+#define PDQ_BITFIELD3(a, b, c) a, b, c
+#define PDQ_BITFIELD4(a, b, c, d) a, b, c, d
+#define PDQ_BITFIELD5(a, b, c, d, e) a, b, c, d, e
+#define PDQ_BITFIELD12(a, b, c, d, e, f, g, h, i, j, k, l) \
+ a, b, c, d, e, f, g, h, i, j, k, l
+#endif
+
+typedef struct {
+ pdq_uint32_t PDQ_BITFIELD5(rxd_pa_hi : 16,
+ rxd_seg_cnt : 4,
+ rxd_seg_len_hi : 9,
+ rxd_seg_len_lo : 2,
+ rxd_sop : 1);
+ pdq_uint32_t rxd_pa_lo;
+} pdq_rxdesc_t;
+
+typedef union {
+ pdq_uint32_t rxs_status;
+ pdq_uint32_t PDQ_BITFIELD12(rxs_len : 13,
+ rxs_rcc_ss : 2,
+ rxs_rcc_dd : 2,
+ rxs_rcc_reason : 3,
+ rxs_rcc_badcrc : 1,
+ rxs_rcc_badpdu : 1,
+ rxs_fsb__reserved : 2,
+ rxs_fsb_c : 1,
+ rxs_fsb_a : 1,
+ rxs_fsb_e : 1,
+ rxs_fsc : 3,
+ rxs__reserved : 2);
+} pdq_rxstatus_t;
+
+typedef struct {
+ pdq_uint32_t PDQ_BITFIELD5(txd_pa_hi : 16,
+ txd_seg_len : 13,
+ txd_mbz : 1,
+ txd_eop : 1,
+ txd_sop : 1);
+ pdq_uint32_t txd_pa_lo;
+} pdq_txdesc_t;
+
+typedef struct {
+ pdq_rxdesc_t pdqdb_receives[256]; /* 2048; 0x0000..0x07FF */
+ pdq_txdesc_t pdqdb_transmits[256]; /* 2048; 0x0800..0x0FFF */
+ pdq_rxdesc_t pdqdb_host_smt[64]; /* 512; 0x1000..0x11FF */
+ pdq_rxdesc_t pdqdb_unsolicited_events[16]; /* 128; 0x1200..0x127F */
+ pdq_rxdesc_t pdqdb_command_responses[16]; /* 128; 0x1280..0x12FF */
+ pdq_txdesc_t pdqdb_command_requests[16]; /* 128; 0x1300..0x137F */
+ /*
+ * The rest of the descriptor block is unused.
+ * As such we could use it for other things.
+ */
+ pdq_consumer_block_t pdqdb_consumer; /* 64; 0x1380..0x13BF */
+ void *pdqdb_receive_buffers[256]; /* 1024/2048; 0x13C0..0x17BF 0x13C0..0x1BBF */
+ void *pdqdb_host_smt_buffers[64]; /* 256/ 512; 0x17C0..0x18BF 0x1BC0..0x1DBF */
+ /*
+ * The maximum command size is 512 so as long as thes
+ * command is at least that long all will be fine.
+ */
+#if defined(__alpha) || defined(__alpha__)
+ pdq_uint32_t pdqdb_command_pool[144];
+#else
+ pdq_uint32_t pdqdb_command_pool[464];
+#endif
+} pdq_descriptor_block_t;
+
+typedef enum {
+ PDQ_DEFPA, /* PCI-bus */
+ PDQ_DEFEA, /* EISA-bus */
+ PDQ_DEFTA, /* TurboChannel */
+ PDQ_DEFAA, /* FutureBus+ */
+ PDQ_DEFQA /* Q-bus */
+} pdq_type_t;
+
+typedef struct {
+ /*
+ * These value manage the available space in command/response
+ * buffer area.
+ */
+ pdq_physaddr_t ci_pa_bufstart;
+ pdq_uint8_t *ci_bufstart;
+ /*
+ * Bitmask of commands to sent to the PDQ
+ */
+ pdq_uint32_t ci_pending_commands;
+ /*
+ * Variables to maintain the PDQ queues.
+ */
+ pdq_uint32_t ci_command_active;
+ pdq_uint32_t ci_request_producer;
+ pdq_uint32_t ci_response_producer;
+ pdq_uint32_t ci_request_completion;
+ pdq_uint32_t ci_response_completion;
+} pdq_command_info_t;
+
+#define PDQ_SIZE_UNSOLICITED_EVENT 512
+#define PDQ_NUM_UNSOLICITED_EVENTS (PDQ_OS_PAGESIZE / PDQ_SIZE_UNSOLICITED_EVENT)
+
+typedef struct _pdq_unsolicited_event_t pdq_unsolicited_event_t;
+
+typedef struct {
+ pdq_physaddr_t ui_pa_bufstart;
+ pdq_unsolicited_event_t *ui_events;
+
+ pdq_uint32_t ui_free;
+ pdq_uint32_t ui_producer;
+ pdq_uint32_t ui_completion;
+} pdq_unsolicited_info_t;
+
+#define PDQ_RX_FC_OFFSET (sizeof(pdq_rxstatus_t) + 3)
+#define PDQ_RX_SEGCNT ((PDQ_FDDI_MAX + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE)
+#define PDQ_DO_TYPE2_PRODUCER(pdq) \
+ (*pdq->pdq_csrs.csr_type_2_producer = (pdq->pdq_rx_info.rx_producer << 0) \
+ | (pdq->pdq_tx_info.tx_producer << 8) \
+ | (pdq->pdq_rx_info.rx_completion << 16) \
+ | (pdq->pdq_tx_info.tx_completion << 24))
+#define PDQ_ADVANCE(n, a, m) ((n) = ((n) + (a)) & (m))
+
+typedef struct {
+ void *q_head;
+ void *q_tail;
+} pdq_databuf_queue_t;
+
+typedef struct {
+ void *rx_buffers;
+
+ pdq_uint32_t rx_target;
+ pdq_uint32_t rx_free;
+ pdq_uint32_t rx_producer;
+ pdq_uint32_t rx_completion;
+} pdq_rx_info_t;
+
+typedef struct {
+ pdq_databuf_queue_t tx_txq;
+ pdq_txdesc_t tx_hdrdesc;
+ pdq_uint8_t tx_descriptor_count[256];
+
+ pdq_uint32_t tx_free;
+ pdq_uint32_t tx_producer;
+ pdq_uint32_t tx_completion;
+} pdq_tx_info_t;
+
+typedef struct {
+ pdq_csrs_t pdq_csrs;
+ pdq_pci_csrs_t pdq_pci_csrs;
+ pdq_type_t pdq_type;
+ pdq_chip_rev_t pdq_chip_rev;
+ pdq_lanaddr_t pdq_hwaddr;
+ pdq_fwrev_t pdq_fwrev;
+ pdq_descriptor_block_t *pdq_dbp;
+ volatile pdq_consumer_block_t *pdq_cbp;
+ pdq_uint32_t pdq_flags;
+#define PDQ_PROMISC 0x0001
+#define PDQ_ALLMULTI 0x0002
+#define PDQ_PASS_SMT 0x0004
+#define PDQ_RUNNING 0x0008
+#define PDQ_PRINTCHARS 0x0010
+#define PDQ_TXOK 0x0020
+ const char *pdq_os_name;
+ void *pdq_os_ctx;
+ pdq_uint32_t pdq_unit;
+ pdq_command_info_t pdq_command_info;
+ pdq_unsolicited_info_t pdq_unsolicited_info;
+ pdq_tx_info_t pdq_tx_info;
+ pdq_rx_info_t pdq_rx_info;
+ pdq_rx_info_t pdq_host_smt_info;
+ pdq_uint8_t pdq_tx_hdr[3];
+} pdq_t;
+
+typedef enum {
+ PDQC_START=0,
+ PDQC_FILTER_SET=1,
+ PDQC_FILTER_GET=2,
+ PDQC_CHARS_SET=3,
+ PDQC_STATUS_CHARS_GET=4,
+ PDQC_COUNTERS_GET=5,
+ PDQC_COUNTERS_SET=6,
+ PDQC_ADDR_FILTER_SET=7,
+ PDQC_ADDR_FILTER_GET=8,
+ PDQC_ERROR_LOG_CLEAR=9,
+ PDQC_ERROR_LOG_GET=10,
+ PDQC_FDDI_MIB_GET=11,
+ PDQC_DEC_EXT_MIB_GET=12,
+ PDQC_DEV_SPECIFIC_GET=13,
+ PDQC_SNMP_SET=14,
+ PDQC_SMT_MIB_GET=16,
+ PDQC_SMT_MIB_SET=17
+} pdq_cmd_code_t;
+
+typedef enum {
+ PDQR_SUCCESS=0,
+ PDQR_FAILURE=1,
+ PDQR_WARNING=2,
+ PDQR_LOOP_MODE_BAD=3,
+ PDQR_ITEM_CODE_BAD=4,
+ PDQR_TVX_BAD=5,
+ PDQR_TREQ_BAD=6,
+ PDQR_RESTRICTED_TOKEN_BAD=7,
+ PDQR_NO_EOL=12,
+ PDQR_FILTER_STATE_BAD=13,
+ PDQR_CMD_TYPE_BAD=14,
+ PDQR_ADAPTER_STATE_BAD=15,
+ PDQR_RING_PURGER_BAD=16,
+ PDQR_LEM_THRESHOLD_BAD=17,
+ PDQR_LOOP_NOT_SUPPORTED=18,
+ PDQR_FLUSH_TIME_BAD=19,
+ PDQR_NOT_YET_IMPLEMENTED=20,
+ PDQR_CONFIG_POLICY_BAD=21,
+ PDQR_STATION_ACTION_BAD=22,
+ PDQR_MAC_ACTION_BAD=23,
+ PDQR_CON_POLICIES_BAD=24,
+ PDQR_MAC_LOOP_TIME_BAD=25,
+ PDQR_TB_MAX_BAD=26,
+ PDQR_LER_CUTOFF_BAD=27,
+ PDQR_LER_ALARM_BAD=28,
+ PDQR_MAC_PATHS_REQ_BAD=29,
+ PDQR_MAC_T_REQ_BAD=30,
+ PDQR_EMAC_RING_PURGER_BAD=31,
+ PDQR_EMAC_RTOKEN_TIMOUT_AD=32,
+ PDQR_NO_SUCH_ENTRY=33,
+ PDQR_T_NOTIFY_BAD=34,
+ PDQR_TR_MAX_EXP_BAD=35,
+ PDQR_FRAME_ERR_THRESHOLD_BAD=36,
+ PDQR_MAX_TREQ_BAD=37,
+ PDQR_FULL_DUPLEX_ENABLE_BAD=38,
+ PDQR_ITEM_INDEX_BAD=39
+} pdq_response_code_t;
+
+typedef enum {
+ PDQI_EOL=0,
+ PDQI_T_REQ=1,
+ PDQI_TVX=2,
+ PDQI_RESTRICTED_TOKEN=3,
+ PDQI_LEM_THRESHOLD=4,
+ PDQI_RING_PURGER=5,
+ PDQI_COUNTER_INTERVAL=6,
+ PDQI_IND_GROUP_PROM=7,
+ PDQI_GROUP_PROM=8,
+ PDQI_BROADCAST=9,
+ PDQI_SMT_PROM=10,
+ PDQI_SMT_USER=11,
+ PDQI_RESERVED=12,
+ PDQI_IMPLEMENTOR=13,
+ PDQI_LOOPBACK_MODE=14,
+ PDQI_SMT_CONFIG_POLICY=16,
+ PDQI_SMT_CONNECTION_POLICY=17,
+ PDQI_SMT_T_NOTIFY=18,
+ PDQI_SMT_STATION_ACTION=19,
+ PDQI_MAC_PATHS_REQUESTED=21,
+ PDQI_MAC_ACTION=23,
+ PDQI_PORT_CONNECTION_POLICIES=24,
+ PDQI_PORT_PATHS_REQUESTED=25,
+ PDQI_PORT_MAC_LOOP_TIME=26,
+ PDQI_PORT_TB_MAX=27,
+ PDQI_PORT_LER_CUTOFF=28,
+ PDQI_PORT_LER_ALARM=29,
+ PDQI_PORT_ACTION=30,
+ PDQI_FLUSH_TIME=32,
+ PDQI_SMT_USER_DATA=33,
+ PDQI_SMT_STATUS_REPORT_POLICY=34,
+ PDQI_SMT_TRACE_MAX_EXPIRATION=35,
+ PDQI_MAC_FRAME_ERR_THRESHOLD=36,
+ PDQI_MAC_UNIT_DATA_ENABLE=37,
+ PDQI_PATH_TVX_LOWER_BOUND=38,
+ PDQI_PATH_TMAX_LOWER_BOUND=39,
+ PDQI_PATH_MAX_TREQ=40,
+ PDQI_MAC_TREQ=41,
+ PDQI_EMAC_RING_PURGER=42,
+ PDQI_EMAC_RTOKEN_TIMEOUT=43,
+ PDQI_FULL_DUPLEX_ENABLE=44
+} pdq_item_code_t;
+
+typedef enum {
+ PDQ_FALSE=0,
+ PDQ_TRUE=1
+} pdq_boolean_t;
+
+typedef enum {
+ PDQ_FILTER_BLOCK=0,
+ PDQ_FILTER_PASS=1
+} pdq_filter_state_t;
+
+typedef enum {
+ PDQ_STATION_TYPE_SAS=0,
+ PDQ_STATION_TYPE_DAC=1,
+ PDQ_STATION_TYPE_SAC=2,
+ PDQ_STATION_TYPE_NAC=3,
+ PDQ_STATION_TYPE_DAS=4
+} pdq_station_type_t;
+
+typedef enum {
+ PDQ_STATION_STATE_OFF=0,
+ PDQ_STATION_STATE_ON=1,
+ PDQ_STATION_STATE_LOOPBACK=2
+} pdq_station_state_t;
+
+typedef enum {
+ PDQ_LINK_STATE_OFF_READY=1,
+ PDQ_LINK_STATE_OFF_FAULT_RECOVERY=2,
+ PDQ_LINK_STATE_ON_RING_INIT=3,
+ PDQ_LINK_STATE_ON_RING_RUN=4,
+ PDQ_LINK_STATE_BROKEN=5
+} pdq_link_state_t;
+
+typedef enum {
+ PDQ_DA_TEST_STATE_UNKNOWN=0,
+ PDQ_DA_TEST_STATE_SUCCESS=1,
+ PDQ_DA_TEST_STATE_DUPLICATE=2
+} pdq_da_test_state_t;
+
+typedef enum {
+ PDQ_RING_PURGER_STATE_OFF=0,
+ PDQ_RING_PURGER_STATE_CANDIDATE=1,
+ PDQ_RING_PURGER_STATE_NON_PURGER=2,
+ PDQ_RING_PURGER_STATE_PURGER=3
+} pdq_ring_purger_state_t;
+
+typedef enum {
+ PDQ_FRAME_STRING_MODE_SA_MATCH=0,
+ PDQ_FRAME_STRING_MODE_FCI_STRIP=1
+} pdq_frame_strip_mode_t;
+
+typedef enum {
+ PDQ_RING_ERROR_REASON_NO_ERROR=0,
+ PDQ_RING_ERROR_REASON_RING_INIT_INITIATED=5,
+ PDQ_RING_ERROR_REASON_RING_INIT_RECEIVED=6,
+ PDQ_RING_ERROR_REASON_RING_BEACONING_INITIATED=7,
+ PDQ_RING_ERROR_REASON_DUPLICATE_ADDRESS_DETECTED=8,
+ PDQ_RING_ERROR_REASON_DUPLICATE_TOKEN_DETECTED=9,
+ PDQ_RING_ERROR_REASON_RING_PURGER_ERROR=10,
+ PDQ_RING_ERROR_REASON_FCI_STRIP_ERROR=11,
+ PDQ_RING_ERROR_REASON_RING_OP_OSCILLATION=12,
+ PDQ_RING_ERROR_REASON_DIRECTED_BEACON_RECEVIED=13,
+ PDQ_RING_ERROR_REASON_PC_TRACE_INITIATED=14,
+ PDQ_RING_ERROR_REASON_PC_TRACE_RECEVIED=15
+} pdq_ring_error_reason_t;
+
+typedef enum {
+ PDQ_STATION_MODE_NORMAL=0,
+ PDQ_STATION_MODE_INTERNAL_LOOPBACK=1
+} pdq_station_mode_t;
+
+typedef enum {
+ PDQ_PHY_TYPE_A=0,
+ PDQ_PHY_TYPE_B=1,
+ PDQ_PHY_TYPE_S=2,
+ PDQ_PHY_TYPE_M=3,
+ PDQ_PHY_TYPE_UNKNOWN=4
+} pdq_phy_type_t;
+
+typedef enum {
+ PDQ_PMD_TYPE_ANSI_MUTLI_MODE=0,
+ PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1=1,
+ PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2=2,
+ PDQ_PMD_TYPE_ANSI_SONET=3,
+ PDQ_PMD_TYPE_LOW_POWER=100,
+ PDQ_PMD_TYPE_THINWIRE=101,
+ PDQ_PMD_TYPE_SHIELDED_TWISTED_PAIR=102,
+ PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR=103
+} pdq_pmd_type_t;
+
+typedef enum {
+ PDQ_PMD_CLASS_ANSI_MULTI_MODE=0,
+ PDQ_PMD_CLASS_SINGLE_MODE_TYPE_1=1,
+ PDQ_PMD_CLASS_SINGLE_MODE_TYPE_2=2,
+ PDQ_PMD_CLASS_SONET=3,
+ PDQ_PMD_CLASS_LOW_COST_POWER_FIBER=4,
+ PDQ_PMD_CLASS_TWISTED_PAIR=5,
+ PDQ_PMD_CLASS_UNKNOWN=6,
+ PDQ_PMD_CLASS_UNSPECIFIED=7
+} pdq_pmd_class_t;
+
+typedef enum {
+ PDQ_PHY_STATE_INTERNAL_LOOPBACK=0,
+ PDQ_PHY_STATE_BROKEN=1,
+ PDQ_PHY_STATE_OFF_READY=2,
+ PDQ_PHY_STATE_WAITING=3,
+ PDQ_PHY_STATE_STARTING=4,
+ PDQ_PHY_STATE_FAILED=5,
+ PDQ_PHY_STATE_WATCH=6,
+ PDQ_PHY_STATE_INUSE=7
+} pdq_phy_state_t;
+
+typedef enum {
+ PDQ_REJECT_REASON_NONE=0,
+ PDQ_REJECT_REASON_LOCAL_LCT=1,
+ PDQ_REJECT_REASON_REMOTE_LCT=2,
+ PDQ_REJECT_REASON_LCT_BOTH_SIDES=3,
+ PDQ_REJECT_REASON_LEM_REJECT=4,
+ PDQ_REJECT_REASON_TOPOLOGY_ERROR=5,
+ PDQ_REJECT_REASON_NOISE_REJECT=6,
+ PDQ_REJECT_REASON_REMOTE_REJECT=7,
+ PDQ_REJECT_REASON_TRACE_IN_PROGRESS=8,
+ PDQ_REJECT_REASON_TRACE_RECEIVED_DISABLED=9,
+ PDQ_REJECT_REASON_STANDBY=10,
+ PDQ_REJECT_REASON_LCT_PROTOCOL_ERROR=11
+} pdq_reject_reason_t;
+
+typedef enum {
+ PDQ_BROKEN_REASON_NONE=0
+} pdq_broken_reason_t;
+
+typedef enum {
+ PDQ_RI_REASON_TVX_EXPIRED=0,
+ PDQ_RI_REASON_TRT_EXPIRED=1,
+ PDQ_RI_REASON_RING_PURGER_ELECTION_ATTEMPT_LIMIT_EXCEEDED=2,
+ PDQ_RI_REASON_PURGE_ERROR_LIMIT_EXCEEDED=3,
+ PDQ_RI_REASON_RESTRICTED_TOKEN_TIMEOUT=4
+} pdq_ri_reason_t;
+
+typedef enum {
+ PDQ_LCT_DIRECTION_LOCAL_LCT=0,
+ PDQ_LCT_DIRECTION_REMOTE_LCT=1,
+ PDQ_LCT_DIRECTION_LCT_BOTH_SIDES=2
+} pdq_lct_direction_t;
+
+typedef enum {
+ PDQ_PORT_A=0,
+ PDQ_PORT_B=1
+} pdq_port_type_t;
+
+typedef struct {
+ pdq_uint8_t station_id_bytes[8];
+} pdq_station_id_t;
+
+typedef pdq_uint32_t pdq_fdditimer_t;
+/*
+ * Command format for Start, Filter_Get, ... commands
+ */
+typedef struct {
+ pdq_cmd_code_t generic_op;
+} pdq_cmd_generic_t;
+
+/*
+ * Response format for Start, Filter_Set, ... commands
+ */
+typedef struct {
+ pdq_uint32_t generic_reserved;
+ pdq_cmd_code_t generic_op;
+ pdq_response_code_t generic_status;
+} pdq_response_generic_t;
+
+/*
+ * Command format for Filter_Set command
+ */
+typedef struct {
+ pdq_cmd_code_t filter_set_op;
+ struct {
+ pdq_item_code_t item_code;
+ pdq_filter_state_t filter_state;
+ } filter_set_items[7];
+ pdq_item_code_t filter_set_eol_item_code;
+} pdq_cmd_filter_set_t;
+
+/*
+ * Response format for Filter_Get command.
+ */
+typedef struct {
+ pdq_uint32_t filter_get_reserved;
+ pdq_cmd_code_t filter_get_op;
+ pdq_response_code_t filter_get_status;
+ pdq_filter_state_t filter_get_ind_group_prom;
+ pdq_filter_state_t filter_get_group_prom;
+ pdq_filter_state_t filter_get_broadcast_all;
+ pdq_filter_state_t filter_get_smt_prom;
+ pdq_filter_state_t filter_get_smt_user;
+ pdq_filter_state_t filter_get_reserved_all;
+ pdq_filter_state_t filter_get_implementor_all;
+} pdq_response_filter_get_t;
+
+#define PDQ_SIZE_RESPONSE_FILTER_GET 0x28
+
+typedef struct {
+ pdq_cmd_code_t chars_set_op;
+ struct {
+ pdq_item_code_t item_code;
+ pdq_uint32_t item_value;
+ pdq_port_type_t item_port;
+ } chars_set_items[1];
+ pdq_item_code_t chars_set_eol_item_code;
+} pdq_cmd_chars_set_t;
+
+typedef struct {
+ pdq_cmd_code_t addr_filter_set_op;
+ pdq_lanaddr_t addr_filter_set_addresses[62];
+} pdq_cmd_addr_filter_set_t;
+
+#define PDQ_SIZE_CMD_ADDR_FILTER_SET 0x1F4
+
+typedef struct {
+ pdq_uint32_t addr_filter_get_reserved;
+ pdq_cmd_code_t addr_filter_get_op;
+ pdq_response_code_t addr_filter_get_status;
+ pdq_lanaddr_t addr_filter_get_addresses[62];
+} pdq_response_addr_filter_get_t;
+
+#define PDQ_SIZE_RESPONSE_ADDR_FILTER_GET 0x1FC
+
+typedef struct {
+ pdq_uint32_t status_chars_get_reserved;
+ pdq_cmd_code_t status_chars_get_op;
+ pdq_response_code_t status_chars_get_status;
+ struct {
+ /* Station Characteristic Attributes */
+ pdq_station_id_t station_id;
+ pdq_station_type_t station_type;
+ pdq_uint32_t smt_version_id;
+ pdq_uint32_t smt_max_version_id;
+ pdq_uint32_t smt_min_version_id;
+ /* Station Status Attributes */
+ pdq_station_state_t station_state;
+ /* Link Characteristic Attributes */
+ pdq_lanaddr_t link_address;
+ pdq_fdditimer_t t_req;
+ pdq_fdditimer_t tvx;
+ pdq_fdditimer_t restricted_token_timeout;
+ pdq_boolean_t ring_purger_enable;
+ pdq_link_state_t link_state;
+ pdq_fdditimer_t negotiated_trt;
+ pdq_da_test_state_t dup_addr_flag;
+ /* Link Status Attributes */
+ pdq_lanaddr_t upstream_neighbor;
+ pdq_lanaddr_t old_upstream_neighbor;
+ pdq_boolean_t upstream_neighbor_dup_addr_flag;
+ pdq_lanaddr_t downstream_neighbor;
+ pdq_lanaddr_t old_downstream_neighbor;
+ pdq_ring_purger_state_t ring_purger_state;
+ pdq_frame_strip_mode_t frame_strip_mode;
+ pdq_ring_error_reason_t ring_error_reason;
+ pdq_boolean_t loopback;
+ pdq_fdditimer_t ring_latency;
+ pdq_lanaddr_t last_dir_beacon_sa;
+ pdq_lanaddr_t last_dir_beacon_una;
+ /* Phy Characteristic Attributes */
+ pdq_phy_type_t phy_type[2];
+ pdq_pmd_type_t pmd_type[2];
+ pdq_uint32_t lem_threshold[2];
+ /* Phy Status Attributes */
+ pdq_phy_state_t phy_state[2];
+ pdq_phy_type_t neighbor_phy_type[2];
+ pdq_uint32_t link_error_estimate[2];
+ pdq_broken_reason_t broken_reason[2];
+ pdq_reject_reason_t reject_reason[2];
+ /* Miscellaneous */
+ pdq_uint32_t counter_interval;
+ pdq_fwrev_t module_rev;
+ pdq_fwrev_t firmware_rev;
+ pdq_uint32_t mop_device_type;
+ pdq_uint32_t fddi_led[2];
+ pdq_uint32_t flush;
+ } status_chars_get;
+} pdq_response_status_chars_get_t;
+
+#define PDQ_SIZE_RESPONSE_STATUS_CHARS_GET 0xF0
+
+typedef struct {
+ pdq_uint32_t fddi_mib_get_reserved;
+ pdq_cmd_code_t fddi_mib_get_op;
+ pdq_response_code_t fddi_mib_get_status;
+ struct {
+ /* SMT Objects */
+ pdq_station_id_t smt_station_id;
+ pdq_uint32_t smt_op_version_id;
+ pdq_uint32_t smt_hi_version_id;
+ pdq_uint32_t smt_lo_version_id;
+ pdq_uint32_t smt_mac_ct;
+ pdq_uint32_t smt_non_master_ct;
+ pdq_uint32_t smt_master_ct;
+ pdq_uint32_t smt_paths_available;
+ pdq_uint32_t smt_config_capabilities;
+ pdq_uint32_t smt_config_policy;
+ pdq_uint32_t smt_connection_policy;
+ pdq_uint32_t smt_t_notify;
+ pdq_uint32_t smt_status_reporting;
+ pdq_uint32_t smt_ecm_state;
+ pdq_uint32_t smt_cf_state;
+ pdq_uint32_t smt_hold_state;
+ pdq_uint32_t smt_remote_disconnect_flag;
+ pdq_uint32_t smt_station_action;
+ /* MAC Objects */
+ pdq_uint32_t mac_frame_status_capabilities;
+ pdq_uint32_t mac_t_max_greatest_lower_bound;
+ pdq_uint32_t mac_tvx_greatest_lower_bound;
+ pdq_uint32_t mac_paths_available;
+ pdq_uint32_t mac_current_path;
+ pdq_lanaddr_t mac_upstream_neighbor;
+ pdq_lanaddr_t mac_old_upstream_neighbor;
+ pdq_uint32_t mac_dup_addr_test;
+ pdq_uint32_t mac_paths_requested;
+ pdq_uint32_t mac_downstream_port_type;
+ pdq_lanaddr_t mac_smt_address;
+ pdq_uint32_t mac_t_req;
+ pdq_uint32_t mac_t_neg;
+ pdq_uint32_t mac_t_max;
+ pdq_uint32_t mac_tvx_value;
+ pdq_uint32_t mac_t_min;
+ pdq_uint32_t mac_current_frame_status;
+ pdq_uint32_t mac_frame_error_threshold;
+ pdq_uint32_t mac_frame_error_ratio;
+ pdq_uint32_t mac_rmt_state;
+ pdq_uint32_t mac_da_flag;
+ pdq_uint32_t mac_una_da_flag;
+ pdq_uint32_t mac_frame_condition;
+ pdq_uint32_t mac_chip_set;
+ pdq_uint32_t mac_action;
+ /* Port Objects */
+ pdq_uint32_t port_pc_type[2];
+ pdq_uint32_t port_pc_neighbor[2];
+ pdq_uint32_t port_connection_policies[2];
+ pdq_uint32_t port_remote_mac_indicated[2];
+ pdq_uint32_t port_ce_state[2];
+ pdq_uint32_t port_paths_requested[2];
+ pdq_uint32_t port_mac_placement[2];
+ pdq_uint32_t port_available_paths[2];
+ pdq_uint32_t port_mac_loop_time[2];
+ pdq_uint32_t port_tb_max[2];
+ pdq_uint32_t port_bs_flag[2];
+ pdq_uint32_t port_ler_estimate[2];
+ pdq_uint32_t port_ler_cutoff[2];
+ pdq_uint32_t port_ler_alarm[2];
+ pdq_uint32_t port_connect_state[2];
+ pdq_uint32_t port_pcm_state[2];
+ pdq_uint32_t port_pc_withhold[2];
+ pdq_uint32_t port_ler_condition[2];
+ pdq_uint32_t port_chip_set[2];
+ pdq_uint32_t port_action[2];
+ /* Attachment Objects */
+ pdq_uint32_t attachment_class;
+ pdq_uint32_t attachment_optical_bypass_present;
+ pdq_uint32_t attachment_imax_expiration;
+ pdq_uint32_t attachment_inserted_status;
+ pdq_uint32_t attachment_insert_policy;
+ } fddi_mib_get;
+} pdq_response_fddi_mib_get_t;
+
+#define PDQ_SIZE_RESPONSE_FDDI_MIB_GET 0x17C
+
+typedef enum {
+ PDQ_FDX_STATE_IDLE=0,
+ PDQ_FDX_STATE_REQUEST=1,
+ PDQ_FDX_STATE_CONFIRM=2,
+ PDQ_FDX_STATE_OPERATION=3
+} pdq_fdx_state_t;
+
+typedef struct {
+ pdq_uint32_t dec_ext_mib_get_reserved;
+ pdq_cmd_code_t dec_ext_mib_get_op;
+ pdq_response_code_t dec_ext_mib_get_response;
+ struct {
+ /* SMT Objects */
+ pdq_uint32_t esmt_station_type;
+ /* MAC Objects */
+ pdq_uint32_t emac_link_state;
+ pdq_uint32_t emac_ring_purger_state;
+ pdq_uint32_t emac_ring_purger_enable;
+ pdq_uint32_t emac_frame_strip_mode;
+ pdq_uint32_t emac_ring_error_reason;
+ pdq_uint32_t emac_upstream_nbr_dupl_address_flag;
+ pdq_uint32_t emac_restricted_token_timeout;
+ /* Port Objects */
+ pdq_uint32_t eport_pmd_type[2];
+ pdq_uint32_t eport_phy_state[2];
+ pdq_uint32_t eport_reject_reason[2];
+ /* Full Duplex Objects */
+ pdq_boolean_t fdx_enable;
+ pdq_boolean_t fdx_operational;
+ pdq_fdx_state_t fdx_state;
+ } dec_ext_mib_get;
+} pdq_response_dec_ext_mib_get_t;
+
+#define PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET 0x50
+
+typedef enum {
+ PDQ_CALLER_ID_NONE=0,
+ PDQ_CALLER_ID_SELFTEST=1,
+ PDQ_CALLER_ID_MFG=2,
+ PDQ_CALLER_ID_FIRMWARE=5,
+ PDQ_CALLER_ID_CONSOLE=8
+} pdq_caller_id_t;
+
+typedef struct {
+ pdq_uint32_t error_log_get__reserved;
+ pdq_cmd_code_t error_log_get_op;
+ pdq_response_code_t error_log_get_status;
+ /* Error Header */
+ pdq_uint32_t error_log_get_event_status;
+ /* Event Information Block */
+ pdq_caller_id_t error_log_get_caller_id;
+ pdq_uint32_t error_log_get_timestamp[2];
+ pdq_uint32_t error_log_get_write_count;
+ /* Diagnostic Information */
+ pdq_uint32_t error_log_get_fru_implication_mask;
+ pdq_uint32_t error_log_get_test_id;
+ pdq_uint32_t error_log_get_diag_reserved[6];
+ /* Firmware Information */
+ pdq_uint32_t error_log_get_fw_reserved[112];
+} pdq_response_error_log_get_t;
+
+
+/*
+ * Definitions for the Unsolicited Event Queue.
+ */
+typedef enum {
+ PDQ_UNSOLICITED_EVENT=0,
+ PDQ_UNSOLICITED_COUNTERS=1
+} pdq_event_t;
+
+typedef enum {
+ PDQ_ENTITY_STATION=0,
+ PDQ_ENTITY_LINK=1,
+ PDQ_ENTITY_PHY_PORT=2
+} pdq_entity_t;
+
+typedef enum {
+ PDQ_STATION_EVENT_TRACE_RECEIVED=1
+} pdq_station_event_t;
+
+typedef enum {
+ PDQ_STATION_EVENT_ARGUMENT_REASON=0, /* pdq_uint32_t */
+ PDQ_STATION_EVENT_ARGUMENT_EOL=0xFF
+} pdq_station_event_argument_t;
+
+typedef enum {
+ PDQ_LINK_EVENT_TRANSMIT_UNDERRUN=0,
+ PDQ_LINK_EVENT_TRANSMIT_FAILED=1,
+ PDQ_LINK_EVENT_BLOCK_CHECK_ERROR=2,
+ PDQ_LINK_EVENT_FRAME_STATUS_ERROR=3,
+ PDQ_LINK_EVENT_PDU_LENGTH_ERROR=4,
+ PDQ_LINK_EVENT_RECEIVE_DATA_OVERRUN=7,
+ PDQ_LINK_EVENT_NO_USER_BUFFER=9,
+ PDQ_LINK_EVENT_RING_INITIALIZATION_INITIATED=10,
+ PDQ_LINK_EVENT_RING_INITIALIZATION_RECEIVED=11,
+ PDQ_LINK_EVENT_RING_BEACON_INITIATED=12,
+ PDQ_LINK_EVENT_DUPLICATE_ADDRESS_FAILURE=13,
+ PDQ_LINK_EVENT_DUPLICATE_TOKEN_DETECTED=14,
+ PDQ_LINK_EVENT_RING_PURGE_ERROR=15,
+ PDQ_LINK_EVENT_FCI_STRIP_ERROR=16,
+ PDQ_LINK_EVENT_TRACE_INITIATED=17,
+ PDQ_LINK_EVENT_DIRECTED_BEACON_RECEIVED=18
+} pdq_link_event_t;
+
+typedef enum {
+ PDQ_LINK_EVENT_ARGUMENT_REASON=0, /* pdq_rireason_t */
+ PDQ_LINK_EVENT_ARGUMENT_DATA_LINK_HEADER=1, /* pdq_dlhdr_t */
+ PDQ_LINK_EVENT_ARGUMENT_SOURCE=2, /* pdq_lanaddr_t */
+ PDQ_LINK_EVENT_ARGUMENT_UPSTREAM_NEIGHBOR=3,/* pdq_lanaddr_t */
+ PDQ_LINK_EVENT_ARGUMENT_EOL=0xFF
+} pdq_link_event_argument_t;
+
+typedef enum {
+ PDQ_PHY_EVENT_LEM_ERROR_MONITOR_REJECT=0,
+ PDQ_PHY_EVENT_ELASTICITY_BUFFER_ERROR=1,
+ PDQ_PHY_EVENT_LINK_CONFIDENCE_TEST_REJECT=2
+} pdq_phy_event_t;
+
+typedef enum {
+ PDQ_PHY_EVENT_ARGUMENT_DIRECTION=0, /* pdq_lct_direction_t */
+ PDQ_PHY_EVENT_ARGUMENT_EOL=0xFF
+} pdq_phy_event_arguments;
+
+struct _pdq_unsolicited_event_t {
+ pdq_uint32_t rvent_reserved;
+ pdq_event_t event_type;
+ pdq_entity_t event_entity;
+ pdq_uint32_t event_index;
+ union {
+ pdq_station_event_t station_event;
+ pdq_link_event_t link_event;
+ pdq_phy_event_t phy_event;
+ pdq_uint32_t value;
+ } event_code;
+ /*
+ * The remainder of this event is an argument list.
+ */
+ pdq_uint32_t event__filler[123];
+};
+
+#endif /* _PDQREG_H */
diff --git a/sys/dev/ic/pdqvar.h b/sys/dev/ic/pdqvar.h
new file mode 100644
index 00000000000..4f4c85901dc
--- /dev/null
+++ b/sys/dev/ic/pdqvar.h
@@ -0,0 +1,252 @@
+/* $NetBSD: pdqvar.h,v 1.2 1995/08/19 04:35:22 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1995 Matt Thomas (thomas@lkg.dec.com)
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough 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.
+ */
+
+/*
+ * DEC PDQ FDDI Controller; PDQ O/S dependent definitions
+ *
+ * Written by Matt Thomas
+ */
+
+#ifndef _PDQ_OS_H
+#define _PDQ_OS_H
+
+#define PDQ_OS_TX_TIMEOUT 5 /* seconds */
+
+#if defined(PDQTEST)
+#include <pdq_os_test.h>
+#elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__NetBSD__)
+
+#include <sys/param.h>
+#ifndef M_MCAST
+#include <sys/mbuf.h>
+#endif /* M_CAST */
+#include <sys/malloc.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+
+#define PDQ_USE_MBUFS
+#define PDQ_OS_PREFIX "%s%d: "
+#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name, pdq->pdq_unit
+
+#define PDQ_OS_PAGESIZE NBPG
+#define PDQ_OS_USEC_DELAY(n) DELAY(n)
+#define PDQ_OS_MEMZERO(p, n) bzero((caddr_t)(p), (n))
+#define PDQ_OS_VA_TO_PA(p) vtophys(p)
+#define PDQ_OS_MEMALLOC(n) malloc(n, M_DEVBUF, M_NOWAIT)
+#define PDQ_OS_MEMFREE(p, n) free((void *) p, M_DEVBUF)
+#ifdef __FreeBSD__
+#define PDQ_OS_MEMALLOC_CONTIG(n) vm_page_alloc_contig(n, 0, 0xffffffff, PAGE_SIZE)
+#define PDQ_OS_MEMFREE_CONTIG(p, n) kmem_free(kernel_map, (vm_offset_t) p, n)
+#else
+#define PDQ_OS_MEMALLOC_CONTIG(n) kmem_alloc(kernel_map, round_page(n))
+#define PDQ_OS_MEMFREE_CONTIG(p, n) kmem_free(kernel_map, (vm_offset_t) p, n)
+#endif /* __FreeBSD__ */
+
+#if !defined(PDQ_HWSUPPORT)
+#if defined(__FreeBSD__)
+#include <machine/cpufunc.h>
+typedef void ifnet_ret_t;
+typedef int ioctl_cmd_t;
+#elif defined(__bsdi__)
+#include <machine/inline.h>
+typedef int ifnet_ret_t;
+typedef int ioctl_cmd_t;
+#elif defined(__NetBSD__)
+typedef void ifnet_ret_t;
+typedef u_long ioctl_cmd_t;
+#endif
+#define PDQ_OS_IORD_32(port) inl(port)
+#define PDQ_OS_IOWR_32(port, data) outl(port, data)
+#define PDQ_OS_IORD_8(port) inb(port)
+#define PDQ_OS_IOWR_8(port, data) outb(port, data)
+
+typedef struct {
+#ifdef __bsdi__
+ struct device sc_dev; /* base device */
+ struct isadev sc_id; /* ISA device */
+ struct intrhand sc_ih; /* intrrupt vectoring */
+ struct atshutdown sc_ats; /* shutdown routine */
+#elif defined(__NetBSD__)
+ struct device sc_dev; /* base device */
+ void *sc_ih; /* intrrupt vectoring */
+ void *sc_ats; /* shutdown hook */
+#endif
+ struct arpcom sc_ac;
+ pdq_t *sc_pdq;
+ unsigned sc_iobase;
+} pdq_softc_t;
+
+#define sc_if sc_ac.ac_if
+#define sc_bpf sc_if.if_bpf
+
+extern void pdq_ifreset(pdq_softc_t *sc);
+extern void pdq_ifinit(pdq_softc_t *sc);
+extern void pdq_ifwatchdog(pdq_softc_t *sc);
+extern ifnet_ret_t pdq_ifstart(struct ifnet *ifp);
+extern int pdq_ifioctl(struct ifnet *ifp, ioctl_cmd_t cmd, caddr_t data);
+extern void pdq_ifattach(pdq_softc_t *sc, ifnet_ret_t (*ifinit)(int unit),
+ ifnet_ret_t (*ifwatchdog)(int unit));
+#endif /* PDQ_HWSUPPORT */
+#elif defined(DLPI_PDQ)
+#include <sys/param.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/stream.h>
+
+#define PDQ_USE_STREAMS
+#define PDQ_OS_PREFIX "%s board %d "
+#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name, pdq->pdq_unit
+
+#define PDQ_OS_PAGESIZE PAGESIZE
+#define PDQ_OS_USEC_DELAY(n) drv_usecwait(n)
+#define PDQ_OS_MEMZERO(p, n) bzero((caddr_t)(p), (n))
+#define PDQ_OS_VA_TO_PA(p) vtop((caddr_t)p, NULL)
+#define PDQ_OS_MEMALLOC(n) kmem_zalloc(n, KM_NOSLEEP)
+#define PDQ_OS_MEMFREE(p, n) kmem_free((caddr_t) p, n)
+#define PDQ_OS_MEMALLOC_CONTIG(n) kmem_zalloc_physreq(n, decfddiphysreq_db, KM_NOSLEEP)
+#define PDQ_OS_MEMFREE_CONTIG(p, n) PDQ_OS_MEMFREE(p, n)
+
+extern physreq_t *decfddiphysreq_db;
+extern physreq_t *decfddiphysreq_mblk;
+
+#define PDQ_OS_DATABUF_ALLOC(b) ((void) (((b) = allocb_physreq(PDQ_OS_DATABUF_SIZE, BPRI_MED, decfddiphysreq_mblk)) && ((b)->b_wptr = (b)->b_rptr + PDQ_OS_DATABUF_SIZE)))
+
+#define PDQ_OS_IORD_8(port) inb(port)
+#define PDQ_OS_IOWR_8(port, data) outb(port, data)
+#endif
+
+
+#ifdef PDQ_USE_MBUFS
+#define PDQ_OS_DATABUF_SIZE (MCLBYTES)
+#define PDQ_OS_DATABUF_FREE(b) (m_freem(b))
+#define PDQ_OS_DATABUF_NEXT(b) ((b)->m_next)
+#define PDQ_OS_DATABUF_NEXT_SET(b, b1) ((b)->m_next = (b1))
+#define PDQ_OS_DATABUF_NEXTPKT(b) ((b)->m_nextpkt)
+#define PDQ_OS_DATABUF_NEXTPKT_SET(b, b1) ((b)->m_nextpkt = (b1))
+#define PDQ_OS_DATABUF_LEN(b) ((b)->m_len)
+#define PDQ_OS_DATABUF_LEN_SET(b, n) ((b)->m_len = (n))
+/* #define PDQ_OS_DATABUF_LEN_ADJ(b, n) ((b)->m_len += (n)) */
+#define PDQ_OS_DATABUF_PTR(b) (mtod((b), pdq_uint8_t *))
+#define PDQ_OS_DATABUF_ADJ(b, n) ((b)->m_data += (n), (b)->m_len -= (n))
+typedef struct mbuf PDQ_OS_DATABUF_T;
+
+#define PDQ_OS_DATABUF_ALLOC(b) do { \
+ PDQ_OS_DATABUF_T *x_m0; \
+ MGETHDR(x_m0, M_DONTWAIT, MT_DATA); \
+ if (x_m0 != NULL) { \
+ MCLGET(x_m0, M_DONTWAIT); \
+ if ((x_m0->m_flags & M_EXT) == 0) { \
+ m_free(x_m0); \
+ (b) = NULL; \
+ } else { \
+ (b) = x_m0; \
+ x_m0->m_len = PDQ_OS_DATABUF_SIZE; \
+ } \
+ } else { \
+ (b) = NULL; \
+ } \
+} while (0)
+#define PDQ_OS_DATABUF_RESET(b) ((b)->m_data = (b)->m_ext.ext_buf, (b)->m_len = MCLBYTES)
+#endif /* PDQ_USE_MBUFS */
+
+#ifdef PDQ_USE_STREAMS
+#define PDQ_OS_DATABUF_SIZE (2048)
+#define PDQ_OS_DATABUF_FREE(b) (freemsg(b))
+#define PDQ_OS_DATABUF_NEXT(b) ((b)->b_cont)
+#define PDQ_OS_DATABUF_NEXT_SET(b, b1) ((b)->b_cont = (b1))
+#define PDQ_OS_DATABUF_NEXTPKT(b) ((b)->b_next)
+#define PDQ_OS_DATABUF_NEXTPKT_SET(b, b1) ((b)->b_next = (b1))
+#define PDQ_OS_DATABUF_LEN(b) ((b)->b_wptr - (b)->b_rptr)
+#define PDQ_OS_DATABUF_LEN_SET(b, n) ((b)->b_wptr = (b)->b_rptr + (n))
+/*#define PDQ_OS_DATABUF_LEN_ADJ(b, n) ((b)->b_wptr += (n))*/
+#define PDQ_OS_DATABUF_PTR(b) ((pdq_uint8_t *) (b)->b_rptr)
+#define PDQ_OS_DATABUF_ADJ(b, n) ((b)->b_rptr += (n))
+typedef mblk_t PDQ_OS_DATABUF_T;
+
+#ifndef PDQ_OS_DATABUF_ALLOC
+#define PDQ_OS_DATABUF_ALLOC(b) ((void) (((b) = allocb(PDQ_OS_DATABUF_SIZE, BPRI_MED)) && ((b)->b_wptr = (b)->b_rptr + PDQ_OS_DATABUF_SIZE)))
+#endif /* PDQ_OS_DATABUF_ALLOC */
+#endif /* PDQ_USE_STREAMS */
+
+#define PDQ_OS_TX_TRANSMIT 5
+
+#define PDQ_OS_DATABUF_ENQUEUE(q, b) do { \
+ PDQ_OS_DATABUF_NEXTPKT_SET(b, NULL); \
+ if ((q)->q_tail == NULL) \
+ (q)->q_head = (b); \
+ else \
+ PDQ_OS_DATABUF_NEXTPKT_SET(((PDQ_OS_DATABUF_T *)(q)->q_tail), b); \
+ (q)->q_tail = (b); \
+} while (0)
+
+#define PDQ_OS_DATABUF_DEQUEUE(q, b) do { \
+ if (((b) = (PDQ_OS_DATABUF_T *) (q)->q_head) != NULL) { \
+ if (((q)->q_head = PDQ_OS_DATABUF_NEXTPKT(b)) == NULL) \
+ (q)->q_tail = NULL; \
+ PDQ_OS_DATABUF_NEXTPKT_SET(b, NULL); \
+ } \
+} while (0)
+
+extern void pdq_os_addr_fill(pdq_t *pdq, pdq_lanaddr_t *addrs, size_t numaddrs);
+extern void pdq_os_receive_pdu(pdq_t *, PDQ_OS_DATABUF_T *pdu, size_t pdulen);
+extern void pdq_os_restart_transmitter(pdq_t *pdq);
+extern void pdq_os_transmit_done(pdq_t *pdq, PDQ_OS_DATABUF_T *pdu);
+
+extern void pdq_print_fddi_chars(pdq_t *pdq, const pdq_response_status_chars_get_t *rsp);
+
+extern void pdq_init_csrs(pdq_csrs_t *csrs, void *csrs_va, size_t csr_size);
+extern void pdq_init_pci_csrs(pdq_pci_csrs_t *csrs, void *csrs_va, size_t csr_size);
+
+extern void pdq_flush_databuf_queue(pdq_databuf_queue_t *q);
+
+extern pdq_boolean_t pdq_do_port_control(const pdq_csrs_t * const csrs, pdq_uint32_t cmd);
+extern void pdq_read_mla(const pdq_csrs_t * const csrs, pdq_lanaddr_t *hwaddr);
+extern void pdq_read_fwrev(const pdq_csrs_t * const csrs, pdq_fwrev_t *fwrev);
+extern pdq_boolean_t pdq_read_error_log(pdq_t *pdq, pdq_response_error_log_get_t *log_entry);
+extern pdq_chip_rev_t pdq_read_chiprev(const pdq_csrs_t * const csrs);
+
+extern void pdq_queue_commands(pdq_t *pdq);
+extern void pdq_process_command_responses(pdq_t *pdq);
+extern void pdq_process_unsolicited_events(pdq_t *pdq);
+
+extern void pdq_process_received_data(pdq_t *pdq, pdq_rx_info_t *rx,
+ pdq_rxdesc_t *receives,
+ pdq_uint32_t completion_goal,
+ pdq_uint32_t ring_mask);
+
+extern pdq_boolean_t pdq_queue_transmit_data(pdq_t *pdq, PDQ_OS_DATABUF_T *pdu);
+extern void pdq_process_transmitted_data(pdq_t *pdq);
+extern void pdq_flush_transmitter(pdq_t *pdq);
+
+
+extern void pdq_hwreset(pdq_t *pdq);
+extern pdq_state_t pdq_stop(pdq_t *pdq);
+extern void pdq_run(pdq_t *pdq);
+
+extern int pdq_interrupt(pdq_t *pdq);
+extern pdq_t *pdq_initialize(void *csr_va, const char *name, int unit, void *ctx, pdq_type_t type);
+
+#endif /* _PDQ_OS_H */
diff --git a/sys/dev/ic/z8530reg.h b/sys/dev/ic/z8530reg.h
new file mode 100644
index 00000000000..30abf6206b2
--- /dev/null
+++ b/sys/dev/ic/z8530reg.h
@@ -0,0 +1,432 @@
+/* $NetBSD: z8530reg.h,v 1.4 1995/08/20 13:24:05 leo Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * @(#)zsreg.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Zilog SCC registers, as implemented on the Sun-4c.
+ *
+ * Each Z8530 implements two channels (called `a' and `b').
+ *
+ * The damnable chip was designed to fit on Z80 I/O ports, and thus
+ * has everything multiplexed out the wazoo. We have to select
+ * a register, then read or write the register, and so on. Worse,
+ * the parameter bits are scattered all over the register space.
+ * This thing is full of `miscellaneous' control registers.
+ *
+ * Worse yet, the registers have incompatible functions on read
+ * and write operations. We describe the registers below according
+ * to whether they are `read registers' (RR) or `write registers' (WR).
+ * As if this were not enough, some of the channel B status bits show
+ * up in channel A, and vice versa. The blasted thing shares write
+ * registers 2 and 9 across both channels, and reads registers 2 and 3
+ * differently for the two channels. We can, however, ignore this much
+ * of the time.
+ */
+#ifndef LOCORE
+struct zschan {
+#if (BYTE_ORDER == BIG_ENDIAN) && !defined(atari)
+ volatile u_char zc_csr; /* ctrl,status, and indirect access */
+ u_char zc_xxx0;
+ volatile u_char zc_data; /* data */
+ u_char zc_xxx1;
+#else
+ u_char zc_xxx0;
+ volatile u_char zc_csr; /* ctrl,status, and indirect access */
+ u_char zc_xxx1;
+ volatile u_char zc_data; /* data */
+#endif
+};
+
+struct zsdevice {
+ struct zschan zs_chan[2];
+};
+#endif
+
+/*
+ * Some of the names in this files were chosen to make the hsis driver
+ * work unchanged (which means that they will match some in SunOS).
+ *
+ * `S.C.' stands for Special Condition, which is any of these:
+ * receiver overrun (aka silo overflow)
+ * framing error (missing stop bit, etc)
+ * end of frame (in synchronous modes)
+ * parity error (when `parity error is S.C.' is set)
+ */
+
+/*
+ * Registers with only a single `numeric value' get a name.
+ * Other registers hold bits and are only numbered; the bit
+ * definitions imply the register number (see below).
+ *
+ * We never use the receive and transmit data registers as
+ * indirects (choosing instead the zc_data register), so they
+ * are not defined here.
+ */
+#define ZSRR_IVEC 2 /* interrupt vector (channel 0) */
+#define ZSRR_IPEND 3 /* interrupt pending (ch. 0 only) */
+#define ZSRR_BAUDLO 12 /* baud rate generator (low half) */
+#define ZSRR_BAUDHI 13 /* baud rate generator (high half) */
+
+#define ZSWR_IVEC 2 /* interrupt vector (shared) */
+#define ZSWR_TXSYNC 6 /* sync transmit char (monosync mode) */
+#define ZSWR_RXSYNC 7 /* sync receive char (monosync mode) */
+#define ZSWR_SYNCLO 6 /* sync low byte (bisync mode) */
+#define ZSWR_SYNCHI 7 /* sync high byte (bisync mode) */
+#define ZSWR_SDLC_ADDR 6 /* SDLC address (SDLC mode) */
+#define ZSWR_SDLC_FLAG 7 /* SDLC flag 0x7E (SDLC mode) */
+#define ZSWR_BAUDLO 12 /* baud rate generator (low half) */
+#define ZSWR_BAUDHI 13 /* baud rate generator (high half) */
+
+/*
+ * Registers 0 through 7 may be written with any one of the 8 command
+ * modifiers, and/or any one of the 4 reset modifiers, defined below.
+ * To write registers 8 through 15, however, the command modifier must
+ * always be `point high'. Rather than track this bizzareness all over
+ * the driver, we try to avoid using any modifiers, ever (but they are
+ * defined here if you want them).
+ */
+#define ZSM_RESET_TXUEOM 0xc0 /* reset xmit underrun / eom latch */
+#define ZSM_RESET_TXCRC 0x80 /* reset xmit crc generator */
+#define ZSM_RESET_RXCRC 0x40 /* reset recv crc checker */
+#define ZSM_NULL 0x00 /* nothing special */
+
+#define ZSM_RESET_IUS 0x38 /* reset interrupt under service */
+#define ZSM_RESET_ERR 0x30 /* reset error cond */
+#define ZSM_RESET_TXINT 0x28 /* reset xmit interrupt pending */
+#define ZSM_EI_NEXTRXC 0x20 /* enable int. on next rcvd char */
+#define ZSM_SEND_ABORT 0x18 /* send abort (SDLC) */
+#define ZSM_RESET_STINT 0x10 /* reset external/status interrupt */
+#define ZSM_POINTHIGH 0x08 /* `point high' (use r8-r15) */
+#define ZSM_NULL 0x00 /* nothing special */
+
+/*
+ * Commands for Write Register 0 (`Command Register').
+ * These are just the command modifiers or'ed with register number 0
+ * (which of course equals the command modifier).
+ */
+#define ZSWR0_RESET_EOM ZSM_RESET_TXUEOM
+#define ZSWR0_RESET_TXCRC ZSM_RESET_TXCRC
+#define ZSWR0_RESET_RXCRC ZSM_RESET_RXCRC
+#define ZSWR0_CLR_INTR ZSM_RESET_IUS
+#define ZSWR0_RESET_ERRORS ZSM_RESET_ERR
+#define ZSWR0_EI_NEXTRXC ZSM_EI_NEXTRXC
+#define ZSWR0_SEND_ABORT ZSM_SEND_ABORT
+#define ZSWR0_RESET_STATUS ZSM_RESET_STINT
+#define ZSWR0_RESET_TXINT ZSM_RESET_TXINT
+
+/*
+ * Bits in Write Register 1 (`Transmit/Receive Interrupt and Data
+ * Transfer Mode Definition'). Note that bits 3 and 4 are taken together
+ * as a single unit, and bits 5 and 6 are useful only if bit 7 is set.
+ */
+#define ZSWR1_REQ_WAIT 0x80 /* WAIT*-REQ* pin gives WAIT* */
+#define ZSWR1_REQ_REQ 0xc0 /* WAIT*-REQ* pin gives REQ* */
+#define ZSWR1_REQ_TX 0x00 /* WAIT*-REQ* pin follows xmit buf */
+#define ZSWR1_REQ_RX 0x20 /* WAIT*-REQ* pin follows recv buf */
+
+#define ZSWR1_RIE_NONE 0x00 /* disable rxint entirely */
+#define ZSWR1_RIE_FIRST 0x08 /* rxint on first char & on S.C. */
+#define ZSWR1_RIE 0x10 /* rxint per char & on S.C. */
+#define ZSWR1_RIE_SPECIAL_ONLY 0x18 /* rxint on S.C. only */
+
+#define ZSWR1_PE_SC 0x04 /* parity error is special condition */
+#define ZSWR1_TIE 0x02 /* transmit interrupt enable */
+#define ZSWR1_SIE 0x01 /* external/status interrupt enable */
+
+/* HSIS compat */
+#define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX)
+
+/*
+ * Bits in Write Register 3 (`Receive Parameters and Control').
+ * Bits 7 and 6 are taken as a unit. Note that the receive bits
+ * per character ordering is insane.
+ *
+ * Here `hardware flow control' means CTS enables the transmitter
+ * and DCD enables the receiver. The latter is neither interesting
+ * nor useful, and gets in our way, making it almost unusable.
+ */
+#define ZSWR3_RX_5 0x00 /* receive 5 bits per char */
+#define ZSWR3_RX_7 0x40 /* receive 7 bits per char */
+#define ZSWR3_RX_6 0x80 /* receive 6 bits per char */
+#define ZSWR3_RX_8 0xc0 /* receive 8 bits per char */
+
+#define ZSWR3_HFC 0x20 /* hardware flow control */
+#define ZSWR3_HUNT 0x10 /* enter hunt mode */
+#define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */
+#define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */
+#define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */
+#define ZSWR3_RX_ENABLE 0x01 /* receiver enable */
+
+/*
+ * Bits in Write Register 4 (`Transmit/Receive Miscellaneous Parameters
+ * and Modes'). Bits 7&6, 5&4, and 3&2 are taken as units.
+ */
+#define ZSWR4_CLK_X1 0x00 /* clock divisor = 1 */
+#define ZSWR4_CLK_X16 0x40 /* clock divisor = 16 */
+#define ZSWR4_CLK_X32 0x80 /* clock divisor = 32 */
+#define ZSWR4_CLK_X64 0xc0 /* clock divisor = 64 */
+
+#define ZSWR4_MONOSYNC 0x00 /* 8 bit sync char (sync only) */
+#define ZSWR4_BISYNC 0x10 /* 16 bit sync char (sync only) */
+#define ZSWR4_SDLC 0x20 /* SDLC mode */
+#define ZSWR4_EXTSYNC 0x30 /* external sync mode */
+
+#define ZSWR4_SYNCMODE 0x00 /* one of the above sync modes */
+#define ZSWR4_ONESB 0x04 /* 1 stop bit */
+#define ZSWR4_1P5SB 0x08 /* 1.5 stop bits (clk cannot be 1x) */
+#define ZSWR4_TWOSB 0x0c /* 2 stop bits */
+
+#define ZSWR4_EVENP 0x02 /* check for even parity */
+#define ZSWR4_PARENB 0x01 /* enable parity checking */
+
+/*
+ * Bits in Write Register 5 (`Transmit Parameter and Controls').
+ * Bits 6 and 5 are taken as a unit; the ordering is, as with RX
+ * bits per char, not sensible.
+ */
+#define ZSWR5_DTR 0x80 /* assert (set to -12V) DTR */
+
+#define ZSWR5_TX_5 0x00 /* transmit 5 or fewer bits */
+#define ZSWR5_TX_7 0x20 /* transmit 7 bits */
+#define ZSWR5_TX_6 0x40 /* transmit 6 bits */
+#define ZSWR5_TX_8 0x60 /* transmit 8 bits */
+
+#define ZSWR5_BREAK 0x10 /* send break (continuous 0s) */
+#define ZSWR5_TX_ENABLE 0x08 /* enable transmitter */
+#define ZSWR5_CRC16 0x04 /* use CRC16 (off => use SDLC) */
+#define ZSWR5_RTS 0x02 /* assert RTS */
+#define ZSWR5_TXCRC_ENABLE 0x01 /* enable xmit crc calculation */
+
+#ifdef not_done_here
+/*
+ * Bits in Write Register 7 when the chip is in SDLC mode.
+ */
+#define ZSWR7_SDLCFLAG 0x7e /* this value makes SDLC mode work */
+#endif
+
+/*
+ * Bits in Write Register 9 (`Master Interrupt Control'). Bits 7 & 6
+ * are taken as a unit and indicate the type of reset; 00 means no reset
+ * (and is not defined here).
+ */
+#define ZSWR9_HARD_RESET 0xc0 /* force hardware reset */
+#define ZSWR9_A_RESET 0x80 /* reset channel A (0) */
+#define ZSWR9_B_RESET 0x40 /* reset channel B (1) */
+ /* 0x20 unused */
+
+#define ZSWR9_STATUS_HIGH 0x10 /* status in high bits of intr vec */
+#define ZSWR9_MASTER_IE 0x08 /* master interrupt enable */
+#define ZSWR9_DLC 0x04 /* disable lower chain */
+#define ZSWR9_NO_VECTOR 0x02 /* no vector */
+#define ZSWR9_VECTOR_INCL_STAT 0x01 /* vector includes status */
+
+/*
+ * Bits in Write Register 10 (`Miscellaneous Transmitter/Receiver Control
+ * Bits'). Bits 6 & 5 are taken as a unit, and some of the bits are
+ * meaningful only in certain modes. Bleah.
+ */
+#define ZSWR10_PRESET_ONES 0x80 /* preset CRC to all 1 (else all 0) */
+
+#define ZSWR10_NRZ 0x00 /* NRZ encoding */
+#define ZSWR10_NRZI 0x20 /* NRZI encoding */
+#define ZSWR10_FM1 0x40 /* FM1 encoding */
+#define ZSWR10_FM0 0x60 /* FM0 encoding */
+
+#define ZSWR10_GA_ON_POLL 0x10 /* go active on poll (loop mode) */
+#define ZSWR10_MARK_IDLE 0x08 /* all 1s (vs flag) when idle (SDLC) */
+#define ZSWR10_ABORT_ON_UNDERRUN 0x4 /* abort on xmit underrun (SDLC) */
+#define ZSWR10_LOOP_MODE 0x02 /* loop mode (SDLC) */
+#define ZSWR10_6_BIT_SYNC 0x01 /* 6 bits per sync char (sync modes) */
+
+/*
+ * Bits in Write Register 11 (`Clock Mode Control'). Bits 6&5, 4&3, and
+ * 1&0 are taken as units. Various bits depend on other bits in complex
+ * ways; see the Zilog manual.
+ */
+#define ZSWR11_XTAL 0x80 /* have xtal between RTxC* and SYNC* */
+ /* (else have TTL oscil. on RTxC*) */
+#define ZSWR11_RXCLK_RTXC 0x00 /* recv clock taken from TRxC* pin */
+#define ZSWR11_RXCLK_TRXC 0x20 /* recv clock taken from TRxC* pin */
+#define ZSWR11_RXCLK_BAUD 0x40 /* recv clock taken from BRG */
+#define ZSWR11_RXCLK_DPLL 0x60 /* recv clock taken from DPLL */
+
+#define ZSWR11_TXCLK_RTXC 0x00 /* xmit clock taken from TRxC* pin */
+#define ZSWR11_TXCLK_TRXC 0x08 /* xmit clock taken from RTxC* pin */
+#define ZSWR11_TXCLK_BAUD 0x10 /* xmit clock taken from BRG */
+#define ZSWR11_TXCLK_DPLL 0x18 /* xmit clock taken from DPLL */
+
+#define ZSWR11_TRXC_OUT_ENA 0x04 /* TRxC* pin will be an output */
+ /* (unless it is being used above) */
+#define ZSWR11_TRXC_XTAL 0x00 /* TRxC output from xtal oscillator */
+#define ZSWR11_TRXC_XMIT 0x01 /* TRxC output from xmit clock */
+#define ZSWR11_TRXC_BAUD 0x02 /* TRxC output from BRG */
+#define ZSWR11_TRXC_DPLL 0x03 /* TRxC output from DPLL */
+
+/*
+ * Formula for Write Registers 12 and 13 (`Lower Byte of Baud Rate
+ * Generator Time Constant' and `Upper Byte of ...'). Inputs:
+ *
+ * f BRG input clock frequency (in Hz) AFTER division
+ * by 1, 16, 32, or 64 (per clock divisor in WR4)
+ * bps desired rate in bits per second (9600, etc)
+ *
+ * We want
+ *
+ * f
+ * ----- + 0.5 - 2
+ * 2 bps
+ *
+ * rounded down to an integer. This can be computed entirely
+ * in integer arithemtic as:
+ *
+ * f + bps
+ * ------- - 2
+ * 2 bps
+ */
+#define BPS_TO_TCONST(f, bps) ((((f) + (bps)) / (2 * (bps))) - 2)
+
+/* inverse of above: given a BRG Time Constant, return Bits Per Second */
+#define TCONST_TO_BPS(f, tc) ((f) / 2 / ((tc) + 2))
+
+/*
+ * Bits in Write Register 14 (`Miscellaneous Control Bits').
+ * Bits 7 through 5 are taken as a unit and make up a `DPLL command'.
+ */
+#define ZSWR14_DPLL_NOOP 0x00 /* leave DPLL alone */
+#define ZSWR14_DPLL_SEARCH 0x20 /* enter search mode */
+#define ZSWR14_DPLL_RESET_CM 0x40 /* reset `clock missing' in RR10 */
+#define ZSWR14_DPLL_DISABLE 0x60 /* disable DPLL (continuous search) */
+#define ZSWR14_DPLL_SRC_BAUD 0x80 /* set DPLL src = BRG */
+#define ZSWR14_DPLL_SRC_RTXC 0xa0 /* set DPLL src = RTxC* or xtal osc */
+#define ZSWR14_DPLL_FM 0xc0 /* operate in FM mode */
+#define ZSWR14_DPLL_NRZI 0xe0 /* operate in NRZI mode */
+
+#define ZSWR14_LOCAL_LOOPBACK 0x10 /* set local loopback mode */
+#define ZSWR14_AUTO_ECHO 0x08 /* set auto echo mode */
+#define ZSWR14_DTR_REQ 0x04 /* DTR* / REQ* pin gives REQ* */
+#define ZSWR14_BAUD_FROM_PCLK 0x02 /* BRG clock taken from PCLK */
+ /* (else from RTxC* pin or xtal osc) */
+#define ZSWR14_BAUD_ENA 0x01 /* enable BRG countdown */
+
+/*
+ * Bits in Write Register 15 (`External/Status Interrupt Control').
+ * Most of these cause status interrupts whenever the corresponding
+ * bit or pin changes state (i.e., any rising or falling edge).
+ */
+#define ZSWR15_BREAK_IE 0x80 /* enable break/abort status int */
+#define ZSWR15_TXUEOM_IE 0x40 /* enable TX underrun/EOM status int */
+#define ZSWR15_CTS_IE 0x20 /* enable CTS* pin status int */
+#define ZSWR15_SYNCHUNT_IE 0x10 /* enable SYNC* pin/hunt status int */
+#define ZSWR15_DCD_IE 0x08 /* enable DCD* pin status int */
+ /* 0x04 unused, must be zero */
+#define ZSWR15_ZERO_COUNT_IE 0x02 /* enable BRG-counter = 0 status int */
+ /* 0x01 unused, must be zero */
+
+/*
+ * Bits in Read Register 0 (`Transmit/Receive Buffer Status and External
+ * Status').
+ */
+#define ZSRR0_BREAK 0x80 /* break/abort detected */
+#define ZSRR0_TXUNDER 0x40 /* transmit underrun/EOM (sync) */
+#define ZSRR0_CTS 0x20 /* clear to send */
+#define ZSRR0_SYNC_HUNT 0x10 /* sync/hunt (sync mode) */
+#define ZSRR0_DCD 0x08 /* data carrier detect */
+#define ZSRR0_TX_READY 0x04 /* transmit buffer empty */
+#define ZSRR0_ZERO_COUNT 0x02 /* zero count in baud clock */
+#define ZSRR0_RX_READY 0x01 /* received character ready */
+
+/*
+ * Bits in Read Register 1 (the Zilog book does not name this one).
+ */
+#define ZSRR1_EOF 0x80 /* end of frame (SDLC mode) */
+#define ZSRR1_FE 0x40 /* CRC/framing error */
+#define ZSRR1_DO 0x20 /* data (receiver) overrun */
+#define ZSRR1_PE 0x10 /* parity error */
+#define ZSRR1_RC0 0x08 /* residue code 0 (SDLC mode) */
+#define ZSRR1_RC1 0x04 /* residue code 1 (SDLC mode) */
+#define ZSRR1_RC2 0x02 /* residue code 2 (SDLC mode) */
+#define ZSRR1_ALL_SENT 0x01 /* all chars out of xmitter (async) */
+
+/*
+ * Read Register 2 in B channel contains status bits if VECTOR_INCL_STAT
+ * is set.
+ */
+
+/*
+ * Bits in Read Register 3 (`Interrupt Pending'). Only channel A
+ * has an RR3.
+ */
+ /* 0x80 unused, returned as 0 */
+ /* 0x40 unused, returned as 0 */
+#define ZSRR3_IP_A_RX 0x20 /* channel A recv int pending */
+#define ZSRR3_IP_A_TX 0x10 /* channel A xmit int pending */
+#define ZSRR3_IP_A_STAT 0x08 /* channel A status int pending */
+#define ZSRR3_IP_B_RX 0x04 /* channel B recv int pending */
+#define ZSRR3_IP_B_TX 0x02 /* channel B xmit int pending */
+#define ZSRR3_IP_B_STAT 0x01 /* channel B status int pending */
+
+/*
+ * Bits in Read Register 10 (`contains some miscellaneous status bits').
+ */
+#define ZSRR10_1_CLOCK_MISSING 0x80 /* 1 clock edge missing (FM mode) */
+#define ZSRR10_2_CLOCKS_MISSING 0x40 /* 2 clock edges missing (FM mode) */
+ /* 0x20 unused */
+#define ZSRR10_LOOP_SENDING 0x10 /* xmitter controls loop (SDLC loop) */
+ /* 0x08 unused */
+ /* 0x04 unused */
+#define ZSRR10_ON_LOOP 0x02 /* SCC is on loop (SDLC/X.21 modes) */
+
+/*
+ * Bits in Read Register 15. This register is one of the few that
+ * simply reads back the corresponding Write Register.
+ */
+#define ZSRR15_BREAK_IE 0x80 /* break/abort status int enable */
+#define ZSRR15_TXUEOM_IE 0x40 /* TX underrun/EOM status int enable */
+#define ZSRR15_CTS_IE 0x20 /* CTS* pin status int enable */
+#define ZSRR15_SYNCHUNT_IE 0x10 /* SYNC* pin/hunt status int enable */
+#define ZSRR15_DCD_IE 0x08 /* DCD* pin status int enable */
+ /* 0x04 unused, returned as zero */
+#define ZSRR15_ZERO_COUNT_IE 0x02 /* BRG-counter = 0 status int enable */
+ /* 0x01 unused, returned as zero */