aboutsummaryrefslogtreecommitdiffstats
path: root/sys/i386/isa
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-07-01 00:00:00 -0800
committersvn2git <svn2git@FreeBSD.org>1994-07-01 00:00:00 -0800
commit5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch)
treee779b5a6edddbb949b7990751b12d6f25304ba86 /sys/i386/isa
parenta16f65c7d117419bd266c28a1901ef129a337569 (diff)
downloadsrc-releng/1.tar.gz
src-releng/1.zip
Release FreeBSD 1.1.5.1release/1.1.5.1_cvsreleng/1
This commit was manufactured to restore the state of the 1.1.5.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'sys/i386/isa')
-rw-r--r--sys/i386/isa/aha1542.c13
-rw-r--r--sys/i386/isa/bt742a.c111
-rw-r--r--sys/i386/isa/bt742a_32.c1694
-rw-r--r--sys/i386/isa/clock.c279
-rw-r--r--sys/i386/isa/com.c101
-rw-r--r--sys/i386/isa/debug.h85
-rw-r--r--sys/i386/isa/elink.c77
-rw-r--r--sys/i386/isa/elink.h39
-rw-r--r--sys/i386/isa/fd.c778
-rw-r--r--sys/i386/isa/fdc.h12
-rw-r--r--sys/i386/isa/fdreg.h20
-rw-r--r--sys/i386/isa/ft.c1188
-rw-r--r--sys/i386/isa/ftreg.h11
-rw-r--r--sys/i386/isa/ic/i82365.h190
-rw-r--r--sys/i386/isa/ic/nec765.h73
-rw-r--r--sys/i386/isa/icu.h12
-rw-r--r--sys/i386/isa/icu.s492
-rw-r--r--sys/i386/isa/if_ed.c1451
-rw-r--r--sys/i386/isa/if_edreg.h2
-rw-r--r--sys/i386/isa/if_el.c800
-rw-r--r--sys/i386/isa/if_elreg.h76
-rw-r--r--sys/i386/isa/if_ep.c164
-rw-r--r--sys/i386/isa/if_ie507.h19
-rw-r--r--sys/i386/isa/if_is.c10
-rw-r--r--sys/i386/isa/if_ze.c1951
-rw-r--r--sys/i386/isa/if_zereg.h859
-rw-r--r--sys/i386/isa/ipl.h7
-rw-r--r--sys/i386/isa/isa.c227
-rw-r--r--sys/i386/isa/isa.h9
-rw-r--r--sys/i386/isa/isa_device.h4
-rw-r--r--sys/i386/isa/kbdtables.h40
-rw-r--r--sys/i386/isa/lpa.c14
-rw-r--r--sys/i386/isa/lpt.c150
-rw-r--r--sys/i386/isa/mcd.c5
-rw-r--r--sys/i386/isa/npx.c22
-rw-r--r--sys/i386/isa/pcaudio.c430
-rw-r--r--sys/i386/isa/pccons.c101
-rw-r--r--sys/i386/isa/psm.c464
-rw-r--r--sys/i386/isa/seagate.c2036
-rw-r--r--sys/i386/isa/sio.c1242
-rw-r--r--sys/i386/isa/sound/CHANGELOG75
-rw-r--r--sys/i386/isa/sound/RELNOTES.Linux256
-rw-r--r--sys/i386/isa/sound/adlib_card.c13
-rw-r--r--sys/i386/isa/sound/audio.c106
-rw-r--r--sys/i386/isa/sound/debug.h29
-rw-r--r--sys/i386/isa/sound/dev_table.c148
-rw-r--r--sys/i386/isa/sound/dev_table.h46
-rw-r--r--sys/i386/isa/sound/dmabuf.c360
-rw-r--r--sys/i386/isa/sound/dsp.c270
-rw-r--r--sys/i386/isa/sound/gus_card.c87
-rw-r--r--sys/i386/isa/sound/gus_hw.h15
-rw-r--r--sys/i386/isa/sound/gus_linearvol.h18
-rw-r--r--sys/i386/isa/sound/gus_midi.c14
-rw-r--r--sys/i386/isa/sound/gus_vol.c70
-rw-r--r--sys/i386/isa/sound/gus_wave.c1834
-rw-r--r--sys/i386/isa/sound/ics2101.c265
-rw-r--r--sys/i386/isa/sound/local.h13
-rw-r--r--sys/i386/isa/sound/midi.c220
-rw-r--r--sys/i386/isa/sound/midibuf.c14
-rw-r--r--sys/i386/isa/sound/mpu401.c129
-rw-r--r--sys/i386/isa/sound/opl3.c68
-rw-r--r--sys/i386/isa/sound/os.h94
-rw-r--r--sys/i386/isa/sound/pas.h12
-rw-r--r--sys/i386/isa/sound/pas2_card.c135
-rw-r--r--sys/i386/isa/sound/pas2_midi.c16
-rw-r--r--sys/i386/isa/sound/pas2_mixer.c40
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c91
-rw-r--r--sys/i386/isa/sound/patmgr.c41
-rw-r--r--sys/i386/isa/sound/pro_midi.c140
-rw-r--r--sys/i386/isa/sound/sb.h28
-rw-r--r--sys/i386/isa/sound/sb16_dsp.c627
-rw-r--r--sys/i386/isa/sound/sb16_midi.c287
-rw-r--r--sys/i386/isa/sound/sb_card.c13
-rw-r--r--sys/i386/isa/sound/sb_dsp.c1140
-rw-r--r--sys/i386/isa/sound/sb_midi.c224
-rw-r--r--sys/i386/isa/sound/sb_mixer.c422
-rw-r--r--sys/i386/isa/sound/sb_mixer.h212
-rw-r--r--sys/i386/isa/sound/sequencer.c311
-rw-r--r--sys/i386/isa/sound/sound_calls.h59
-rw-r--r--sys/i386/isa/sound/sound_config.h43
-rw-r--r--sys/i386/isa/sound/sound_switch.c445
-rw-r--r--sys/i386/isa/sound/soundcard.c307
-rw-r--r--sys/i386/isa/spkr.c23
-rw-r--r--sys/i386/isa/syscons.c623
-rw-r--r--sys/i386/isa/tw.c997
-rw-r--r--sys/i386/isa/ultra14f.c6
-rw-r--r--sys/i386/isa/vector.s196
-rw-r--r--sys/i386/isa/wd.c204
-rw-r--r--sys/i386/isa/wt.c3
-rw-r--r--sys/i386/isa/wt.c.orig902
90 files changed, 20908 insertions, 6041 deletions
diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c
index efeee385ba51..df1e3cada643 100644
--- a/sys/i386/isa/aha1542.c
+++ b/sys/i386/isa/aha1542.c
@@ -12,7 +12,7 @@
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
- * $Id: aha1542.c,v 1.20.2.2 1994/05/03 05:16:50 rgrimes Exp $
+ * $Id: aha1542.c,v 1.27 1994/06/05 19:18:10 ats Exp $
*/
/*
@@ -299,8 +299,8 @@ struct aha_data {
struct aha_ccb *aha_ccb_free; /* the next free ccb */
struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */
int aha_int; /* our irq level */
- int aha_dma; /* out DMA req channel */
- int aha_scsi_dev; /* ourscsi bus address */
+ int aha_dma; /* our DMA req channel */
+ int aha_scsi_dev; /* our scsi bus address */
struct scsi_link sc_link; /* prototype for subdevs */
} *ahadata[NAHA];
@@ -589,6 +589,7 @@ ahaattach(dev)
aha->sc_link.adapter_targ = aha->aha_scsi_dev;
aha->sc_link.adapter = &aha_switch;
aha->sc_link.device = &aha_dev;
+ aha->sc_link.flags = SDEV_BOUNCE;
/*
* ask the adapter what subunits are present
@@ -741,7 +742,7 @@ aha_get_ccb(unit, flags)
* to come free
*/
while ((!(rc = aha->aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) {
- sleep(&aha->aha_ccb_free, PRIBIO);
+ tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0);
}
if (rc) {
aha->aha_ccb_free = aha->aha_ccb_free->next;
@@ -916,7 +917,7 @@ aha_init(unit)
#ifdef AHADEBUG
printf("aha%d: extended bios flags %x\n", unit, extbios.flags);
#endif /* AHADEBUG */
- printf("aha%d: 1542C/CF detected, unlocking mailbox\n");
+ printf("aha%d: 1542C/CF detected, unlocking mailbox\n", unit);
aha_cmd(unit, 2, 0, 0, 0, AHA_MBX_ENABLE,
0, extbios.mailboxlock);
}
@@ -1006,7 +1007,7 @@ aha_init(unit)
return (EIO);
}
#else
- printf ("\n");
+ printf (" (bus speed defaulted)\n");
#endif /*TUNE_1542*/
/*
* Initialize mail box
diff --git a/sys/i386/isa/bt742a.c b/sys/i386/isa/bt742a.c
index e160e9167cb1..990344f28ea6 100644
--- a/sys/i386/isa/bt742a.c
+++ b/sys/i386/isa/bt742a.c
@@ -12,7 +12,7 @@
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
- * $Id: bt742a.c,v 1.12 1993/12/19 00:50:29 wollman Exp $
+ * $Id: bt742a.c,v 1.22 1994/06/15 04:19:23 jkh Exp $
*/
/*
@@ -126,7 +126,7 @@ struct bt_cmd_buf {
* these could be bigger but we need the bt_data to fit on a single page..
*/
-#define BT_MBX_SIZE 16 /* mail box size (MAX 255 MBxs) */
+#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
/* don't need that many really */
#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */
/* in bt742a H/W ( Not MAX ? ) */
@@ -299,6 +299,21 @@ struct bt_config {
u_char :5;
};
+/*
+ * Determin 32bit address/Data firmware functionality from Bus type
+ * Note: bt742a/747[s|d]/757/946/445s will return 'E'
+ * bt542b/545s/545d will be return 'A'
+ * 94/05/18 amurai@spec.co.jp
+ */
+#define BT_BUS_TYPE_24bit 'A' /* PC/AT 24 bit address bus type */
+#define BT_BUS_TYPE_32bit 'E' /* EISA/VLB/PCI 32 bit address bus type */
+#define BT_BUS_TYPE_MCA 'M' /* Micro chanel is ? forget it right now */
+struct bt_ext_info {
+ u_char bus_type; /* Host adapter bus type */
+ u_char bios_addr; /* Bios Address-Not use*/
+ u_short max_seg; /* Max segment List */
+};
+
#define INT9 0x01
#define INT10 0x02
#define INT11 0x04
@@ -568,7 +583,8 @@ btprobe(dev)
}
/*
* If it's there, put in it's interrupt vectors
- */ dev->id_unit = unit;
+ */
+ dev->id_unit = unit;
dev->id_irq = (1 << bt->bt_int);
dev->id_drq = bt->bt_dma;
@@ -593,6 +609,7 @@ btattach(dev)
bt->sc_link.adapter_targ = bt->bt_scsi_dev;
bt->sc_link.adapter = &bt_switch;
bt->sc_link.device = &bt_dev;
+ bt->sc_link.flags = SDEV_BOUNCE;
/*
* ask the adapter what subunits are present
@@ -818,7 +835,8 @@ bt_get_ccb(unit, flags)
goto gottit;
} else {
if (!(flags & SCSI_NOSLEEP)) {
- sleep(&bt->bt_ccb_free, PRIBIO);
+ tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO,
+ "btccb", 0);
}
}
}
@@ -987,6 +1005,7 @@ bt_init(unit)
unsigned char ad[4];
volatile int i, sts;
struct bt_config conf;
+ struct bt_ext_info info;
/*
* reset board, If it doesn't respond, assume
@@ -1008,6 +1027,32 @@ bt_init(unit)
return (ENXIO);
}
/*
+ * Make sure board has a capability of 32bit addressing.
+ * and Firmware also need a capability of 32bit addressing pointer
+ * in Extended mailbox and ccb structure.
+ * 94/05/18 amurai@spec.co.jp
+ */
+ bt_cmd(unit, 1, sizeof(info),0,&info, BT_INQUIRE_EXTENDED,sizeof(info));
+ switch (info.bus_type) {
+ case BT_BUS_TYPE_24bit: /* PC/AT 24 bit address bus */
+ printf("bt%d: bt54x-ISA(24bit) bus detected\n", unit);
+ break;
+ case BT_BUS_TYPE_32bit: /* EISA/VLB/PCI 32 bit bus */
+ printf("bt%d: PCI/EISA/VLB(32bit) bus detected\n",unit);
+ break;
+ case BT_BUS_TYPE_MCA: /* forget it right now */
+ printf("bt%d: MCA bus architecture detected..", unit);
+ printf("[giving up]\n");
+ return (ENXIO);
+ break;
+ default:
+ printf("bt%d: Unknown state detected...", unit);
+ printf("[giving up]\n");
+ return (ENXIO);
+ break;
+ }
+
+ /*
* Assume we have a board at this stage
* setup dma channel from jumpers and save int
* level
@@ -1107,8 +1152,6 @@ bt_init(unit)
bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0];
bt_inquire_setup_information(unit);
- /* Enable round-robin scheme - appeared at firmware rev. 3.31 */
- bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
/*
* Note that we are going and return (to probe)
@@ -1122,9 +1165,14 @@ bt_inquire_setup_information(unit)
{
struct bt_data *bt = btdata[unit];
struct bt_setup setup;
+ char dummy[8];
struct bt_boardID bID;
int i;
+ /* Inquire Installed Devices */
+ bzero( &dummy[0], sizeof(dummy) );
+ bt_cmd(unit, 0, sizeof(dummy), 10, &dummy[0], BT_DEV_GET);
+
/* Inquire Board ID to Bt742 for firmware version */
bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE);
printf("bt%d: version %c.%c, ",
@@ -1143,19 +1191,37 @@ bt_inquire_setup_information(unit)
} else {
printf("no parity, ");
}
- printf("%d mbxs, %d ccbs\n", setup.num_mbx, bt->numccbs);
+ printf("%d mbxs, %d ccbs\n", setup.num_mbx, BT_CCB_MAX);
+
+ /*
+ * Displaying SCSI negotiation value by each target.
+ * How can I determin FAST scsi value? XXX amurai@spec.co.jp
+ */
for (i = 0; i < 8; i++) {
- if (!setup.sync[i].offset &&
- !setup.sync[i].period &&
- !setup.sync[i].valid)
+ if (!setup.sync[i].valid)
continue;
+ if (!setup.sync[i].offset && !setup.sync[i].period )
+ printf("bt%d: targ %d async\n", unit, i);
+ else
+ printf("bt%d: targ %d offset=%02d, period=%dnsec\n",
+ unit, i,
+ setup.sync[i].offset,
+ 200 + setup.sync[i].period * 50 );
+ }
- printf("bt%d: dev%02d Offset=%d,Transfer period=%d, Synchronous? %s",
- unit, i,
- setup.sync[i].offset, setup.sync[i].period,
- setup.sync[i].valid ? "Yes" : "No");
+ /*
+ * Enable round-robin scheme - appeared at firmware rev. 3.31
+ * Below rev 2.XX firmware has a problem for issuing
+ * BT_ROUND_ROBIN command amurai@spec.co.jp
+ */
+ if ( bID.firm_revision != '2' ) {
+ printf("bt%d: Enabling Round robin scheme\n", unit);
+ bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
+ } else {
+ printf("bt%d: Not Enabling Round robin scheme\n", unit);
}
+
}
#ifndef min
@@ -1434,13 +1500,15 @@ bt_timeout(caddr_t arg1, int arg2)
struct bt_data *bt;
int s = splbio();
+ /*
+ * A timeout routine in kernel DONOT unlink
+ * Entry chains when time outed....So infinity Loop..
+ * 94/04/20 amurai@spec.co.jp
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+
unit = ccb->xfer->sc_link->adapter_unit;
bt = btdata[unit];
- printf("bt%d:%d:%d (%s%d) timed out ", unit
- ,ccb->xfer->sc_link->target
- ,ccb->xfer->sc_link->lun
- ,ccb->xfer->sc_link->device->name
- ,ccb->xfer->sc_link->dev_unit);
#ifdef UTEST
bt_print_active_ccbs(unit);
@@ -1467,13 +1535,14 @@ bt_timeout(caddr_t arg1, int arg2)
ccb->xfer->retries = 0; /* I MEAN IT ! */
ccb->host_stat = BT_ABORTED;
bt_done(unit, ccb);
- } else { /* abort the operation that has timed out */
+ } else {
+ /* abort the operation that has timed out */
printf("bt%d: Try to abort\n", unit);
bt_send_mbo(unit, ~SCSI_NOMASK,
BT_MBO_ABORT, ccb);
/* 2 secs for the abort */
- timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
ccb->flags = CCB_ABORTED;
+ timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
}
splx(s);
}
diff --git a/sys/i386/isa/bt742a_32.c b/sys/i386/isa/bt742a_32.c
new file mode 100644
index 000000000000..f8eabf4de61f
--- /dev/null
+++ b/sys/i386/isa/bt742a_32.c
@@ -0,0 +1,1694 @@
+/*
+ * 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.
+ *
+ * $Id: bt742a_32.c,v 1.1 1994/06/17 19:05:57 jkh Exp $
+ */
+
+/*
+ * Bulogic/Bustek 32 bit Addressing Mode SCSI driver (Was bt742a.c)
+ *
+ * THIS DRIVER IS EXPERIMENTAL AND NOT ENABLED BY DEFAULT. It is
+ * provided here merely for reference purposes.
+ *
+ * NOTE: 1. Some bt5xx card can NOT handling 32 bit addressing mode.
+ * 2. OLD bt445s Revision A,B,C,D(nowired) + any firmware version
+ * has broken busmaster for handling 32 bit addressing on H/W bus side.
+ * 3. Extend probing still need to confirm by user base due to
+ * several H/W and firmware dependency. If you have a problem with
+ * extend probing, please contact to 'amurai@spec.co.jp'
+ *
+ * amurai@spec.co.jp 94/6/16
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh.. it compiles to a program too.. look */
+#include <bt.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#endif /* KERNEL */
+
+#include <i386/isa/isa_device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include "ddb.h"
+#include "kernel.h"
+#else /*KERNEL */
+#define NBT 1
+#endif /*KERNEL */
+
+typedef unsigned long int physaddr;
+
+/*
+ * I/O Port Interface
+ */
+
+#define BT_BASE bt->bt_base
+#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */
+#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */
+#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */
+
+/*
+ * BT_CTRL_STAT bits (write)
+ */
+
+#define BT_HRST 0x80 /* Hardware reset */
+#define BT_SRST 0x40 /* Software reset */
+#define BT_IRST 0x20 /* Interrupt reset */
+#define BT_SCRST 0x10 /* SCSI bus reset */
+
+/*
+ * BT_CTRL_STAT bits (read)
+ */
+
+#define BT_STST 0x80 /* Self test in Progress */
+#define BT_DIAGF 0x40 /* Diagnostic Failure */
+#define BT_INIT 0x20 /* Mbx Init required */
+#define BT_IDLE 0x10 /* Host Adapter Idle */
+#define BT_CDF 0x08 /* cmd/data out port full */
+#define BT_DF 0x04 /* Data in port full */
+#define BT_INVDCMD 0x01 /* Invalid command */
+
+/*
+ * BT_CMD_DATA bits (write)
+ */
+
+#define BT_NOP 0x00 /* No operation */
+#define BT_MBX_INIT 0x01 /* Mbx initialization */
+#define BT_START_SCSI 0x02 /* start scsi command */
+#define BT_START_BIOS 0x03 /* start bios command */
+#define BT_INQUIRE 0x04 /* Adapter Inquiry */
+#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
+#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
+#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */
+#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
+#define BT_SPEED_SET 0x09 /* set transfer speed */
+#define BT_DEV_GET 0x0a /* return installed devices */
+#define BT_CONF_GET 0x0b /* return configuration data */
+#define BT_TARGET_EN 0x0c /* enable target mode */
+#define BT_SETUP_GET 0x0d /* return setup data */
+#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */
+#define BT_READ_CH2 0x1b /* read channel 2 buffer */
+#define BT_WRITE_FIFO 0x1c /* write fifo buffer */
+#define BT_READ_FIFO 0x1d /* read fifo buffer */
+#define BT_ECHO 0x1e /* Echo command data */
+#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */
+#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */
+
+/* The following command appeared at FirmWare 3.31 */
+#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */
+#define BT_DISABLE 0x00 /* Parameter value for Disable */
+#define BT_ENABLE 0x01 /* Parameter value for Enable */
+
+struct bt_cmd_buf {
+ u_char byte[16];
+};
+
+/*
+ * BT_INTR_PORT bits (read)
+ */
+
+#define BT_ANY_INTR 0x80 /* Any interrupt */
+#define BT_SCRD 0x08 /* SCSI reset detected */
+#define BT_HACC 0x04 /* Command complete */
+#define BT_MBOA 0x02 /* MBX out empty */
+#define BT_MBIF 0x01 /* MBX in full */
+
+/*
+ * Mail box defs etc.
+ * these could be bigger but we need the bt_data to fit on a single page..
+ */
+
+#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
+ /* don't need that many really */
+#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */
+ /* in bt742a H/W ( Not MAX ? ) */
+#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */
+ /* a ccb and need to find the ccb in */
+ /* space, look it up in the hash table */
+#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */
+#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE)
+
+#define bt_nextmbx( wmb, mbx, mbio ) \
+ if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \
+ (wmb) = &((mbx)->mbio[0]); \
+ else \
+ (wmb)++;
+
+typedef struct bt_mbx_out {
+ physaddr ccb_addr;
+ unsigned char dummy[3];
+ unsigned char cmd;
+} BT_MBO;
+
+typedef struct bt_mbx_in {
+ physaddr ccb_addr;
+ unsigned char btstat;
+ unsigned char sdstat;
+ unsigned char dummy;
+ unsigned char stat;
+} BT_MBI;
+
+struct bt_mbx {
+ BT_MBO mbo[BT_MBX_SIZE];
+ BT_MBI mbi[BT_MBX_SIZE];
+ BT_MBO *tmbo; /* Target Mail Box out */
+ BT_MBI *tmbi; /* Target Mail Box in */
+};
+
+/*
+ * mbo.cmd values
+ */
+
+#define BT_MBO_FREE 0x0 /* MBO entry is free */
+#define BT_MBO_START 0x1 /* MBO activate entry */
+#define BT_MBO_ABORT 0x2 /* MBO abort entry */
+
+/*
+ * mbi.stat values
+ */
+
+#define BT_MBI_FREE 0x0 /* MBI entry is free */
+#define BT_MBI_OK 0x1 /* completed without error */
+#define BT_MBI_ABORT 0x2 /* aborted ccb */
+#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
+#define BT_MBI_ERROR 0x4 /* Completed with error */
+
+#if defined(BIG_DMA)
+WARNING...THIS WON'T WORK(won't fit on 1 page)
+/* #define BT_NSEG 2048*/ /* Number of scatter gather segments - to much vm */
+#define BT_NSEG 128
+#else
+#define BT_NSEG 33
+#endif /* BIG_DMA */
+
+struct bt_scat_gath {
+ unsigned long seg_len;
+ physaddr seg_addr;
+};
+
+struct bt_ccb {
+ unsigned char opcode;
+ unsigned char:3, data_in:1, data_out:1,:3;
+ unsigned char scsi_cmd_length;
+ unsigned char req_sense_length;
+ /*------------------------------------longword boundary */
+ unsigned long data_length;
+ /*------------------------------------longword boundary */
+ physaddr data_addr;
+ /*------------------------------------longword boundary */
+ unsigned char dummy[2];
+ unsigned char host_stat;
+ unsigned char target_stat;
+ /*------------------------------------longword boundary */
+ unsigned char target;
+ unsigned char lun;
+ unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */
+ unsigned char dummy2[1];
+ unsigned char link_id;
+ /*------------------------------------4 longword boundary */
+ physaddr link_addr;
+ /*------------------------------------longword boundary */
+ physaddr sense_ptr;
+/*-----end of HW fields-------------------------------longword boundary */
+ struct scsi_sense_data scsi_sense;
+ /*------------------------------------longword boundary */
+ struct bt_scat_gath scat_gath[BT_NSEG];
+ /*------------------------------------longword boundary */
+ struct bt_ccb *next;
+ /*------------------------------------longword boundary */
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ /*------------------------------------longword boundary */
+ struct bt_mbx_out *mbx; /* pointer to mail box */
+ /*------------------------------------longword boundary */
+ int flags;
+#define CCB_FREE 0
+#define CCB_ACTIVE 1
+#define CCB_ABORTED 2
+ /*------------------------------------longword boundary */
+ struct bt_ccb *nexthash; /* if two hash the same */
+ /*------------------------------------longword boundary */
+ physaddr hashkey; /*physaddr of this ccb */
+ /*------------------------------------longword boundary */
+};
+
+/*
+ * opcode fields
+ */
+
+#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
+#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */
+#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */
+#define BT_RESET_CCB 0x81 /* SCSI Bus reset */
+
+/*
+ * bt_ccb.host_stat values
+ */
+
+#define BT_OK 0x00 /* cmd ok */
+#define BT_LINK_OK 0x0a /* Link cmd ok */
+#define BT_LINK_IT 0x0b /* Link cmd ok + int */
+#define BT_SEL_TIMEOUT 0x11 /* Selection time out */
+#define BT_OVER_UNDER 0x12 /* Data over/under run */
+#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */
+#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */
+#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */
+#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */
+#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */
+#define BT_INV_TARGET 0x18 /* Invalid target direction */
+#define BT_CCB_DUP 0x19 /* Duplicate CCB received */
+#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */
+#define BT_ABORTED 42 /* pseudo value from driver */
+
+struct bt_boardID {
+ u_char board_type;
+ u_char custom_feture;
+ char firm_revision;
+ u_char firm_version;
+};
+
+struct bt_setup {
+ u_char sync_neg:1;
+ u_char parity:1;
+ u_char :6;
+ u_char speed;
+ u_char bus_on;
+ u_char bus_off;
+ u_char num_mbx;
+ u_char mbx[3]; /* make a sense with back-word compatibility*/
+ struct {
+ u_char offset:4;
+ u_char period:3;
+ u_char valid:1;
+ } sync[8];
+ u_char disc_sts;
+};
+
+struct bt_config {
+ u_char chan;
+ u_char intr;
+ u_char scsi_dev:3;
+ u_char :5;
+};
+
+#define BT_INQUIRE_REV_THIRD 0x84 /* Get Adapter FirmWare version #3 */
+#define BT_INQUIRE_REV_FOURTH 0x85 /* Get Adapter FirmWare version #4 */
+
+/*
+ * Determine 32bit address/Data firmware functionality from the bus type
+ * Note: bt742a/747[s|d]/757/946/445s will return 'E'
+ * bt542b/545s/545d will return 'A'
+ * 94/05/18 amurai@spec.co.jp
+ */
+#define BT_BUS_TYPE_24bit 'A' /* PC/AT 24 bit address bus type */
+#define BT_BUS_TYPE_32bit 'E' /* EISA/VLB/PCI 32 bit address bus type */
+#define BT_BUS_TYPE_MCA 'M' /* Micro chanel is ? forget it right now */
+struct bt_ext_info {
+ u_char bus_type; /* Host adapter bus type */
+ u_char bios_addr; /* Bios Address-Not used */
+ u_short max_seg; /* Max segment List */
+ u_char num_mbx; /* Number of mailbox */
+ int32 mbx_base; /* mailbox base address */
+ struct {
+ u_char resv1:2; /* ??? */
+ u_char maxsync:1; /* ON: 10MB/s , OFF: 5MB/s */
+ u_char resv2:2; /* ??? */
+ u_char sync:1; /* ON: Sync, OFF: async ONLY!! */
+ u_char resv3:2; /* ??? */
+ } s;
+ u_char firmid[3]; /* Firmware ver. & rev. w/o last char */
+};
+
+#define BT_GET_BOARD_INFO 0x8b /* Get H/W ID and Revision */
+struct bt_board_info {
+ u_char id[4]; /* i.e bt742a -> '7','4','2','A' */
+ u_char ver[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */
+};
+
+#define BT_GET_SYNC_VALUE 0x8c /* Get Synchronous Value */
+struct bt_sync_value {
+ u_char value[8]; /* Synchrnous value (value * 10 nsec) */
+};
+
+#define INT9 0x01
+#define INT10 0x02
+#define INT11 0x04
+#define INT12 0x08
+#define INT14 0x20
+#define INT15 0x40
+
+#define EISADMA 0x00
+#define CHAN0 0x01
+#define CHAN5 0x20
+#define CHAN6 0x40
+#define CHAN7 0x80
+
+#define KVTOPHYS(x) vtophys(x)
+#define PAGESIZ 4096
+#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
+
+u_char bt_scratch_buf[256];
+
+struct bt_data {
+ short bt_base; /* base port for each board */
+ struct bt_mbx bt_mbx; /* all our mailboxes */
+ struct bt_ccb *bt_ccb_free; /* list of free CCBs */
+ struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */
+ int bt_int; /* int. read off board */
+ int bt_dma; /* DMA channel read of board */
+ int bt_scsi_dev; /* adapters scsi id */
+ int numccbs; /* how many we have malloc'd */
+ struct scsi_link sc_link; /* prototype for devs */
+} *btdata[NBT];
+
+/***********debug values *************/
+#define BT_SHOWCCBS 0x01
+#define BT_SHOWINTS 0x02
+#define BT_SHOWCMDS 0x04
+#define BT_SHOWMISC 0x08
+int bt_debug = 0;
+
+#ifdef KERNEL
+int btprobe();
+int btattach();
+int btintr();
+int32 bt_scsi_cmd();
+void bt_timeout(caddr_t, int);
+void bt_inquire_setup_information();
+void bt_done();
+void btminphys();
+u_int32 bt_adapter_info();
+struct bt_ccb *bt_get_ccb();
+struct bt_ccb *bt_ccb_phys_kv();
+
+static int btunit = 0;
+
+struct isa_driver btdriver =
+{
+ btprobe,
+ btattach,
+ "bt"
+};
+
+struct scsi_adapter bt_switch =
+{
+ bt_scsi_cmd,
+ btminphys,
+ 0,
+ 0,
+ bt_adapter_info,
+ "bt",
+ 0, 0
+};
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device bt_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "bt",
+ 0,
+ 0, 0
+};
+
+#endif /*KERNEL */
+
+#define BT_RESET_TIMEOUT 1000
+#ifndef KERNEL
+main()
+{
+ printf("bt_data is %d bytes\n", sizeof(struct bt_data));
+ printf("bt_ccb is %d bytes\n", sizeof(struct bt_ccb));
+ printf("bt_mbx is %d bytes\n", sizeof(struct bt_mbx));
+}
+
+#else /*KERNEL */
+
+/*
+ * bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args)
+ *
+ * Activate Adapter command
+ * icnt: number of args (outbound bytes written after opcode)
+ * ocnt: number of expected returned bytes
+ * wait: number of seconds to wait for response
+ * retval: buffer where to place returned bytes
+ * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ...
+ * args: parameters
+ *
+ * Performs an adapter command through the ports. Not to be confused with a
+ * scsi command, which is read in via the dma; one of the adapter commands
+ * tells it to read in a scsi command.
+ */
+int
+bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args)
+ int unit;
+ int icnt;
+ int ocnt;
+ int wait;
+ u_char *retval;
+ unsigned opcode;
+ u_char args;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned *ic = &opcode;
+ u_char oc;
+ register i;
+ int sts;
+
+ /*
+ * multiply the wait argument by a big constant
+ * zero defaults to 1
+ */
+ if (wait)
+ wait *= 100000;
+ else
+ wait = 100000;
+ /*
+ * Wait for the adapter to go idle, unless it's one of
+ * the commands which don't need this
+ */
+ if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) {
+ i = 100000; /* 1 sec? */
+ while (--i) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts & BT_IDLE) {
+ break;
+ }
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, host not idle(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ }
+ /*
+ * Now that it is idle, if we expect output, preflush the
+ * queue feeding to us.
+ */
+ if (ocnt) {
+ while ((inb(BT_CTRL_STAT_PORT)) & BT_DF)
+ inb(BT_CMD_DATA_PORT);
+ }
+ /*
+ * Output the command and the number of arguments given
+ * for each byte, first check the port is empty.
+ */
+ icnt++;
+ /* include the command */
+ while (icnt--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (!(sts & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return (ENXIO);
+ }
+ outb(BT_CMD_DATA_PORT, (u_char) (*ic++));
+ }
+ /*
+ * If we expect input, loop that many times, each time,
+ * looking for the data register to have valid data
+ */
+ while (ocnt--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts & BT_DF)
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, cmd/data port empty %d\n",
+ unit, ocnt);
+ return (ENXIO);
+ }
+ oc = inb(BT_CMD_DATA_PORT);
+ if (retval)
+ *retval++ = oc;
+ }
+ /*
+ * Wait for the board to report a finised instruction
+ */
+ i = 100000; /* 1 sec? */
+ while (--i) {
+ sts = inb(BT_INTR_PORT);
+ if (sts & BT_HACC) {
+ break;
+ }
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, host not finished(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return (0);
+}
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, set it up ready for further work
+ * as an argument, takes the isa_device structure from
+ * autoconf.c
+ */
+int
+btprobe(dev)
+ struct isa_device *dev;
+{
+ /*
+ * find unit and check we have that many defined
+ */
+ int unit = btunit;
+ struct bt_data *bt;
+
+ if (unit >= NBT) {
+ printf("bt%d: unit number too high\n", unit);
+ return 0;
+ }
+ /*
+ * Allocate a storage area for us
+ */
+ if (btdata[unit]) {
+ printf("bt%d: memory already allocated\n", unit);
+ return 0;
+ }
+ bt = malloc(sizeof(struct bt_data), M_TEMP, M_NOWAIT);
+ if (!bt) {
+ printf("bt%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(bt, sizeof(struct bt_data));
+ btdata[unit] = bt;
+ bt->bt_base = dev->id_iobase;
+
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads bt->bt_int
+ */
+ if (bt_init(unit) != 0) {
+ btdata[unit] = NULL;
+ free(bt, M_TEMP);
+ return 0;
+ }
+ /*
+ * If it's there, put in it's interrupt vectors
+ */
+ dev->id_unit = unit;
+ dev->id_irq = (1 << bt->bt_int);
+ dev->id_drq = bt->bt_dma;
+
+ btunit++;
+ return 1;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+btattach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct bt_data *bt = btdata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ bt->sc_link.adapter_unit = unit;
+ bt->sc_link.adapter_targ = bt->bt_scsi_dev;
+ bt->sc_link.adapter = &bt_switch;
+ bt->sc_link.device = &bt_dev;
+
+ /*
+ * Forcely Bounce buffer mechanizum is ON for some broken busmaster
+ * chip with over 16Mbytes boundary for while...
+ * amurai@spec.co.jp 94/06/16
+ */
+ bt->sc_link.flags = SDEV_BOUNCE; /*XXX*/
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(bt->sc_link));
+ return 1;
+}
+
+/*
+ * Return some information to the caller about the adapter and its
+ * capabilities.
+ */
+u_int32
+bt_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+btintr(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ BT_MBI *wmbi;
+ struct bt_mbx *wmbx;
+ struct bt_ccb *ccb;
+ unsigned char stat;
+ int i, wait;
+ int found = 0;
+
+#ifdef UTEST
+ printf("btintr ");
+#endif
+ /*
+ * First acknowlege the interrupt, Then if it's
+ * not telling about a completed operation
+ * just return.
+ */
+ stat = inb(BT_INTR_PORT);
+
+ /* Mail Box out empty ? */
+ if (stat & BT_MBOA) {
+ printf("bt%d: Available Free mbo post\n", unit);
+ /* Disable MBO available interrupt */
+ outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN);
+ wait = 100000; /* 1 sec enough? */
+ for (i = wait; i; i--) {
+ if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_intr, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return 1;
+ }
+ outb(BT_CMD_DATA_PORT, 0x00); /* Disable */
+ wakeup((caddr_t)&bt->bt_mbx);
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+ }
+ if (!(stat & BT_MBIF)) {
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+ }
+ /*
+ * If it IS then process the competed operation
+ */
+ wmbx = &bt->bt_mbx;
+ wmbi = wmbx->tmbi;
+ AGAIN:
+ while (wmbi->stat != BT_MBI_FREE) {
+ ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr));
+ if (!ccb) {
+ wmbi->stat = BT_MBI_FREE;
+ printf("bt: BAD CCB ADDR!\n");
+ continue;
+ }
+ found++;
+ if ((stat = wmbi->stat) != BT_MBI_OK) {
+ switch (stat) {
+ case BT_MBI_ABORT:
+#ifdef UTEST
+ if (bt_debug & BT_SHOWMISC)
+ printf("abort ");
+#endif
+ ccb->host_stat = BT_ABORTED;
+ break;
+
+ case BT_MBI_UNKNOWN:
+ ccb = (struct bt_ccb *) 0;
+#ifdef UTEST
+ if (bt_debug & BT_SHOWMISC)
+ printf("unknown ccb for abort");
+#endif
+ break;
+
+ case BT_MBI_ERROR:
+ break;
+
+ default:
+ panic("Impossible mbxi status");
+
+ }
+#ifdef UTEST
+ if ((bt_debug & BT_SHOWCMDS) && ccb) {
+ u_char *cp;
+ cp = ccb->scsi_cmd;
+ printf("op=%x %x %x %x %x %x\n",
+ cp[0], cp[1], cp[2],
+ cp[3], cp[4], cp[5]);
+ printf("stat %x for mbi addr = 0x%08x\n"
+ ,wmbi->stat, wmbi);
+ printf("addr = 0x%x\n", ccb);
+ }
+#endif
+ }
+ wmbi->stat = BT_MBI_FREE;
+ if (ccb) {
+ untimeout(bt_timeout, (caddr_t)ccb);
+ bt_done(unit, ccb);
+ }
+ /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi);
+ }
+ if (!found) {
+ for (i = 0; i < BT_MBX_SIZE; i++) {
+ if (wmbi->stat != BT_MBI_FREE) {
+ found++;
+ break;
+ }
+ bt_nextmbx(wmbi, wmbx, mbi);
+ }
+ if (!found) {
+ printf("bt%d: mbi at 0x%08x should be found, stat=%02x..resync\n",
+ unit, wmbi, stat);
+ } else {
+ found = 0;
+ goto AGAIN;
+ }
+ }
+ wmbx->tmbi = wmbi;
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+}
+
+/*
+ * A ccb is put onto the free list.
+ */
+void
+bt_free_ccb(unit, ccb, flags)
+ int unit;
+ struct bt_ccb *ccb;
+ int flags;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned int opri = 0;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ccb->next = bt->bt_ccb_free;
+ bt->bt_ccb_free = ccb;
+ ccb->flags = CCB_FREE;
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if (!ccb->next) {
+ wakeup((caddr_t)&bt->bt_ccb_free);
+ }
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free ccb
+ *
+ * If there are none, see if we can allocate a new one. If so, put it in
+ * the hash table too otherwise either return an error or sleep.
+ */
+struct bt_ccb *
+bt_get_ccb(unit, flags)
+ int unit;
+ int flags;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned opri = 0;
+ struct bt_ccb *ccbp;
+ struct bt_mbx *wmbx; /* Mail Box pointer specified unit */
+ BT_MBO *wmbo; /* Out Mail Box pointer */
+ int hashnum;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ while (!(ccbp = bt->bt_ccb_free)) {
+ if (bt->numccbs < BT_CCB_MAX) {
+ if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb),
+ M_TEMP,
+ M_NOWAIT)) {
+ bzero(ccbp, sizeof(struct bt_ccb));
+ bt->numccbs++;
+ ccbp->flags = CCB_ACTIVE;
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ccbp->hashkey = KVTOPHYS(ccbp);
+ hashnum = CCB_HASH(ccbp->hashkey);
+ ccbp->nexthash = bt->ccbhash[hashnum];
+ bt->ccbhash[hashnum] = ccbp;
+ } else {
+ printf("bt%d: Can't malloc CCB\n", unit);
+ }
+ goto gottit;
+ } else {
+ if (!(flags & SCSI_NOSLEEP)) {
+ tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO,
+ "btccb", 0);
+ }
+ }
+ }
+ if (ccbp) {
+ /* Get CCB from from free list */
+ bt->bt_ccb_free = ccbp->next;
+ ccbp->flags = CCB_ACTIVE;
+ }
+ gottit:
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (ccbp);
+}
+
+/*
+ * given a physical address, find the ccb that
+ * it corresponds to:
+ */
+struct bt_ccb *
+bt_ccb_phys_kv(bt, ccb_phys)
+ struct bt_data *bt;
+ physaddr ccb_phys;
+{
+ int hashnum = CCB_HASH(ccb_phys);
+ struct bt_ccb *ccbp = bt->ccbhash[hashnum];
+
+ while (ccbp) {
+ if (ccbp->hashkey == ccb_phys)
+ break;
+ ccbp = ccbp->nexthash;
+ }
+ return ccbp;
+}
+
+/*
+ * Get a MBO and then Send it
+ */
+BT_MBO *
+bt_send_mbo(int unit, int flags, int cmd, struct bt_ccb *ccb)
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned opri = 0;
+ BT_MBO *wmbo; /* Mail Box Out pointer */
+ struct bt_mbx *wmbx; /* Mail Box pointer specified unit */
+ int i, wait;
+
+ wmbx = &bt->bt_mbx;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ /* Get the Target OUT mail Box pointer and move to Next */
+ wmbo = wmbx->tmbo;
+ wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ?
+ &(wmbx->mbo[0]) : wmbo + 1);
+
+ /*
+ * Check the outmail box is free or not.
+ * Note: Under the normal operation, it shuld NOT happen to wait.
+ */
+ while (wmbo->cmd != BT_MBO_FREE) {
+ wait = 100000; /* 1 sec enough? */
+ /* Enable MBO available interrupt */
+ outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN);
+ for (i = wait; i; i--) {
+ if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_send_mbo, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return ((BT_MBO *) 0);
+ }
+ outb(BT_CMD_DATA_PORT, 0x01); /* Enable */
+ tsleep((caddr_t)wmbx, PRIBIO, "btsend", 0);
+ /* XXX */ /*can't do this! */
+ /* May be servicing an int */
+ }
+ /* Link CCB to the Mail Box */
+ wmbo->ccb_addr = KVTOPHYS(ccb);
+ ccb->mbx = wmbo;
+ wmbo->cmd = cmd;
+
+ /* Send it! */
+ outb(BT_CMD_DATA_PORT, BT_START_SCSI);
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (wmbo);
+}
+
+/*
+ * We have a ccb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went. Wake up the owner if waiting
+ */
+void
+bt_done(unit, ccb)
+ int unit;
+ struct bt_ccb *ccb;
+{
+ struct bt_data *bt = btdata[unit];
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ccb->xfer;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK)
+ && (!(xs->flags & SCSI_ERR_OK))) {
+
+ s1 = &(ccb->scsi_sense);
+ s2 = &(xs->sense);
+
+ if (ccb->host_stat) {
+ switch (ccb->host_stat) {
+ case BT_ABORTED: /* No response */
+ case BT_SEL_TIMEOUT: /* No response */
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("timeout reported back\n"));
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected host_stat: %x\n",
+ ccb->host_stat));
+ }
+ } else {
+ switch (ccb->target_stat) {
+ case 0x02:
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case 0x08:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected target_stat: %x\n",
+ ccb->target_stat));
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ } else { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ }
+ xs->flags |= ITSDONE;
+ bt_free_ccb(unit, ccb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+bt_init(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned char ad[4];
+ volatile int i, sts;
+ struct bt_config conf;
+ struct bt_ext_info info;
+ struct bt_board_info binfo;
+
+ /*
+ * reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+
+ outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST);
+
+ for (i = BT_RESET_TIMEOUT; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts == (BT_IDLE | BT_INIT))
+ break;
+ DELAY(1000);
+ }
+ if (i == 0) {
+#ifdef UTEST
+ printf("bt_init: No answer from board\n");
+#endif
+ return (ENXIO);
+ }
+
+ /*
+ * Displaying Board ID and Hardware Revision
+ * 94/05/18 amurai@spec.co.jp
+ */
+ bt_cmd(unit, 1, sizeof(binfo),0,&binfo,BT_GET_BOARD_INFO,sizeof(binfo));
+ printf("bt%d: Bt%c%c%c%c/%c%d-", unit,
+ binfo.id[0],
+ binfo.id[1],
+ binfo.id[2],
+ binfo.id[3],
+ binfo.ver[0],
+ (unsigned) binfo.ver[1]
+ );
+
+ /*
+ * Make sure board has a capability of 32bit addressing.
+ * and Firmware also need a capability of 32bit addressing pointer
+ * in Extended mailbox and ccb structure.
+ * 94/05/18 amurai@spec.co.jp
+ */
+ bt_cmd(unit, 1, sizeof(info),0,&info, BT_INQUIRE_EXTENDED,sizeof(info));
+ switch (info.bus_type) {
+ case BT_BUS_TYPE_24bit: /* PC/AT 24 bit address bus */
+ printf("ISA(24bit) bus\n");
+ break;
+ case BT_BUS_TYPE_32bit: /* EISA/VLB/PCI 32 bit bus */
+ printf("PCI/EISA/VLB(32bit) bus\n");
+ break;
+ case BT_BUS_TYPE_MCA: /* forget it right now */
+ printf("MCA bus architecture...");
+ printf("giving up\n");
+ return (ENXIO);
+ break;
+ default:
+ printf("Unknown state...");
+ printf("giving up\n");
+ return (ENXIO);
+ break;
+ }
+ if ( binfo.id[0] == '5' ) {
+ printf("bt%d: This driver is designed for using 32 bit addressing\n",unit);
+ printf("bt%d: mode firmware and EISA/PCI/VLB bus architecture bus\n",unit);
+ printf("bt%d: WITHOUT any software trick/overhead (i.e.bounce buffer).\n",unit);
+ printf("bt%d: If you have more than 16MBytes memory\n",unit);
+ printf("bt%d: your filesystem will get a serious damage.\n",unit);
+ } else if ( info.bus_type == BT_BUS_TYPE_24bit ) {
+ printf("bt%d: Your board should report a 32bit bus architecture type..\n",unit);
+ printf("bt%d: A firmware on your board may have a problem with over\n",unit);
+ printf("bt%d: 16MBytes memory handling with this driver.\n",unit);
+ }
+
+ /*
+ * Assume we have a board at this stage
+ * setup dma channel from jumpers and save int
+ * level
+ */
+ printf("bt%d: reading board settings, ", unit);
+
+ bt_cmd(unit, 0, sizeof(conf), 0, &conf, BT_CONF_GET);
+ switch (conf.chan) {
+ case EISADMA:
+ bt->bt_dma = -1;
+ break;
+ case CHAN0:
+ outb(0x0b, 0x0c);
+ outb(0x0a, 0x00);
+ bt->bt_dma = 0;
+ break;
+ case CHAN5:
+ outb(0xd6, 0xc1);
+ outb(0xd4, 0x01);
+ bt->bt_dma = 5;
+ break;
+ case CHAN6:
+ outb(0xd6, 0xc2);
+ outb(0xd4, 0x02);
+ bt->bt_dma = 6;
+ break;
+ case CHAN7:
+ outb(0xd6, 0xc3);
+ outb(0xd4, 0x03);
+ bt->bt_dma = 7;
+ break;
+ default:
+ printf("illegal dma setting %x\n", conf.chan);
+ return (EIO);
+ }
+ if (bt->bt_dma == -1)
+ printf("busmastering, ");
+ else
+ printf("dma=%d, ", bt->bt_dma);
+
+ switch (conf.intr) {
+ case INT9:
+ bt->bt_int = 9;
+ break;
+ case INT10:
+ bt->bt_int = 10;
+ break;
+ case INT11:
+ bt->bt_int = 11;
+ break;
+ case INT12:
+ bt->bt_int = 12;
+ break;
+ case INT14:
+ bt->bt_int = 14;
+ break;
+ case INT15:
+ bt->bt_int = 15;
+ break;
+ default:
+ printf("illegal int setting\n");
+ return (EIO);
+ }
+ printf("int=%d\n", bt->bt_int);
+
+ /* who are we on the scsi bus */
+ bt->bt_scsi_dev = conf.scsi_dev;
+ /*
+ * Initialize mail box
+ */
+ *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx);
+ bt_cmd(unit, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED
+ ,BT_MBX_SIZE
+ ,ad[0]
+ ,ad[1]
+ ,ad[2]
+ ,ad[3]);
+
+ /*
+ * Set Pointer chain null for just in case
+ * Link the ccb's into a free-list W/O mbox
+ * Initialize mail box status to free
+ */
+ if (bt->bt_ccb_free != (struct bt_ccb *) 0) {
+ printf("bt%d: bt_ccb_free is NOT initialized but init here\n",
+ unit);
+ bt->bt_ccb_free = (struct bt_ccb *) 0;
+ }
+ for (i = 0; i < BT_MBX_SIZE; i++) {
+ bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE;
+ bt->bt_mbx.mbi[i].stat = BT_MBI_FREE;
+ }
+ /*
+ * Set up initial mail box for round-robin operation.
+ */
+ bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0];
+ bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0];
+ bt_inquire_setup_information(unit, &info);
+
+
+ /*
+ * Note that we are going and return (to probe)
+ */
+ return 0;
+}
+
+void
+bt_inquire_setup_information(
+ int unit,
+ struct bt_ext_info *info )
+{
+ struct bt_data *bt = btdata[unit];
+ struct bt_setup setup;
+ struct bt_sync_value sync;
+ char dummy[8];
+ char sub_ver[3];
+ struct bt_boardID bID;
+ int i;
+
+ /* Inquire Installed Devices */
+ bzero( &dummy[0], sizeof(dummy) );
+ bt_cmd(unit, 0, sizeof(dummy), 100, &dummy[0], BT_DEV_GET);
+
+ /*
+ * If board has a capbility of Syncrhonouse mode,
+ * Get a SCSI Synchronous value
+ */
+ if ( info->s.sync ) {
+ bt_cmd(unit, 1, sizeof(sync), 100,
+ &sync,BT_GET_SYNC_VALUE,sizeof(sync));
+ }
+
+ /*
+ * Inquire Board ID to board for firmware version
+ */
+ bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE);
+ bt_cmd(unit, 0, 1, 0, &sub_ver[0], BT_INQUIRE_REV_THIRD );
+ i = ((int)(bID.firm_revision-'0')) * 10 + (int)(bID.firm_version-'0');
+ if ( i >= 33 ) {
+ bt_cmd(unit, 0, 1, 0, &sub_ver[1], BT_INQUIRE_REV_FOURTH );
+ } else {
+ /*
+ * Below rev 3.3 firmware has a problem for issuing
+ * the BT_INQUIRE_REV_FOURTH command.
+ */
+ sub_ver[1]='\0';
+ }
+ sub_ver[2]='\0';
+ if (sub_ver[1]==' ')
+ sub_ver[1]='\0';
+ printf("bt%d: version %c.%c%s, ",
+ unit, bID.firm_revision, bID.firm_version, sub_ver );
+
+ /*
+ * Obtain setup information from board.
+ */
+ bt_cmd(unit, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup));
+
+ if (setup.sync_neg && info->s.sync ) {
+ if ( info->s.maxsync ) {
+ printf("fast sync, "); /* Max 10MB/s */
+ } else {
+ printf("sync, "); /* Max 5MB/s */
+ }
+ } else {
+ if ( info->s.sync ) {
+ printf("async, "); /* Never try by board */
+ } else {
+ printf("async only, "); /* Doesn't has a capability on board */
+ }
+ }
+ if (setup.parity) {
+ printf("parity, ");
+ } else {
+ printf("no parity, ");
+ }
+ printf("%d mbxs, %d ccbs\n", setup.num_mbx, BT_CCB_MAX);
+
+ /*
+ * Displayi SCSI negotiation value by each target.
+ * amurai@spec.co.jp
+ */
+ for (i = 0; i < 8; i++) {
+ if (!setup.sync[i].valid )
+ continue;
+ if ( (!setup.sync[i].offset && !setup.sync[i].period)
+ || !info->s.sync ) {
+ printf("bt%d: targ %d async\n", unit, i);
+ } else {
+ printf("bt%d: targ %d sync rate=%2d.%02dMB/s(%dns), offset=%02d\n",
+ unit, i,
+ 100 / sync.value[i],
+ (100 % sync.value[i]) * 100 / sync.value[i],
+ sync.value[i] * 10,
+ setup.sync[i].offset );
+ }
+ }
+
+ /*
+ * Enable round-robin scheme - appeared at firmware rev. 3.31
+ * Below rev 3.XX firmware has a problem for issuing
+ * BT_ROUND_ROBIN command amurai@spec.co.jp
+ */
+ if ( bID.firm_revision >= '3' ) {
+ printf("bt%d: Enabling Round robin scheme\n", unit);
+ bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
+ } else {
+ printf("bt%d: Not Enabling Round robin scheme\n", unit);
+ }
+
+}
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif /* min */
+
+void
+btminphys(bp)
+ struct buf *bp;
+{
+ if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and the data address. Also needs
+ * the unit, target and lu.
+ */
+int32
+bt_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1, *s2;
+ struct bt_ccb *ccb;
+ struct bt_scat_gath *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int c = 0;
+ int thiskv;
+ physaddr thisphys, nextphys;
+ int unit = xs->sc_link->adapter_unit;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct iovec *iovp;
+ struct bt_data *bt = btdata[unit];
+ BT_MBO *mbo;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_scsi_cmd\n"));
+ /*
+ * get a ccb (mbox-out) 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 (xs->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (flags & ITSDONE) {
+ printf("bt%d: Already done?\n", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if (!(flags & INUSE)) {
+ printf("bt%d: Not in use?\n", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(ccb = bt_get_ccb(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("start ccb(%x)\n", ccb));
+ /*
+ * Put all the arguments for the xfer in the ccb
+ */
+ ccb->xfer = xs;
+ if (flags & SCSI_RESET) {
+ ccb->opcode = BT_RESET_CCB;
+ } else {
+ /* can't use S/G if zero length */
+ ccb->opcode = (xs->datalen ?
+ BT_INIT_SCAT_GATH_CCB
+ : BT_INITIATOR_CCB);
+ }
+ ccb->target = xs->sc_link->target;
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->lun = xs->sc_link->lun;
+ ccb->scsi_cmd_length = xs->cmdlen;
+ ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense));
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+
+ if ((xs->datalen) && (!(flags & SCSI_RESET))) { /* can use S/G only if not zero length */
+ ccb->data_addr = KVTOPHYS(ccb->scat_gath);
+ sg = ccb->scat_gath;
+ seg = 0;
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < BT_NSEG)) {
+ sg->seg_addr = (physaddr) iovp->iov_base;
+ xs->datalen += sg->seg_len = iovp->iov_len;
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)"
+ ,iovp->iov_len, iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ } else
+#endif /* TFS */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < BT_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->seg_addr = thisphys;
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("0x%x", thisphys));
+
+ /* 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 & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ 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 & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ sg->seg_len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ }
+ /* end of iov/kv decision */
+ ccb->data_length = seg * sizeof(struct bt_scat_gath);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+ if (datalen) {
+ /*
+ * there's still data, must have run out of segs!
+ */
+ printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n",
+ unit, BT_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ ccb->data_addr = (physaddr) 0;
+ ccb->data_length = 0;
+ }
+ ccb->link_id = 0;
+ ccb->link_addr = (physaddr) 0;
+ /*
+ * Put the scsi command in the ccb and start it
+ */
+ if (!(flags & SCSI_RESET)) {
+ bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length);
+ }
+ if (bt_send_mbo(unit, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) {
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (TRY_AGAIN_LATER);
+ }
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ if (!(flags & SCSI_NOMASK)) {
+ timeout(bt_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000);
+ return (SUCCESSFULLY_QUEUED);
+ }
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ return (bt_poll(unit, xs, ccb));
+}
+
+/*
+ * Poll a particular unit, looking for a particular xs
+ */
+int
+bt_poll(unit, xs, ccb)
+ int unit;
+ struct scsi_xfer *xs;
+ struct bt_ccb *ccb;
+{
+ struct bt_data *bt = btdata[unit];
+ int done = 0;
+ int count = xs->timeout;
+ u_char stat;
+
+ /* timeouts are in msec, so we loop in 1000 usec cycles */
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ stat = inb(BT_INTR_PORT);
+ if (stat & BT_ANY_INTR) {
+ btintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out, so call the timeout handler manually,
+ * accounting for the fact that the clock is not running yet
+ * by taking out the clock queue entry it makes.
+ */
+ bt_timeout((caddr_t)ccb, 0);
+
+ /*
+ * because we are polling, take out the timeout entry
+ * bt_timeout made
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+ count = 2000;
+ while (count) {
+ /*
+ * Once again, wait for the int bit
+ */
+ stat = inb(BT_INTR_PORT);
+ if (stat & BT_ANY_INTR) {
+ btintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out again... This is bad. Notice that
+ * this time there is no clock queue entry to remove.
+ */
+ bt_timeout((caddr_t)ccb, 0);
+ }
+ }
+ if (xs->error)
+ return (HAD_ERROR);
+ return (COMPLETE);
+}
+
+void
+bt_timeout(caddr_t arg1, int arg2)
+{
+ struct bt_ccb * ccb = (struct bt_ccb *)arg1;
+ int unit;
+ struct bt_data *bt;
+ int s = splbio();
+
+ /*
+ * A timeout routine in kernel DONOT unlink
+ * Entry chains when time outed....So infinity Loop..
+ * 94/04/20 amurai@spec.co.jp
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+
+ unit = ccb->xfer->sc_link->adapter_unit;
+ bt = btdata[unit];
+
+#ifdef UTEST
+ bt_print_active_ccbs(unit);
+#endif
+
+ /*
+ * If the ccb's mbx is not free, then the board has gone Far East?
+ */
+ if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb &&
+ ccb->mbx->cmd != BT_MBO_FREE) {
+ printf("bt%d: not taking commands!\n", unit);
+ Debugger("bt742a");
+ }
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ccb->flags == CCB_ABORTED) {
+ /*
+ * abort timed out
+ */
+ printf("bt%d: Abort Operation has timed out\n", unit);
+ ccb->xfer->retries = 0; /* I MEAN IT ! */
+ ccb->host_stat = BT_ABORTED;
+ bt_done(unit, ccb);
+ } else {
+ /* abort the operation that has timed out */
+ printf("bt%d: Try to abort\n", unit);
+ bt_send_mbo(unit, ~SCSI_NOMASK,
+ BT_MBO_ABORT, ccb);
+ /* 2 secs for the abort */
+ ccb->flags = CCB_ABORTED;
+ timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
+ }
+ splx(s);
+}
+
+#ifdef UTEST
+void
+bt_print_ccb(ccb)
+ struct bt_ccb *ccb;
+{
+ printf("ccb:%x op:%x cmdlen:%d senlen:%d\n"
+ ,ccb
+ ,ccb->opcode
+ ,ccb->scsi_cmd_length
+ ,ccb->req_sense_length);
+ printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
+ ,ccb->data_length
+ ,ccb->host_stat
+ ,ccb->target_stat
+ ,ccb->flags);
+}
+
+void
+bt_print_active_ccbs(int unit)
+{
+ struct bt_data *bt = btdata[unit];
+ struct bt_ccb *ccb;
+ int i = 0;
+
+ while (i < CCB_HASH_SIZE) {
+ ccb = bt->ccbhash[i];
+ while (ccb) {
+ if (ccb->flags != CCB_FREE)
+ bt_print_ccb(ccb);
+ ccb = ccb->nexthash;
+ }
+ i++;
+ }
+}
+#endif /*UTEST */
+#endif /*KERNEL */
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
index cd87b28b90e6..5832801d24ae 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ * $Id: clock.c,v 1.9 1994/05/02 09:41:24 sos Exp $
*/
/*
@@ -45,6 +45,7 @@
#include "time.h"
#include "kernel.h"
#include "machine/segments.h"
+#include "machine/frame.h"
#include "i386/isa/icu.h"
#include "i386/isa/isa.h"
#include "i386/isa/rtc.h"
@@ -55,22 +56,225 @@
#ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
-static void findcpuspeed(void);
void
startrtclock()
{
int s;
- findcpuspeed(); /* use the clock (while it's free)
- to find the cpu speed */
/* initialize 8253 clock */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
/* Correct rounding will buy us a better precision in timekeeping */
- outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
- outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA);
@@ -83,44 +287,18 @@ startrtclock()
printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
}
-unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
-
-#define FIRST_GUESS 0x2000
-static void
-findcpuspeed()
-{
- unsigned char low;
- unsigned int remainder;
-
- /* Put counter in count down mode */
- outb(IO_TIMER1+3, 0x34);
- outb(IO_TIMER1, 0xff);
- outb(IO_TIMER1, 0xff);
- delaycount = FIRST_GUESS;
- spinwait(1);
- /* Read the value left in the counter */
- low = inb(IO_TIMER1); /* least siginifcant */
- remainder = inb(IO_TIMER1); /* most significant */
- remainder = (remainder<<8) + low ;
- /* Formula for delaycount is :
- * (loopcount * timer clock speed)/ (counter ticks * 1000)
- */
- delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
-}
-
/* convert 2 digit BCD number */
int
-bcd(i)
- int i;
+bcd(int i)
{
return ((i/16)*10 + (i%16));
}
+
/* convert years to seconds (from 1970) */
unsigned long
-ytos(y)
-int y;
+ytos(int y)
{
int i;
unsigned long ret;
@@ -133,16 +311,16 @@ int y;
return ret;
}
+
/* convert months to seconds */
unsigned long
-mtos(m,leap)
-int m,leap;
+mtos(int m, int leap)
{
int i;
unsigned long ret;
ret = 0;
- for(i=1;i<m;i++) {
+ for(i=1; i<m; i++) {
switch(i){
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
ret += 31*24*60*60; break;
@@ -162,11 +340,10 @@ int m,leap;
* from a filesystem.
*/
void
-inittodr(base)
- time_t base;
+inittodr(time_t base)
{
unsigned long sec;
- int leap,day_week,t,yd;
+ int leap, day_week, t, yd;
int sa,s;
/* do we have a realtime clock present? (otherwise we loop below) */
@@ -180,26 +357,25 @@ inittodr(base)
sec = bcd(rtcin(RTC_YEAR)) + 1900;
if (sec < 1970)
sec += 100;
- leap = !(sec % 4); sec = ytos(sec); /* year */
- yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
- t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
day_week = rtcin(RTC_WDAY); /* day */
sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
sec += bcd(rtcin(RTC_SEC)); /* seconds */
-
sec += tz.tz_minuteswest * 60;
-
time.tv_sec = sec;
}
+
#ifdef garbage
/*
* Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem.
*/
-test_inittodr(base)
- time_t base;
+test_inittodr(time_t base)
{
outb(IO_RTC,9); /* year */
@@ -219,6 +395,7 @@ test_inittodr(base)
}
#endif
+
/*
* Restart the clock.
*/
@@ -227,12 +404,14 @@ resettodr()
{
}
+
/*
* Wire clock interrupt in.
*/
#define V(s) __CONCAT(V, s)
extern void V(clk)();
+
void
enablertclock()
{
@@ -240,12 +419,12 @@ enablertclock()
INTREN(IRQ0);
}
+
/*
* Delay for some number of milliseconds.
*/
void
-spinwait(millisecs)
- int millisecs;
+spinwait(int millisecs)
{
DELAY(1000 * millisecs);
}
diff --git a/sys/i386/isa/com.c b/sys/i386/isa/com.c
index dcaf878685be..25b4dee3238c 100644
--- a/sys/i386/isa/com.c
+++ b/sys/i386/isa/com.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: com.c,v 1.7 1993/12/19 00:50:32 wollman Exp $
+ * $Id: com.c,v 1.10 1994/05/30 03:14:13 ache Exp $
*/
#include "com.h"
@@ -86,7 +86,7 @@ int comconsinit;
int comdefaultrate = TTYDEF_SPEED;
int commajor;
short com_addr[NCOM];
-struct tty com_tty[NCOM];
+struct tty *com_tty[NCOM];
struct speedtab comspeedtab[] = {
0, 0,
@@ -199,12 +199,11 @@ comopen(int /*dev_t*/ dev, int flag, int mode, struct proc *p)
unit = UNIT(dev);
if (unit >= NCOM || (com_active & (1 << unit)) == 0)
return (ENXIO);
- tp = &com_tty[unit];
+ tp = com_tty[unit] = ttymalloc(com_tty[unit]);
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);
if (tp->t_ispeed == 0) {
tp->t_iflag = TTYDEF_IFLAG;
@@ -223,9 +222,8 @@ comopen(int /*dev_t*/ dev, int flag, int mode, struct proc *p)
tp->t_state |= TS_CARR_ON;
while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
(tp->t_state & TS_CARR_ON) == 0) {
- tp->t_state |= TS_WOPEN;
- if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- ttopen, 0))
+ if (error = tsleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "comdcd", 0))
break;
}
(void) spl0();
@@ -247,7 +245,7 @@ comclose(dev, flag, mode, p)
unit = UNIT(dev);
com = com_addr[unit];
- tp = &com_tty[unit];
+ tp = com_tty[unit];
(*linesw[tp->t_line].l_close)(tp, flag);
outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
#ifdef KGDB
@@ -255,10 +253,16 @@ comclose(dev, flag, mode, p)
if (kgdb_dev != makedev(commajor, unit))
#endif
outb(com+com_ier, 0);
- if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
- (tp->t_state&TS_ISOPEN) == 0)
+ if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN) == 0)
(void) commctl(dev, 0, DMSET);
ttyclose(tp);
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ ttyfree(tp);
+ com_tty[unit] = (struct tty *)NULL;
+#endif
+ return (0);
+
+
return(0);
}
@@ -268,7 +272,7 @@ comread(dev, uio, flag)
struct uio *uio;
int flag;
{
- register struct tty *tp = &com_tty[UNIT(dev)];
+ register struct tty *tp = com_tty[UNIT(dev)];
return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
}
@@ -280,7 +284,7 @@ comwrite(dev, uio, flag)
int flag;
{
int unit = UNIT(dev);
- register struct tty *tp = &com_tty[unit];
+ register struct tty *tp = com_tty[unit];
/*
* (XXX) We disallow virtual consoles if the physical console is
@@ -309,7 +313,7 @@ comintr(unit)
return;
case IIR_RXTOUT:
case IIR_RXRDY:
- tp = &com_tty[unit];
+ tp = com_tty[unit];
/*
* Process received bytes. Inline for speed...
*/
@@ -340,7 +344,7 @@ comintr(unit)
}
break;
case IIR_TXRDY:
- tp = &com_tty[unit];
+ tp = com_tty[unit];
tp->t_state &=~ (TS_BUSY|TS_FLUSH);
if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
@@ -371,7 +375,7 @@ comeint(unit, stat, com)
register struct tty *tp;
register int c;
- tp = &com_tty[unit];
+ tp = com_tty[unit];
c = inb(com+com_data);
if ((tp->t_state & TS_ISOPEN) == 0) {
#ifdef KGDB
@@ -401,7 +405,7 @@ commint(unit, com)
register struct tty *tp;
register int stat;
- tp = &com_tty[unit];
+ tp = com_tty[unit];
stat = inb(com+com_msr);
if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
if (stat & MSR_DCD)
@@ -432,7 +436,7 @@ comioctl(dev, cmd, data, flag)
register com;
register int error;
- tp = &com_tty[unit];
+ tp = com_tty[unit];
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
if (error >= 0)
return (error);
@@ -545,26 +549,17 @@ comstart(tp)
s = spltty();
if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
goto out;
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
- if (RB_LEN(&tp->t_out) == 0)
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
+ if (RB_LEN(tp->t_out) == 0)
goto out;
if (inb(com+com_lsr) & LSR_TXRDY) {
- c = getc(&tp->t_out);
+ c = getc(tp->t_out);
tp->t_state |= TS_BUSY;
outb(com+com_data, c);
if (com_hasfifo & (1 << unit))
- for (c = 1; c < 16 && RB_LEN(&tp->t_out); ++c)
- outb(com+com_data, getc(&tp->t_out));
+ for (c = 1; c < 16 && RB_LEN(tp->t_out); ++c)
+ outb(com+com_data, getc(tp->t_out));
}
out:
splx(s);
@@ -647,7 +642,7 @@ comcnprobe(cp)
/* initialize required fields */
cp->cn_dev = makedev(commajor, unit);
- cp->cn_tp = &com_tty[unit];
+ cp->cn_tp = com_tty[unit];
#ifdef COMCONSOLE
cp->cn_pri = CN_REMOTE; /* Force a serial port console */
#else
@@ -747,43 +742,3 @@ comcnputc(dev, c)
splx(s);
}
#endif
-
-int
-comselect(dev, rw, p)
- dev_t dev;
- int rw;
- struct proc *p;
-{
- register struct tty *tp = &com_tty[UNIT(dev)];
- int nread;
- int s = spltty();
- struct proc *selp;
-
- switch (rw) {
-
- case FREAD:
- nread = ttnread(tp);
- if (nread > 0 ||
- ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
- goto win;
- if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
- tp->t_state |= TS_RCOLL;
- else
- tp->t_rsel = p->p_pid;
- break;
-
- case FWRITE:
- if (RB_LEN(&tp->t_out) <= tp->t_lowat)
- goto win;
- if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
- tp->t_state |= TS_WCOLL;
- else
- tp->t_wsel = p->p_pid;
- break;
- }
- splx(s);
- return (0);
- win:
- splx(s);
- return (1);
-}
diff --git a/sys/i386/isa/debug.h b/sys/i386/isa/debug.h
deleted file mode 100644
index 92ecbd67f0fd..000000000000
--- a/sys/i386/isa/debug.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * from: debug.h, part of Bruce Evans interrupt code
- * $Id: debug.h,v 1.3 1993/11/13 02:25:20 davidg Exp $
- */
-
-#define SHOW_A_LOT_NOT
-
-#define BDBTRAP(name) \
- ss ; \
- cmpb $0,_bdb_exists ; \
- je 1f ; \
- testb $SEL_RPL_MASK,4(%esp) ; \
- jne 1f ; \
- ss ; \
-bdb_/**/name/**/_ljmp: ; \
- ljmp $0,$0 ; \
-1:
-
-#if 1
-#define COUNT_EVENT(group, event) incl (group) + (event) * 4
-#else
-#define COUNT_EVENT(group, event)
-#endif
-
-#ifdef SHOW_A_LOT
-
-#define GREEN 0x27 /* 0x27 for true green, 0x07 for mono */
-#define CLI_STI_X 63
-#define CPL_X 46
-#define IMEN_X 64
-#define IPENDING_X 29
-#define RED 0x47 /* 0x47 for true red, 0x70 for mono */
-
-#define SHOW_BIT(bit) ; \
- movl %ecx,%eax ; \
- shr $bit,%eax ; \
- andl $1,%eax ; \
- movb bit_colors(%eax),%al ; \
- movb %al,bit * 2 + 1(%ebx)
-
-#define SHOW_BITS(var, screen_offset) ; \
- pushl %ebx ; \
- pushl %ecx ; \
- movl _Crtat,%ebx ; \
- addl $screen_offset * 2,%ebx ; \
- movl _/**/var,%ecx ; \
- call show_bits ; \
- popl %ecx ; \
- popl %ebx
-
-#define SHOW_CLI \
- COUNT_EVENT(_intrcnt_show, 0) ; \
- pushl %eax ; \
- movl _Crtat,%eax ; \
- movb $RED,CLI_STI_X * 2 + 1(%eax) ; \
- popl %eax
-
-#define SHOW_CPL \
- COUNT_EVENT(_intrcnt_show, 1) ; \
- SHOW_BITS(cpl, CPL_X) ; \
-
-#define SHOW_IMEN \
- COUNT_EVENT(_intrcnt_show, 2) ; \
- SHOW_BITS(imen, IMEN_X)
-
-#define SHOW_IPENDING \
- COUNT_EVENT(_intrcnt_show, 3) ; \
- SHOW_BITS(ipending, IPENDING_X)
-
-#define SHOW_STI \
- COUNT_EVENT(_intrcnt_show, 4) ; \
- pushl %eax ; \
- movl _Crtat,%eax ; \
- movb $GREEN,CLI_STI_X * 2 + 1(%eax) ; \
- popl %eax
-
-#else /* not SHOW_A_LOT */
-
-#define SHOW_CLI COUNT_EVENT(_intrcnt_show, 0)
-#define SHOW_CPL COUNT_EVENT(_intrcnt_show, 1)
-#define SHOW_IMEN COUNT_EVENT(_intrcnt_show, 2)
-#define SHOW_IPENDING COUNT_EVENT(_intrcnt_show, 3)
-#define SHOW_STI COUNT_EVENT(_intrcnt_show, 4)
-
-#endif /* SHOW_A_LOT */
diff --git a/sys/i386/isa/elink.c b/sys/i386/isa/elink.c
new file mode 100644
index 000000000000..cd0057644a89
--- /dev/null
+++ b/sys/i386/isa/elink.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1994 Charles 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 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.
+ *
+ * $Id: elink.c,v 1.1 1994/05/25 20:06:40 ats Exp $
+ */
+
+/*
+ * Common code for dealing with 3COM ethernet cards.
+ */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/pio.h>
+#include <i386/isa/elink.h>
+
+/*
+ * Issue a `global reset' to all cards. We have to be careful to do this only
+ * once during autoconfig, to prevent resetting boards that have already been
+ * configured.
+ */
+void
+elink_reset()
+{
+ static int x = 0;
+
+ if (x == 0) {
+ x = 1;
+ outb(ELINK_ID_PORT, ELINK_RESET);
+ }
+}
+
+/*
+ * The `ID sequence' is really just snapshots of an 8-bit CRC register as 0
+ * bits are shifted in. Different board types use different polynomials.
+ */
+void
+elink_idseq(p)
+ register u_char p;
+{
+ register int i;
+ register u_char c;
+
+ c = 0xff;
+ for (i = 255; i; i--) {
+ outb(ELINK_ID_PORT, c);
+ if (c & 0x80) {
+ c <<= 1;
+ c ^= p;
+ } else
+ c <<= 1;
+ }
+}
diff --git a/sys/i386/isa/elink.h b/sys/i386/isa/elink.h
new file mode 100644
index 000000000000..93a5dac6f5ce
--- /dev/null
+++ b/sys/i386/isa/elink.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1994 Charles 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 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.
+ *
+ * $Id: elink.h,v 1.1 1994/05/25 20:06:43 ats Exp $
+ */
+
+#define ELINK_ID_PORT 0x100
+#define ELINK_RESET 0xc0
+
+#define ELINK_507_POLY 0xe7
+#define ELINK_509_POLY 0xcf
+
+void elink_reset __P((void));
+void elink_idseq __P((u_char p));
diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c
index 8f3e1dc9cc94..f4632b9f2cb1 100644
--- a/sys/i386/isa/fd.c
+++ b/sys/i386/isa/fd.c
@@ -6,6 +6,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
+ * Portions Copyright (c) 1993, 1994 by
+ * jc@irbs.UUCP (John Capo)
+ * vak@zebub.msk.su (Serge Vakulenko)
+ * ache@astral.msk.su (Andrew A. Chernov)
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,7 +41,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.21.2.1 1994/03/07 02:08:43 rgrimes Exp $
+ * $Id: fd.c,v 1.26 1994/05/22 12:30:32 joerg Exp $
*
*/
@@ -59,28 +65,29 @@
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
#include <sys/syslog.h>
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/fdreg.h"
#include "i386/isa/fdc.h"
-#include "i386/isa/icu.h"
#include "i386/isa/rtc.h"
-#if NFT > 0
-extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
-#endif
-
#define b_cylin b_resid
-#define FDBLK 512
/* misuse a flag to identify format operation */
#define B_FORMAT B_XXX
+/*
+ * this biotab field doubles as a field for the physical unit number
+ * on the controller
+ */
+#define id_physid id_scsiid
+
#define NUMTYPES 14
#define NUMDENS (NUMTYPES - 6)
-/* This defines (-1) must match index for fd_types */
+/* These defines (-1) must match index for fd_types */
#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
#define FD_1720 1
@@ -132,16 +139,17 @@ struct fdc_data fdc_data[NFDC];
struct fd_data {
struct fdc_data *fdc; /* pointer to controller structure */
int fdsu; /* this units number on this controller */
- int type; /* Drive type (HD, DD */
+ int type; /* Drive type (FD_1440...) */
struct fd_type *ft; /* pointer to the type descriptor */
int flags;
#define FD_OPEN 0x01 /* it's open */
#define FD_ACTIVE 0x02 /* it's active */
#define FD_MOTOR 0x04 /* motor should be on */
#define FD_MOTOR_WAIT 0x08 /* motor coming up */
- int skip;
- int hddrv;
- int track; /* where we think the head is */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+ int options; /* user configurable options, see ioctl_fd.h */
} fd_data[NFD];
/***********************************************************************\
@@ -153,10 +161,48 @@ struct fd_data {
* fdsu is the floppy drive unit number on that controller. (sub-unit) *
\***********************************************************************/
-#define id_physid id_scsiid /* this biotab field doubles as a field */
- /* for the physical unit number on the controller */
+#if NFT > 0
+int ftopen(dev_t, int);
+int ftintr(/* ftu_t */ int ftu);
+int ftclose(/* dev_t */ int, int);
+void ftstrategy(struct buf *);
+int ftioctl(/* dev_t */ int, int, caddr_t, int, struct proc *);
+int ftdump(/* dev_t */ int);
+int ftsize(/* dev_t */ int);
+int ftattach(struct isa_device *, struct isa_device *);
+#endif
+/* autoconfig functions */
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+/* exported functions */
+int fdsize (/* dev_t */ int);
+void fdintr(fdcu_t);
+int Fdopen(/* dev_t */int, int);
+int fdclose(/* dev_t */int, int);
+void fdstrategy(struct buf *);
+int fdioctl(/* dev_t */ int, int, caddr_t, int, struct proc *);
+
+/* needed for ft driver, thus exported */
+int in_fdc(fdcu_t);
+int out_fdc(fdcu_t, int);
+
+/* internal functions */
+static void set_motor(fdcu_t, int, int);
+# define TURNON 1
+# define TURNOFF 0
+static void fd_turnoff(caddr_t arg1, int arg2);
+static void fd_motor_on(caddr_t arg1, int arg2);
+static void fd_turnon(fdu_t);
+static void fdc_reset(fdc_p);
+static void fdstart(fdcu_t);
+static void fd_timeout(caddr_t, int);
+static void fd_pseudointr(caddr_t, int);
+static int fdstate(fdcu_t, fdc_p);
static int retrier(fdcu_t);
+static int fdformat(/* dev_t */ int, struct fd_formb *, struct proc *);
+
#define DEVIDLE 0
#define FINDWORK 1
@@ -188,25 +234,18 @@ char *fdstates[] =
"IOTIMEDOUT"
};
-
-int fd_debug = 1;
+/* CAUTION: fd_debug causes huge amounts of logging output */
+int fd_debug = 0;
#define TRACE0(arg) if(fd_debug) printf(arg)
-#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
#else /* DEBUG */
#define TRACE0(arg)
-#define TRACE1(arg1,arg2)
+#define TRACE1(arg1, arg2)
#endif /* DEBUG */
-static void fdstart(fdcu_t);
-void fdintr(fdcu_t);
-static void fd_turnoff(caddr_t, int);
-
/****************************************************************************/
/* autoconfiguration stuff */
/****************************************************************************/
-static int fdprobe(struct isa_device *);
-static int fdattach(struct isa_device *);
-
struct isa_driver fdcdriver = {
fdprobe, fdattach, "fdc",
};
@@ -214,56 +253,55 @@ struct isa_driver fdcdriver = {
/*
* probe for existance of controller
*/
-int
+static int
fdprobe(dev)
struct isa_device *dev;
{
fdcu_t fdcu = dev->id_unit;
if(fdc_data[fdcu].flags & FDC_ATTACHED)
{
- printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ printf("fdc: same unit (%d) used multiple times\n", fdcu);
return 0;
}
fdc_data[fdcu].baseport = dev->id_iobase;
/* First - lets reset the floppy controller */
-
- outb(dev->id_iobase+fdout,0);
+ outb(dev->id_iobase+FDOUT, 0);
DELAY(100);
- outb(dev->id_iobase+fdout,FDO_FRST);
+ outb(dev->id_iobase+FDOUT, FDO_FRST);
/* see if it can handle a command */
- if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ if (out_fdc(fdcu, NE7CMD_SPECIFY) < 0)
{
return(0);
}
- out_fdc(fdcu,0xDF);
- out_fdc(fdcu,2);
+ out_fdc(fdcu, NE7_SPEC_1(3, 240));
+ out_fdc(fdcu, NE7_SPEC_2(2, 0));
return (IO_FDCSIZE);
}
/*
* wire controller into system, look for floppy units
*/
-int
+static int
fdattach(dev)
struct isa_device *dev;
{
- unsigned fdt,st0, cyl;
- int hdr;
+ unsigned fdt;
fdu_t fdu;
fdcu_t fdcu = dev->id_unit;
fdc_p fdc = fdc_data + fdcu;
fd_p fd;
- int fdsu;
+ int fdsu, st0;
struct isa_device *fdup;
fdc->fdcu = fdcu;
fdc->flags |= FDC_ATTACHED;
fdc->dmachan = dev->id_drq;
fdc->state = DEVIDLE;
- hdr = 0;
+ /* reset controller, turn motor off, clear fdout mirror reg */
+ outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
printf("fdc%d:", fdcu);
/* check for each floppy drive */
@@ -303,25 +341,33 @@ fdattach(dev)
continue;
}
-#ifdef notyet
/* select it */
- fd_turnon1(fdu);
- spinwait(1000); /* 1 sec */
- out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
- out_fdc(fdcu,fdsu);
+ set_motor(fdcu, fdsu, TURNON);
spinwait(1000); /* 1 sec */
+ out_fdc(fdcu, NE7CMD_SEEK); /* seek some steps... */
+ out_fdc(fdcu, fdsu);
+ out_fdc(fdcu, 10);
+ spinwait(300); /* ...wait a moment... */
+ out_fdc(fdcu, NE7CMD_SENSEI); /* make controller happy */
+ (void)in_fdc(fdcu);
+ (void)in_fdc(fdcu);
+ out_fdc(fdcu, NE7CMD_RECAL); /* ...and go back to 0 */
+ out_fdc(fdcu, fdsu);
+ spinwait(1000); /* a second be enough for full stroke seek */
/* anything responding */
- out_fdc(fdcu,NE7CMD_SENSEI);
+ out_fdc(fdcu, NE7CMD_SENSEI);
st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
- if (st0 & 0xd0)
+ (void)in_fdc(fdcu);
+ set_motor(fdcu, fdsu, TURNOFF);
+
+ if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
continue;
-#endif
fd->track = -2;
fd->fdc = fdc;
fd->fdsu = fdsu;
+ fd->options = 0;
printf(" [%d: fd%d: ", fdsu, fdu);
switch (fdt) {
@@ -346,15 +392,10 @@ fdattach(dev)
fd->type = NO_TYPE;
break;
}
-
- fd_turnoff((caddr_t)fdu, 0);
- hdr = 1;
}
printf("\n");
- /* Set transfer to 500kbps */
- outb(fdc->baseport+fdctl,0); /*XXX*/
- return 1;
+ return (1);
}
int
@@ -365,102 +406,47 @@ fdsize(dev)
}
/****************************************************************************/
-/* fdstrategy */
-/****************************************************************************/
-void fdstrategy(struct buf *bp)
-{
- register struct buf *dp,*dp0,*dp1;
- long nblocks,blknum;
- int s;
- fdcu_t fdcu;
- fdu_t fdu;
- fdc_p fdc;
- fd_p fd;
-
- fdu = FDUNIT(minor(bp->b_dev));
- fd = &fd_data[fdu];
- fdc = fd->fdc;
- fdcu = fdc->fdcu;
-
-#if NFT > 0
- /* check for controller already busy with tape */
- if (fdc->flags & FDC_TAPE_BUSY) {
- bp->b_error = EBUSY;
- bp->b_flags |= B_ERROR;
- return;
- }
-#endif
- if ((fdu >= NFD) || (bp->b_blkno < 0)) {
- printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
- fdu, bp->b_blkno, bp->b_bcount);
- pg("fd:error in fdstrategy");
- bp->b_error = EINVAL;
- bp->b_flags |= B_ERROR;
- goto bad;
- }
- /*
- * Set up block calculations.
- */
- blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
- nblocks = fd->ft->size;
- if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
- if (blknum == nblocks) {
- bp->b_resid = bp->b_bcount;
- } else {
- bp->b_error = ENOSPC;
- bp->b_flags |= B_ERROR;
- }
- goto bad;
- }
- bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
- dp = &(fdc->head);
- s = splbio();
- disksort(dp, bp);
- untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
- fdstart(fdcu);
- splx(s);
- return;
-
-bad:
- biodone(bp);
- return;
-}
-
-/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
/****************************************************************************/
-void
-set_motor(fdcu, fdu, reset)
+static void
+set_motor(fdcu, fdsu, turnon)
fdcu_t fdcu;
- fdu_t fdu;
- int reset;
+ int fdsu;
+ int turnon;
{
- int m0,m1;
- int selunit;
- fd_p fd;
- if(fd = fdc_data[fdcu].fd)/* yes an assign! */
- {
- selunit = fd->fdsu;
+ int fdout = fdc_data[fdcu].fdout;
+ int needspecify = 0;
+
+ if(turnon) {
+ fdout &= ~FDO_FDSEL;
+ fdout |= (FDO_MOEN0 << fdsu) + fdsu;
+ } else
+ fdout &= ~(FDO_MOEN0 << fdsu);
+
+ if(!turnon
+ && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
+ /* gonna turn off the last drive, put FDC to bed */
+ fdout &= ~ (FDO_FRST|FDO_FDMAEN);
+ else {
+ /* make sure controller is selected and specified */
+ if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
+ needspecify = 1;
+ fdout |= (FDO_FRST|FDO_FDMAEN);
}
- else
- {
- selunit = 0;
+
+ outb(fdc_data[fdcu].baseport+FDOUT, fdout);
+ fdc_data[fdcu].fdout = fdout;
+ TRACE1("[0x%x->FDOUT]", fdout);
+
+ if(needspecify) {
+ out_fdc(fdcu, NE7CMD_SPECIFY);
+ out_fdc(fdcu, NE7_SPEC_1(3, 240));
+ out_fdc(fdcu, NE7_SPEC_2(2, 0));
}
- m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
- m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
- outb(fdc_data[fdcu].baseport+fdout,
- selunit
- | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
- | (m0 ? FDO_MOEN0 : 0)
- | (m1 ? FDO_MOEN1 : 0));
- TRACE1("[0x%x->fdout]",(
- selunit
- | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
- | (m0 ? FDO_MOEN0 : 0)
- | (m1 ? FDO_MOEN1 : 0)));
}
+/* ARGSUSED */
static void
fd_turnoff(caddr_t arg1, int arg2)
{
@@ -470,11 +456,12 @@ fd_turnoff(caddr_t arg1, int arg2)
fd_p fd = fd_data + fdu;
s = splbio();
fd->flags &= ~FD_MOTOR;
- set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF);
splx(s);
}
-void
+/* ARGSUSED */
+static void
fd_motor_on(caddr_t arg1, int arg2)
{
fdu_t fdu = (fdu_t)arg1;
@@ -490,27 +477,39 @@ fd_motor_on(caddr_t arg1, int arg2)
splx(s);
}
-static void fd_turnon1(fdu_t);
-
-void
+static void
fd_turnon(fdu)
fdu_t fdu;
{
fd_p fd = fd_data + fdu;
if(!(fd->flags & FD_MOTOR))
{
- fd_turnon1(fdu);
- fd->flags |= FD_MOTOR_WAIT;
+ fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
+ set_motor(fd->fdc->fdcu, fd->fdsu, TURNON);
timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
}
}
static void
-fd_turnon1(fdu_t fdu)
+fdc_reset(fdc)
+ fdc_p fdc;
{
- fd_p fd = fd_data + fdu;
- fd->flags |= FD_MOTOR;
- set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ fdcu_t fdcu = fdc->fdcu;
+
+ /* Try a reset, keep motor on */
+ outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
+ TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
+ DELAY(100);
+ /* enable FDC, but defer interrupts a moment */
+ outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN);
+ TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
+ DELAY(100);
+ outb(fdc->baseport + FDOUT, fdc->fdout);
+ TRACE1("[0x%x->FDOUT]", fdc->fdout);
+
+ out_fdc(fdcu, NE7CMD_SPECIFY);
+ out_fdc(fdcu, NE7_SPEC_1(3, 240));
+ out_fdc(fdcu, NE7_SPEC_2(2, 0));
}
/****************************************************************************/
@@ -522,17 +521,17 @@ in_fdc(fdcu)
{
int baseport = fdc_data[fdcu].baseport;
int i, j = 100000;
- while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
!= (NE7_DIO|NE7_RQM) && j-- > 0)
if (i == NE7_RQM) return -1;
if (j <= 0)
return(-1);
#ifdef DEBUG
- i = inb(baseport+fddata);
- TRACE1("[fddata->0x%x]",(unsigned char)i);
+ i = inb(baseport+FDDATA);
+ TRACE1("[FDDATA->0x%x]", (unsigned char)i);
return(i);
#else
- return inb(baseport+fddata);
+ return inb(baseport+FDDATA);
#endif
}
@@ -546,17 +545,17 @@ out_fdc(fdcu, x)
/* Check that the direction bit is set */
i = 100000;
- while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
if (i <= 0) return (-1); /* Floppy timed out */
/* Check that the floppy controller is ready for a command */
i = 100000;
- while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
if (i <= 0) return (-1); /* Floppy timed out */
/* Send the command and return */
- outb(baseport+fddata,x);
- TRACE1("[0x%x->fddata]",x);
+ outb(baseport+FDDATA, x);
+ TRACE1("[0x%x->FDDATA]", x);
return (0);
}
@@ -647,17 +646,97 @@ fdclose(dev, flags)
int flags;
{
fdu_t fdu = FDUNIT(minor(dev));
- int type = FDTYPE(minor(dev));
#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
if (type & F_TAPE_TYPE)
- return ftclose(0);
+ return ftclose(dev, flags);
#endif
fd_data[fdu].flags &= ~FD_OPEN;
+ fd_data[fdu].options &= ~FDOPT_NORETRY;
return(0);
}
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void
+fdstrategy(struct buf *bp)
+{
+ register struct buf *dp;
+ long nblocks, blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+ size_t fdblk;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+ fdblk = 128 << (fd->ft->secsize);
+
+#if NFT > 0
+ if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
+ /* ft tapes do not (yet) support strategy i/o */
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+#endif
+ if (!(bp->b_flags & B_FORMAT)) {
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ if ((bp->b_bcount % fdblk) != 0) {
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ }
+
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/fdblk;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / fdblk) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
/***************************************************************\
* fdstart *
* We have just queued something.. if the controller is not busy *
@@ -671,9 +750,7 @@ static void
fdstart(fdcu)
fdcu_t fdcu;
{
- register struct buf *dp,*bp;
int s;
- fdu_t fdu;
s = splbio();
if(fdc_data[fdcu].state == DEVIDLE)
@@ -683,38 +760,43 @@ fdstart(fdcu)
splx(s);
}
+/* ARGSUSED */
static void
fd_timeout(caddr_t arg1, int arg2)
{
fdcu_t fdcu = (fdcu_t)arg1;
fdu_t fdu = fdc_data[fdcu].fdu;
- int st0, st3, cyl;
- struct buf *dp,*bp;
- int s;
+ int baseport = fdc_data[fdcu].baseport;
+ struct buf *dp, *bp;
+ int s;
dp = &fdc_data[fdcu].head;
- s = splbio();
bp = dp->b_actf;
- out_fdc(fdcu,NE7CMD_SENSED);
- out_fdc(fdcu,fd_data[fdu].hddrv);
- st3 = in_fdc(fdcu);
-
- out_fdc(fdcu,NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
- printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
- fdu,
- st0,
- NE7_ST0BITS,
- cyl,
- st3,
- NE7_ST3BITS);
+ /*
+ * Due to IBM's brain-dead design, the FDC has a faked ready
+ * signal, hardwired to ready == true. Thus, any command
+ * issued if there's no diskette in the drive will _never_
+ * complete, and must be aborted by resetting the FDC.
+ * Many thanks, Big Blue!
+ */
+
+ s = splbio();
+
+ TRACE1("fd%d[fd_timeout()]", fdu);
+ /* See if the controller is still busy (patiently awaiting data) */
+ if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB)
+ {
+ TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS));
+ /* yup, it is; kill it now */
+ fdc_reset(&fdc_data[fdcu]);
+ printf("fd%d: Operation timeout\n", fdu);
+ }
if (bp)
{
retrier(fdcu);
- fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].status[0] = NE7_ST0_IC_RC;
fdc_data[fdcu].state = IOTIMEDOUT;
if( fdc_data[fdcu].retry < 6)
fdc_data[fdcu].retry = 6;
@@ -730,11 +812,13 @@ fd_timeout(caddr_t arg1, int arg2)
}
/* just ensure it has the right spl */
+/* ARGSUSED */
static void
fd_pseudointr(caddr_t arg1, int arg2)
{
fdcu_t fdcu = (fdcu_t)arg1;
int s;
+
s = splbio();
fdintr(fdcu);
splx(s);
@@ -756,25 +840,26 @@ fdintr(fdcu_t fdcu)
(ftintr(fdu));
else
#endif
- while(fdstate(fdcu, fdc))
- ;
+ while(fdstate(fdcu, fdc))
+ ;
}
/***********************************************************************\
* The controller state machine. *
* if it returns a non zero value, it should be called again immediatly *
\***********************************************************************/
-int
+static int
fdstate(fdcu, fdc)
fdcu_t fdcu;
fdc_p fdc;
{
- int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ int read, format, head, sec = 0, i = 0, sectrac, st0, cyl, st3;
unsigned long blknum;
fdu_t fdu = fdc->fdu;
fd_p fd;
- register struct buf *dp,*bp;
+ register struct buf *dp, *bp;
struct fd_formb *finfo = NULL;
+ size_t fdblk;
dp = &(fdc->head);
bp = dp->b_actf;
@@ -787,16 +872,17 @@ fdstate(fdcu, fdc)
fdc->state = DEVIDLE;
if(fdc->fd)
{
- printf("unexpected valid fd pointer (fdu = %d)\n"
- ,fdc->fdu);
+ printf("unexpected valid fd pointer (fdu = %d)\n",
+ fdc->fdu);
fdc->fd = (fd_p) 0;
fdc->fdu = -1;
}
- TRACE1("[fdc%d IDLE]",fdcu);
+ TRACE1("[fdc%d IDLE]", fdcu);
return(0);
}
fdu = FDUNIT(minor(bp->b_dev));
fd = fd_data + fdu;
+ fdblk = 128 << fd->ft->secsize;
if (fdc->fd && (fd != fdc->fd))
{
printf("confused fd pointers\n");
@@ -805,9 +891,9 @@ fdstate(fdcu, fdc)
format = bp->b_flags & B_FORMAT;
if(format)
finfo = (struct fd_formb *)bp->b_un.b_addr;
- TRACE1("fd%d",fdu);
- TRACE1("[%s]",fdstates[fdc->state]);
- TRACE1("(0x%x)",fd->flags);
+ TRACE1("fd%d", fdu);
+ TRACE1("[%s]", fdstates[fdc->state]);
+ TRACE1("(0x%x)", fd->flags);
untimeout(fd_turnoff, (caddr_t)fdu);
timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
switch (fdc->state)
@@ -818,6 +904,8 @@ fdstate(fdcu, fdc)
fd->skip = 0;
fdc->fd = fd;
fdc->fdu = fdu;
+ outb(fdc->baseport+FDCTL, fd->ft->trans);
+ TRACE1("[0x%x->FDCTL]", fd->ft->trans);
/*******************************************************\
* If the next drive has a motor startup pending, then *
* it will start up in it's own good time *
@@ -838,7 +926,7 @@ fdstate(fdcu, fdc)
}
else /* at least make sure we are selected */
{
- set_motor(fdcu,fd->fdsu,0);
+ set_motor(fdcu, fd->fdsu, TURNON);
}
fdc->state = DOSEEK;
break;
@@ -848,33 +936,55 @@ fdstate(fdcu, fdc)
fdc->state = SEEKCOMPLETE;
break;
}
- out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
- out_fdc(fdcu,fd->fdsu); /* Drive number */
- out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ out_fdc(fdcu, NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu, fd->fdsu); /* Drive number */
+ out_fdc(fdcu, bp->b_cylin * fd->ft->steptrac);
fd->track = -2;
fdc->state = SEEKWAIT;
- timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
return(0); /* will return later */
case SEEKWAIT:
- untimeout(fd_timeout, (caddr_t)fdcu);
/* allow heads to settle */
- timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32);
fdc->state = SEEKCOMPLETE;
return(0); /* will return later */
- break;
-
case SEEKCOMPLETE : /* SEEK DONE, START DMA */
/* Make sure seek really happened*/
if(fd->track == -2)
{
int descyl = bp->b_cylin * fd->ft->steptrac;
- out_fdc(fdcu,NE7CMD_SENSEI);
- i = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
+ do {
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ /*
+ * if this was a "ready changed" interrupt,
+ * fetch status again (can happen after
+ * enabling controller from reset state)
+ */
+ } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+ if (0 == descyl)
+ {
+ /*
+ * seek to cyl 0 requested; make sure we are
+ * really there
+ */
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, fdu);
+ st3 = in_fdc(fdcu);
+ if ((st3 & NE7_ST3_T0) == 0) {
+ printf(
+ "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
+ fdu, st3, NE7_ST3BITS);
+ if(fdc->retry < 3)
+ fdc->retry = 3;
+ return(retrier(fdcu));
+ }
+ }
if (cyl != descyl)
{
- printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
- fdu, descyl, cyl, i, NE7_ST0BITS);
+ printf(
+ "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, st0, NE7_ST0BITS);
return(retrier(fdcu));
}
}
@@ -884,46 +994,73 @@ fdstate(fdcu, fdc)
fd->skip = (char *)&(finfo->fd_formb_cylno(0))
- (char *)finfo;
isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
- format ? bp->b_bcount : FDBLK, fdc->dmachan);
- blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
- + fd->skip/FDBLK;
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk
+ + fd->skip/fdblk;
sectrac = fd->ft->sectrac;
sec = blknum % (sectrac * fd->ft->heads);
head = sec / sectrac;
sec = sec % sectrac + 1;
-/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format || !read)
+ {
+ /* make sure the drive is writable */
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, fdu);
+ st3 = in_fdc(fdcu);
+ if(st3 & NE7_ST3_WP)
+ {
+ /*
+ * XXX YES! this is ugly.
+ * in order to force the current operation
+ * to fail, we will have to fake an FDC
+ * error - all error handling is done
+ * by the retrier()
+ */
+ fdc->status[0] = NE7_ST0_IC_AT;
+ fdc->status[1] = NE7_ST1_NW;
+ fdc->status[2] = 0;
+ fdc->status[3] = fd->track;
+ fdc->status[4] = head;
+ fdc->status[5] = sec;
+ fdc->retry = 8; /* break out immediately */
+ fdc->state = IOTIMEDOUT; /* not really... */
+ return (1);
+ }
+ }
if(format)
{
/* formatting */
- out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
- out_fdc(fdcu,head << 2 | fdu);
- out_fdc(fdcu,finfo->fd_formb_secshift);
- out_fdc(fdcu,finfo->fd_formb_nsecs);
- out_fdc(fdcu,finfo->fd_formb_gaplen);
- out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ out_fdc(fdcu, NE7CMD_FORMAT);
+ out_fdc(fdcu, head << 2 | fdu);
+ out_fdc(fdcu, finfo->fd_formb_secshift);
+ out_fdc(fdcu, finfo->fd_formb_nsecs);
+ out_fdc(fdcu, finfo->fd_formb_gaplen);
+ out_fdc(fdcu, finfo->fd_formb_fillbyte);
}
else
{
if (read)
{
- out_fdc(fdcu,NE7CMD_READ); /* READ */
+ out_fdc(fdcu, NE7CMD_READ); /* READ */
}
else
{
- out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ out_fdc(fdcu, NE7CMD_WRITE); /* WRITE */
}
- out_fdc(fdcu,head << 2 | fdu); /* head & unit */
- out_fdc(fdcu,fd->track); /* track */
- out_fdc(fdcu,head);
- out_fdc(fdcu,sec); /* sector XXX +1? */
- out_fdc(fdcu,fd->ft->secsize); /* sector size */
- out_fdc(fdcu,sectrac); /* sectors/track */
- out_fdc(fdcu,fd->ft->gap); /* gap size */
- out_fdc(fdcu,fd->ft->datalen); /* data length */
+ out_fdc(fdcu, head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu, fd->track); /* track */
+ out_fdc(fdcu, head);
+ out_fdc(fdcu, sec); /* sector XXX +1? */
+ out_fdc(fdcu, fd->ft->secsize); /* sector size */
+ out_fdc(fdcu, sectrac); /* sectors/track */
+ out_fdc(fdcu, fd->ft->gap); /* gap size */
+ out_fdc(fdcu, fd->ft->datalen); /* data length */
}
fdc->state = IOCOMPLETE;
- timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ timeout(fd_timeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
case IOCOMPLETE: /* IO DONE, post-analyze */
untimeout(fd_timeout, (caddr_t)fdcu);
@@ -931,30 +1068,43 @@ fdstate(fdcu, fdc)
{
fdc->status[i] = in_fdc(fdcu);
}
- case IOTIMEDOUT: /*XXX*/
+ fdc->state = IOTIMEDOUT;
+ /* FALLTHROUGH */
+ case IOTIMEDOUT:
isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
- format ? bp->b_bcount : FDBLK, fdc->dmachan);
- if (fdc->status[0]&0xF8)
+ format ? bp->b_bcount : fdblk, fdc->dmachan);
+ if (fdc->status[0] & NE7_ST0_IC)
{
- if (fdc->status[1] & 0x10) {
+ if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
+ && fdc->status[1] & NE7_ST1_OR) {
/*
- * Operation not completed in reasonable time.
- * Just restart it, don't increment retry count.
- * (vak)
+ * DMA overrun. Someone hogged the bus
+ * and didn't release it in time for the
+ * next FDC transfer.
+ * Just restart it, don't increment retry
+ * count. (vak)
*/
fdc->state = SEEKCOMPLETE;
return (1);
}
+ else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
+ && fdc->retry < 6)
+ fdc->retry = 6; /* force a reset */
+ else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
+ && fdc->status[2] & NE7_ST2_WC
+ && fdc->retry < 3)
+ fdc->retry = 3; /* force recalibrate */
return(retrier(fdcu));
}
/* All OK */
- fd->skip += FDBLK;
+ fd->skip += fdblk;
if (!format && fd->skip < bp->b_bcount)
{
/* set up next transfer */
- blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
- + fd->skip/FDBLK;
- bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk
+ + fd->skip/fdblk;
+ bp->b_cylin =
+ (blknum / (fd->ft->sectrac * fd->ft->heads));
fdc->state = DOSEEK;
}
else
@@ -970,68 +1120,76 @@ fdstate(fdcu, fdc)
}
return(1);
case RESETCTLR:
- /* Try a reset, keep motor on */
- set_motor(fdcu,fd->fdsu,1);
- DELAY(100);
- set_motor(fdcu,fd->fdsu,0);
- outb(fdc->baseport+fdctl,fd->ft->trans);
- TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc_reset(fdc);
fdc->retry++;
fdc->state = STARTRECAL;
break;
case STARTRECAL:
- out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
- out_fdc(fdcu,0xDF);
- out_fdc(fdcu,2);
- out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
- out_fdc(fdcu,fdu);
+ out_fdc(fdcu, NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu, fdu);
fdc->state = RECALWAIT;
return(0); /* will return later */
case RECALWAIT:
/* allow heads to settle */
- timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32);
fdc->state = RECALCOMPLETE;
return(0); /* will return later */
case RECALCOMPLETE:
- out_fdc(fdcu,NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
- if (cyl != 0)
+ do {
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ /*
+ * if this was a "ready changed" interrupt,
+ * fetch status again (can happen after
+ * enabling controller from reset state)
+ */
+ } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+ if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
{
printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
st0, NE7_ST0BITS, cyl);
+ if(fdc->retry < 3) fdc->retry = 3;
return(retrier(fdcu));
}
fd->track = 0;
/* Seek (probably) necessary */
fdc->state = DOSEEK;
return(1); /* will return immediatly */
- case MOTORWAIT:
+ case MOTORWAIT:
if(fd->flags & FD_MOTOR_WAIT)
{
return(0); /* time's not up yet */
}
- fdc->state = DOSEEK;
+ /*
+ * since the controller was off, it has lost its
+ * idea about the current track it were; thus,
+ * recalibrate the bastard
+ */
+ fdc->state = STARTRECAL;
return(1); /* will return immediatly */
default:
printf("Unexpected FD int->");
- out_fdc(fdcu,NE7CMD_SENSEI);
+ out_fdc(fdcu, NE7CMD_SENSEI);
st0 = in_fdc(fdcu);
cyl = in_fdc(fdcu);
- printf("ST0 = %lx, PCN = %lx\n",i,sec);
- out_fdc(fdcu,0x4A);
- out_fdc(fdcu,fd->fdsu);
+ printf("ST0 = %x, PCN = %x\n", st0, cyl);
+ out_fdc(fdcu, NE7CMD_READID);
+ out_fdc(fdcu, fd->fdsu);
for(i=0;i<7;i++) {
fdc->status[i] = in_fdc(fdcu);
}
- printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
- fdc->status[0],
- fdc->status[1],
- fdc->status[2],
- fdc->status[3],
- fdc->status[4],
- fdc->status[5],
- fdc->status[6] );
+ if(fdc->status[0] != -1)
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx\n",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ else
+ printf("FDC timed out\n");
return(0);
}
return(1); /* Come back immediatly to new state */
@@ -1042,11 +1200,13 @@ retrier(fdcu)
fdcu_t fdcu;
{
fdc_p fdc = fdc_data + fdcu;
- register struct buf *dp,*bp;
+ register struct buf *dp, *bp;
dp = &(fdc->head);
bp = dp->b_actf;
+ if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY)
+ goto fail;
switch(fdc->retry)
{
case 0: case 1: case 2:
@@ -1061,12 +1221,15 @@ retrier(fdcu)
case 7:
break;
default:
+ fail:
{
dev_t sav_b_dev = bp->b_dev;
/* Trick diskerr */
- bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ bp->b_dev = makedev(major(bp->b_dev),
+ (FDUNIT(minor(bp->b_dev))<<3)|3);
diskerr(bp, "fd", "hard error", LOG_PRINTF,
- fdc->fd->skip, (struct disklabel *)NULL);
+ fdc->fd->skip / DEV_BSIZE,
+ (struct disklabel *)NULL);
bp->b_dev = sav_b_dev;
printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
@@ -1101,9 +1264,11 @@ fdformat(dev, finfo, p)
struct buf *bp;
int rv = 0, s;
-
+ size_t fdblk;
+
fdu = FDUNIT(minor(dev));
fd = &fd_data[fdu];
+ fdblk = 128 << fd->ft->secsize;
/* set up a buffer header for fdstrategy() */
bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
@@ -1119,7 +1284,7 @@ fdformat(dev, finfo, p)
* seek to the requested cylinder
*/
bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
- + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+ + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
bp->b_un.b_addr = (caddr_t)finfo;
@@ -1138,41 +1303,39 @@ fdformat(dev, finfo, p)
splx(s);
if(rv == EWOULDBLOCK)
- {
/* timed out */
- biodone(bp);
rv = EIO;
- }
+ if(bp->b_flags & B_ERROR)
+ rv = bp->b_error;
+ biodone(bp);
free(bp, M_TEMP);
return rv;
}
/*
- * fdioctl() from jc@irbs.UUCP (John Capo)
- * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
- * defines fdioctl to be enxio.
*
- * TODO: Reformat.
- * Think about allocating buffer off stack.
+ * TODO: Think about allocating buffer off stack.
* Don't pass uncast 0's and NULL's to read/write/setdisklabel().
* Watch out for NetBSD's different *disklabel() interface.
*
- * Added functionality for floppy formatting
- * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
*/
int
-fdioctl (dev, cmd, addr, flag, p)
+fdioctl(dev, cmd, addr, flag, p)
dev_t dev;
int cmd;
caddr_t addr;
int flag;
struct proc *p;
{
+ fdu_t fdu = FDUNIT(minor(dev));
+ fd_p fd = &fd_data[fdu];
+ size_t fdblk;
+
struct fd_type *fdt;
struct disklabel *dl;
char buffer[DEV_BSIZE];
- int error;
+ int error = 0;
#if NFT > 0
int type = FDTYPE(minor(dev));
@@ -1182,14 +1345,14 @@ fdioctl (dev, cmd, addr, flag, p)
return ftioctl(dev, cmd, addr, flag, p);
#endif
- error = 0;
+ fdblk = 128 << fd->ft->secsize;
switch (cmd)
{
case DIOCGDINFO:
bzero(buffer, sizeof (buffer));
dl = (struct disklabel *)buffer;
- dl->d_secsize = FDBLK;
+ dl->d_secsize = fdblk;
fdt = fd_data[FDUNIT(minor(dev))].ft;
dl->d_secpercyl = fdt->size / fdt->tracks;
dl->d_type = DTYPE_FLOPPY;
@@ -1221,12 +1384,12 @@ fdioctl (dev, cmd, addr, flag, p)
dl = (struct disklabel *)addr;
- if (error = setdisklabel ((struct disklabel *)buffer,
- dl, 0, NULL))
+ if ((error =
+ setdisklabel ((struct disklabel *)buffer, dl, 0, NULL)))
break;
error = writedisklabel(dev, fdstrategy,
- (struct disklabel *)buffer, NULL);
+ (struct disklabel *)buffer, NULL);
break;
case FD_FORM:
@@ -1243,11 +1406,42 @@ fdioctl (dev, cmd, addr, flag, p)
*(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
break;
+ case FD_STYPE: /* set drive type */
+ /* this is considered harmful; only allow for superuser */
+ if(suser(p->p_ucred, &p->p_acflag) != 0)
+ return EPERM;
+ *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr;
+ break;
+
+ case FD_GOPTS: /* get drive options */
+ *(int *)addr = fd_data[FDUNIT(minor(dev))].options;
+ break;
+
+ case FD_SOPTS: /* set drive options */
+ fd_data[FDUNIT(minor(dev))].options = *(int *)addr;
+ break;
+
default:
- error = EINVAL;
+ error = ENOTTY;
break;
}
return (error);
}
#endif
+/*
+ * Hello emacs, these are the
+ * Local Variables:
+ * c-indent-level: 8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * c-brace-offset: -8
+ * c-brace-imaginary-offset: 0
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c++-hanging-braces: 1
+ * c++-access-specifier-offset: -8
+ * c++-empty-arglist-indent: 8
+ * c++-friend-offset: 0
+ * End:
+ */
diff --git a/sys/i386/isa/fdc.h b/sys/i386/isa/fdc.h
index 7d75d5a81b48..ef81b11a8387 100644
--- a/sys/i386/isa/fdc.h
+++ b/sys/i386/isa/fdc.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fdc.h,v 1.2 1994/02/14 22:24:25 nate Exp $
+ * $Id: fdc.h,v 1.3 1994/05/22 12:35:38 joerg Exp $
*
*/
@@ -49,12 +49,12 @@ struct fdc_data
#define FDC_HASFTAPE 0x02
#define FDC_TAPE_BUSY 0x04
struct fd_data *fd;
- int fdu; /* the active drive */
+ int fdu; /* the active drive */
+ int state;
+ int retry;
+ int fdout; /* mirror of the w/o digital output reg */
+ int status[7]; /* copy of the registers */
struct buf head; /* Head of buf chain */
- struct buf rhead; /* Raw head of buf chain */
- int state;
- int retry;
- int status[7]; /* copy of the registers */
};
/***********************************************************************\
diff --git a/sys/i386/isa/fdreg.h b/sys/i386/isa/fdreg.h
index b0e9593a93c5..9b5be2b87b1c 100644
--- a/sys/i386/isa/fdreg.h
+++ b/sys/i386/isa/fdreg.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
- * $Id: fdreg.h,v 1.4 1994/02/07 22:12:42 alm Exp $
+ * $Id: fdreg.h,v 1.5 1994/05/22 12:35:40 joerg Exp $
*/
/*
@@ -42,24 +42,26 @@
#include "../i386/isa/ic/nec765.h"
/* registers */
-#define fdout 2 /* Digital Output Register (W) */
+#define FDOUT 2 /* Digital Output Register (W) */
#define FDO_FDSEL 0x03 /* floppy device select */
#define FDO_FRST 0x04 /* floppy controller reset */
#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
#define FDO_MOEN0 0x10 /* motor enable drive 0 */
#define FDO_MOEN1 0x20 /* motor enable drive 1 */
-#define FDO_MOEN2 0x30 /* motor enable drive 2 */
-#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+#define FDO_MOEN2 0x40 /* motor enable drive 2 */
+#define FDO_MOEN3 0x80 /* motor enable drive 3 */
-#define fdsts 4 /* NEC 765 Main Status Register (R) */
-#define fddata 5 /* NEC 765 Data Register (R/W) */
+#define FDSTS 4 /* NEC 765 Main Status Register (R) */
+#define FDDATA 5 /* NEC 765 Data Register (R/W) */
-#define fdctl 7 /* Control Register (W) */
+#define FDCTL 7 /* Control Register (W) */
#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+ /* for some controllers 1MPBS instead */
-#define fdin 7 /* Digital Input Register (R) */
+#define FDIN 7 /* Digital Input Register (R) */
#define FDI_DCHG 0x80 /* diskette has been changed */
-
+ /* requires drive and motor being selected */
+ /* is cleared by any step pulse to drive */
diff --git a/sys/i386/isa/ft.c b/sys/i386/isa/ft.c
index 09bc127090aa..1204613bcd8e 100644
--- a/sys/i386/isa/ft.c
+++ b/sys/i386/isa/ft.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Steve Gerakines
+ * Copyright (c) 1993, 1994 Steve Gerakines
*
* This is freely redistributable software. You may do anything you
* wish with it, so long as the above notice stays intact.
@@ -17,8 +17,15 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* ft.c - QIC-40/80 floppy tape driver
- * $Id: ft.c,v 1.4 1994/02/14 22:24:28 nate Exp $
+ * $Id: ft.c,v 1.7 1994/06/22 05:52:36 jkh Exp $
*
+ * 06/07/94 v0.9 ++sg
+ * Tape stuck on segment problem should be gone. Re-wrote buffering
+ * scheme. Added support for drives that do not automatically perform
+ * seek load point. Can handle more wakeup types now and should correctly
+ * report most manufacturer names. Fixed places where unit 0 was being
+ * sent to the fdc instead of the actual unit number. Added ioctl support
+ * for an in-core badmap.
*
* 01/26/94 v0.3b - Jim Babb
* Got rid of the hard coded device selection. Moved (some of) the
@@ -76,12 +83,13 @@
#include "ftreg.h"
/* Enable or disable debugging messages. */
-#define FTDBGALL 0 /* everything */
-/* #define DPRT(a) printf a */
-#define DPRT(a)
+#define FTDBGALL 0 /* 1 if you want everything */
+/*#define DPRT(a) printf a */
+#define DPRT(a)
/* Constants private to the driver */
#define FTPRI (PRIBIO) /* sleep priority */
+#define FTNBUFF 9 /* 8 for buffering, 1 for header */
/* The following items are needed from the fd driver. */
extern int in_fdc(int); /* read fdc registers */
@@ -92,11 +100,13 @@ extern int hz; /* system clock rate */
/* Type of tape attached */
/* use numbers that don't interfere with the possible floppy types */
#define NO_TYPE 0 /* (same as NO_TYPE in fd.c) */
- /* F_TAPE_TYPE must match value in fd.c */
-#define F_TAPE_TYPE 0x020 /* bit for ft->types to indicate tape */
-#define FT_MOUNTAIN (F_TAPE_TYPE | 1)
-#define FT_COLORADO (F_TAPE_TYPE | 2)
+/* F_TAPE_TYPE must match value in fd.c */
+#define F_TAPE_TYPE 0x020 /* bit for ft->types to indicate tape */
+#define FT_NONE (F_TAPE_TYPE | 0) /* no method required */
+#define FT_MOUNTAIN (F_TAPE_TYPE | 1) /* mountain */
+#define FT_COLORADO (F_TAPE_TYPE | 2) /* colorado */
+#define FT_INSIGHT (F_TAPE_TYPE | 3) /* insight */
/* Mode FDC is currently in: tape or disk */
enum { FDC_TAPE_MODE, FDC_DISK_MODE };
@@ -150,15 +160,25 @@ QIC_Geom *ftg = NULL; /* Current tape's geometry */
/*
* things relating to asynchronous commands
*/
-static int astk_depth; /* async_cmd stack depth */
static int awr_state; /* state of async write */
static int ard_state; /* state of async read */
static int arq_state; /* state of async request */
static int async_retries; /* retries, one per invocation */
static int async_func; /* function to perform */
static int async_state; /* state current function is at */
-static int async_arg[5]; /* up to 5 arguments for async cmds */
+static int async_arg0; /* up to 3 arguments for async cmds */
+static int async_arg1; /**/
+static int async_arg2; /**/
static int async_ret; /* return value */
+static struct _astk {
+ int over_func;
+ int over_state;
+ int over_retries;
+ int over_arg0;
+ int over_arg1;
+ int over_arg2;
+} astk[10];
+static struct _astk *astk_ptr = &astk[0]; /* Pointer to stack position */
/* List of valid async (interrupt driven) tape support functions. */
enum {
@@ -172,29 +192,36 @@ enum {
};
/* Call another asyncronous command from within async_cmd(). */
-#define CALL_ACMD(r,f,a,b,c,d,e) \
- astk[astk_depth].over_retries = async_retries; \
- astk[astk_depth].over_func = async_func; \
- astk[astk_depth].over_state = (r); \
- for (i = 0; i < 5; i++) \
- astk[astk_depth].over_arg[i] = async_arg[i]; \
+#define CALL_ACMD(r,f,a,b,c) \
+ astk_ptr->over_retries = async_retries; \
+ astk_ptr->over_func = async_func; \
+ astk_ptr->over_state = (r); \
+ astk_ptr->over_arg0 = async_arg0; \
+ astk_ptr->over_arg1 = async_arg1; \
+ astk_ptr->over_arg2 = async_arg2; \
async_func = (f); async_state = 0; async_retries = 0; \
- async_arg[0]=(a); async_arg[1]=(b); async_arg[2]=(c); \
- async_arg[3]=(d); async_arg[4]=(e); \
- astk_depth++; \
+ async_arg0=(a); async_arg1=(b); async_arg2=(c); \
+ astk_ptr++; \
goto restate
/* Perform an asyncronous command from outside async_cmd(). */
-#define ACMD_FUNC(r,f,a,b,c,d,e) over_async = (r); astk_depth = 0; \
+#define ACMD_FUNC(r,f,a,b,c) over_async = (r); astk_ptr = &astk[0]; \
async_func = (f); async_state = 0; async_retries = 0; \
- async_arg[0]=(a); async_arg[1]=(b); async_arg[2]=(c); \
- async_arg[3]=(d); async_arg[4]=(e); \
+ async_arg0=(a); async_arg1=(b); async_arg2=(c); \
async_cmd(ftu); \
return
/* Various wait channels */
+static char *wc_buff_avail = "bavail";
+static char *wc_buff_done = "bdone";
+static char *wc_iosts_change = "iochg";
+static char *wc_long_delay = "ldelay";
+static char *wc_intr_wait = "intrw";
+#define ftsleep(wc,to) tsleep((caddr_t)(wc),FTPRI,(wc),(to))
+
static struct {
int buff_avail;
+ int buff_done;
int iosts_change;
int long_delay;
int intr_wait;
@@ -223,8 +250,17 @@ struct ft_data {
unsigned char *xptr; /* pointer to buffer blk to xfer */
int xcnt; /* transfer count */
int xblk; /* block number to transfer */
- SegReq *curseg; /* Current segment to do I/O on */
- SegReq *bufseg; /* Buffered segment to r/w ahead */
+ int xseg; /* segment being transferred */
+ SegReq *segh; /* Current I/O request */
+ SegReq *segt; /* Tail of queued I/O requests */
+ SegReq *doneh; /* Completed I/O request queue */
+ SegReq *donet; /* Completed I/O request tail */
+ SegReq *segfree; /* Free segments */
+ SegReq *hdr; /* Current tape header */
+ int nsegq; /* Segments on request queue */
+ int ndoneq; /* Segments on completed queue */
+ int nfreelist; /* Segments on free list */
+
/* the next 3 should be defines in 'flags' */
int active; /* TRUE if transfer is active */
int rdonly; /* TRUE if tape is read-only */
@@ -261,85 +297,237 @@ void ftstrategy(struct buf *);
int ftioctl(dev_t, int, caddr_t, int, struct proc *);
int ftdump(dev_t);
int ftsize(dev_t);
-static void ft_timeout(caddr_t arg1, int arg2);
-void async_cmd(ftu_t);
-void async_req(ftu_t, int);
-void async_read(ftu_t, int);
-void async_write(ftu_t, int);
-void tape_start(ftu_t);
-void tape_end(ftu_t);
-void tape_inactive(ftu_t);
+static void ft_timeout(caddr_t, int);
+static void async_cmd(ftu_t);
+static void async_req(ftu_t, int);
+static void async_read(ftu_t, int);
+static void async_write(ftu_t, int);
+static void tape_start(ftu_t, int);
+static void tape_end(ftu_t);
+static void tape_inactive(ftu_t);
+static int tape_cmd(ftu_t, int);
+static int tape_status(ftu_t);
+static int qic_status(ftu_t, int, int);
+static int ftreq_rewind(ftu_t);
+static int ftreq_hwinfo(ftu_t, QIC_HWInfo *);
+
+/*****************************************************************************/
+
+
+/*
+ * Allocate a segment I/O buffer from the free list.
+ */
+static SegReq *
+segio_alloc(ft_p ft)
+{
+ SegReq *r;
+
+ /* Grab first item from free list */
+ if ((r = ft->segfree) != NULL) {
+ ft->segfree = ft->segfree->next;
+ ft->nfreelist--;
+ }
+ DPRT(("segio_alloc: nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+ return(r);
+}
+
+
+/*
+ * Queue a segment I/O request.
+ */
+static void
+segio_queue(ft_p ft, SegReq *sp)
+{
+ /* Put request on in process queue. */
+ if (ft->segt == NULL)
+ ft->segh = sp;
+ else
+ ft->segt->next = sp;
+ sp->next = NULL;
+ ft->segt = sp;
+ ft->nsegq++;
+ DPRT(("segio_queue: nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+}
+/*
+ * Segment I/O completed, place on correct queue.
+ */
+static void
+segio_done(ft_p ft, SegReq *sp)
+{
+ /* First remove from current I/O queue */
+ ft->segh = sp->next;
+ if (ft->segh == NULL) ft->segt = NULL;
+ ft->nsegq--;
+
+ if (sp->reqtype == FTIO_WRITING) {
+ /* Place on free list */
+ sp->next = ft->segfree;
+ ft->segfree = sp;
+ ft->nfreelist++;
+ wakeup((caddr_t)wc_buff_avail);
+ DPRT(("segio_done: (w) nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+ } else {
+ /* Put on completed I/O queue */
+ if (ft->donet == NULL)
+ ft->doneh = sp;
+ else
+ ft->donet->next = sp;
+ sp->next = NULL;
+ ft->donet = sp;
+ ft->ndoneq++;
+ wakeup((caddr_t)wc_buff_done);
+ DPRT(("segio_done: (r) nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+ }
+}
+/*
+ * Take I/O request from finished queue to free queue.
+ */
+static void
+segio_free(ft_p ft, SegReq *sp)
+{
+ /* First remove from done queue */
+ ft->doneh = sp->next;
+ if (ft->doneh == NULL) ft->donet = NULL;
+ ft->ndoneq--;
+
+ /* Place on free list */
+ sp->next = ft->segfree;
+ ft->segfree = sp;
+ ft->nfreelist++;
+ wakeup((caddr_t)wc_buff_avail);
+ DPRT(("segio_free: nfree=%d ndone=%d nreq=%d\n", ft->nfreelist, ft->ndoneq, ft->nsegq));
+}
+
/*
* Probe/attach floppy tapes.
*/
-int ftattach(isadev, fdup)
+int
+ftattach(isadev, fdup)
struct isa_device *isadev, *fdup;
{
- fdcu_t fdcu = isadev->id_unit; /* fdc active unit */
- fdc_p fdc = fdc_data + fdcu; /* pointer to controller structure */
- ftu_t ftu = fdup->id_unit;
- ft_p ft;
- ftsu_t ftsu = fdup->id_physid;
-
- if (ftu >= NFT)
- return 0;
- ft = &ft_data[ftu];
- /* Probe for tape */
- ft->attaching = 1;
- ft->type = NO_TYPE;
- ft->fdc = fdc;
- ft->ftsu = ftsu;
-
- tape_start(ftu); /* ready controller for tape */
- tape_cmd(ftu, QC_COL_ENABLE1);
- tape_cmd(ftu, QC_COL_ENABLE2);
- if (tape_status(ftu) >= 0) {
- ft->type = FT_COLORADO;
- fdc->flags |= FDC_HASFTAPE;
- printf(" [%d: ft%d: Colorado tape]",
- fdup->id_physid, fdup->id_unit );
- tape_cmd(ftu, QC_COL_DISABLE);
- goto out;
- }
+ fdcu_t fdcu = isadev->id_unit; /* fdc active unit */
+ fdc_p fdc = fdc_data + fdcu; /* pointer to controller structure */
+ ftu_t ftu = fdup->id_unit;
+ ft_p ft;
+ ftsu_t ftsu = fdup->id_physid;
+ QIC_HWInfo hw;
+ char *manu;
+
+ if (ftu >= NFT) return 0;
+ ft = &ft_data[ftu];
+
+ /* Probe for tape */
+ ft->attaching = 1;
+ ft->type = NO_TYPE;
+ ft->fdc = fdc;
+ ft->ftsu = ftsu;
- tape_start(ftu); /* ready controller for tape */
- tape_cmd(ftu, QC_MTN_ENABLE1);
- tape_cmd(ftu, QC_MTN_ENABLE2);
- if (tape_status(ftu) >= 0) {
- ft->type = FT_MOUNTAIN;
- fdc->flags |= FDC_HASFTAPE;
- printf(" [%d: ft%d: Mountain tape]",
- fdup->id_physid, fdup->id_unit );
- tape_cmd(ftu, QC_MTN_DISABLE);
- goto out;
- }
+ /*
+ * FT_NONE - no method, just do it
+ */
+ tape_start(ftu, 0);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_NONE;
+ ftreq_hwinfo(ftu, &hw);
+ goto out;
+ }
+
+ /*
+ * FT_COLORADO - colorado style
+ */
+ tape_start(ftu, 0);
+ tape_cmd(ftu, QC_COL_ENABLE1);
+ tape_cmd(ftu, QC_COL_ENABLE2 + ftu);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_COLORADO;
+ ftreq_hwinfo(ftu, &hw);
+ tape_cmd(ftu, QC_COL_DISABLE);
+ goto out;
+ }
+
+ /*
+ * FT_MOUNTAIN - mountain style
+ */
+ tape_start(ftu, 0);
+ tape_cmd(ftu, QC_MTN_ENABLE1);
+ tape_cmd(ftu, QC_MTN_ENABLE2);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_MOUNTAIN;
+ ftreq_hwinfo(ftu, &hw);
+ tape_cmd(ftu, QC_MTN_DISABLE);
+ goto out;
+ }
+
+ /*
+ * FT_INSIGHT - insight style
+ */
+ tape_start(ftu, 1);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_INSIGHT;
+ ftreq_hwinfo(ftu, &hw);
+ goto out;
+ }
out:
- tape_end(ftu);
- ft->attaching = 0;
- return(ft->type);
+ tape_end(ftu);
+ if (ft->type != NO_TYPE) {
+ fdc->flags |= FDC_HASFTAPE;
+ switch(hw.hw_make) {
+ case 0x0000:
+ if (ft->type == FT_COLORADO)
+ manu = "Colorado";
+ else if (ft->type == FT_INSIGHT)
+ manu = "Insight";
+ else if (ft->type == FT_MOUNTAIN && hw.hw_model == 0x05)
+ manu = "Archive";
+ else if (ft->type == FT_MOUNTAIN)
+ manu = "Mountain";
+ else
+ manu = "Unknown";
+ break;
+ case 0x0001:
+ manu = "Colorado";
+ break;
+ case 0x0005:
+ if (hw.hw_model >= 0x09)
+ manu = "Conner";
+ else
+ manu = "Archive";
+ break;
+ case 0x0006:
+ manu = "Mountain";
+ break;
+ case 0x0007:
+ manu = "Wangtek";
+ break;
+ case 0x0222:
+ manu = "IOMega";
+ break;
+ default:
+ manu = "Unknown";
+ break;
+ }
+ printf(" [%d: ft%d: %s tape]", fdup->id_physid, fdup->id_unit, manu);
+ }
+ ft->attaching = 0;
+ return(ft->type);
}
/*
* Perform common commands asynchronously.
*/
-void async_cmd(ftu_t ftu) {
+static void
+async_cmd(ftu_t ftu) {
ft_p ft = &ft_data[ftu];
fdcu_t fdcu = ft->fdc->fdcu;
int cmd, i, st0, st3, pcn;
static int bitn, retval, retpos, nbits, newcn;
- static struct {
- int over_func;
- int over_state;
- int over_retries;
- int over_arg[5];
- } astk[15];
static int wanttrk, wantblk, wantdir;
static int curpos, curtrk, curblk, curdir, curdiff;
static int errcnt = 0;
@@ -356,7 +544,7 @@ restate:
*/
switch (async_state) {
case 0:
- cmd = async_arg[0];
+ cmd = async_arg0;
#if FTDBGALL
DPRT(("===>async_seek cmd = %d\n", cmd));
#endif
@@ -364,7 +552,7 @@ restate:
async_state = 1;
i = 0;
if (out_fdc(fdcu, NE7CMD_SEEK) < 0) i = 1;
- if (!i && out_fdc(fdcu, 0x00) < 0) i = 1;
+ if (!i && out_fdc(fdcu, ftu) < 0) i = 1;
if (!i && out_fdc(fdcu, newcn) < 0) i = 1;
if (i) {
if (++async_retries >= 10) {
@@ -399,7 +587,7 @@ restate:
DPRT(("ft%d: async_seek error st0 = $%02x pcn = %d\n",
ftu, st0, pcn));
#endif
- if (async_arg[1]) goto complete;
+ if (async_arg1) goto complete;
async_state = 2;
timeout(ft_timeout, (caddr_t)ftu, hz/50);
break;
@@ -420,14 +608,14 @@ restate:
case 0:
bitn = 0;
retval = 0;
- cmd = async_arg[0];
- nbits = async_arg[1];
+ cmd = async_arg0;
+ nbits = async_arg1;
DPRT(("async_status got cmd = %d nbits = %d\n", cmd,nbits));
- CALL_ACMD(5, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_SEEK, QC_NEXTBIT, 0, 0);
/* NOTREACHED */
case 1:
out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
st3 = in_fdc(fdcu);
if (st3 < 0) {
DPRT(("ft%d: async_status timed out on bit %d r=$%02x\n",
@@ -440,7 +628,7 @@ restate:
if (bitn >= (nbits+2)) {
if ((retval & 1) && (retval & (1 << (nbits+1)))) {
async_ret = (retval & ~(1<<(nbits+1))) >> 1;
- if (async_arg[0] == QC_STATUS && async_arg[2] == 0 &&
+ if (async_arg0 == QC_STATUS && async_arg2 == 0 &&
(async_ret & (QS_ERROR|QS_NEWCART))) {
async_state = 2;
goto restate;
@@ -453,31 +641,31 @@ restate:
}
goto complete;
}
- CALL_ACMD(1, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(1, ACMD_SEEK, QC_NEXTBIT, 0, 0);
/* NOTREACHED */
case 2:
if (async_ret & QS_NEWCART) ft->newcart = 1;
- CALL_ACMD(3, ACMD_STATUS, QC_ERRCODE, 16, 1, 0, 0);
+ CALL_ACMD(3, ACMD_STATUS, QC_ERRCODE, 16, 1);
case 3:
ft->lasterr = async_ret;
if ((ft->lasterr & QS_NEWCART) == 0 && ft->lasterr) {
DPRT(("ft%d: QIC error %d occurred on cmd %d\n",
ftu, ft->lasterr & 0xff, ft->lasterr >> 8));
}
- cmd = async_arg[0];
- nbits = async_arg[1];
- CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 1, 0, 0);
+ cmd = async_arg0;
+ nbits = async_arg1;
+ CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 1);
case 4:
goto complete;
case 5:
- CALL_ACMD(6, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(6, ACMD_SEEK, QC_NEXTBIT, 0, 0);
case 6:
- CALL_ACMD(7, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(7, ACMD_SEEK, QC_NEXTBIT, 0, 0);
case 7:
- CALL_ACMD(8, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ CALL_ACMD(8, ACMD_SEEK, QC_NEXTBIT, 0, 0);
case 8:
- cmd = async_arg[0];
- CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0, 0, 0);
+ cmd = async_arg0;
+ CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0);
}
break;
@@ -488,9 +676,9 @@ restate:
*/
switch(async_state) {
case 0:
- CALL_ACMD(1, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ CALL_ACMD(1, ACMD_STATUS, QC_STATUS, 8, 0);
case 1:
- if ((async_ret & async_arg[0]) != 0) goto complete;
+ if ((async_ret & async_arg0) != 0) goto complete;
async_state = 0;
if (++async_retries == 360) { /* 90 secs. */
DPRT(("ft%d: acmd_state exceeded retry count\n", ftu));
@@ -510,13 +698,13 @@ restate:
*/
switch(async_state) {
case 0:
- cmd = async_arg[0];
- async_retries = (async_arg[2]) ? (async_arg[2]*4) : 10;
- CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0, 0, 0);
+ cmd = async_arg0;
+ async_retries = (async_arg2) ? (async_arg2 * 4) : 10;
+ CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0);
case 1:
- CALL_ACMD(2, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ CALL_ACMD(2, ACMD_STATUS, QC_STATUS, 8, 0);
case 2:
- if ((async_ret & async_arg[1]) != 0) goto complete;
+ if ((async_ret & async_arg1) != 0) goto complete;
if (--async_retries == 0) {
DPRT(("ft%d: acmd_seeksts retries exceeded\n", ftu));
goto complete;
@@ -534,12 +722,12 @@ restate:
switch(async_state) {
case 0:
if (!ft->moving) {
- CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
/* NOTREACHED */
}
async_state = 1;
out_fdc(fdcu, 0x4a); /* READ_ID */
- out_fdc(fdcu, 0);
+ out_fdc(fdcu, ftu);
break;
case 1:
for (i = 0; i < 7; i++) ft->rid[i] = in_fdc(fdcu);
@@ -548,25 +736,36 @@ restate:
DPRT(("readid st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d\n",
ft->rid[0], ft->rid[1], ft->rid[2], ft->rid[3],
ft->rid[4], ft->rid[5], async_ret));
- if ((ft->rid[0] & 0xc0) == 0x40) {
- if (++errcnt >= 10) {
+ if ((ft->rid[0] & 0xc0) != 0 || async_ret < 0) {
+ /*
+ * Method for retry:
+ * errcnt == 1 regular retry
+ * 2 microstep head 1
+ * 3 microstep head 2
+ * 4 microstep head back to 0
+ * 5 fail
+ */
+ if (++errcnt >= 5) {
DPRT(("ft%d: acmd_readid errcnt exceeded\n", fdcu));
- async_ret = ft->lastpos;
+ async_ret = -2;
errcnt = 0;
goto complete;
}
- if (errcnt > 2) {
+ if (errcnt == 1) {
+ ft->moving = 0;
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
+ } else {
ft->moving = 0;
- CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STPAUSE, QS_READY, 0);
}
- DPRT(("readid retry...\n"));
+ DPRT(("readid retry %d...\n", errcnt));
async_state = 0;
goto restate;
}
if ((async_ret % ftg->g_blktrk) == (ftg->g_blktrk-1)) {
DPRT(("acmd_readid detected last block on track\n"));
retpos = async_ret;
- CALL_ACMD(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0, 0, 0);
+ CALL_ACMD(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0);
/* NOTREACHED */
}
ft->lastpos = async_ret;
@@ -574,13 +773,13 @@ restate:
goto complete;
/* NOTREACHED */
case 2:
- CALL_ACMD(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ CALL_ACMD(3, ACMD_STATE, QS_READY, 0, 0);
case 3:
ft->moving = 0;
async_ret = retpos+1;
goto complete;
case 4:
- CALL_ACMD(5, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_SEEK, QC_FORWARD, 0, 0);
case 5:
ft->moving = 1;
async_state = 0;
@@ -598,27 +797,27 @@ restate:
*/
switch (async_state) {
case 0:
- wanttrk = async_arg[0] / ftg->g_blktrk;
- wantblk = async_arg[0] % ftg->g_blktrk;
+ wanttrk = async_arg0 / ftg->g_blktrk;
+ wantblk = async_arg0 % ftg->g_blktrk;
wantdir = wanttrk & 1;
ft->moving = 0;
- CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
case 1:
curtrk = wanttrk;
curdir = curtrk & 1;
DPRT(("Changing to track %d\n", wanttrk));
- CALL_ACMD(2, ACMD_SEEK, QC_SEEKTRACK, 0, 0, 0, 0);
+ CALL_ACMD(2, ACMD_SEEK, QC_SEEKTRACK, 0, 0);
case 2:
cmd = wanttrk+2;
- CALL_ACMD(3, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ CALL_ACMD(3, ACMD_SEEKSTS, cmd, QS_READY, 0);
case 3:
- CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 0);
case 4:
ft->laststs = async_ret;
if (wantblk == 0) {
curblk = 0;
cmd = (wantdir) ? QC_SEEKEND : QC_SEEKSTART;
- CALL_ACMD(6, ACMD_SEEKSTS, cmd, QS_READY, 90, 0, 0);
+ CALL_ACMD(6, ACMD_SEEKSTS, cmd, QS_READY, 90);
}
if (ft->laststs & QS_BOT) {
DPRT(("Tape is at BOT\n"));
@@ -632,15 +831,23 @@ restate:
async_state = 6;
goto restate;
}
- CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0);
case 5:
+ if (async_ret < 0) {
+ ft->moving = 0;
+ ft->lastpos = -2;
+ if (async_ret == -2) {
+ CALL_ACMD(9, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
+ }
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
+ }
curtrk = (async_ret+1) / ftg->g_blktrk;
curblk = (async_ret+1) % ftg->g_blktrk;
DPRT(("gotid: curtrk=%d wanttrk=%d curblk=%d wantblk=%d\n",
curtrk, wanttrk, curblk, wantblk));
if (curtrk != wanttrk) { /* oops! */
DPRT(("oops!! wrong track!\n"));
- CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
}
async_state = 6;
goto restate;
@@ -650,22 +857,22 @@ restate:
ft->lastpos = curblk - 1;
async_ret = ft->lastpos;
if (ft->moving) goto complete;
- CALL_ACMD(7, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ CALL_ACMD(7, ACMD_STATE, QS_READY, 0, 0);
}
if (curblk > wantblk) { /* passed it */
ft->moving = 0;
- CALL_ACMD(10, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(10, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
}
- if ((wantblk - curblk) <= 96) { /* approaching it */
- CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ if ((wantblk - curblk) <= 256) { /* approaching it */
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0);
}
/* way up ahead */
ft->moving = 0;
- CALL_ACMD(14, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ CALL_ACMD(14, ACMD_SEEKSTS, QC_STOP, QS_READY, 0);
break;
case 7:
ft->moving = 1;
- CALL_ACMD(8, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ CALL_ACMD(8, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 8:
async_state = 9;
@@ -677,26 +884,26 @@ restate:
curdiff = ((curblk - wantblk) / QCV_BLKSEG) + 2;
if (curdiff >= ftg->g_segtrk) curdiff = ftg->g_segtrk - 1;
DPRT(("pos %d past %d, reverse %d\n", curblk, wantblk, curdiff));
- CALL_ACMD(11, ACMD_SEEK, QC_SEEKREV, 0, 0, 0, 0);
+ CALL_ACMD(11, ACMD_SEEK, QC_SEEKREV, 0, 0);
case 11:
DPRT(("reverse 1 done\n"));
- CALL_ACMD(12, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0, 0, 0);
+ CALL_ACMD(12, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0);
case 12:
DPRT(("reverse 2 done\n"));
- CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90, 0, 0);
+ CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90);
case 13:
- CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0);
case 14:
curdiff = ((wantblk - curblk) / QCV_BLKSEG) - 2;
if (curdiff < 0) curdiff = 0;
DPRT(("pos %d before %d, forward %d\n", curblk, wantblk, curdiff));
- CALL_ACMD(15, ACMD_SEEK, QC_SEEKFWD, 0, 0, 0, 0);
+ CALL_ACMD(15, ACMD_SEEK, QC_SEEKFWD, 0, 0);
case 15:
DPRT(("forward 1 done\n"));
- CALL_ACMD(16, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0, 0, 0);
+ CALL_ACMD(16, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0);
case 16:
DPRT(("forward 2 done\n"));
- CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90, 0, 0);
+ CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90);
}
break;
}
@@ -704,13 +911,14 @@ restate:
return;
complete:
- if (astk_depth) {
- astk_depth--;
- async_retries = astk[astk_depth].over_retries;
- async_func = astk[astk_depth].over_func;
- async_state = astk[astk_depth].over_state;
- for(i = 0; i < 5; i++)
- async_arg[i] = astk[astk_depth].over_arg[i];
+ if (astk_ptr != &astk[0]) {
+ astk_ptr--;
+ async_retries = astk_ptr->over_retries;
+ async_func = astk_ptr->over_func;
+ async_state = astk_ptr->over_state;
+ async_arg0 = astk_ptr->over_arg0;
+ async_arg1 = astk_ptr->over_arg1;
+ async_arg2 = astk_ptr->over_arg2;
goto restate;
}
async_func = ACMD_NONE;
@@ -720,6 +928,7 @@ complete:
async_req(ftu, 2);
break;
case FTIO_READING:
+ case FTIO_RDAHEAD:
async_read(ftu, 2);
break;
case FTIO_WRITING:
@@ -735,10 +944,11 @@ complete:
/*
* Entry point for the async request processor.
*/
-void async_req(ftu_t ftu, int from)
+static void
+async_req(ftu_t ftu, int from)
{
ft_p ft = &ft_data[ftu];
- SegReq *sp;
+ SegReq *nsp, *sp;
static int over_async, lastreq, domore;
int cmd;
@@ -747,56 +957,73 @@ void async_req(ftu_t ftu, int from)
restate:
switch (arq_state) {
case 0: /* Process segment */
- ft->io_sts = ft->curseg->reqtype;
+ sp = ft->segh;
+ ft->io_sts = (sp == NULL) ? FTIO_READY : sp->reqtype;
+
if (ft->io_sts == FTIO_WRITING)
async_write(ftu, from);
else
async_read(ftu, from);
if (ft->io_sts != FTIO_READY) return;
- /* Swap buffered and current segment */
- lastreq = ft->curseg->reqtype;
- ft->curseg->reqtype = FTIO_READY;
- sp = ft->curseg;
- ft->curseg = ft->bufseg;
- ft->bufseg = sp;
+ /* Pull buffer from current I/O queue */
+ if (sp != NULL) {
+ lastreq = sp->reqtype;
+ segio_done(ft, sp);
- wakeup((caddr_t)&ftsem.buff_avail);
+ /* If I/O cancelled, clear finished queue. */
+ if (sp->reqcan) {
+ while (ft->doneh != NULL)
+ segio_free(ft, ft->doneh);
+ lastreq = FTIO_READY;
+ }
+ } else
+ lastreq = FTIO_READY;
/* Detect end of track */
if (((ft->xblk / QCV_BLKSEG) % ftg->g_segtrk) == 0) {
- domore = (ft->curseg->reqtype != FTIO_READY);
- ACMD_FUNC(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0, 0, 0);
+ ACMD_FUNC(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0);
}
arq_state = 1;
goto restate;
case 1: /* Next request */
- if (ft->curseg->reqtype != FTIO_READY) {
- ft->curseg->reqcrc = 0;
+ /* If we have another request queued, start it running. */
+ if (ft->segh != NULL) {
+ sp = ft->segh;
+ sp->reqcrc = 0;
arq_state = ard_state = awr_state = 0;
- ft->xblk = ft->curseg->reqblk;
+ ft->xblk = sp->reqblk;
+ ft->xseg = sp->reqseg;
ft->xcnt = 0;
- ft->xptr = ft->curseg->buff;
- DPRT(("I/O reqblk = %d\n", ft->curseg->reqblk));
+ ft->xptr = sp->buff;
+ DPRT(("I/O reqblk = %d\n", ft->xblk));
goto restate;
}
- if (lastreq == FTIO_READING) {
- ft->curseg->reqtype = FTIO_RDAHEAD;
- ft->curseg->reqblk = ft->xblk;
- ft->curseg->reqcrc = 0;
- ft->curseg->reqcan = 0;
- bzero(ft->curseg->buff, QCV_SEGSIZE);
+
+ /* If the last request was reading, do read ahead. */
+ if ((lastreq == FTIO_READING || lastreq == FTIO_RDAHEAD) &&
+ (sp = segio_alloc(ft)) != NULL) {
+ sp->reqtype = FTIO_RDAHEAD;
+ sp->reqblk = ft->xblk;
+ sp->reqseg = ft->xseg+1;
+ sp->reqcrc = 0;
+ sp->reqcan = 0;
+ segio_queue(ft, sp);
+ bzero(sp->buff, QCV_SEGSIZE);
arq_state = ard_state = awr_state = 0;
- ft->xblk = ft->curseg->reqblk;
+ ft->xblk = sp->reqblk;
+ ft->xseg = sp->reqseg;
ft->xcnt = 0;
- ft->xptr = ft->curseg->buff;
- DPRT(("Processing readahead reqblk = %d\n", ft->curseg->reqblk));
+ ft->xptr = sp->buff;
+ DPRT(("Processing readahead reqblk = %d\n", ft->xblk));
goto restate;
}
+
if (ft->moving) {
DPRT(("No more I/O.. Stopping.\n"));
- ACMD_FUNC(7, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ ft->moving = 0;
+ ACMD_FUNC(7, ACMD_SEEKSTS, QC_PAUSE, QS_READY, 0);
break;
}
arq_state = 7;
@@ -804,26 +1031,26 @@ restate:
case 2: /* End of track */
ft->moving = 0;
- ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0);
break;
case 3:
DPRT(("async_req seek head to track %d\n", ft->xblk / ftg->g_blktrk));
- ACMD_FUNC(4, ACMD_SEEK, QC_SEEKTRACK, 0, 0, 0, 0);
+ ACMD_FUNC(4, ACMD_SEEK, QC_SEEKTRACK, 0, 0);
break;
case 4:
cmd = (ft->xblk / ftg->g_blktrk) + 2;
- if (domore) {
- ACMD_FUNC(5, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ if (ft->segh != NULL) {
+ ACMD_FUNC(5, ACMD_SEEKSTS, cmd, QS_READY, 0);
} else {
- ACMD_FUNC(7, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ ACMD_FUNC(7, ACMD_SEEKSTS, cmd, QS_READY, 0);
}
break;
case 5:
ft->moving = 1;
- ACMD_FUNC(6, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ ACMD_FUNC(6, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 6:
@@ -832,26 +1059,22 @@ restate:
break;
case 7:
- ft->moving = 0;
-
- /* Check one last time to see if a request came in. */
- if (ft->curseg->reqtype != FTIO_READY) {
- DPRT(("async_req: Never say no!\n"));
- arq_state = 1;
- goto restate;
- }
-
/* Time to rest. */
ft->active = 0;
- wakeup((caddr_t)&ftsem.iosts_change); /* wakeup those who want an i/o chg */
+ ft->lastpos = -2;
+
+ /* wakeup those who want an i/o chg */
+ wakeup((caddr_t)wc_iosts_change);
break;
}
}
+
/*
* Entry for async read.
*/
-void async_read(ftu_t ftu, int from)
+static void
+async_read(ftu_t ftu, int from)
{
ft_p ft = &ft_data[ftu];
fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
@@ -859,6 +1082,7 @@ void async_read(ftu_t ftu, int from)
int i, cmd, newcn, rddta[7];
int st0, pcn, where;
static int over_async;
+ static int retries = 0;
if (from == 2) ard_state = over_async;
@@ -872,13 +1096,13 @@ restate:
if (ft->lastpos != (ft->xblk-1)) {
DPRT(("ft%d: position unknown: lastpos:%d ft->xblk:%d\n",
ftu, ft->lastpos, ft->xblk));
- ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0, 0, 0);
+ ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0);
}
/* Tape is in position but stopped. */
if (!ft->moving) {
DPRT(("async_read ******STARTING TAPE\n"));
- ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0);
}
ard_state = 1;
goto restate;
@@ -887,8 +1111,8 @@ restate:
/* Tape is now moving and in position-- start DMA now! */
isa_dmastart(B_READ, ft->xptr, QCV_BLKSIZE, 2);
out_fdc(fdcu, 0x66); /* read */
- out_fdc(fdcu, 0x00); /* unit */
- out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
+ out_fdc(fdcu, ftu); /* unit */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
out_fdc(fdcu, ft->xblk / ftg->g_fdside); /* head */
out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* sector */
out_fdc(fdcu, 0x03); /* 1K sectors */
@@ -905,7 +1129,8 @@ restate:
#if FTDBGALL
/* Compute where the controller thinks we are */
- where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside) + rddta[5]-1;
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside)
+ + rddta[5]-1;
DPRT(("xfer done: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
where, ft->xblk));
@@ -913,34 +1138,44 @@ restate:
/* Check for errors */
if ((rddta[0] & 0xc0) != 0x00) {
- if (rddta[1] & 0x04) {
+#if !FTDBGALL
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside)
+ + rddta[5]-1;
+ DPRT(("xd: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
+ rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
+ where, ft->xblk));
+#endif
+ if ((rddta[1] & 0x04) == 0x04 && retries < 2) {
/* Probably wrong position */
+ DPRT(("async_read: doing retry %d\n", retries));
ft->lastpos = ft->xblk;
ard_state = 0;
+ retries++;
goto restate;
} else {
/* CRC/Address-mark/Data-mark, et. al. */
DPRT(("ft%d: CRC error on block %d\n", fdcu, ft->xblk));
- ft->curseg->reqcrc |= (1 << ft->xcnt);
+ ft->segh->reqcrc |= (1 << ft->xcnt);
}
}
/* Otherwise, transfer completed okay. */
+ retries = 0;
ft->lastpos = ft->xblk;
ft->xblk++;
ft->xcnt++;
ft->xptr += QCV_BLKSIZE;
- if (ft->xcnt < QCV_BLKSEG && ft->curseg->reqcan == 0) {
+ if (ft->xcnt < QCV_BLKSEG && ft->segh->reqcan == 0) {
ard_state = 0;
goto restate;
}
- DPRT(("Read done.. Cancel = %d\n", ft->curseg->reqcan));
+ DPRT(("Read done.. Cancel = %d\n", ft->segh->reqcan));
ft->io_sts = FTIO_READY;
break;
case 3:
ft->moving = 1;
- ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 4:
@@ -960,7 +1195,8 @@ restate:
* routine, if it's 1 then it was a timeout, if it's 2, then an
* async_cmd completed.
*/
-void async_write(ftu_t ftu, int from)
+static void
+async_write(ftu_t ftu, int from)
{
ft_p ft = &ft_data[ftu];
fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
@@ -982,13 +1218,13 @@ restate:
if (ft->lastpos != (ft->xblk-1)) {
DPRT(("ft%d: position unknown: lastpos:%d ft->xblk:%d\n",
ftu, ft->lastpos, ft->xblk));
- ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0, 0, 0);
+ ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0);
}
/* Tape is in position but stopped. */
if (!ft->moving) {
DPRT(("async_write ******STARTING TAPE\n"));
- ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0);
}
awr_state = 1;
goto restate;
@@ -997,8 +1233,8 @@ restate:
/* Tape is now moving and in position-- start DMA now! */
isa_dmastart(B_WRITE, ft->xptr, QCV_BLKSIZE, 2);
out_fdc(fdcu, 0x45); /* write */
- out_fdc(fdcu, 0x00); /* unit */
- out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
+ out_fdc(fdcu, ftu); /* unit */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cyl */
out_fdc(fdcu, ft->xblk / ftg->g_fdside); /* head */
out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* sector */
out_fdc(fdcu, 0x03); /* 1K sectors */
@@ -1023,13 +1259,16 @@ restate:
/* Check for errors */
if ((rddta[0] & 0xc0) != 0x00) {
- if (rddta[1] & 0x04) {
- /* Probably wrong position */
- ft->lastpos = ft->xblk;
- awr_state = 0;
- goto restate;
- } else if (retries < 5) {
+#if !FTDBGALL
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside)
+ + rddta[5]-1;
+ DPRT(("xfer done: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
+ rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
+ where, ft->xblk));
+#endif
+ if (retries < 3) {
/* Something happened -- try again */
+ DPRT(("async_write: doing retry %d\n", retries));
ft->lastpos = ft->xblk;
awr_state = 0;
retries++;
@@ -1037,11 +1276,11 @@ restate:
} else {
/*
* Retries failed. Note the unrecoverable error.
- * Marking the block as bad is fairly useless.
+ * Marking the block as bad is useless right now.
*/
printf("ft%d: unrecoverable write error on block %d\n",
ftu, ft->xblk);
- ft->curseg->reqcrc |= (1 << ft->xcnt);
+ ft->segh->reqcrc |= (1 << ft->xcnt);
}
}
@@ -1063,7 +1302,7 @@ restate:
case 3:
ft->moving = 1;
- ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0);
break;
case 4:
@@ -1081,11 +1320,14 @@ restate:
/*
* Interrupt handler for active tape. Bounced off of fdintr().
*/
-int ftintr(ftu_t ftu)
+int
+ftintr(ftu_t ftu)
{
int st0, pcn, i;
ft_p ft = &ft_data[ftu];
- fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ int s = splbio();
+
st0 = 0;
pcn = 0;
@@ -1093,12 +1335,14 @@ int ftintr(ftu_t ftu)
if (ft->active) {
if (async_func != ACMD_NONE) {
async_cmd(ftu);
+ splx(s);
return(1);
}
#if FTDBGALL
DPRT(("Got request interrupt\n"));
#endif
async_req(ftu, 0);
+ splx(s);
return(1);
}
@@ -1113,20 +1357,21 @@ int ftintr(ftu_t ftu)
huh_what:
printf("ft%d: unexpected interrupt; st0 = $%02x pcn = %d\n",
ftu, st0, pcn);
+ splx(s);
return(1);
}
switch (ft->cmd_wait) {
case FTCMD_RESET:
ft->sts_wait = FTSTS_INTERRUPT;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
break;
case FTCMD_RECAL:
case FTCMD_SEEK:
if (st0 & 0x20) { /* seek done */
ft->sts_wait = FTSTS_INTERRUPT;
ft->pcn = pcn;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
}
#if FTDBGALL
else
@@ -1137,20 +1382,23 @@ huh_what:
case FTCMD_READID:
for (i = 0; i < 7; i++) ft->rid[i] = in_fdc(fdcu);
ft->sts_wait = FTSTS_INTERRUPT;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
break;
default:
goto huh_what;
}
+ splx(s);
return(1);
}
+
/*
* Interrupt timeout routine.
*/
-static void ft_timeout(caddr_t arg1, int arg2)
+static void
+ft_timeout(caddr_t arg1, int arg2)
{
int s;
ftu_t ftu = (ftu_t)arg1;
@@ -1166,17 +1414,19 @@ static void ft_timeout(caddr_t arg1, int arg2)
async_req(ftu, 1);
} else {
ft->sts_wait = FTSTS_TIMEOUT;
- wakeup((caddr_t)&ftsem.intr_wait);
+ wakeup((caddr_t)wc_intr_wait);
}
splx(s);
}
+
/*
* Wait for a particular interrupt to occur. ftintr() will wake us up
* if it sees what we want. Otherwise, time out and return error.
* Should always disable ints before trigger is sent and calling here.
*/
-int ftintr_wait(ftu_t ftu, int cmd, int ticks)
+static int
+ftintr_wait(ftu_t ftu, int cmd, int ticks)
{
int retries, st0, pcn;
ft_p ft = &ft_data[ftu];
@@ -1211,8 +1461,7 @@ int ftintr_wait(ftu_t ftu, int cmd, int ticks)
goto intrdone;
}
- if (ticks) timeout(ft_timeout, (caddr_t)ftu, ticks);
- sleep((caddr_t)&ftsem.intr_wait, FTPRI);
+ ftsleep(wc_intr_wait, ticks);
intrdone:
if (ft->sts_wait == FTSTS_TIMEOUT) { /* timeout */
@@ -1230,11 +1479,13 @@ intrdone:
return(0);
}
+
/*
* Recalibrate tape drive. Parameter totape is true, if we should
* recalibrate to tape drive settings.
*/
-int tape_recal(ftu_t ftu, int totape)
+static int
+tape_recal(ftu_t ftu, int totape)
{
int s;
ft_p ft = &ft_data[ftu];
@@ -1248,7 +1499,7 @@ int tape_recal(ftu_t ftu, int totape)
s = splbio();
out_fdc(fdcu, NE7CMD_RECAL);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
if (ftintr_wait(ftu, FTCMD_RECAL, hz)) {
splx(s);
@@ -1265,18 +1516,25 @@ int tape_recal(ftu_t ftu, int totape)
return(0);
}
-static void state_timeout(caddr_t arg1, int arg2)
+
+/*
+ * Timeout for long delays.
+ */
+static void
+state_timeout(caddr_t arg1, int arg2)
{
ftu_t ftu = (ftu_t)arg1;
- wakeup((caddr_t)&ftsem.long_delay);
+ wakeup((caddr_t)wc_long_delay);
}
+
/*
* Wait for a particular tape status to be met. If all is TRUE, then
* all states must be met, otherwise any state can be met.
*/
-int tape_state(ftu_t ftu, int all, int mask, int seconds)
+static int
+tape_state(ftu_t ftu, int all, int mask, int seconds)
{
int r, tries, maxtries;
@@ -1287,20 +1545,19 @@ int tape_state(ftu_t ftu, int all, int mask, int seconds)
if (all && (r & mask) == mask) return(r);
if ((r & mask) != 0) return(r);
}
- if (seconds) {
- timeout(state_timeout, (caddr_t)ftu, hz/4);
- sleep((caddr_t)&ftsem.long_delay, FTPRI);
- }
+ if (seconds) ftsleep(wc_long_delay, hz/4);
}
DPRT(("ft%d: tape_state failed on mask=$%02x maxtries=%d\n",
ftu, mask, maxtries));
return(-1);
}
+
/*
* Send a QIC command to tape drive, wait for completion.
*/
-int tape_cmd(ftu_t ftu, int cmd)
+static int
+tape_cmd(ftu_t ftu, int cmd)
{
int newcn;
int retries = 0;
@@ -1316,7 +1573,7 @@ retry:
/* Perform seek */
s = splbio();
out_fdc(fdcu, NE7CMD_SEEK);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
out_fdc(fdcu, newcn);
if (ftintr_wait(ftu, FTCMD_SEEK, hz)) {
@@ -1338,25 +1595,40 @@ redo:
return(0);
}
+
/*
* Return status of tape drive
*/
-int tape_status(ftu_t ftu)
+static int
+tape_status(ftu_t ftu)
{
int r, err, tries;
- ft_p ft = &ft_data[ftu];
+ ft_p ft = &ft_data[ftu];
+ int max = (ft->attaching) ? 2 : 3;
- for (r = -1, tries = 0; r < 0 && tries < 3; tries++)
+ for (r = -1, tries = 0; r < 0 && tries < max; tries++)
r = qic_status(ftu, QC_STATUS, 8);
- if (tries == 3) return(-1);
+ if (tries == max) return(-1);
+
+recheck:
DPRT(("tape_status got $%04x\n",r));
ft->laststs = r;
if (r & (QS_ERROR|QS_NEWCART)) {
- if (r & QS_NEWCART) ft->newcart = 1;
err = qic_status(ftu, QC_ERRCODE, 16);
ft->lasterr = err;
- if ((r & QS_NEWCART) == 0 && err && ft->attaching == 0) {
+ if (r & QS_NEWCART) {
+ ft->newcart = 1;
+ /* If tape not referenced, do a seek load point. */
+ if ((r & QS_FMTOK) == 0 && !ft->attaching) {
+ tape_cmd(ftu, QC_SEEKLP);
+ do {
+ ftsleep(wc_long_delay, hz);
+ } while ((r = qic_status(ftu, QC_STATUS, 8)) < 0 ||
+ (r & (QS_READY|QS_CART)) == QS_CART);
+ goto recheck;
+ }
+ } else if (err && !ft->attaching) {
DPRT(("ft%d: QIC error %d occurred on cmd %d\n",
ftu, err & 0xff, err >> 8));
}
@@ -1364,29 +1636,36 @@ int tape_status(ftu_t ftu)
ft->laststs = r;
DPRT(("tape_status got error code $%04x new sts = $%02x\n",err,r));
}
+
ft->rdonly = (r & QS_RDONLY);
return(r);
}
+
/*
* Transfer control to tape drive.
*/
-void tape_start(ftu_t ftu)
+static void
+tape_start(ftu_t ftu, int motor)
{
ft_p ft = &ft_data[ftu];
fdc_p fdc = ft->fdc;
- int s;
-
- DPRT(("tape_start start\n"));
+ int s, mbits;
s = splbio();
+ DPRT(("tape_start start\n"));
/* reset, dma disable */
- outb(fdc->baseport+fdout, 0x00);
+ outb(fdc->baseport+FDOUT, 0x00);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
- /* raise reset, enable DMA */
- outb(fdc->baseport+fdout, FDO_FRST | FDO_FDMAEN);
+ /* raise reset, enable DMA, motor on if needed */
+ if (motor)
+ mbits = (!ftu) ? FDO_MOEN0 : FDO_MOEN1;
+ else
+ mbits = 0;
+
+ outb(fdc->baseport+FDOUT, FDO_FRST | FDO_FDMAEN | mbits);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
splx(s);
@@ -1394,16 +1673,18 @@ void tape_start(ftu_t ftu)
tape_recal(ftu, 1);
/* set transfer speed */
- outb(fdc->baseport+fdctl, FDC_500KBPS);
+ outb(fdc->baseport+FDCTL, FDC_500KBPS);
DELAY(10);
DPRT(("tape_start end\n"));
}
+
/*
* Transfer control back to floppy disks.
*/
-void tape_end(ftu_t ftu)
+static void
+tape_end(ftu_t ftu)
{
ft_p ft = &ft_data[ftu];
fdc_p fdc = ft->fdc;
@@ -1415,41 +1696,59 @@ void tape_end(ftu_t ftu)
s = splbio();
/* reset, dma disable */
- outb(fdc->baseport+fdout, 0x00);
+ outb(fdc->baseport+FDOUT, 0x00);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
/* raise reset, enable DMA */
- outb(fdc->baseport+fdout, FDO_FRST | FDO_FDMAEN);
+ outb(fdc->baseport+FDOUT, FDO_FRST | FDO_FDMAEN);
(void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
splx(s);
/* set transfer speed */
- outb(fdc->baseport+fdctl, FDC_500KBPS);
+ outb(fdc->baseport+FDCTL, FDC_500KBPS);
DELAY(10);
fdc->flags &= ~FDC_TAPE_BUSY;
DPRT(("tape_end end\n"));
}
+
/*
* Wait for the driver to go inactive, cancel readahead if necessary.
*/
-void tape_inactive(ftu_t ftu)
+static void
+tape_inactive(ftu_t ftu)
{
ft_p ft = &ft_data[ftu];
-
- if (ft->curseg->reqtype == FTIO_RDAHEAD) {
- ft->curseg->reqcan = 1; /* XXX cancel rdahead */
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ int s = splbio();
+
+ if (ft->segh != NULL) {
+ if (ft->segh->reqtype == FTIO_RDAHEAD) {
+ /* cancel read-ahead */
+ ft->segh->reqcan = 1;
+ } else if (ft->segh->reqtype == FTIO_WRITING && !ft->active) {
+ /* flush out any remaining writes */
+ DPRT(("Flushing write I/O chain\n"));
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = ft->segh->reqblk;
+ ft->xseg = ft->segh->reqseg;
+ ft->xcnt = 0;
+ ft->xptr = ft->segh->buff;
+ ft->active = 1;
+ timeout(ft_timeout, (caddr_t)ftu, 1);
+ }
}
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ while (ft->active) ftsleep(wc_iosts_change, 0);
+ splx(s);
}
+
/*
* Get the geometry of the tape currently in the drive.
*/
-int ftgetgeom(ftu_t ftu)
+static int
+ftgetgeom(ftu_t ftu)
{
int r, i, tries;
int cfg, qic80, ext;
@@ -1459,7 +1758,7 @@ int ftgetgeom(ftu_t ftu)
r = tape_status(ftu);
/* XXX fix me when format mode is finished */
- if ((r & QS_CART) == 0 || (r & QS_FMTOK) == 0) {
+ if (r < 0 || (r & QS_CART) == 0 || (r & QS_FMTOK) == 0) {
DPRT(("ftgetgeom: no cart or not formatted 0x%04x\n",r));
ftg = NULL;
ft->newcart = 1;
@@ -1539,20 +1838,21 @@ int ftgetgeom(ftu_t ftu)
return(0);
}
+
/*
* Switch between tape/floppy. This will send the tape enable/disable
* codes for this drive's manufacturer.
*/
-int set_fdcmode(dev_t dev, int newmode)
+static int
+set_fdcmode(dev_t dev, int newmode)
{
ftu_t ftu = FDUNIT(minor(dev));
ft_p ft = &ft_data[ftu];
fdc_p fdc = ft->fdc;
-
static int havebufs = 0;
void *buf;
int r, s, i;
- SegReq *sp;
+ SegReq *sp, *rsp;
if (newmode == FDC_TAPE_MODE) {
/* Wake up the tape drive */
@@ -1560,19 +1860,22 @@ int set_fdcmode(dev_t dev, int newmode)
case NO_TYPE:
fdc->flags &= ~FDC_TAPE_BUSY;
return(ENXIO);
+ case FT_NONE:
+ tape_start(ftu, 0);
+ break;
case FT_COLORADO:
- tape_start(ftu);
+ tape_start(ftu, 0);
if (tape_cmd(ftu, QC_COL_ENABLE1)) {
tape_end(ftu);
return(EIO);
}
- if (tape_cmd(ftu, QC_COL_ENABLE2)) {
+ if (tape_cmd(ftu, QC_COL_ENABLE2 + ftu)) {
tape_end(ftu);
return(EIO);
}
break;
case FT_MOUNTAIN:
- tape_start(ftu);
+ tape_start(ftu, 0);
if (tape_cmd(ftu, QC_MTN_ENABLE1)) {
tape_end(ftu);
return(EIO);
@@ -1582,56 +1885,93 @@ int set_fdcmode(dev_t dev, int newmode)
return(EIO);
}
break;
+ case FT_INSIGHT:
+ tape_start(ftu, 1);
+ break;
default:
DPRT(("ft%d: bad tape type\n", ftu));
return(ENXIO);
}
if (tape_status(ftu) < 0) {
- tape_cmd(ftu, (ft->type == FT_COLORADO) ? QC_COL_DISABLE : QC_MTN_DISABLE);
+ if (ft->type == FT_COLORADO)
+ tape_cmd(ftu, QC_COL_DISABLE);
+ else if (ft->type == FT_MOUNTAIN)
+ tape_cmd(ftu, QC_MTN_DISABLE);
tape_end(ftu);
return(EIO);
}
/* Grab buffers from memory. */
if (!havebufs) {
- ft->curseg = malloc(sizeof(SegReq), M_DEVBUF, M_NOWAIT);
- if (ft->curseg == NULL) {
- printf("ft%d: not enough memory for buffers\n", ftu);
- return(ENOMEM);
- }
- ft->bufseg = malloc(sizeof(SegReq), M_DEVBUF, M_NOWAIT);
- if (ft->bufseg == NULL) {
- free(ft->curseg, M_DEVBUF);
- printf("ft%d: not enough memory for buffers\n", ftu);
- return(ENOMEM);
+ ft->segh = ft->segt = NULL;
+ ft->doneh = ft->donet = NULL;
+ ft->segfree = NULL;
+ ft->hdr = NULL;
+ ft->nsegq = ft->ndoneq = ft->nfreelist = 0;
+ for (i = 0; i < FTNBUFF; i++) {
+ sp = malloc(sizeof(SegReq), M_DEVBUF, M_WAITOK);
+ if (sp == NULL) {
+ printf("ft%d: not enough memory for buffers\n", ftu);
+ for (sp=ft->segfree; sp != NULL; sp=sp->next)
+ free(sp, M_DEVBUF);
+ if (ft->type == FT_COLORADO)
+ tape_cmd(ftu, QC_COL_DISABLE);
+ else if (ft->type == FT_MOUNTAIN)
+ tape_cmd(ftu, QC_MTN_DISABLE);
+ tape_end(ftu);
+ return(ENOMEM);
+ }
+ sp->reqtype = FTIO_READY;
+ sp->next = ft->segfree;
+ ft->segfree = sp;
+ ft->nfreelist++;
}
+ /* take one buffer for header */
+ ft->hdr = ft->segfree;
+ ft->segfree = ft->segfree->next;
+ ft->nfreelist--;
havebufs = 1;
}
- ft->curseg->reqtype = FTIO_READY;
- ft->bufseg->reqtype = FTIO_READY;
ft->io_sts = FTIO_READY; /* tape drive is ready */
ft->active = 0; /* interrupt driver not active */
ft->moving = 0; /* tape not moving */
ft->rdonly = 0; /* tape read only */
- ft->newcart = 0; /* a new cart was inserted */
+ ft->newcart = 0; /* new cartridge flag */
ft->lastpos = -1; /* tape is rewound */
+ async_func = ACMD_NONE; /* No async function */
tape_state(ftu, 0, QS_READY, 60);
tape_cmd(ftu, QC_RATE);
tape_cmd(ftu, QCF_RT500+2); /* 500K bps */
tape_state(ftu, 0, QS_READY, 60);
ft->mode = FTM_PRIMARY;
- tape_cmd(ftu, QC_PRIMARY); /* Make sure we're in primary mode */
+ tape_cmd(ftu, QC_PRIMARY); /* Make sure we're in primary mode */
tape_state(ftu, 0, QS_READY, 60);
ftg = NULL; /* No geometry yet */
ftgetgeom(ftu); /* Get tape geometry */
ftreq_rewind(ftu); /* Make sure tape is rewound */
} else {
- tape_cmd(ftu, (ft->type == FT_COLORADO) ? QC_COL_DISABLE : QC_MTN_DISABLE);
+ if (ft->type == FT_COLORADO)
+ tape_cmd(ftu, QC_COL_DISABLE);
+ else if (ft->type == FT_MOUNTAIN)
+ tape_cmd(ftu, QC_MTN_DISABLE);
tape_end(ftu);
ft->newcart = 0; /* clear new cartridge */
+ if (ft->hdr != NULL) free(ft->hdr, M_DEVBUF);
+ if (havebufs) {
+ for (sp = ft->segfree; sp != NULL;) {
+ rsp = sp; sp = sp->next;
+ free(rsp, M_DEVBUF);
+ }
+ for (sp = ft->segh; sp != NULL;) {
+ rsp = sp; sp = sp->next;
+ free(rsp, M_DEVBUF);
+ }
+ for (sp = ft->doneh; sp != NULL;) {
+ rsp = sp; sp = sp->next;
+ free(rsp, M_DEVBUF);
+ }
+ }
havebufs = 0;
- free(ft->curseg, M_DEVBUF);
- free(ft->bufseg, M_DEVBUF);
}
return(0);
}
@@ -1640,7 +1980,8 @@ int set_fdcmode(dev_t dev, int newmode)
/*
* Perform a QIC status function.
*/
-int qic_status(ftu_t ftu, int cmd, int nbits)
+static int
+qic_status(ftu_t ftu, int cmd, int nbits)
{
int st3, val, r, i;
ft_p ft = &ft_data[ftu];
@@ -1653,7 +1994,7 @@ int qic_status(ftu_t ftu, int cmd, int nbits)
/* Sense drive status */
out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
st3 = in_fdc(fdcu);
if ((st3 & 0x10) == 0) { /* track 0 */
@@ -1668,7 +2009,7 @@ int qic_status(ftu_t ftu, int cmd, int nbits)
}
out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, ftu);
st3 = in_fdc(fdcu);
if (st3 < 0) {
DPRT(("ft%d: controller timed out on bit %d r=$%02x\n",
@@ -1690,11 +2031,13 @@ int qic_status(ftu_t ftu, int cmd, int nbits)
return(r);
}
+
/*
* Open tape drive for use. Bounced off of Fdopen if tape minor is
* detected.
*/
-int ftopen(dev_t dev, int arg2) {
+int
+ftopen(dev_t dev, int arg2) {
ftu_t ftu = FDUNIT(minor(dev));
int type = FDTYPE(minor(dev));
fdc_p fdc;
@@ -1714,19 +2057,21 @@ int ftopen(dev_t dev, int arg2) {
return(set_fdcmode(dev, FDC_TAPE_MODE)); /* try to switch to tape */
}
+
/*
* Close tape and return floppy controller to disk mode.
*/
-int ftclose(dev_t dev, int flags)
+int
+ftclose(dev_t dev, int flags)
{
int s;
SegReq *sp;
ftu_t ftu = FDUNIT(minor(dev));
ft_p ft = &ft_data[ftu];
+
/* Wait for any remaining I/O activity to complete. */
- if (ft->curseg->reqtype == FTIO_RDAHEAD) ft->curseg->reqcan = 1;
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ tape_inactive(ftu);
ft->mode = FTM_PRIMARY;
tape_cmd(ftu, QC_PRIMARY);
@@ -1735,94 +2080,124 @@ int ftclose(dev_t dev, int flags)
return(set_fdcmode(dev, FDC_DISK_MODE)); /* Otherwise, close tape */
}
+
/*
- * Perform strategy on a given buffer (not!). The driver was not
- * performing very efficiently using the buffering routines. After
- * support for error correction was added, this routine became
- * obsolete in favor of doing ioctl's. Ugly, yes.
+ * Perform strategy on a given buffer (not!). Changed so that the
+ * driver will at least return 'Operation not supported'.
*/
-void ftstrategy(struct buf *bp)
+void
+ftstrategy(struct buf *bp)
{
- return;
+ bp->b_error = ENODEV;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
}
-/* Read or write a segment. */
-int ftreq_rw(ftu_t ftu, int cmd, QIC_Segment *sr, struct proc *p)
+
+/*
+ * Read or write a segment.
+ */
+static int
+ftreq_rw(ftu_t ftu, int cmd, QIC_Segment *sr, struct proc *p)
{
int r, i, j;
SegReq *sp;
int s;
- long blk, bad;
+ long blk, bad, seg;
unsigned char *cp, *cp2;
ft_p ft = &ft_data[ftu];
- if (!ft->active) {
+ if (!ft->active && ft->segh == NULL) {
r = tape_status(ftu);
- if ((r & QS_CART) == 0) {
+ if ((r & QS_CART) == 0)
return(ENXIO); /* No cartridge */
- }
- if ((r & QS_FMTOK) == 0) {
+ if ((r & QS_FMTOK) == 0)
return(ENXIO); /* Not formatted */
- }
tape_state(ftu, 0, QS_READY, 90);
}
if (ftg == NULL || ft->newcart) {
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ tape_inactive(ftu);
tape_state(ftu, 0, QS_READY, 90);
- if (ftgetgeom(ftu) < 0) {
+ if (ftgetgeom(ftu) < 0)
return(ENXIO);
- }
}
/* Write not allowed on a read-only tape. */
- if (cmd == QIOWRITE && ft->rdonly) {
+ if (cmd == QIOWRITE && ft->rdonly)
return(EROFS);
- }
+
/* Quick check of request and buffer. */
- if (sr == NULL || sr->sg_data == NULL) {
+ if (sr == NULL || sr->sg_data == NULL)
return(EINVAL);
- }
- if (sr->sg_trk >= ftg->g_trktape ||
- sr->sg_seg >= ftg->g_segtrk) {
+
+ /* Make sure requested track and segment is in range. */
+ if (sr->sg_trk >= ftg->g_trktape || sr->sg_seg >= ftg->g_segtrk)
return(EINVAL);
- }
+
blk = sr->sg_trk * ftg->g_blktrk + sr->sg_seg * QCV_BLKSEG;
+ seg = sr->sg_trk * ftg->g_segtrk + sr->sg_seg;
s = splbio();
if (cmd == QIOREAD) {
- if (ft->curseg->reqtype == FTIO_RDAHEAD) {
- if (blk == ft->curseg->reqblk) {
- sp = ft->curseg;
+ /*
+ * See if the driver is reading ahead.
+ */
+ if (ft->doneh != NULL ||
+ (ft->segh != NULL && ft->segh->reqtype == FTIO_RDAHEAD)) {
+ /*
+ * Eat the completion queue and see if the request
+ * is already there.
+ */
+ while (ft->doneh != NULL) {
+ if (blk == ft->doneh->reqblk) {
+ sp = ft->doneh;
+ sp->reqtype = FTIO_READING;
+ sp->reqbad = sr->sg_badmap;
+ goto rddone;
+ }
+ segio_free(ft, ft->doneh);
+ }
+
+ /*
+ * Not on the completed queue, in progress maybe?
+ */
+ if (ft->segh != NULL && ft->segh->reqtype == FTIO_RDAHEAD &&
+ blk == ft->segh->reqblk) {
+ sp = ft->segh;
sp->reqtype = FTIO_READING;
sp->reqbad = sr->sg_badmap;
goto rdwait;
- } else
- ft->curseg->reqcan = 1; /* XXX cancel rdahead */
+ }
}
/* Wait until we're ready. */
- while (ft->active) sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ tape_inactive(ftu);
/* Set up a new read request. */
- sp = ft->curseg;
+ sp = segio_alloc(ft);
sp->reqcrc = 0;
sp->reqbad = sr->sg_badmap;
sp->reqblk = blk;
+ sp->reqseg = seg;
sp->reqcan = 0;
sp->reqtype = FTIO_READING;
+ segio_queue(ft, sp);
/* Start the read request off. */
DPRT(("Starting read I/O chain\n"));
arq_state = ard_state = awr_state = 0;
ft->xblk = sp->reqblk;
+ ft->xseg = sp->reqseg;
ft->xcnt = 0;
ft->xptr = sp->buff;
ft->active = 1;
timeout(ft_timeout, (caddr_t)ftu, 1);
rdwait:
- sleep((caddr_t)&ftsem.buff_avail, FTPRI);
+ ftsleep(wc_buff_done, 0);
+
+rddone:
bad = sp->reqbad;
sr->sg_crcmap = sp->reqcrc & ~bad;
@@ -1833,17 +2208,29 @@ rdwait:
copyout(cp, cp2, QCV_BLKSIZE);
cp2 += QCV_BLKSIZE;
}
+ segio_free(ft, sp);
} else {
- if (ft->curseg->reqtype == FTIO_RDAHEAD) {
- ft->curseg->reqcan = 1; /* XXX cancel rdahead */
- while (ft->active)
- sleep((caddr_t)&ftsem.iosts_change, FTPRI);
+ if (ft->segh != NULL && ft->segh->reqtype != FTIO_WRITING)
+ tape_inactive(ftu);
+
+ /* Allocate a buffer and start tape if we're running low. */
+ sp = segio_alloc(ft);
+ if (!ft->active && (sp == NULL || ft->nfreelist <= 1)) {
+ DPRT(("Starting write I/O chain\n"));
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = ft->segh->reqblk;
+ ft->xseg = ft->segh->reqseg;
+ ft->xcnt = 0;
+ ft->xptr = ft->segh->buff;
+ ft->active = 1;
+ timeout(ft_timeout, (caddr_t)ftu, 1);
}
/* Sleep until a buffer becomes available. */
- while (ft->bufseg->reqtype != FTIO_READY)
- sleep((caddr_t)&ftsem.buff_avail, FTPRI);
- sp = (ft->curseg->reqtype == FTIO_READY) ? ft->curseg : ft->bufseg;
+ while (sp == NULL) {
+ ftsleep(wc_buff_avail, 0);
+ sp = segio_alloc(ft);
+ }
/* Copy in segment and expand bad blocks. */
bad = sr->sg_badmap;
@@ -1853,28 +2240,22 @@ rdwait:
copyin(cp, cp2, QCV_BLKSIZE);
cp += QCV_BLKSIZE;
}
-
sp->reqblk = blk;
+ sp->reqseg = seg;
sp->reqcan = 0;
sp->reqtype = FTIO_WRITING;
-
- if (!ft->active) {
- DPRT(("Starting write I/O chain\n"));
- arq_state = ard_state = awr_state = 0;
- ft->xblk = sp->reqblk;
- ft->xcnt = 0;
- ft->xptr = sp->buff;
- ft->active = 1;
- timeout(ft_timeout, (caddr_t)ftu, 1);
- }
+ segio_queue(ft, sp);
}
splx(s);
return(0);
}
-/* Rewind to beginning of tape */
-int ftreq_rewind(ftu_t ftu)
+/*
+ * Rewind to beginning of tape
+ */
+static int
+ftreq_rewind(ftu_t ftu)
{
ft_p ft = &ft_data[ftu];
@@ -1891,8 +2272,12 @@ int ftreq_rewind(ftu_t ftu)
return(0);
}
-/* Move to logical beginning or end of track */
-int ftreq_trkpos(ftu_t ftu, int req)
+
+/*
+ * Move to logical beginning or end of track
+ */
+static int
+ftreq_trkpos(ftu_t ftu, int req)
{
int curtrk, r, cmd;
ft_p ft = &ft_data[ftu];
@@ -1919,8 +2304,12 @@ int ftreq_trkpos(ftu_t ftu, int req)
return(0);
}
-/* Seek tape head to a particular track. */
-int ftreq_trkset(ftu_t ftu, int *trk)
+
+/*
+ * Seek tape head to a particular track.
+ */
+static int
+ftreq_trkset(ftu_t ftu, int *trk)
{
int curtrk, r, cmd;
ft_p ft = &ft_data[ftu];
@@ -1942,27 +2331,45 @@ int ftreq_trkset(ftu_t ftu, int *trk)
return(0);
}
-/* Start tape moving forward. */
-int ftreq_lfwd(ftu_t ftu)
+
+/*
+ * Start tape moving forward.
+ */
+static int
+ftreq_lfwd(ftu_t ftu)
{
+ ft_p ft = &ft_data[ftu];
+
tape_inactive(ftu);
tape_cmd(ftu, QC_STOP);
tape_state(ftu, 0, QS_READY, 90);
tape_cmd(ftu, QC_FORWARD);
+ ft->moving = 1;
return(0);
}
-/* Stop the tape */
-int ftreq_stop(ftu_t ftu)
+
+/*
+ * Stop the tape
+ */
+static int
+ftreq_stop(ftu_t ftu)
{
+ ft_p ft = &ft_data[ftu];
+
tape_inactive(ftu);
tape_cmd(ftu, QC_STOP);
tape_state(ftu, 0, QS_READY, 90);
+ ft->moving = 0;
return(0);
}
-/* Set the particular mode the drive should be in. */
-int ftreq_setmode(ftu_t ftu, int cmd)
+
+/*
+ * Set the particular mode the drive should be in.
+ */
+static int
+ftreq_setmode(ftu_t ftu, int cmd)
{
int r;
ft_p ft = &ft_data[ftu];
@@ -1989,8 +2396,12 @@ int ftreq_setmode(ftu_t ftu, int cmd)
return(0);
}
-/* Return drive status bits */
-int ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
+
+/*
+ * Return drive status bits
+ */
+static int
+ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
{
ft_p ft = &ft_data[ftu];
@@ -2001,8 +2412,12 @@ int ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
return(0);
}
-/* Return drive configuration bits */
-int ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
+
+/*
+ * Return drive configuration bits
+ */
+static int
+ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
{
int r, tries;
ft_p ft = &ft_data[ftu];
@@ -2018,8 +2433,12 @@ int ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
return(0);
}
-/* Return current tape's geometry. */
-int ftreq_geom(ftu_t ftu, QIC_Geom *g)
+
+/*
+ * Return current tape's geometry.
+ */
+static int
+ftreq_geom(ftu_t ftu, QIC_Geom *g)
{
tape_inactive(ftu);
if (ftg == NULL && ftgetgeom(ftu) < 0) return(ENXIO);
@@ -2027,8 +2446,12 @@ int ftreq_geom(ftu_t ftu, QIC_Geom *g)
return(0);
}
-/* Return drive hardware information */
-int ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
+
+/*
+ * Return drive hardware information
+ */
+static int
+ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
{
int r, tries;
int rom, vend;
@@ -2053,10 +2476,31 @@ int ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
return(0);
}
+
+/*
+ * Receive or Send the in-core header segment.
+ */
+static int
+ftreq_hdr(ftu_t ftu, int cmd, QIC_Segment *sp)
+{
+ ft_p ft = &ft_data[ftu];
+ QIC_Header *h = (QIC_Header *)ft->hdr->buff;
+
+ if (sp == NULL || sp->sg_data == NULL) return(EINVAL);
+ if (cmd == QIOSENDHDR) {
+ copyin(sp->sg_data, ft->hdr->buff, QCV_SEGSIZE);
+ } else {
+ if (h->qh_sig != QCV_HDRMAGIC) return(EIO);
+ copyout(ft->hdr->buff, sp->sg_data, QCV_SEGSIZE);
+ }
+ return(0);
+}
+
/*
* I/O functions.
*/
-int ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+int
+ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
{
ftu_t ftu = FDUNIT(minor(dev));
ft_p ft = &ft_data[ftu];
@@ -2104,20 +2548,30 @@ int ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
case QIOHWINFO:
return(ftreq_hwinfo(ftu, (QIC_HWInfo *)data));
+
+ case QIOSENDHDR:
+ case QIORECVHDR:
+ return(ftreq_hdr(ftu, cmd, (QIC_Segment *)data));
}
badreq:
DPRT(("ft%d: unknown ioctl(%d) request\n", ftu, cmd));
return(ENXIO);
}
-/* Not implemented */
-int ftdump(dev_t dev)
+/*
+ * Not implemented
+ */
+int
+ftdump(dev_t dev)
{
return(EINVAL);
}
-/* Not implemented */
-int ftsize(dev_t dev)
+/*
+ * Not implemented
+ */
+int
+ftsize(dev_t dev)
{
return(EINVAL);
}
diff --git a/sys/i386/isa/ftreg.h b/sys/i386/isa/ftreg.h
index 7b4ca6a27236..c29540ce0a96 100644
--- a/sys/i386/isa/ftreg.h
+++ b/sys/i386/isa/ftreg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Steve Gerakines
+ * Copyright (c) 1993, 1994 Steve Gerakines
*
* This is freely redistributable software. You may do anything you
* wish with it, so long as the above notice stays intact.
@@ -17,6 +17,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* ftreg.h - QIC-40/80 floppy tape driver header
+ * 06/03/94 v0.9
+ * Changed seek load point to QC_SEEKLP, added reqseg to SegReq structure.
+ *
* 10/30/93 v0.3
* More things will end up here. QC_VENDORID and QC_VERSION now used.
*
@@ -42,7 +45,7 @@
#define QC_SEEKSTART 11 /* seek to track start */
#define QC_SEEKEND 12 /* seek to track end */
#define QC_SEEKTRACK 13 /* seek head to track */
-#define QC_SEEKLOAD 14 /* seek load point */
+#define QC_SEEKLP 14 /* seek load point */
#define QC_FORMAT 15 /* format mode */
#define QC_WRITEREF 16 /* write reference */
#define QC_VERIFY 17 /* verify mode */
@@ -62,7 +65,7 @@
/* Colorado enable/disable. */
#define QC_COL_ENABLE1 46 /* enable */
-#define QC_COL_ENABLE2 2 /* null-op */
+#define QC_COL_ENABLE2 2 /* unit+2 */
#define QC_COL_DISABLE 47 /* disable */
/* Mountain enable/disable. */
@@ -77,5 +80,7 @@ typedef struct segq {
long reqcrc; /* CRC Errors found */
long reqbad; /* Bad sector map */
long reqblk; /* Block request starts at */
+ long reqseg; /* Segment request is at */
int reqcan; /* Cancel read-ahead */
+ struct segq *next; /* Next request */
} SegReq;
diff --git a/sys/i386/isa/ic/i82365.h b/sys/i386/isa/ic/i82365.h
new file mode 100644
index 000000000000..ab381250ea72
--- /dev/null
+++ b/sys/i386/isa/ic/i82365.h
@@ -0,0 +1,190 @@
+#ifndef __83265_H__
+#define __83265_H__
+
+/***********************************************************************
+ * 82365.h -- information necessary for direct manipulation of PCMCIA
+ * cards and controllers
+ *
+ * Support is included for Intel 82365SL PCIC controllers and clones
+ * thereof.
+ *
+ * originally by Barry Jaspan; hacked over by Keith Moore
+ *
+ ***********************************************************************/
+
+/*
+ * PCIC Registers
+ * Each register is given a name, and most of the bits are named too.
+ * I should really name them all.
+ *
+ * Finally, since the banks can be addressed with a regular syntax,
+ * some macros are provided for that purpose.
+ */
+
+#define PCIC_BASE 0x03e0 /* base adddress of pcic register set */
+
+/* First, all the registers */
+#define PCIC_ID_REV 0x00 /* Identification and Revision */
+#define PCIC_STATUS 0x01 /* Interface Status */
+#define PCIC_POWER 0x02 /* Power and RESETDRV control */
+#define PCIC_INT_GEN 0x03 /* Interrupt and General Control */
+#define PCIC_STAT_CHG 0x04 /* Card Status Change */
+#define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */
+#define PCIC_ADDRWINE 0x06 /* Address Window Enable */
+#define PCIC_IOCTL 0x07 /* I/O Control */
+#define PCIC_IO0_STL 0x08 /* I/O Address 0 Start Low Byte */
+#define PCIC_IO0_STH 0x09 /* I/O Address 0 Start High Byte */
+#define PCIC_IO0_SPL 0x0a /* I/O Address 0 Stop Low Byte */
+#define PCIC_IO0_SPH 0x0b /* I/O Address 0 Stop High Byte */
+#define PCIC_IO1_STL 0x0c /* I/O Address 1 Start Low Byte */
+#define PCIC_IO1_STH 0x0d /* I/O Address 1 Start High Byte */
+#define PCIC_IO1_SPL 0x0e /* I/O Address 1 Stop Low Byte */
+#define PCIC_IO1_SPH 0x0f /* I/O Address 1 Stop High Byte */
+#define PCIC_SM0_STL 0x10 /* System Memory Address 0 Mapping Start Low Byte */
+#define PCIC_SM0_STH 0x11 /* System Memory Address 0 Mapping Start High Byte */
+#define PCIC_SM0_SPL 0x12 /* System Memory Address 0 Mapping Stop Low Byte */
+#define PCIC_SM0_SPH 0x13 /* System Memory Address 0 Mapping Stop High Byte */
+#define PCIC_CM0_L 0x14 /* Card Memory Offset Address 0 Low Byte */
+#define PCIC_CM0_H 0x15 /* Card Memory Offset Address 0 High Byte */
+#define PCIC_CDGC 0x16 /* Card Detect and General Control */
+#define PCIC_RES17 0x17 /* Reserved */
+#define PCIC_SM1_STL 0x18 /* System Memory Address 1 Mapping Start Low Byte */
+#define PCIC_SM1_STH 0x19 /* System Memory Address 1 Mapping Start High Byte */
+#define PCIC_SM1_SPL 0x1a /* System Memory Address 1 Mapping Stop Low Byte */
+#define PCIC_SM1_SPH 0x1b /* System Memory Address 1 Mapping Stop High Byte */
+#define PCIC_CM1_L 0x1c /* Card Memory Offset Address 1 Low Byte */
+#define PCIC_CM1_H 0x1d /* Card Memory Offset Address 1 High Byte */
+#define PCIC_GLO_CTRL 0x1e /* Global Control Register */
+#define PCIC_RES1F 0x1f /* Reserved */
+#define PCIC_SM2_STL 0x20 /* System Memory Address 2 Mapping Start Low Byte */
+#define PCIC_SM2_STH 0x21 /* System Memory Address 2 Mapping Start High Byte */
+#define PCIC_SM2_SPL 0x22 /* System Memory Address 2 Mapping Stop Low Byte */
+#define PCIC_SM2_SPH 0x23 /* System Memory Address 2 Mapping Stop High Byte */
+#define PCIC_CM2_L 0x24 /* Card Memory Offset Address 2 Low Byte */
+#define PCIC_CM2_H 0x25 /* Card Memory Offset Address 2 High Byte */
+#define PCIC_RES26 0x26 /* Reserved */
+#define PCIC_RES27 0x27 /* Reserved */
+#define PCIC_SM3_STL 0x28 /* System Memory Address 3 Mapping Start Low Byte */
+#define PCIC_SM3_STH 0x29 /* System Memory Address 3 Mapping Start High Byte */
+#define PCIC_SM3_SPL 0x2a /* System Memory Address 3 Mapping Stop Low Byte */
+#define PCIC_SM3_SPH 0x2b /* System Memory Address 3 Mapping Stop High Byte */
+#define PCIC_CM3_L 0x2c /* Card Memory Offset Address 3 Low Byte */
+#define PCIC_CM3_H 0x2d /* Card Memory Offset Address 3 High Byte */
+#define PCIC_RES2E 0x2e /* Reserved */
+#define PCIC_RES2F 0x2f /* Reserved */
+#define PCIC_SM4_STL 0x30 /* System Memory Address 4 Mapping Start Low Byte */
+#define PCIC_SM4_STH 0x31 /* System Memory Address 4 Mapping Start High Byte */
+#define PCIC_SM4_SPL 0x32 /* System Memory Address 4 Mapping Stop Low Byte */
+#define PCIC_SM4_SPH 0x33 /* System Memory Address 4 Mapping Stop High Byte */
+#define PCIC_CM4_L 0x34 /* Card Memory Offset Address 4 Low Byte */
+#define PCIC_CM4_H 0x35 /* Card Memory Offset Address 4 High Byte */
+#define PCIC_RES36 0x36 /* Reserved */
+#define PCIC_RES37 0x37 /* Reserved */
+#define PCIC_RES38 0x38 /* Reserved */
+#define PCIC_RES39 0x39 /* Reserved */
+#define PCIC_RES3A 0x3a /* Reserved */
+#define PCIC_RES3B 0x3b /* Reserved */
+#define PCIC_RES3C 0x3c /* Reserved */
+#define PCIC_RES3D 0x3d /* Reserved */
+#define PCIC_RES3E 0x3e /* Reserved */
+#define PCIC_RES3F 0x3f /* Reserved */
+
+/* Now register bits, ordered by reg # */
+
+/* For Identification and Revision (PCIC_ID_REV) */
+#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */
+#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */
+#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */
+#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */
+
+/* For Interface Status register (PCIC_STATUS) */
+#define PCIC_VPPV 0x80 /* Vpp_valid */
+#define PCIC_POW 0x40 /* PC Card power active */
+#define PCIC_READY 0x20 /* Ready/~Busy */
+#define PCIC_MWP 0x10 /* Memory Write Protect */
+#define PCIC_CD 0x0C /* Both card detect bits */
+#define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */
+
+/* For the Power and RESETDRV register (PCIC_POWER) */
+#define PCIC_OUTENA 0x80 /* Output Enable */
+#define PCIC_DISRST 0x40 /* Disable RESETDRV */
+#define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */
+#define PCIC_PCPWRE 0x10 /* PC Card Power Enable */
+
+/* For the Interrupt and General Control register (PCIC_INT_GEN) */
+#define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */
+#define PCIC_IOCARD 0x20
+#define PCIC_MEMCARD 0x00
+#define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */
+
+/* For the Card Status Change register (PCIC_STAT_CHG) */
+#define PCIC_CDTCH 0x08 /* Card Detect Change */
+#define PCIC_RDYCH 0x04 /* Ready Change */
+#define PCIC_BATWRN 0x02 /* Battery Warning */
+#define PCIC_BATDED 0x01 /* Battery Dead */
+
+/* For the Address Window Enable Register (PCIC_ADDRWINE) */
+#define PCIC_SM0_EN 0x01 /* Memory Window 0 Enable */
+#define PCIC_SM1_EN 0x02 /* Memory Window 1 Enable */
+#define PCIC_SM2_EN 0x04 /* Memory Window 2 Enable */
+#define PCIC_SM3_EN 0x08 /* Memory Window 3 Enable */
+#define PCIC_SM4_EN 0x10 /* Memory Window 4 Enable */
+#define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */
+#define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */
+#define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */
+
+/* For the I/O Control Register (PCIC_IOCTL) */
+#define PCIC_IO0_16BIT 0x01 /* I/O to this segment is 16 bit */
+#define PCIC_IO0_CS16 0x02 /* I/O cs16 source is the card */
+#define PCIC_IO0_0WS 0x04 /* zero wait states added on 8 bit cycles */
+#define PCIC_IO0_WS 0x08 /* Wait states added for 16 bit cycles */
+#define PCIC_IO1_16BIT 0x10 /* I/O to this segment is 16 bit */
+#define PCIC_IO1_CS16 0x20 /* I/O cs16 source is the card */
+#define PCIC_IO1_0WS 0x04 /* zero wait states added on 8 bit cycles */
+#define PCIC_IO1_WS 0x80 /* Wait states added for 16 bit cycles */
+
+/* For the various I/O and Memory windows */
+#define PCIC_ADDR_LOW 0
+#define PCIC_ADDR_HIGH 1
+#define PCIC_START 0x00 /* Start of mapping region */
+#define PCIC_END 0x02 /* End of mapping region */
+#define PCIC_MOFF 0x04 /* Card Memory Mapping region offset */
+#define PCIC_IO0 0x08 /* I/O Address 0 */
+#define PCIC_IO1 0x0c /* I/O Address 1 */
+#define PCIC_SM0 0x10 /* System Memory Address 0 Mapping */
+#define PCIC_SM1 0x18 /* System Memory Address 1 Mapping */
+#define PCIC_SM2 0x20 /* System Memory Address 2 Mapping */
+#define PCIC_SM3 0x28 /* System Memory Address 3 Mapping */
+#define PCIC_SM4 0x30 /* System Memory Address 4 Mapping */
+
+/* For System Memory Window start registers
+ (PCIC_SMx|PCIC_START|PCIC_ADDR_HIGH) */
+#define PCIC_ZEROWS 0x40 /* Zero wait states */
+#define PCIC_DATA16 0x80 /* Data width is 16 bits */
+
+/* For System Memory Window stop registers
+ (PCIC_SMx|PCIC_END|PCIC_ADDR_HIGH) */
+#define PCIC_MW0 0x40 /* Wait state bit 0 */
+#define PCIC_MW1 0x80 /* Wait state bit 1 */
+
+/* For System Memory Window offset registers
+ (PCIC_SMx|PCIC_MOFF|PCIC_ADDR_HIGH) */
+#define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */
+#define PCIC_WP 0x80 /* Write-protect this window */
+
+/* For Card Detect and General Control register (PCIC_CDGC) */
+#define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */
+#define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */
+#define PCIC_GPI_EN 0x04 /* GPI Enable */
+#define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */
+#define PCIC_CDRES_EN 0x10 /* card detect resume enable */
+#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */
+
+/* For Global Control register (PCIC_GLO_CTRL) */
+#define PCIC_PWR_DOWN 0x01 /* power down */
+#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */
+#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */
+#define PCIC_IRQ14_PULSE 0x08 /* irq 14 pulse mode enable */
+
+/* DON'T ADD ANYTHING AFTER THIS #endif */
+#endif /* __83265_H__ */
diff --git a/sys/i386/isa/ic/nec765.h b/sys/i386/isa/ic/nec765.h
index df6c337482aa..c02e6ef362ba 100644
--- a/sys/i386/isa/ic/nec765.h
+++ b/sys/i386/isa/ic/nec765.h
@@ -30,8 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
- * $Id: nec765.h,v 1.2 1993/10/16 13:48:50 rgrimes Exp $
+ * @(#)nec765.h 7.1 (Berkeley) 5/9/91
*/
/*
@@ -47,26 +46,90 @@
#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"
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005equ_chck\004drive_notrdy\003top_head"
+
+#define NE7_ST0_IC 0xc0 /* interrupt completion code */
+
+#define NE7_ST0_IC_RC 0xc0 /* terminated due to ready changed, n/a */
+#define NE7_ST0_IC_IV 0x80 /* invalid command; must reset FDC */
+#define NE7_ST0_IC_AT 0x40 /* abnormal termination, check error stat */
+#define NE7_ST0_IC_NT 0x00 /* normal termination */
+
+#define NE7_ST0_SE 0x20 /* seek end */
+#define NE7_ST0_EC 0x10 /* equipment check, recalibrated but no trk0 */
+#define NE7_ST0_NR 0x08 /* not ready (n/a) */
+#define NE7_ST0_HD 0x04 /* upper head selected */
+#define NE7_ST0_DR 0x03 /* drive code */
/* Status register ST1 */
#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+#define NE7_ST1_EN 0x80 /* end of cylinder, access past last record */
+#define NE7_ST1_DE 0x20 /* data error, CRC fail in ID or data */
+#define NE7_ST1_OR 0x10 /* DMA overrun, DMA failed to do i/o quickly */
+#define NE7_ST1_ND 0x04 /* no data, sector not found or CRC in ID f. */
+#define NE7_ST1_NW 0x02 /* not writeable, attempt to violate WP */
+#define NE7_ST1_MA 0x01 /* missing address mark (in ID or data field)*/
+
/* Status register ST2 */
#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+#define NE7_ST2_CM 0x40 /* control mark; found deleted data */
+#define NE7_ST2_DD 0x20 /* data error in data field, CRC fail */
+#define NE7_ST2_WC 0x10 /* wrong cylinder, ID field mismatches cmd */
+#define NE7_ST2_SH 0x08 /* scan equal hit */
+#define NE7_ST2_SN 0x04 /* scan not satisfied */
+#define NE7_ST2_BC 0x02 /* bad cylinder, cylinder marked 0xff */
+#define NE7_ST2_MD 0x01 /* missing address mark in data field */
+
/* Status register ST3 */
#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+#define NE7_ST3_FT 0x80 /* fault; PC: n/a */
+#define NE7_ST3_WP 0x40 /* write protected */
+#define NE7_ST3_RD 0x20 /* ready; PC: always true */
+#define NE7_ST3_T0 0x10 /* track 0 */
+#define NE7_ST3_TS 0x08 /* two-sided; PC: n/a */
+#define NE7_ST3_HD 0x04 /* upper head select */
+#define NE7_ST3_US 0x03 /* unit select */
+
/* Commands */
+/*
+ * the top three bits -- where appropriate -- are set as follows:
+ *
+ * 0x80 - MT multi-track; allow both sides to be handled in single cmd
+ * 0x40 - MFM modified frequency modulation; use MFM encoding
+ * 0x20 - SK skip; skip sectors marked as "deleted"
+ */
+#define NE7CMD_READTRK 0x42 /* read whole track */
#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
+#define NE7CMD_WRITEDEL 0xc9 /* write deleted data */
+#define NE7CMD_READID 0x4a /* read ID field */
+#define NE7CMD_READDEL 0xec /* read deleted data */
+#define NE7CMD_FORMAT 0x4d /* format - requires five additional bytes */
+#define NE7CMD_SEEK 0x0f /* seek drive - requires unit select byte
and new cyl byte */
+#define NE7CMD_SCNEQU 0xf1 /* scan equal */
+#define NE7CMD_SCNLE 0xf9 /* scan less or equal */
+#define NE7CMD_SCNGE 0xfd /* scan greater or equal */
+
+
+/*
+ * "specify" definitions
+ *
+ * acronyms (times are relative to a FDC clock of 8 MHz):
+ * srt - step rate; PC usually 3 ms
+ * hut - head unload time; PC usually maximum of 240 ms
+ * hlt - head load time; PC usually minimum of 2 ms
+ * nd - no DMA flag; PC usually not set (0)
+ */
+
+#define NE7_SPEC_1(srt, hut) (((16 - (srt)) << 4) | (((hut) / 16)))
+#define NE7_SPEC_2(hlt, nd) (((hlt) & 0xFE) | ((nd) & 1))
diff --git a/sys/i386/isa/icu.h b/sys/i386/isa/icu.h
index af50335f4468..523f3351a859 100644
--- a/sys/i386/isa/icu.h
+++ b/sys/i386/isa/icu.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)icu.h 5.6 (Berkeley) 5/9/91
- * $Id: icu.h,v 1.2 1993/10/16 13:45:51 rgrimes Exp $
+ * $Id: icu.h,v 1.3 1994/04/02 07:00:40 davidg Exp $
*/
/*
@@ -51,12 +51,6 @@
* Interrupt "level" mechanism variables, masks, and macros
*/
extern unsigned imen; /* interrupt mask enable */
-extern unsigned cpl; /* current priority level mask */
-
-extern unsigned highmask; /* group of interrupts masked with splhigh() */
-extern unsigned ttymask; /* group of interrupts masked with spltty() */
-extern unsigned biomask; /* group of interrupts masked with splbio() */
-extern unsigned netmask; /* group of interrupts masked with splimp() */
#define INTREN(s) (imen &= ~(s), SET_ICUS())
#define INTRDIS(s) (imen |= (s), SET_ICUS())
@@ -74,7 +68,7 @@ extern unsigned netmask; /* group of interrupts masked with splimp() */
#endif
/*
- * Interrupt enable bits -- in order of priority
+ * Interrupt enable bits - in normal order of priority (which we change)
*/
#define IRQ0 0x0001 /* highest priority - timer */
#define IRQ1 0x0002
@@ -88,7 +82,7 @@ extern unsigned netmask; /* group of interrupts masked with splimp() */
#define IRQ13 0x2000
#define IRQ14 0x4000
#define IRQ15 0x8000
-#define IRQ3 0x0008
+#define IRQ3 0x0008 /* this is highest after rotation */
#define IRQ4 0x0010
#define IRQ5 0x0020
#define IRQ6 0x0040
diff --git a/sys/i386/isa/icu.s b/sys/i386/isa/icu.s
index d1c843951b83..9484e5cdbedd 100644
--- a/sys/i386/isa/icu.s
+++ b/sys/i386/isa/icu.s
@@ -36,7 +36,7 @@
*
* @(#)icu.s 7.2 (Berkeley) 5/21/91
*
- * $Id: icu.s,v 1.7 1993/12/20 14:58:21 wollman Exp $
+ * $Id: icu.s,v 1.8 1994/04/02 07:00:41 davidg Exp $
*/
/*
@@ -45,215 +45,131 @@
*/
/*
- * XXX - this file is now misnamed. All spls are now soft and the only thing
- * related to the hardware icu is that the bit numbering is the same in the
- * soft priority masks as in the hard ones.
+ * XXX this file should be named ipl.s. All spls are now soft and the
+ * only thing related to the hardware icu is that the h/w interrupt
+ * numbers are used without translation in the masks.
*/
-#include "sio.h"
-#define HIGHMASK 0xffff
-#define SOFTCLOCKMASK 0x8000
+#include "../net/netisr.h"
.data
-
.globl _cpl
-_cpl: .long 0xffff /* current priority (all off) */
-
+_cpl: .long HWI_MASK | SWI_MASK /* current priority (all off) */
.globl _imen
-_imen: .long 0xffff /* interrupt mask enable (all off) */
-
-/* .globl _highmask */
-_highmask: .long HIGHMASK
-
- .globl _ttymask, _biomask, _netmask
-_ttymask: .long 0
-_biomask: .long 0
-_netmask: .long 0
-
- .globl _ipending, _astpending
+_imen: .long HWI_MASK /* interrupt mask enable (all h/w off) */
+_high_imask: .long HWI_MASK | SWI_MASK
+ .globl _tty_imask
+_tty_imask: .long 0
+ .globl _bio_imask
+_bio_imask: .long 0
+ .globl _net_imask
+_net_imask: .long 0
+ .globl _ipending
_ipending: .long 0
+ .globl _astpending
_astpending: .long 0 /* tells us an AST needs to be taken */
-
.globl _netisr
_netisr: .long 0 /* set with bits for which queue to service */
-
vec:
.long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7
.long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15
-#define GENSPL(name, mask, event) \
- .globl _spl/**/name ; \
- ALIGN_TEXT ; \
-_spl/**/name: ; \
- COUNT_EVENT(_intrcnt_spl, event) ; \
- movl _cpl,%eax ; \
- movl %eax,%edx ; \
- orl mask,%edx ; \
- movl %edx,_cpl ; \
- SHOW_CPL ; \
- ret
-
-#define FASTSPL(mask) \
- movl mask,_cpl ; \
- SHOW_CPL
-
-#define FASTSPL_VARMASK(varmask) \
- movl varmask,%eax ; \
- movl %eax,_cpl ; \
- SHOW_CPL
-
.text
- ALIGN_TEXT
-unpend_v:
- COUNT_EVENT(_intrcnt_spl, 0)
- bsfl %eax,%eax # slow, but not worth optimizing
- btrl %eax,_ipending
- jnc unpend_v_next # some intr cleared the in-memory bit
- SHOW_IPENDING
- movl Vresume(,%eax,4),%eax
- testl %eax,%eax
- je noresume
- jmp %eax
-
- ALIGN_TEXT
-/*
- * XXX - must be some fastintr, need to register those too.
- */
-noresume:
-#if NSIO > 0
- call _softsio1
-#endif
-unpend_v_next:
- movl _cpl,%eax
- movl %eax,%edx
- notl %eax
- andl _ipending,%eax
- je none_to_unpend
- jmp unpend_v
-
/*
- * Handle return from interrupt after device handler finishes
- */
- ALIGN_TEXT
-doreti:
- COUNT_EVENT(_intrcnt_spl, 1)
- addl $4,%esp # discard unit arg
- popl %eax # get previous priority
-/*
- * Now interrupt frame is a trap frame!
- *
- * XXX - setting up the interrupt frame to be almost a stack frame is mostly
- * a waste of time.
+ * Handle return from interrupts, traps and syscalls.
*/
+ SUPERALIGN_TEXT
+_doreti:
+ FAKE_MCOUNT(_bintr) /* init "from" _bintr -> _doreti */
+ addl $4,%esp /* discard unit number */
+ popl %eax /* cpl to restore */
+doreti_next:
+ /*
+ * Check for pending HWIs and SWIs atomically with restoring cpl
+ * and exiting. The check has to be atomic with exiting to stop
+ * (ipending & ~cpl) changing from zero to nonzero while we're
+ * looking at it (this wouldn't be fatal but it would increase
+ * interrupt latency). Restoring cpl has to be atomic with exiting
+ * so that the stack cannot pile up (the nesting level of interrupt
+ * handlers is limited by the number of bits in cpl).
+ */
+ movl %eax,%ecx
+ notl %ecx
+ cli
+ andl _ipending,%ecx
+ jne doreti_unpend
+doreti_exit:
movl %eax,_cpl
- SHOW_CPL
- movl %eax,%edx
- notl %eax
- andl _ipending,%eax
- jne unpend_v
-none_to_unpend:
- testl %edx,%edx # returning to zero priority?
- jne 1f # nope, going to non-zero priority
- movl _netisr,%eax
- testl %eax,%eax # check for softint s/traps
- jne 2f # there are some
- jmp test_resched # XXX - schedule jumps better
- COUNT_EVENT(_intrcnt_spl, 2) # XXX
-
- ALIGN_TEXT # XXX
-1: # XXX
- COUNT_EVENT(_intrcnt_spl, 3)
+ MEXITCOUNT
popl %es
popl %ds
popal
addl $8,%esp
iret
-#include "../net/netisr.h"
-
-#define DONET(s, c, event) ; \
- .globl c ; \
- btrl $s,_netisr ; \
- jnc 1f ; \
- COUNT_EVENT(_intrcnt_spl, event) ; \
- call c ; \
-1:
-
ALIGN_TEXT
-2:
- COUNT_EVENT(_intrcnt_spl, 4)
-/*
- * XXX - might need extra locking while testing reg copy of netisr, but
- * interrupt routines setting it would not cause any new problems (since we
- * don't loop, fresh bits will not be processed until the next doreti or spl0).
- */
- testl $~((1 << NETISR_SCLK) | (1 << NETISR_AST)),%eax
- je test_ASTs # no net stuff, just temporary AST's
- FASTSPL_VARMASK(_netmask)
-#if 0
- DONET(NETISR_RAW, _rawintr, 5)
-#endif
-
-#ifdef INET
- DONET(NETISR_IP, _ipintr, 6)
-#endif /* INET */
-
-#ifdef IMP
- DONET(NETISR_IMP, _impintr, 7)
-#endif /* IMP */
-
-#ifdef NS
- DONET(NETISR_NS, _nsintr, 8)
-#endif /* NS */
-
-#ifdef ISO
- DONET(NETISR_ISO, _clnlintr, 9)
-#endif /* ISO */
+doreti_unpend:
+ /*
+ * Enabling interrupts is safe because we haven't restored cpl yet.
+ * The locking from the "btrl" test is probably no longer necessary.
+ * We won't miss any new pending interrupts because we will check
+ * for them again.
+ */
+ sti
+ bsfl %ecx,%ecx /* slow, but not worth optimizing */
+ btrl %ecx,_ipending
+ jnc doreti_next /* some intr cleared memory copy */
+ movl ihandlers(,%ecx,4),%edx
+ testl %edx,%edx
+ je doreti_next /* "can't happen" */
+ cmpl $NHWI,%ecx
+ jae doreti_swi
+ cli
+ movl %eax,_cpl
+ MEXITCOUNT
+ jmp %edx
-#ifdef CCITT
- DONET(NETISR_X25, _pkintr, 29)
- DONET(NETISR_HDLC, _hdintr, 30)
-#endif /* CCITT */
+ ALIGN_TEXT
+doreti_swi:
+ pushl %eax
+ /*
+ * The SWI_AST handler has to run at cpl = SWI_AST_MASK and the
+ * SWI_CLOCK handler at cpl = SWI_CLOCK_MASK, so we have to restore
+ * all the h/w bits in cpl now and have to worry about stack growth.
+ * The worst case is currently (30 Jan 1994) 2 SWI handlers nested
+ * in dying interrupt frames and about 12 HWIs nested in active
+ * interrupt frames. There are only 4 different SWIs and the HWI
+ * and SWI masks limit the nesting further.
+ */
+ orl imasks(,%ecx,4),%eax
+ movl %eax,_cpl
+ call %edx
+ popl %eax
+ jmp doreti_next
- FASTSPL($0)
-test_ASTs:
- btrl $NETISR_SCLK,_netisr
- jnc test_resched
- COUNT_EVENT(_intrcnt_spl, 10)
- FASTSPL($SOFTCLOCKMASK)
-/*
- * Back to an interrupt frame for a moment.
- */
- pushl $0 # previous cpl (probably not used)
- pushl $0x7f # dummy unit number
- call _softclock
- addl $8,%esp # discard dummies
- FASTSPL($0)
-test_resched:
-#ifdef notused1
- btrl $NETISR_AST,_netisr
- jnc 2f
-#endif
-#ifdef notused2
- cmpl $0,_want_resched
- je 2f
-#endif
- cmpl $0,_astpending # XXX - put it back in netisr to
- je 2f # reduce the number of tests
+ ALIGN_TEXT
+swi_ast:
+ addl $8,%esp /* discard raddr & cpl to get trap frame */
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
- # to non-kernel (i.e., user)?
- je 2f # nope, leave
- COUNT_EVENT(_intrcnt_spl, 11)
- movl $0,_astpending
+ je swi_ast_phantom
+ movl $T_ASTFLT,(2+8+0)*4(%esp)
call _trap
-2:
- COUNT_EVENT(_intrcnt_spl, 12)
- popl %es
- popl %ds
- popal
- addl $8,%esp
- iret
+ subl %eax,%eax /* recover cpl */
+ jmp doreti_next
+
+ ALIGN_TEXT
+swi_ast_phantom:
+ /*
+ * These happen when there is an interrupt in a trap handler before
+ * ASTs can be masked or in an lcall handler before they can be
+ * masked or after they are unmasked. They could be avoided for
+ * trap entries by using interrupt gates, and for lcall exits by
+ * using by using cli, but they are unavoidable for lcall entries.
+ */
+ cli
+ orl $SWI_AST_PENDING,_ipending
+ jmp doreti_exit /* SWI_AST is highest so we must be done */
/*
* Interrupt priority mechanism
@@ -262,121 +178,84 @@ test_resched:
* -- ipending = active interrupts currently masked by cpl
*/
- GENSPL(bio, _biomask, 13)
- GENSPL(clock, $HIGHMASK, 14) /* splclock == splhigh ex for count */
- GENSPL(high, $HIGHMASK, 15)
- GENSPL(imp, _netmask, 16) /* splimp == splnet except for count */
- GENSPL(net, _netmask, 17)
- GENSPL(softclock, $SOFTCLOCKMASK, 18)
- GENSPL(tty, _ttymask, 19)
-
- .globl _splnone
- .globl _spl0
- ALIGN_TEXT
-_splnone:
-_spl0:
- COUNT_EVENT(_intrcnt_spl, 20)
-in_spl0:
+ENTRY(splz)
+ /*
+ * The caller has restored cpl and checked that (ipending & ~cpl)
+ * is nonzero. We have to repeat the check since if there is an
+ * interrupt while we're looking, _doreti processing for the
+ * interrupt will handle all the unmasked pending interrupts
+ * because we restored early. We're repeating the calculation
+ * of (ipending & ~cpl) anyway so that the caller doesn't have
+ * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx"
+ * is undefined when %ecx is 0 so we can't rely on the secondary
+ * btrl tests.
+ */
movl _cpl,%eax
- pushl %eax # save old priority
- testl $(1 << NETISR_RAW) | (1 << NETISR_IP),_netisr
- je over_net_stuff_for_spl0
- movl _netmask,%eax # mask off those network devices
- movl %eax,_cpl # set new priority
- SHOW_CPL
-/*
- * XXX - what about other net intrs?
- */
-#if 0
- DONET(NETISR_RAW, _rawintr, 21)
-#endif
-
-#ifdef INET
- DONET(NETISR_IP, _ipintr, 22)
-#endif /* INET */
-
-#ifdef IMP
- DONET(NETISR_IMP, _impintr, 23)
-#endif /* IMP */
-
-#ifdef NS
- DONET(NETISR_NS, _nsintr, 24)
-#endif /* NS */
-
-#ifdef ISO
- DONET(NETISR_ISO, _clnlintr, 25)
-#endif /* ISO */
-
-over_net_stuff_for_spl0:
- movl $0,_cpl # set new priority
- SHOW_CPL
- movl _ipending,%eax
- testl %eax,%eax
- jne unpend_V
- popl %eax # return old priority
+splz_next:
+ /*
+ * We don't need any locking here. (ipending & ~cpl) cannot grow
+ * while we're looking at it - any interrupt will shrink it to 0.
+ */
+ movl %eax,%ecx
+ notl %ecx
+ andl _ipending,%ecx
+ jne splz_unpend
ret
- .globl _splx
ALIGN_TEXT
-_splx:
- COUNT_EVENT(_intrcnt_spl, 26)
- movl 4(%esp),%eax # new priority
- testl %eax,%eax
- je in_spl0 # going to "zero level" is special
- COUNT_EVENT(_intrcnt_spl, 27)
- movl _cpl,%edx # save old priority
- movl %eax,_cpl # set new priority
- SHOW_CPL
- notl %eax
- andl _ipending,%eax
- jne unpend_V_result_edx
- movl %edx,%eax # return old priority
- ret
-
- ALIGN_TEXT
-unpend_V_result_edx:
- pushl %edx
-unpend_V:
- COUNT_EVENT(_intrcnt_spl, 28)
- bsfl %eax,%eax
- btrl %eax,_ipending
- jnc unpend_V_next
- SHOW_IPENDING
- movl Vresume(,%eax,4),%edx
+splz_unpend:
+ bsfl %ecx,%ecx
+ btrl %ecx,_ipending
+ jnc splz_next
+ movl ihandlers(,%ecx,4),%edx
testl %edx,%edx
- je noresumeV
-/*
- * We would prefer to call the intr handler directly here but that doesn't
- * work for badly behaved handlers that want the interrupt frame. Also,
- * there's a problem determining the unit number. We should change the
- * interface so that the unit number is not determined at config time.
- */
- jmp *vec(,%eax,4)
+ je splz_next /* "can't happen" */
+ cmpl $NHWI,%ecx
+ jae splz_swi
+ /*
+ * We would prefer to call the intr handler directly here but that
+ * doesn't work for badly behaved handlers that want the interrupt
+ * frame. Also, there's a problem determining the unit number.
+ * We should change the interface so that the unit number is not
+ * determined at config time.
+ */
+ jmp *vec(,%ecx,4)
ALIGN_TEXT
+splz_swi:
+ cmpl $SWI_AST,%ecx
+ je splz_next /* "can't happen" */
+ pushl %eax
+ orl imasks(,%ecx,4),%eax
+ movl %eax,_cpl
+ call %edx
+ popl %eax
+ movl %eax,_cpl
+ jmp splz_next
+
/*
- * XXX - must be some fastintr, need to register those too.
+ * Fake clock IRQ so that it appears to come from our caller and not from
+ * vec0, so that kernel profiling works.
+ * XXX do this more generally (for all vectors; look up the C entry point).
+ * XXX frame bogusness stops us from just jumping to the C entry point.
*/
-noresumeV:
-#if NSIO > 0
- call _softsio1
-#endif
-unpend_V_next:
- movl _cpl,%eax
- notl %eax
- andl _ipending,%eax
- jne unpend_V
- popl %eax
- ret
+ ALIGN_TEXT
+vec0:
+ popl %eax /* return address */
+ pushfl
+#define KCSEL 8
+ pushl $KCSEL
+ pushl %eax
+ cli
+ MEXITCOUNT
+ jmp _Vclk
#define BUILD_VEC(irq_num) \
ALIGN_TEXT ; \
vec/**/irq_num: ; \
int $ICU_OFFSET + (irq_num) ; \
- popl %eax ; \
ret
- BUILD_VEC(0)
BUILD_VEC(1)
BUILD_VEC(2)
BUILD_VEC(3)
@@ -392,3 +271,58 @@ vec/**/irq_num: ; \
BUILD_VEC(13)
BUILD_VEC(14)
BUILD_VEC(15)
+
+ ALIGN_TEXT
+swi_clock:
+ MCOUNT
+ subl %eax,%eax
+ cmpl $_splz,(%esp) /* XXX call from splz()? */
+ jae 1f /* yes, usermode = 0 */
+ movl 4+4+TRAPF_CS_OFF(%esp),%eax /* no, check trap frame */
+ andl $SEL_RPL_MASK,%eax
+1:
+ pushl %eax
+ call _softclock
+ addl $4,%esp
+ ret
+
+#define DONET(s, c, event) ; \
+ .globl c ; \
+ btrl $s,_netisr ; \
+ jnc 9f ; \
+ call c ; \
+9:
+
+ ALIGN_TEXT
+swi_net:
+ MCOUNT
+#if 0
+ DONET(NETISR_RAW, _rawintr,netisr_raw)
+#endif
+#ifdef INET
+ DONET(NETISR_IP, _ipintr,netisr_ip)
+#endif
+#ifdef IMP
+ DONET(NETISR_IMP, _impintr,netisr_imp)
+#endif
+#ifdef NS
+ DONET(NETISR_NS, _nsintr,netisr_ns)
+#endif
+#ifdef ISO
+ DONET(NETISR_ISO, _clnlintr,netisr_iso)
+#endif
+#ifdef CCITT
+ DONET(NETISR_X25, _pkintr, 29)
+ DONET(NETISR_HDLC, _hdintr, 30)
+#endif
+ ret
+
+ ALIGN_TEXT
+swi_tty:
+ MCOUNT
+#include "sio.h"
+#if NSIO > 0
+ jmp _siopoll
+#else
+ ret
+#endif
diff --git a/sys/i386/isa/if_ed.c b/sys/i386/isa/if_ed.c
index 079f09cc9d3b..e806b1e471f9 100644
--- a/sys/i386/isa/if_ed.c
+++ b/sys/i386/isa/if_ed.c
@@ -16,7 +16,7 @@
*/
/*
- * $Id: if_ed.c,v 1.33.2.2 1994/04/17 06:04:33 rgrimes Exp $
+ * $Id: if_ed.c,v 1.42 1994/06/16 08:27:21 davidg Exp $
*/
#include "ed.h"
@@ -65,65 +65,71 @@
#ifndef IFF_ALTPHYS
#define IFF_ALTPHYS IFF_LLC0
#endif
-
+
/*
* ed_softc: per line info and status
*/
-struct ed_softc {
- struct arpcom arpcom; /* ethernet common */
+struct ed_softc {
+ struct arpcom arpcom; /* ethernet common */
- char *type_str; /* pointer to type string */
- u_char vendor; /* interface vendor */
- u_char type; /* interface type code */
+ char *type_str; /* pointer to type string */
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
- u_short asic_addr; /* ASIC I/O bus address */
- u_short nic_addr; /* NIC (DS8390) I/O bus address */
+ u_short asic_addr; /* ASIC I/O bus address */
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
/*
* The following 'proto' variable is part of a work-around for 8013EBT asics
* being write-only. It's sort of a prototype/shadow of the real thing.
*/
- u_char wd_laar_proto;
- u_char isa16bit; /* width of access to card 0=8 or 1=16 */
- int is790; /* set by the probe code if the card is 790 based */
-
- caddr_t bpf; /* BPF "magic cookie" */
- caddr_t mem_start; /* NIC memory start address */
- caddr_t mem_end; /* NIC memory end address */
- u_long mem_size; /* total NIC memory size */
- caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
-
- u_char mem_shared; /* NIC memory is shared with host */
- u_char xmit_busy; /* transmitter is busy */
- u_char txb_cnt; /* number of transmit buffers */
- u_char txb_inuse; /* number of TX buffers currently in-use*/
-
- u_char txb_new; /* pointer to where new buffer will be added */
- u_char txb_next_tx; /* pointer to next buffer ready to xmit */
- u_short txb_len[8]; /* buffered xmit buffer lengths */
- u_char tx_page_start; /* first page of TX buffer area */
- u_char rec_page_start; /* first page of RX ring-buffer */
- u_char rec_page_stop; /* last page of RX ring-buffer */
- u_char next_packet; /* pointer to next unread RX packet */
-} ed_softc[NED];
-
-int ed_attach(struct isa_device *);
-void ed_init(int);
-void edintr(int);
-int ed_ioctl(struct ifnet *, int, caddr_t);
-int ed_probe(struct isa_device *);
-void ed_start(struct ifnet *);
-void ed_reset(int, int);
-void ed_watchdog(int);
-
-static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
+ u_char wd_laar_proto;
+ u_char isa16bit; /* width of access to card 0=8 or 1=16 */
+ int is790; /* set by the probe code if the card is 790
+ * based */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+ caddr_t mem_start; /* NIC memory start address */
+ caddr_t mem_end; /* NIC memory end address */
+ u_long mem_size; /* total NIC memory size */
+ caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
+
+ u_char mem_shared; /* NIC memory is shared with host */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* number of transmit buffers */
+ u_char txb_inuse; /* number of TX buffers currently in-use */
+
+ u_char txb_new; /* pointer to where new buffer will be added */
+ u_char txb_next_tx; /* pointer to next buffer ready to xmit */
+ u_short txb_len[8]; /* buffered xmit buffer lengths */
+ u_char tx_page_start; /* first page of TX buffer area */
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ed_softc[NED];
+
+int ed_attach(struct isa_device *);
+void ed_init(int);
+void edintr(int);
+int ed_ioctl(struct ifnet *, int, caddr_t);
+int ed_probe(struct isa_device *);
+void ed_start(struct ifnet *);
+void ed_reset(int, int);
+void ed_watchdog(int);
+
+#ifdef MULTICAST
+void ds_getmcaf();
+
+#endif
+
+static void ed_get_packet(struct ed_softc *, char *, int /* u_short */ );
static void ed_stop(int);
static inline void ed_rint();
static inline void ed_xmit();
static inline char *ed_ring_copy();
-void ed_pio_readmem(), ed_pio_writemem();
+void ed_pio_readmem(), ed_pio_writemem();
u_short ed_pio_write_mbufs();
extern int ether_output();
@@ -138,7 +144,8 @@ struct isa_driver eddriver = {
ed_attach,
"ed"
};
-/*
+
+/*
* Interrupt conversion table for WD/SMC ASIC
* (IRQ* are defined in icu.h)
*/
@@ -152,7 +159,7 @@ static unsigned short ed_intr_mask[] = {
IRQ15,
IRQ4
};
-
+
/*
* Interrupt conversion table for 585/790 Combo
*/
@@ -166,6 +173,7 @@ static unsigned short ed_790_intr_mask[] = {
IRQ11,
IRQ15
};
+
#define ETHER_MIN_LEN 64
#define ETHER_MAX_LEN 1518
#define ETHER_ADDR_LEN 6
@@ -185,7 +193,7 @@ ed_probe(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- int nports;
+ int nports;
if (nports = ed_probe_WD80x3(isa_dev))
return (nports);
@@ -196,7 +204,7 @@ ed_probe(isa_dev)
if (nports = ed_probe_Novell(isa_dev))
return (nports);
- return(0);
+ return (0);
}
/*
@@ -219,7 +227,7 @@ ed_probe(isa_dev)
* the others would require changing register pages (which would be
* intrusive if this isn't an 8390).
*
- * Return 1 if 8390 was found, 0 if not.
+ * Return 1 if 8390 was found, 0 if not.
*/
int
@@ -227,15 +235,15 @@ ed_probe_generic8390(sc)
struct ed_softc *sc;
{
if ((inb(sc->nic_addr + ED_P0_CR) &
- (ED_CR_RD2|ED_CR_TXP|ED_CR_STA|ED_CR_STP)) !=
- (ED_CR_RD2|ED_CR_STP))
+ (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
+ (ED_CR_RD2 | ED_CR_STP))
return (0);
if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST)
return (0);
- return(1);
+ return (1);
}
-
+
/*
* Probe and vendor-specific initialization routine for SMC/WD80x3 boards
*/
@@ -244,9 +252,9 @@ ed_probe_WD80x3(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- int i;
- u_int memsize;
- u_char iptr, isa16bit, sum;
+ int i;
+ u_int memsize;
+ u_char iptr, isa16bit, sum;
sc->asic_addr = isa_dev->id_iobase;
sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
@@ -256,26 +264,27 @@ ed_probe_WD80x3(isa_dev)
outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW);
DELAY(10000);
#endif
+
/*
- * Attempt to do a checksum over the station address PROM.
- * If it fails, it's probably not a SMC/WD board. There
- * is a problem with this, though: some clone WD boards
- * don't pass the checksum test. Danpex boards for one.
+ * Attempt to do a checksum over the station address PROM. If it
+ * fails, it's probably not a SMC/WD board. There is a problem with
+ * this, though: some clone WD boards don't pass the checksum test.
+ * Danpex boards for one.
*/
for (sum = 0, i = 0; i < 8; ++i)
sum += inb(sc->asic_addr + ED_WD_PROM + i);
if (sum != ED_WD_ROM_CHECKSUM_TOTAL) {
+
/*
- * Checksum is invalid. This often happens with cheap
- * WD8003E clones. In this case, the checksum byte
- * (the eighth byte) seems to always be zero.
+ * Checksum is invalid. This often happens with cheap WD8003E
+ * clones. In this case, the checksum byte (the eighth byte)
+ * seems to always be zero.
*/
if (inb(sc->asic_addr + ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
inb(sc->asic_addr + ED_WD_PROM + 7) != 0)
- return(0);
+ return (0);
}
-
/* reset card to force it into a known state. */
#ifdef TOSH_ETHER
outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
@@ -318,7 +327,7 @@ ed_probe_WD80x3(isa_dev)
memsize = 16384;
isa16bit = 1;
break;
- case ED_TYPE_WD8013EP: /* also WD8003EP */
+ case ED_TYPE_WD8013EP: /* also WD8003EP */
if (inb(sc->asic_addr + ED_WD_ICR)
& ED_WD_ICR_16BIT) {
isa16bit = 1;
@@ -371,33 +380,35 @@ ed_probe_WD80x3(isa_dev)
sc->type_str = "";
break;
}
+
/*
- * Make some adjustments to initial values depending on what is
- * found in the ICR.
+ * Make some adjustments to initial values depending on what is found
+ * in the ICR.
*/
if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
#ifdef TOSH_ETHER
- && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
+ && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
#endif
&& ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
isa16bit = 0;
memsize = 8192;
}
-
#if ED_DEBUG
printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n",
- sc->type,sc->type_str,isa16bit,memsize,isa_dev->id_msize);
- for (i=0; i<8; i++)
+ sc->type, sc->type_str, isa16bit, memsize, isa_dev->id_msize);
+ for (i = 0; i < 8; i++)
printf("%x -> %x\n", i, inb(sc->asic_addr + i));
#endif
+
/*
* Allow the user to override the autoconfiguration
*/
if (isa_dev->id_msize)
memsize = isa_dev->id_msize;
+
/*
- * (note that if the user specifies both of the following flags
- * that '8bit' mode intentionally has precedence)
+ * (note that if the user specifies both of the following flags that
+ * '8bit' mode intentionally has precedence)
*/
if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
isa16bit = 1;
@@ -406,60 +417,66 @@ ed_probe_WD80x3(isa_dev)
/*
* Check 83C584 interrupt configuration register if this board has one
- * XXX - we could also check the IO address register. But why
- * bother...if we get past this, it *has* to be correct.
+ * XXX - we could also check the IO address register. But why
+ * bother...if we get past this, it *has* to be correct.
*/
if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) {
+
/*
* Assemble together the encoded interrupt number.
*/
iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) |
- ((inb(isa_dev->id_iobase + ED_WD_IRR) &
- (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+ ((inb(isa_dev->id_iobase + ED_WD_IRR) &
+ (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+
/*
- * Translate it using translation table, and check for correctness.
+ * Translate it using translation table, and check for
+ * correctness.
*/
if (ed_intr_mask[iptr] != isa_dev->id_irq) {
printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
- isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
- ffs(ed_intr_mask[iptr]) - 1);
- return(0);
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_intr_mask[iptr]) - 1);
+ return (0);
}
+
/*
* Enable the interrupt.
*/
outb(isa_dev->id_iobase + ED_WD_IRR,
- inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
+ inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
}
if (sc->is790) {
outb(isa_dev->id_iobase + ED_WD790_HWR,
- inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
+ inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
iptr = (((inb(isa_dev->id_iobase + ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
- (inb(isa_dev->id_iobase + ED_WD790_GCR) &
- (ED_WD790_GCR_IR1|ED_WD790_GCR_IR0)) >> 2);
+ (inb(isa_dev->id_iobase + ED_WD790_GCR) &
+ (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2);
outb(isa_dev->id_iobase + ED_WD790_HWR,
- inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
+ inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
if (ed_790_intr_mask[iptr] != isa_dev->id_irq) {
printf("ed%d: kernel configured irq %d doesn't match board configured irq %d %d\n",
- isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
- ffs(ed_790_intr_mask[iptr]) - 1, iptr);
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_790_intr_mask[iptr]) - 1, iptr);
return 0;
}
+
/*
* Enable interrupts.
*/
outb(isa_dev->id_iobase + ED_WD790_ICR,
- inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
+ inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
}
-
sc->isa16bit = isa16bit;
-#ifdef notyet /* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+/* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+#ifdef notyet
+
/*
* The following allows the WD/SMC boards to be used in Programmed I/O
- * mode - without mapping the NIC memory shared. ...Not the prefered
- * way, but it might be the only way.
+ * mode - without mapping the NIC memory shared. ...Not the prefered
+ * way, but it might be the only way.
*/
if (isa_dev->id_flags & ED_FLAGS_FORCE_PIO) {
sc->mem_shared = 0;
@@ -472,7 +489,7 @@ ed_probe_WD80x3(isa_dev)
#endif
isa_dev->id_msize = memsize;
- sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_start = (caddr_t) isa_dev->id_maddr;
/*
* allocate one xmit buffer if < 16k, two buffers otherwise
@@ -498,27 +515,6 @@ ed_probe_WD80x3(isa_dev)
sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i);
if (sc->mem_shared) {
- /*
- * Set address and enable interface shared memory.
- */
- if(!sc->is790) {
-#ifdef TOSH_ETHER
- outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
- outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
- outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
-
-#else
- outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
- ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
-#endif
- } else {
- outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
- outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
- outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
- ((kvtop(sc->mem_start) >> 11) & 0x40) |
- (inb(sc->asic_addr + 0x0b) & 0xb0));
- outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
- }
/*
* Set upper address bits and 8/16 bit access to shared memory
@@ -530,57 +526,85 @@ ed_probe_WD80x3(isa_dev)
(void) inb(0x84);
} else {
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
- ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
- ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
}
- } else {
+ } else {
if ((sc->type & ED_WD_SOFTCONFIG) ||
#ifdef TOSH_ETHER
(sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) ||
#endif
(sc->type == ED_TYPE_WD8013EBT) && (!sc->is790)) {
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
- ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
}
}
/*
+ * Set address and enable interface shared memory.
+ */
+ if (!sc->is790) {
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
+ outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
+
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
+ ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
+#endif
+ } else {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
+ outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
+ ((kvtop(sc->mem_start) >> 11) & 0x40) |
+ (inb(sc->asic_addr + 0x0b) & 0xb0));
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
+ }
+
+ /*
* Now zero memory and verify that it is clear
*/
bzero(sc->mem_start, memsize);
for (i = 0; i < memsize; ++i)
if (sc->mem_start[i]) {
- printf("ed%d: failed to clear shared memory at %x - check configuration\n",
- isa_dev->id_unit, kvtop(sc->mem_start + i));
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
/*
* Disable 16 bit access to shared memory
*/
if (isa16bit) {
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
- ~ED_WD_LAAR_M16EN));
+ ~ED_WD_LAAR_M16EN));
(void) inb(0x84);
}
-
- return(0);
+ return (0);
}
-
+
/*
- * Disable 16bit access to shared memory - we leave it disabled so
- * that 1) machines reboot properly when the board is set
- * 16 bit mode and there are conflicting 8bit devices/ROMS
- * in the same 128k address space as this boards shared
- * memory. and 2) so that other 8 bit devices with shared
- * memory can be used in this 128k region, too.
+ * Disable 16bit access to shared memory - we leave it
+ * disabled so that 1) machines reboot properly when the board
+ * is set 16 bit mode and there are conflicting 8bit
+ * devices/ROMS in the same 128k address space as this boards
+ * shared memory. and 2) so that other 8 bit devices with
+ * shared memory can be used in this 128k region, too.
*/
if (isa16bit) {
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
- ~ED_WD_LAAR_M16EN));
+ ~ED_WD_LAAR_M16EN));
(void) inb(0x84);
}
}
-
return (ED_WD_IO_PORTS);
}
@@ -592,84 +616,84 @@ ed_probe_3Com(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- int i;
- u_int memsize;
- u_char isa16bit, sum;
+ int i;
+ u_int memsize;
+ u_char isa16bit, sum;
sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
/*
* Verify that the kernel configured I/O address matches the board
- * configured address
+ * configured address
*/
switch (inb(sc->asic_addr + ED_3COM_BCFR)) {
case ED_3COM_BCFR_300:
if (isa_dev->id_iobase != 0x300)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_310:
if (isa_dev->id_iobase != 0x310)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_330:
if (isa_dev->id_iobase != 0x330)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_350:
if (isa_dev->id_iobase != 0x350)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_250:
if (isa_dev->id_iobase != 0x250)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_280:
if (isa_dev->id_iobase != 0x280)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_2A0:
if (isa_dev->id_iobase != 0x2a0)
- return(0);
+ return (0);
break;
case ED_3COM_BCFR_2E0:
if (isa_dev->id_iobase != 0x2e0)
- return(0);
+ return (0);
break;
default:
- return(0);
+ return (0);
}
/*
- * Verify that the kernel shared memory address matches the
- * board configured address.
+ * Verify that the kernel shared memory address matches the board
+ * configured address.
*/
switch (inb(sc->asic_addr + ED_3COM_PCFR)) {
case ED_3COM_PCFR_DC000:
if (kvtop(isa_dev->id_maddr) != 0xdc000)
- return(0);
+ return (0);
break;
case ED_3COM_PCFR_D8000:
if (kvtop(isa_dev->id_maddr) != 0xd8000)
- return(0);
+ return (0);
break;
case ED_3COM_PCFR_CC000:
if (kvtop(isa_dev->id_maddr) != 0xcc000)
- return(0);
+ return (0);
break;
case ED_3COM_PCFR_C8000:
if (kvtop(isa_dev->id_maddr) != 0xc8000)
- return(0);
+ return (0);
break;
default:
- return(0);
+ return (0);
}
/*
* Reset NIC and ASIC. Enable on-board transceiver throughout reset
- * sequence because it'll lock up if the cable isn't connected
- * if we don't.
+ * sequence because it'll lock up if the cable isn't connected if we
+ * don't.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
@@ -677,10 +701,11 @@ ed_probe_3Com(isa_dev)
* Wait for a while, then un-reset it
*/
DELAY(50);
+
/*
* The 3Com ASIC defaults to rather strange settings for the CR after
- * a reset - it's important to set it again after the following
- * outb (this is done when we map the PROM below).
+ * a reset - it's important to set it again after the following outb
+ * (this is done when we map the PROM below).
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
@@ -695,17 +720,18 @@ ed_probe_3Com(isa_dev)
sc->mem_shared = 1;
/*
- * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k
- * window to it.
+ * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k window
+ * to it.
*/
memsize = 8192;
/*
* Get station address from on-board ROM
*/
+
/*
* First, map ethernet address PROM over the top of where the NIC
- * registers normally appear.
+ * registers normally appear.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
@@ -714,9 +740,8 @@ ed_probe_3Com(isa_dev)
/*
* Unmap PROM - select NIC registers. The proper setting of the
- * tranceiver is set in ed_init so that the attach code
- * is given a chance to set the default based on a compile-time
- * config option
+ * tranceiver is set in ed_init so that the attach code is given a
+ * chance to set the default based on a compile-time config option
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
@@ -727,18 +752,18 @@ ed_probe_3Com(isa_dev)
/*
* select page 0 registers
*/
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
/*
- * Attempt to clear WTS bit. If it doesn't clear, then this is a
- * 16bit board.
+ * Attempt to clear WTS bit. If it doesn't clear, then this is a 16bit
+ * board.
*/
outb(sc->nic_addr + ED_P0_DCR, 0);
/*
* select page 2 registers
*/
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2 | ED_CR_RD2 | ED_CR_STP);
/*
* The 3c503 forces the WTS bit to a one if this is a 16bit board
@@ -751,24 +776,23 @@ ed_probe_3Com(isa_dev)
/*
* select page 0 registers
*/
- outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2 | ED_CR_STP);
- sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_start = (caddr_t) isa_dev->id_maddr;
sc->mem_size = memsize;
sc->mem_end = sc->mem_start + memsize;
/*
* We have an entire 8k window to put the transmit buffers on the
- * 16bit boards. But since the 16bit 3c503's shared memory
- * is only fast enough to overlap the loading of one full-size
- * packet, trying to load more than 2 buffers can actually
- * leave the transmitter idle during the load. So 2 seems
- * the best value. (Although a mix of variable-sized packets
- * might change this assumption. Nonetheless, we optimize for
- * linear transfers of same-size packets.)
+ * 16bit boards. But since the 16bit 3c503's shared memory is only
+ * fast enough to overlap the loading of one full-size packet, trying
+ * to load more than 2 buffers can actually leave the transmitter idle
+ * during the load. So 2 seems the best value. (Although a mix of
+ * variable-sized packets might change this assumption. Nonetheless,
+ * we optimize for linear transfers of same-size packets.)
*/
if (isa16bit) {
- if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
+ if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
sc->txb_cnt = 1;
else
sc->txb_cnt = 2;
@@ -776,22 +800,22 @@ ed_probe_3Com(isa_dev)
sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
sc->rec_page_stop = memsize / ED_PAGE_SIZE +
- ED_3COM_RX_PAGE_OFFSET_16BIT;
+ ED_3COM_RX_PAGE_OFFSET_16BIT;
sc->mem_ring = sc->mem_start;
} else {
sc->txb_cnt = 1;
sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
sc->rec_page_stop = memsize / ED_PAGE_SIZE +
- ED_3COM_TX_PAGE_OFFSET_8BIT;
+ ED_3COM_TX_PAGE_OFFSET_8BIT;
sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
}
sc->isa16bit = isa16bit;
/*
- * Initialize GA page start/stop registers. Probably only needed
- * if doing DMA, but what the hell.
+ * Initialize GA page start/stop registers. Probably only needed if
+ * doing DMA, but what the hell.
*/
outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start);
outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop);
@@ -814,21 +838,22 @@ ed_probe_3Com(isa_dev)
break;
default:
printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
- isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
- return(0);
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
+ return (0);
}
/*
- * Initialize GA configuration register. Set bank and enable shared mem.
+ * Initialize GA configuration register. Set bank and enable shared
+ * mem.
*/
outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
- ED_3COM_GACFR_MBS0);
+ ED_3COM_GACFR_MBS0);
/*
- * Initialize "Vector Pointer" registers. These gawd-awful things
- * are compared to 20 bits of the address on ISA, and if they
- * match, the shared memory is disabled. We set them to
- * 0xffff0...allegedly the reset vector.
+ * Initialize "Vector Pointer" registers. These gawd-awful things are
+ * compared to 20 bits of the address on ISA, and if they match, the
+ * shared memory is disabled. We set them to 0xffff0...allegedly the
+ * reset vector.
*/
outb(sc->asic_addr + ED_3COM_VPTR2, 0xff);
outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
@@ -841,13 +866,12 @@ ed_probe_3Com(isa_dev)
for (i = 0; i < memsize; ++i)
if (sc->mem_start[i]) {
- printf("ed%d: failed to clear shared memory at %x - check configuration\n",
- isa_dev->id_unit, kvtop(sc->mem_start + i));
- return(0);
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+ return (0);
}
-
isa_dev->id_msize = memsize;
- return(ED_3COM_IO_PORTS);
+ return (ED_3COM_IO_PORTS);
}
/*
@@ -858,10 +882,10 @@ ed_probe_Novell(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
- u_int memsize, n;
- u_char romdata[16], isa16bit = 0, tmp;
+ u_int memsize, n;
+ u_char romdata[16], isa16bit = 0, tmp;
static char test_pattern[32] = "THIS is A memory TEST pattern";
- char test_buffer[32];
+ char test_buffer[32];
sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET;
sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET;
@@ -869,50 +893,54 @@ ed_probe_Novell(isa_dev)
/* XXX - do Novell-specific probe here */
/* Reset the board */
+#ifdef GWETHER
+ outb(sc->asic_addr + ED_NOVELL_RESET, 0);
+ DELAY(200);
+#endif /* GWETHER */
tmp = inb(sc->asic_addr + ED_NOVELL_RESET);
/*
* I don't know if this is necessary; probably cruft leftover from
- * Clarkson packet driver code. Doesn't do a thing on the boards
- * I've tested. -DG [note that a outb(0x84, 0) seems to work
- * here, and is non-invasive...but some boards don't seem to reset
- * and I don't have complete documentation on what the 'right'
- * thing to do is...so we do the invasive thing for now. Yuck.]
+ * Clarkson packet driver code. Doesn't do a thing on the boards I've
+ * tested. -DG [note that a outb(0x84, 0) seems to work here, and is
+ * non-invasive...but some boards don't seem to reset and I don't have
+ * complete documentation on what the 'right' thing to do is...so we
+ * do the invasive thing for now. Yuck.]
*/
outb(sc->asic_addr + ED_NOVELL_RESET, tmp);
DELAY(5000);
/*
* This is needed because some NE clones apparently don't reset the
- * NIC properly (or the NIC chip doesn't reset fully on power-up)
- * XXX - this makes the probe invasive! ...Done against my better
- * judgement. -DLG
+ * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
+ * - this makes the probe invasive! ...Done against my better
+ * judgement. -DLG
*/
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
DELAY(5000);
/* Make sure that we really have an 8390 based board */
if (!ed_probe_generic8390(sc))
- return(0);
+ return (0);
sc->vendor = ED_VENDOR_NOVELL;
sc->mem_shared = 0;
isa_dev->id_maddr = 0;
/*
- * Test the ability to read and write to the NIC memory. This has
- * the side affect of determining if this is an NE1000 or an NE2000.
+ * Test the ability to read and write to the NIC memory. This has the
+ * side affect of determining if this is an NE1000 or an NE2000.
*/
/*
- * This prevents packets from being stored in the NIC memory when
- * the readmem routine turns on the start bit in the CR.
+ * This prevents packets from being stored in the NIC memory when the
+ * readmem routine turns on the start bit in the CR.
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
/* Temporarily initialize DCR for byte operations */
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE);
outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE);
@@ -921,8 +949,8 @@ ed_probe_Novell(isa_dev)
/*
* Write a test pattern in byte mode. If this fails, then there
- * probably isn't any memory at 8k - which likely means
- * that the board is an NE2000.
+ * probably isn't any memory at 8k - which likely means that the board
+ * is an NE2000.
*/
ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern));
ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern));
@@ -930,20 +958,21 @@ ed_probe_Novell(isa_dev)
if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
/* not an NE1000 - try NE2000 */
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS|ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE);
outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE);
sc->isa16bit = 1;
+
/*
* Write a test pattern in word mode. If this also fails, then
- * we don't know what this board is.
+ * we don't know what this board is.
*/
ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern));
ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern));
if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)))
- return(0); /* not an NE2000 either */
+ return (0); /* not an NE2000 either */
sc->type = ED_TYPE_NE2000;
sc->type_str = "NE2000";
@@ -951,11 +980,11 @@ ed_probe_Novell(isa_dev)
sc->type = ED_TYPE_NE1000;
sc->type_str = "NE1000";
}
-
+
/* 8k of memory plus an additional 8k if 16bit */
memsize = 8192 + sc->isa16bit * 8192;
-#if 0 /* probably not useful - NE boards only come two ways */
+#if 0 /* probably not useful - NE boards only come two ways */
/* allow kernel config file overrides */
if (isa_dev->id_msize)
memsize = isa_dev->id_msize;
@@ -969,9 +998,72 @@ ed_probe_Novell(isa_dev)
sc->mem_end = sc->mem_start + memsize;
sc->tx_page_start = memsize / ED_PAGE_SIZE;
+#ifdef GWETHER
+ {
+ int x, i, mstart = 0, msize = 0;
+ char pbuf0[ED_PAGE_SIZE], pbuf[ED_PAGE_SIZE], tbuf[ED_PAGE_SIZE];
+
+ for (i = 0; i < ED_PAGE_SIZE; i++)
+ pbuf0[i] = 0;
+
+ /* Clear all the memory. */
+ for (x = 1; x < 256; x++)
+ ed_pio_writemem(sc, pbuf0, x * 256, ED_PAGE_SIZE);
+
+ /* Search for the start of RAM. */
+ for (x = 1; x < 256; x++) {
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) {
+ for (i = 0; i < ED_PAGE_SIZE; i++)
+ pbuf[i] = 255 - x;
+ ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE);
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) {
+ mstart = x * ED_PAGE_SIZE;
+ msize = ED_PAGE_SIZE;
+ break;
+ }
+ }
+ }
+
+ if (mstart == 0) {
+ printf("ed%d: Cannot find start of RAM.\n", isa_dev->id_unit);
+ return 0;
+ }
+ /* Search for the start of RAM. */
+ for (x = (mstart / ED_PAGE_SIZE) + 1; x < 256; x++) {
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) {
+ for (i = 0; i < ED_PAGE_SIZE; i++)
+ pbuf[i] = 255 - x;
+ ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE);
+ ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE);
+ if (memcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0)
+ msize += ED_PAGE_SIZE;
+ else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (msize == 0) {
+ printf("ed%d: Cannot find any RAM, start : %d, x = %d.\n", isa_dev->id_unit, mstart, x);
+ return 0;
+ }
+ printf("ed%d: RAM start at %d, size : %d.\n", isa_dev->id_unit, mstart, msize);
+
+ sc->mem_size = msize;
+ sc->mem_start = (char *) mstart;
+ sc->mem_end = (char *) (msize + mstart);
+ sc->tx_page_start = mstart / ED_PAGE_SIZE;
+ }
+#endif /* GWETHER */
+
/*
* Use one xmit buffer if < 16k, two buffers otherwise (if not told
- * otherwise).
+ * otherwise).
*/
if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING))
sc->txb_cnt = 1;
@@ -985,14 +1077,19 @@ ed_probe_Novell(isa_dev)
ed_pio_readmem(sc, 0, romdata, 16);
for (n = 0; n < ETHER_ADDR_LEN; n++)
- sc->arpcom.ac_enaddr[n] = romdata[n*(sc->isa16bit+1)];
+ sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)];
+
+#ifdef GWETHER
+ if (sc->arpcom.ac_enaddr[2] == 0x86)
+ sc->type_str = "Gateway AT";
+#endif /* GWETHER */
/* clear any pending interrupts that might have occurred above */
outb(sc->nic_addr + ED_P0_ISR, 0xff);
- return(ED_NOVELL_IO_PORTS);
+ return (ED_NOVELL_IO_PORTS);
}
-
+
/*
* Install interface into kernel networking data structures
*/
@@ -1004,7 +1101,7 @@ ed_attach(isa_dev)
struct ifnet *ifp = &sc->arpcom.ac_if;
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
-
+
/*
* Set interface to stopped condition (reset)
*/
@@ -1014,7 +1111,7 @@ ed_attach(isa_dev)
* Initialize ifnet structure
*/
ifp->if_unit = isa_dev->id_unit;
- ifp->if_name = "ed" ;
+ ifp->if_name = "ed";
ifp->if_mtu = ETHERMTU;
ifp->if_init = ed_init;
ifp->if_output = ether_output;
@@ -1025,13 +1122,16 @@ ed_attach(isa_dev)
/*
* Set default state for ALTPHYS flag (used to disable the tranceiver
- * for AUI operation), based on compile-time config option.
+ * for AUI operation), based on compile-time config option.
*/
if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
ifp->if_flags =
(IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
else
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+#ifdef MULTICAST
+ ifp->if_flags |= IFF_MULTICAST;
+#endif
/*
* Attach the interface
@@ -1041,20 +1141,22 @@ ed_attach(isa_dev)
/*
* Search down the ifa address list looking for the AF_LINK type entry
*/
- ifa = ifp->if_addrlist;
+ ifa = ifp->if_addrlist;
while ((ifa != 0) && (ifa->ifa_addr != 0) &&
- (ifa->ifa_addr->sa_family != AF_LINK))
+ (ifa->ifa_addr->sa_family != AF_LINK))
ifa = ifa->ifa_next;
+
/*
* If we find an AF_LINK type entry we fill in the hardware address.
- * This is useful for netstat(1) to keep track of which interface
- * is which.
+ * This is useful for netstat(1) to keep track of which interface is
+ * which.
*/
if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+
/*
* Fill in the link-level address for this interface
*/
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl = (struct sockaddr_dl *) ifa->ifa_addr;
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ETHER_ADDR_LEN;
sdl->sdl_slen = 0;
@@ -1065,17 +1167,17 @@ ed_attach(isa_dev)
* Print additional info when attached
*/
printf("ed%d: address %s, ", isa_dev->id_unit,
- ether_sprintf(sc->arpcom.ac_enaddr));
+ ether_sprintf(sc->arpcom.ac_enaddr));
if (sc->type_str && (*sc->type_str != 0))
printf("type %s ", sc->type_str);
else
printf("type unknown (0x%x) ", sc->type);
- printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)");
+ printf("%s ", sc->isa16bit ? "(16 bit)" : "(8 bit)");
printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
- (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
+ (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
/*
* If BPF is in the kernel, call the attach for it
@@ -1085,16 +1187,16 @@ ed_attach(isa_dev)
#endif
return 1;
}
-
+
/*
* Reset interface.
*/
void
ed_reset(unit, uban)
- int unit;
- int uban; /* XXX */
+ int unit;
+ int uban; /* XXX */
{
- int s;
+ int s;
s = splimp();
@@ -1106,29 +1208,30 @@ ed_reset(unit, uban)
(void) splx(s);
}
-
+
/*
* Take interface offline.
*/
void
ed_stop(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
- int n = 5000;
-
+ int n = 5000;
+
/*
* Stop everything on the interface, and select page 0 registers.
*/
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
}
+
/*
- * Wait for interface to enter stopped state, but limit # of checks
- * to 'n' (about 5ms). It shouldn't even take 5us on modern
- * DS8390's, but just in case it's an old one.
+ * Wait for interface to enter stopped state, but limit # of checks to
+ * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
+ * just in case it's an old one.
*/
while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
@@ -1140,7 +1243,7 @@ ed_stop(unit)
*/
void
ed_watchdog(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
@@ -1151,25 +1254,26 @@ ed_watchdog(unit)
}
/*
- * Initialize device.
+ * Initialize device.
*/
void
ed_init(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
struct ifnet *ifp = &sc->arpcom.ac_if;
- int i, s;
- u_char command;
+ int i, s;
+ u_char command;
/* address not known */
- if (ifp->if_addrlist == (struct ifaddr *)0) return;
+ if (ifp->if_addrlist == (struct ifaddr *) 0)
+ return;
/*
* Initialize the NIC in the exact order outlined in the NS manual.
- * This init procedure is "mandatory"...don't change what or when
- * things happen.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
*/
s = splimp();
@@ -1190,19 +1294,21 @@ ed_init(unit)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
}
if (sc->isa16bit) {
+
/*
- * Set FIFO threshold to 8, No auto-init Remote DMA,
- * byte order=80x86, word-wide DMA xfers,
+ * Set FIFO threshold to 8, No auto-init Remote DMA, byte
+ * order=80x86, word-wide DMA xfers,
*/
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
} else {
+
/*
* Same as above, but byte-wide DMA xfers
*/
- outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
}
/*
@@ -1210,11 +1316,19 @@ ed_init(unit)
*/
outb(sc->nic_addr + ED_P0_RBCR0, 0);
outb(sc->nic_addr + ED_P0_RBCR1, 0);
+#ifndef MULTICAST
/*
* Enable reception of broadcast packets
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+#else
+
+ /*
+ * Tell RCR to do nothing for now.
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
+#endif
/*
* Place NIC in internal loopback mode
@@ -1238,41 +1352,62 @@ ed_init(unit)
/*
* Clear all interrupts. A '1' in each bit position clears the
- * corresponding flag.
+ * corresponding flag.
*/
outb(sc->nic_addr + ED_P0_ISR, 0xff);
/*
* Enable the following interrupts: receive/transmit complete,
- * receive/transmit error, and Receiver OverWrite.
- *
+ * receive/transmit error, and Receiver OverWrite.
+ *
* Counter overflow and Remote DMA complete are *not* enabled.
*/
outb(sc->nic_addr + ED_P0_IMR,
- ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE);
+ ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | ED_IMR_OVWE);
/*
* Program Command Register for page 1
*/
if (sc->is790) {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STP);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_RD2 | ED_CR_STP);
}
+
/*
* Copy out our station address
*/
for (i = 0; i < ETHER_ADDR_LEN; ++i)
outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+#ifndef MULTICAST
#if NBPFILTER > 0
+
/*
- * Initialize multicast address hashing registers to accept
- * all multicasts (only used when in promiscuous mode)
+ * Initialize multicast address hashing registers to accept all
+ * multicasts (only used when in promiscuous mode)
*/
for (i = 0; i < 8; ++i)
outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
#endif
+#else
+ /* set up multicast addresses and filter modes */
+ if (sc != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) {
+ u_long mcaf[2];
+
+ if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
+ mcaf[0] = 0xffffffff;
+ mcaf[1] = 0xffffffff;
+ } else
+ ds_getmcaf(sc, mcaf);
+
+ /*
+ * Set multicast filter on chip.
+ */
+ for (i = 0; i < 8; i++)
+ outb(sc->nic_addr + ED_P1_MAR0 + i, ((u_char *) mcaf)[i]);
+ }
+#endif
/*
* Set Current Page pointer to next_packet (initialized above)
@@ -1280,14 +1415,22 @@ ed_init(unit)
outb(sc->nic_addr + ED_P1_CURR, sc->next_packet);
/*
- * Set Command Register for page 0, Remote DMA complete,
- * and interface Start.
+ * Set Command Register for page 0, Remote DMA complete, and interface
+ * Start.
*/
if (sc->is790) {
outb(sc->nic_addr + ED_P1_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2 | ED_CR_STA);
}
+#ifdef MULTICAST
+
+ /*
+ * Clear all interrupts
+ */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+#endif
+
/*
* Take interface out of loopback
*/
@@ -1295,7 +1438,7 @@ ed_init(unit)
/*
* If this is a 3Com board, the tranceiver must be software enabled
- * (there is no settable hardware default).
+ * (there is no settable hardware default).
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_ALTPHYS) {
@@ -1304,6 +1447,25 @@ ed_init(unit)
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
}
+#ifdef MULTICAST
+ i = ED_RCR_AB;
+ if (sc != 0) {
+ if ((ifp->if_flags & IFF_PROMISC) != 0) {
+
+ /*
+ * Set promiscuous mode. Also reconfigure the
+ * multicast filter.
+ */
+ int j;
+
+ i |= ED_RCR_PRO | ED_RCR_AM | ED_RCR_AR | ED_RCR_SEP;
+ for (j = 0; j < 8; j++)
+ outb(sc->nic_addr + ED_P1_MAR0 + j, 0xff);
+ }
+ i |= ED_RCR_AM;
+ }
+ outb(sc->nic_addr + ED_P0_RCR, i);
+#endif
/*
* Set 'running' flag, and clear output active flag.
@@ -1318,11 +1480,12 @@ ed_init(unit)
(void) splx(s);
}
-
+
/*
* This routine actually starts the transmission on the interface
*/
-static inline void ed_xmit(ifp)
+static inline void
+ed_xmit(ifp)
struct ifnet *ifp;
{
struct ed_softc *sc = &ed_softc[ifp->if_unit];
@@ -1336,13 +1499,14 @@ static inline void ed_xmit(ifp)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
+
/*
* Set TX buffer start page
*/
outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start +
- sc->txb_next_tx * ED_TXBUF_SIZE);
+ sc->txb_next_tx * ED_TXBUF_SIZE);
/*
* Set TX length
@@ -1356,10 +1520,10 @@ static inline void ed_xmit(ifp)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_TXP | ED_CR_STA);
}
sc->xmit_busy = 1;
-
+
/*
* Point to next transmit buffer slot and wrap if necessary.
*/
@@ -1389,12 +1553,13 @@ ed_start(ifp)
struct ed_softc *sc = &ed_softc[ifp->if_unit];
struct mbuf *m0, *m;
caddr_t buffer;
- int len;
+ int len;
outloop:
+
/*
- * First, see if there are buffered packets and an idle
- * transmitter - should never happen at this point.
+ * First, see if there are buffered packets and an idle transmitter -
+ * should never happen at this point.
*/
if (sc->txb_inuse && (sc->xmit_busy == 0)) {
printf("ed: packets buffers, but transmitter idle\n");
@@ -1405,23 +1570,23 @@ outloop:
* See if there is room to put another packet in the buffer.
*/
if (sc->txb_inuse == sc->txb_cnt) {
+
/*
- * No room. Indicate this to the outside world
- * and exit.
+ * No room. Indicate this to the outside world and exit.
*/
ifp->if_flags |= IFF_OACTIVE;
return;
}
-
IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
if (m == 0) {
- /*
- * We are using the !OACTIVE flag to indicate to the outside
- * world that we can accept an additional packet rather than
- * that the transmitter is _actually_ active. Indeed, the
- * transmitter may be active, but if we haven't filled all
- * the buffers with data then we still want to accept more.
- */
+
+ /*
+ * We are using the !OACTIVE flag to indicate to the outside
+ * world that we can accept an additional packet rather than
+ * that the transmitter is _actually_ active. Indeed, the
+ * transmitter may be active, but if we haven't filled all the
+ * buffers with data then we still want to accept more.
+ */
ifp->if_flags &= ~IFF_OACTIVE;
return;
}
@@ -1436,45 +1601,49 @@ outloop:
buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE);
if (sc->mem_shared) {
+
/*
* Special case setup for 16 bit boards...
*/
if (sc->isa16bit) {
switch (sc->vendor) {
- /*
- * For 16bit 3Com boards (which have 16k of memory),
- * we have the xmit buffers in a different page
- * of memory ('page 0') - so change pages.
- */
+
+ /*
+ * For 16bit 3Com boards (which have 16k of
+ * memory), we have the xmit buffers in a
+ * different page of memory ('page 0') - so
+ * change pages.
+ */
case ED_VENDOR_3COM:
outb(sc->asic_addr + ED_3COM_GACFR,
- ED_3COM_GACFR_RSEL);
+ ED_3COM_GACFR_RSEL);
break;
- /*
- * Enable 16bit access to shared memory on WD/SMC boards
- * Don't update wd_laar_proto because we want to restore the
- * previous state (because an arp reply in the input code
- * may cause a call-back to ed_start)
- * XXX - the call-back to 'start' is a bug, IMHO.
- */
- case ED_VENDOR_WD_SMC: {
- outb(sc->asic_addr + ED_WD_LAAR,
- (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
- (void) inb(0x84);
- if (sc->is790) {
- outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+
+ /*
+ * Enable 16bit access to shared memory on
+ * WD/SMC boards Don't update wd_laar_proto
+ * because we want to restore the previous
+ * state (because an arp reply in the input
+ * code may cause a call-back to ed_start) XXX
+ * - the call-back to 'start' is a bug, IMHO.
+ */
+ case ED_VENDOR_WD_SMC:{
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
(void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ (void) inb(0x84);
+ break;
}
- (void) inb(0x84);
- break;
- }
}
}
-
for (len = 0; m != 0; m = m->m_next) {
bcopy(mtod(m, caddr_t), buffer, m->m_len);
buffer += m->m_len;
- len += m->m_len;
+ len += m->m_len;
}
/*
@@ -1484,23 +1653,23 @@ outloop:
switch (sc->vendor) {
case ED_VENDOR_3COM:
outb(sc->asic_addr + ED_3COM_GACFR,
- ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
+ ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
break;
- case ED_VENDOR_WD_SMC: {
- outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
- (void) inb(0x84);
- if (sc->is790) {
- outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ case ED_VENDOR_WD_SMC:{
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
(void) inb(0x84);
+ break;
}
- break;
- }
}
}
} else {
len = ed_pio_write_mbufs(sc, m, buffer);
}
-
+
sc->txb_len[sc->txb_new] = MAX(len, ETHER_MIN_LEN);
sc->txb_inuse++;
@@ -1514,40 +1683,37 @@ outloop:
if (sc->xmit_busy == 0)
ed_xmit(ifp);
+
/*
- * If there is BPF support in the configuration, tap off here.
- * The following has support for converting trailer packets
- * back to normal.
- * XXX - support for trailer packets in BPF should be moved into
- * the bpf code proper to avoid code duplication in all of
- * the drivers.
+ * If there is BPF support in the configuration, tap off here. The
+ * following has support for converting trailer packets back to
+ * normal. XXX - support for trailer packets in BPF should be moved
+ * into the bpf code proper to avoid code duplication in all of the
+ * drivers.
*/
#if NBPFILTER > 0
if (sc->bpf) {
u_short etype;
- int off, datasize, resid;
+ int off, datasize, resid;
struct ether_header *eh;
struct trailer_header trailer_header;
- char ether_packet[ETHER_MAX_LEN];
- char *ep;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
ep = ether_packet;
/*
- * We handle trailers below:
- * Copy ether header first, then residual data,
- * then data. Put all this in a temporary buffer
- * 'ether_packet' and send off to bpf. Since the
- * system has generated this packet, we assume
- * that all of the offsets in the packet are
- * correct; if they're not, the system will almost
- * certainly crash in m_copydata.
- * We make no assumptions about how the data is
- * arranged in the mbuf chain (i.e. how much
- * data is in each mbuf, if mbuf clusters are
- * used, etc.), which is why we use m_copydata
- * to get the ether header rather than assume
- * that this is located in the first mbuf.
+ * We handle trailers below: Copy ether header first, then
+ * residual data, then data. Put all this in a temporary
+ * buffer 'ether_packet' and send off to bpf. Since the system
+ * has generated this packet, we assume that all of the
+ * offsets in the packet are correct; if they're not, the
+ * system will almost certainly crash in m_copydata. We make
+ * no assumptions about how the data is arranged in the mbuf
+ * chain (i.e. how much data is in each mbuf, if mbuf clusters
+ * are used, etc.), which is why we use m_copydata to get the
+ * ether header rather than assume that this is located in the
+ * first mbuf.
*/
/* copy ether header */
m_copydata(m0, 0, sizeof(struct ether_header), ep);
@@ -1555,17 +1721,17 @@ outloop:
ep += sizeof(struct ether_header);
etype = ntohs(eh->ether_type);
if (etype >= ETHERTYPE_TRAIL &&
- etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
datasize = ((etype - ETHERTYPE_TRAIL) << 9);
off = datasize + sizeof(struct ether_header);
/* copy trailer_header into a data structure */
m_copydata(m0, off, sizeof(struct trailer_header),
- (caddr_t)&trailer_header.ether_type);
+ (caddr_t) & trailer_header.ether_type);
/* copy residual data */
- m_copydata(m0, off+sizeof(struct trailer_header),
- resid = ntohs(trailer_header.ether_residual) -
+ m_copydata(m0, off + sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
sizeof(struct trailer_header), ep);
ep += resid;
@@ -1590,35 +1756,36 @@ outloop:
*/
goto outloop;
}
-
+
/*
* Ethernet interface receiver interrupt.
*/
static inline void
ed_rint(unit)
- int unit;
+ int unit;
{
register struct ed_softc *sc = &ed_softc[unit];
- u_char boundry, current;
+ u_char boundry, current;
u_short len;
struct ed_ring packet_hdr;
- char *packet_ptr;
+ char *packet_ptr;
/*
* Set NIC to page 1 registers to get 'current' pointer
*/
if (sc->is790) {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_RD2 | ED_CR_STA);
}
+
/*
- * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
- * it points to where new data has been buffered. The 'CURR'
- * (current) register points to the logical end of the ring-buffer
- * - i.e. it points to where additional new data will be added.
- * We loop here until the logical beginning equals the logical
- * end (or in other words, until the ring-buffer is empty).
+ * 'sc->next_packet' is the logical beginning of the ring-buffer -
+ * i.e. it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer -
+ * i.e. it points to where additional new data will be added. We loop
+ * here until the logical beginning equals the logical end (or in
+ * other words, until the ring-buffer is empty).
*/
while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) {
@@ -1628,25 +1795,28 @@ ed_rint(unit)
/*
* The byte count includes the FCS - Frame Check Sequence (a
- * 32 bit CRC).
+ * 32 bit CRC).
*/
if (sc->mem_shared)
- packet_hdr = *(struct ed_ring *)packet_ptr;
+ packet_hdr = *(struct ed_ring *) packet_ptr;
else
ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr,
- sizeof(packet_hdr));
+ sizeof(packet_hdr));
len = packet_hdr.count;
if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+
/*
* Go get packet. len - 4 removes CRC from length.
*/
ed_get_packet(sc, packet_ptr + 4, len - 4);
++sc->arpcom.ac_if.if_ipackets;
} else {
+
/*
- * Really BAD...probably indicates that the ring pointers
- * are corrupted. Also seen on early rev chips under
- * high load - the byte order of the length gets switched.
+ * Really BAD...probably indicates that the ring
+ * pointers are corrupted. Also seen on early rev
+ * chips under high load - the byte order of the
+ * length gets switched.
*/
log(LOG_ERR,
"ed%d: NIC memory corrupt - invalid packet length %d\n",
@@ -1662,8 +1832,8 @@ ed_rint(unit)
sc->next_packet = packet_hdr.next_packet;
/*
- * Update NIC boundry pointer - being careful to keep it
- * one buffer behind. (as recommended by NS databook)
+ * Update NIC boundry pointer - being careful to keep it one
+ * buffer behind. (as recommended by NS databook)
*/
boundry = sc->next_packet - 1;
if (boundry < sc->rec_page_start)
@@ -1675,18 +1845,18 @@ ed_rint(unit)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
outb(sc->nic_addr + ED_P0_BNRY, boundry);
/*
- * Set NIC to page 1 registers before looping to top (prepare to
- * get 'CURR' current pointer)
+ * Set NIC to page 1 registers before looping to top (prepare
+ * to get 'CURR' current pointer)
*/
if (sc->is790) {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_RD2 | ED_CR_STA);
}
}
}
@@ -1696,10 +1866,10 @@ ed_rint(unit)
*/
void
edintr(unit)
- int unit;
+ int unit;
{
struct ed_softc *sc = &ed_softc[unit];
- u_char isr;
+ u_char isr;
/*
* Set NIC to page 0 registers
@@ -1707,36 +1877,36 @@ edintr(unit)
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
+
/*
* loop until there are no more new interrupts
*/
while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
/*
- * reset all the bits that we are 'acknowledging'
- * by writing a '1' to each bit position that was set
- * (writing a '1' *clears* the bit)
+ * reset all the bits that we are 'acknowledging' by writing a
+ * '1' to each bit position that was set (writing a '1'
+ * *clears* the bit)
*/
outb(sc->nic_addr + ED_P0_ISR, isr);
/*
- * Handle transmitter interrupts. Handle these first
- * because the receiver will reset the board under
- * some conditions.
+ * Handle transmitter interrupts. Handle these first because
+ * the receiver will reset the board under some conditions.
*/
- if (isr & (ED_ISR_PTX|ED_ISR_TXE)) {
- u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
+ if (isr & (ED_ISR_PTX | ED_ISR_TXE)) {
+ u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
/*
* Check for transmit error. If a TX completed with an
* error, we end up throwing the packet away. Really
* the only error that is possible is excessive
- * collisions, and in this case it is best to allow the
- * automatic mechanisms of TCP to backoff the flow. Of
- * course, with UDP we're screwed, but this is expected
- * when a network is heavily loaded.
+ * collisions, and in this case it is best to allow
+ * the automatic mechanisms of TCP to backoff the
+ * flow. Of course, with UDP we're screwed, but this
+ * is expected when a network is heavily loaded.
*/
(void) inb(sc->nic_addr + ED_P0_TSR);
if (isr & ED_ISR_TXE) {
@@ -1746,8 +1916,9 @@ edintr(unit)
*/
if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT)
&& (collisions == 0)) {
+
/*
- * When collisions total 16, the
+ * When collisions total 16, the
* P0_NCR will indicate 0, and the
* TSR_ABT is set.
*/
@@ -1759,9 +1930,10 @@ edintr(unit)
*/
++sc->arpcom.ac_if.if_oerrors;
} else {
+
/*
* Update total number of successfully
- * transmitted packets.
+ * transmitted packets.
*/
++sc->arpcom.ac_if.if_opackets;
}
@@ -1779,16 +1951,16 @@ edintr(unit)
/*
* Add in total number of collisions on last
- * transmission.
+ * transmission.
*/
sc->arpcom.ac_if.if_collisions += collisions;
/*
* Decrement buffer in-use count if not zero (can only
- * be zero if a transmitter interrupt occured while
- * not actually transmitting).
- * If data is ready to transmit, start it transmitting,
- * otherwise defer until after handling receiver
+ * be zero if a transmitter interrupt occured while
+ * not actually transmitting). If data is ready to
+ * transmit, start it transmitting, otherwise defer
+ * until after handling receiver
*/
if (sc->txb_inuse && --sc->txb_inuse)
ed_xmit(&sc->arpcom.ac_if);
@@ -1797,110 +1969,111 @@ edintr(unit)
/*
* Handle receiver interrupts
*/
- if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) {
- /*
- * Overwrite warning. In order to make sure that a lockup
- * of the local DMA hasn't occurred, we reset and
- * re-init the NIC. The NSC manual suggests only a
- * partial reset/re-init is necessary - but some
- * chips seem to want more. The DMA lockup has been
- * seen only with early rev chips - Methinks this
- * bug was fixed in later revs. -DG
- */
+ if (isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) {
+
+ /*
+ * Overwrite warning. In order to make sure that a
+ * lockup of the local DMA hasn't occurred, we reset
+ * and re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some chips
+ * seem to want more. The DMA lockup has been seen
+ * only with early rev chips - Methinks this bug was
+ * fixed in later revs. -DG
+ */
if (isr & ED_ISR_OVW) {
++sc->arpcom.ac_if.if_ierrors;
#ifdef DIAGNOSTIC
log(LOG_WARNING,
- "ed%d: warning - receiver ring buffer overrun\n",
- unit);
+ "ed%d: warning - receiver ring buffer overrun\n",
+ unit);
#endif
+
/*
* Stop/reset/re-init NIC
*/
ed_reset(unit, 0);
} else {
- /*
- * Receiver Error. One or more of: CRC error, frame
- * alignment error FIFO overrun, or missed packet.
- */
+ /*
+ * Receiver Error. One or more of: CRC error,
+ * frame alignment error FIFO overrun, or
+ * missed packet.
+ */
if (isr & ED_ISR_RXE) {
++sc->arpcom.ac_if.if_ierrors;
#ifdef ED_DEBUG
printf("ed%d: receive error %x\n", unit,
- inb(sc->nic_addr + ED_P0_RSR));
+ inb(sc->nic_addr + ED_P0_RSR));
#endif
}
/*
- * Go get the packet(s)
- * XXX - Doing this on an error is dubious
- * because there shouldn't be any data to
- * get (we've configured the interface to
- * not accept packets with errors).
+ * Go get the packet(s) XXX - Doing this on an
+ * error is dubious because there shouldn't be
+ * any data to get (we've configured the
+ * interface to not accept packets with
+ * errors).
*/
/*
* Enable 16bit access to shared memory first
- * on WD/SMC boards.
+ * on WD/SMC boards.
*/
if (sc->isa16bit &&
(sc->vendor == ED_VENDOR_WD_SMC)) {
outb(sc->asic_addr + ED_WD_LAAR,
(sc->wd_laar_proto |=
- ED_WD_LAAR_M16EN));
+ ED_WD_LAAR_M16EN));
(void) inb(0x84);
if (sc->is790) {
outb(sc->asic_addr + ED_WD_MSR,
- ED_WD_MSR_MENB);
+ ED_WD_MSR_MENB);
(void) inb(0x84);
}
}
-
- ed_rint (unit);
+ ed_rint(unit);
/* disable 16bit access */
if (sc->isa16bit &&
- (sc->vendor == ED_VENDOR_WD_SMC)) {
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
- outb(sc->asic_addr + ED_WD_LAAR,
- (sc->wd_laar_proto &=
- ~ED_WD_LAAR_M16EN));
- (void) inb(0x84);
if (sc->is790) {
outb(sc->asic_addr + ED_WD_MSR, 0x00);
(void) inb(0x84);
}
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
}
}
}
/*
* If it looks like the transmitter can take more data,
- * attempt to start output on the interface.
- * This is done after handling the receiver to
- * give the receiver priority.
+ * attempt to start output on the interface. This is done
+ * after handling the receiver to give the receiver priority.
*/
if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0)
ed_start(&sc->arpcom.ac_if);
/*
- * return NIC CR to standard state: page 0, remote DMA complete,
- * start (toggling the TXP bit off, even if was just set
- * in the transmit routine, is *okay* - it is 'edge'
- * triggered from low to high)
+ * return NIC CR to standard state: page 0, remote DMA
+ * complete, start (toggling the TXP bit off, even if was just
+ * set in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
*/
if (sc->is790) {
outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
} else {
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
}
+
/*
- * If the Network Talley Counters overflow, read them to
- * reset them. It appears that old 8390's won't
- * clear the ISR flag otherwise - resulting in an
- * infinite loop.
+ * If the Network Talley Counters overflow, read them to reset
+ * them. It appears that old 8390's won't clear the ISR flag
+ * otherwise - resulting in an infinite loop.
*/
if (isr & ED_ISR_CNT) {
(void) inb(sc->nic_addr + ED_P0_CNTR0);
@@ -1909,7 +2082,7 @@ edintr(unit)
}
}
}
-
+
/*
* Process an ioctl request. This code needs some work - it looks
* pretty ugly.
@@ -1917,13 +2090,13 @@ edintr(unit)
int
ed_ioctl(ifp, command, data)
register struct ifnet *ifp;
- int command;
+ int command;
caddr_t data;
{
- register struct ifaddr *ifa = (struct ifaddr *)data;
+ register struct ifaddr *ifa = (struct ifaddr *) data;
struct ed_softc *sc = &ed_softc[ifp->if_unit];
- struct ifreq *ifr = (struct ifreq *)data;
- int s, error = 0;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
s = splimp();
@@ -1936,41 +2109,40 @@ ed_ioctl(ifp, command, data)
#ifdef INET
case AF_INET:
ed_init(ifp->if_unit); /* before arpwhohas */
+
/*
- * See if another station has *our* IP address.
- * i.e.: There is an address conflict! If a
- * conflict exists, a message is sent to the
- * console.
+ * See if another station has *our* IP address. i.e.:
+ * There is an address conflict! If a conflict exists,
+ * a message is sent to the console.
*/
- ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
- arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
break;
#endif
#ifdef NS
- /*
- * XXX - This code is probably wrong
- */
+
+ /*
+ * XXX - This code is probably wrong
+ */
case AF_NS:
- {
- register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
-
- if (ns_nullhost(*ina))
- ina->x_host =
- *(union ns_host *)(sc->arpcom.ac_enaddr);
- else {
- /*
- *
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *) (sc->arpcom.ac_enaddr);
+ else {
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+
+ /*
+ * Set new address
*/
- bcopy((caddr_t)ina->x_host.c_host,
- (caddr_t)sc->arpcom.ac_enaddr,
- sizeof(sc->arpcom.ac_enaddr));
+ ed_init(ifp->if_unit);
+ break;
}
- /*
- * Set new address
- */
- ed_init(ifp->if_unit);
- break;
- }
#endif
default:
ed_init(ifp->if_unit);
@@ -1981,13 +2153,15 @@ ed_ioctl(ifp, command, data)
case SIOCGIFADDR:
{
struct sockaddr *sa;
- sa = (struct sockaddr *)&ifr->ifr_data;
- bcopy((caddr_t)sc->arpcom.ac_enaddr,
- (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+
+ sa = (struct sockaddr *) & ifr->ifr_data;
+ bcopy((caddr_t) sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
}
break;
case SIOCSIFFLAGS:
+
/*
* If interface is marked down and it is running, then stop it
*/
@@ -1996,37 +2170,42 @@ ed_ioctl(ifp, command, data)
ed_stop(ifp->if_unit);
ifp->if_flags &= ~IFF_RUNNING;
} else {
- /*
- * If interface is marked up and it is stopped, then start it
- */
+
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it
+ */
if ((ifp->if_flags & IFF_UP) &&
- ((ifp->if_flags & IFF_RUNNING) == 0))
+ ((ifp->if_flags & IFF_RUNNING) == 0))
ed_init(ifp->if_unit);
}
+#ifndef MULTICAST
#if NBPFILTER > 0
if (ifp->if_flags & IFF_PROMISC) {
+
/*
- * Set promiscuous mode on interface.
- * XXX - for multicasts to work, we would need to
- * write 1's in all bits of multicast
- * hashing array. For now we assume that
- * this was done in ed_init().
+ * Set promiscuous mode on interface. XXX - for
+ * multicasts to work, we would need to write 1's in
+ * all bits of multicast hashing array. For now we
+ * assume that this was done in ed_init().
*/
outb(sc->nic_addr + ED_P0_RCR,
- ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
+ ED_RCR_PRO | ED_RCR_AM | ED_RCR_AB);
} else {
+
/*
* XXX - for multicasts to work, we would need to
- * rewrite the multicast hashing array with the
- * proper hash (would have been destroyed above).
+ * rewrite the multicast hashing array with the proper
+ * hash (would have been destroyed above).
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
}
#endif
+
/*
- * An unfortunate hack to provide the (required) software control
- * of the tranceiver for 3Com boards. The ALTPHYS flag disables
- * the tranceiver if set.
+ * An unfortunate hack to provide the (required) software
+ * control of the tranceiver for 3Com boards. The ALTPHYS flag
+ * disables the tranceiver if set.
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_ALTPHYS) {
@@ -2035,16 +2214,37 @@ ed_ioctl(ifp, command, data)
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
}
-
break;
+#else
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+
+ /*
+ * Update out multicast list.
+ */
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti((struct ifreq *) data, &sc->arpcom) :
+ ether_delmulti((struct ifreq *) data, &sc->arpcom);
+ if (error == ENETRESET) {
+
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ ed_stop(ifp->if_unit); /* XXX for ds_setmcaf? */
+ ed_init(ifp->if_unit);
+ error = 0;
+ }
+ break;
+#endif
default:
error = EINVAL;
}
(void) splx(s);
return (error);
}
-
+
/*
* Macro to calculate a new address within shared memory when given an offset
* from an address, taking into account ring-wrap.
@@ -2062,13 +2262,13 @@ ed_ioctl(ifp, command, data)
static void
ed_get_packet(sc, buf, len)
struct ed_softc *sc;
- char *buf;
+ char *buf;
u_short len;
{
struct ether_header *eh;
- struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
+ struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
u_short off;
- int resid;
+ int resid;
u_short etype;
struct trailer_header trailer_header;
@@ -2086,8 +2286,8 @@ ed_get_packet(sc, buf, len)
#define EOFF (EROUND - sizeof(struct ether_header))
/*
- * The following assumes there is room for
- * the ether header in the header mbuf
+ * The following assumes there is room for the ether header in the
+ * header mbuf
*/
head->m_data += EOFF;
eh = mtod(head, struct ether_header *);
@@ -2101,18 +2301,16 @@ ed_get_packet(sc, buf, len)
head->m_len += sizeof(struct ether_header);
len -= sizeof(struct ether_header);
- etype = ntohs((u_short)eh->ether_type);
+ etype = ntohs((u_short) eh->ether_type);
/*
- * Deal with trailer protocol:
- * If trailer protocol, calculate the datasize as 'off',
- * which is also the offset to the trailer header.
- * Set resid to the amount of packet data following the
- * trailer header.
- * Finally, copy residual data into mbuf chain.
+ * Deal with trailer protocol: If trailer protocol, calculate the
+ * datasize as 'off', which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the trailer
+ * header. Finally, copy residual data into mbuf chain.
*/
if (etype >= ETHERTYPE_TRAIL &&
- etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
off = (etype - ETHERTYPE_TRAIL) << 9;
if ((off + sizeof(struct trailer_header)) > len)
@@ -2120,14 +2318,15 @@ ed_get_packet(sc, buf, len)
/*
* If we have shared memory, we can get info directly from the
- * stored packet, otherwise we must get a local copy
- * of the trailer header using PIO.
+ * stored packet, otherwise we must get a local copy of the
+ * trailer header using PIO.
*/
if (sc->mem_shared) {
eh->ether_type = *ringoffset(sc, buf, off, u_short *);
- resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+ resid = ntohs(*ringoffset(sc, buf, off + 2, u_short *));
} else {
struct trailer_header trailer_header;
+
ed_pio_readmem(sc,
ringoffset(sc, buf, off, caddr_t),
(char *) &trailer_header,
@@ -2136,30 +2335,35 @@ ed_get_packet(sc, buf, len)
resid = trailer_header.ether_residual;
}
- if ((off + resid) > len) goto bad; /* insanity */
+ if ((off + resid) > len)
+ goto bad; /* insanity */
resid -= sizeof(struct trailer_header);
- if (resid < 0) goto bad; /* insanity */
+ if (resid < 0)
+ goto bad; /* insanity */
- m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *),
+ m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off + 4, char *),
head, resid);
- if (m == 0) goto bad;
+ if (m == 0)
+ goto bad;
len = off;
- head->m_pkthdr.len -= 4; /* subtract trailer header */
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
}
/*
- * Pull packet off interface. Or if this was a trailer packet,
- * the data portion is appended.
+ * Pull packet off interface. Or if this was a trailer packet, the
+ * data portion is appended.
*/
m = ed_ring_to_mbuf(sc, buf, m, len);
- if (m == 0) goto bad;
+ if (m == 0)
+ goto bad;
#if NBPFILTER > 0
+
/*
- * Check if there's a BPF listener on this interface.
- * If so, hand off the raw packet to bpf.
+ * Check if there's a BPF listener on this interface. If so, hand off
+ * the raw packet to bpf.
*/
if (sc->bpf) {
bpf_mtap(sc->bpf, head);
@@ -2168,17 +2372,17 @@ ed_get_packet(sc, buf, len)
* 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.
- *
+ *
* XXX This test does not support multicasts.
*/
if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- sizeof(eh->ether_dhost)) != 0 &&
+ sizeof(eh->ether_dhost)) != 0 &&
bcmp(eh->ether_dhost, etherbroadcastaddr,
sizeof(eh->ether_dhost)) != 0) {
- m_freem(head);
- return;
+ m_freem(head);
+ return;
}
}
#endif
@@ -2213,8 +2417,8 @@ bad: if (head)
* This routine is currently Novell-specific.
*/
void
-ed_pio_readmem(sc,src,dst,amount)
- struct ed_softc *sc;
+ed_pio_readmem(sc, src, dst, amount)
+ struct ed_softc *sc;
unsigned short src;
unsigned char *dst;
unsigned short amount;
@@ -2222,24 +2426,25 @@ ed_pio_readmem(sc,src,dst,amount)
unsigned short tmp_amount;
/* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
/* round up to a word */
tmp_amount = amount;
- if (amount & 1) ++amount;
+ if (amount & 1)
+ ++amount;
/* set up DMA byte count */
outb(sc->nic_addr + ED_P0_RBCR0, amount);
- outb(sc->nic_addr + ED_P0_RBCR1, amount>>8);
+ outb(sc->nic_addr + ED_P0_RBCR1, amount >> 8);
/* set up source address in NIC mem */
outb(sc->nic_addr + ED_P0_RSAR0, src);
- outb(sc->nic_addr + ED_P0_RSAR1, src>>8);
+ outb(sc->nic_addr + ED_P0_RSAR1, src >> 8);
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA);
if (sc->isa16bit) {
- insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount/2);
+ insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount / 2);
} else
insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount);
@@ -2251,41 +2456,42 @@ ed_pio_readmem(sc,src,dst,amount)
* be even.
*/
void
-ed_pio_writemem(sc,src,dst,len)
+ed_pio_writemem(sc, src, dst, len)
struct ed_softc *sc;
- char *src;
+ char *src;
unsigned short dst;
unsigned short len;
{
- int maxwait=100; /* about 120us */
+ int maxwait = 100; /* about 120us */
/* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
/* reset remote DMA complete flag */
outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
/* set up DMA byte count */
outb(sc->nic_addr + ED_P0_RBCR0, len);
- outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+ outb(sc->nic_addr + ED_P0_RBCR1, len >> 8);
/* set up destination address in NIC mem */
outb(sc->nic_addr + ED_P0_RSAR0, dst);
- outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8);
/* set remote DMA write */
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
if (sc->isa16bit)
- outsw(sc->asic_addr + ED_NOVELL_DATA, src, len/2);
+ outsw(sc->asic_addr + ED_NOVELL_DATA, src, len / 2);
else
outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+
/*
* Wait for remote DMA complete. This is necessary because on the
- * transmit side, data is handled internally by the NIC in bursts
- * and we can't start another remote DMA until this one completes.
- * Not waiting causes really bad things to happen - like the NIC
- * irrecoverably jamming the ISA bus.
+ * transmit side, data is handled internally by the NIC in bursts and
+ * we can't start another remote DMA until this one completes. Not
+ * waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
*/
while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
}
@@ -2295,7 +2501,7 @@ ed_pio_writemem(sc,src,dst,len)
* programmed I/O.
*/
u_short
-ed_pio_write_mbufs(sc,m,dst)
+ed_pio_write_mbufs(sc, m, dst)
struct ed_softc *sc;
struct mbuf *m;
unsigned short dst;
@@ -2303,40 +2509,40 @@ ed_pio_write_mbufs(sc,m,dst)
unsigned short len, mb_offset;
struct mbuf *mp;
unsigned char residual[2];
- int maxwait=100; /* about 120us */
+ int maxwait = 100; /* about 120us */
/* First, count up the total number of bytes to copy */
for (len = 0, mp = m; mp; mp = mp->m_next)
len += mp->m_len;
-
+
/* select page 0 registers */
- outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
/* reset remote DMA complete flag */
outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
/* set up DMA byte count */
outb(sc->nic_addr + ED_P0_RBCR0, len);
- outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+ outb(sc->nic_addr + ED_P0_RBCR1, len >> 8);
/* set up destination address in NIC mem */
outb(sc->nic_addr + ED_P0_RSAR0, dst);
- outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst >> 8);
/* set remote DMA write */
outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
mb_offset = 0;
+
/*
- * Transfer the mbuf chain to the NIC memory.
- * The following code isn't too pretty. The problem is that we can only
- * transfer words to the board, and if an mbuf has an odd number
- * of bytes in it, this is a problem. It's not a simple matter of
- * just removing a byte from the next mbuf (adjusting data++ and
- * len--) because this will hose-over the mbuf chain which might
- * be needed later for BPF. Instead, we maintain an offset
- * (mb_offset) which let's us skip over the first byte in the
- * following mbuf.
+ * Transfer the mbuf chain to the NIC memory. The following code isn't
+ * too pretty. The problem is that we can only transfer words to the
+ * board, and if an mbuf has an odd number of bytes in it, this is a
+ * problem. It's not a simple matter of just removing a byte from the
+ * next mbuf (adjusting data++ and len--) because this will hose-over
+ * the mbuf chain which might be needed later for BPF. Instead, we
+ * maintain an offset (mb_offset) which let's us skip over the first
+ * byte in the following mbuf.
*/
while (m) {
if (m->m_len - mb_offset) {
@@ -2347,24 +2553,27 @@ ed_pio_write_mbufs(sc,m,dst)
(m->m_len - mb_offset) / 2);
/*
- * if odd number of bytes, get the odd byte from
- * the next mbuf with data
+ * if odd number of bytes, get the odd byte
+ * from the next mbuf with data
*/
if ((m->m_len - mb_offset) & 1) {
/* first the last byte in current mbuf */
residual[0] = *(mtod(m, caddr_t) +
- m->m_len - 1);
-
+ m->m_len - 1);
+
/* advance past any empty mbufs */
while (m->m_next && (m->m_next->m_len == 0))
m = m->m_next;
if (m->m_next) {
- /* remove first byte in next mbuf */
+
+ /*
+ * remove first byte in next
+ * mbuf
+ */
residual[1] = *(mtod(m->m_next, caddr_t));
mb_offset = 1;
}
-
outw(sc->asic_addr + ED_NOVELL_DATA,
*((unsigned short *) residual));
} else
@@ -2378,10 +2587,10 @@ ed_pio_write_mbufs(sc,m,dst)
/*
* Wait for remote DMA complete. This is necessary because on the
- * transmit side, data is handled internally by the NIC in bursts
- * and we can't start another remote DMA until this one completes.
- * Not waiting causes really bad things to happen - like the NIC
- * irrecoverably jamming the ISA bus.
+ * transmit side, data is handled internally by the NIC in bursts and
+ * we can't start another remote DMA until this one completes. Not
+ * waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
*/
while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
@@ -2390,23 +2599,22 @@ ed_pio_write_mbufs(sc,m,dst)
sc->arpcom.ac_if.if_unit);
ed_reset(sc->arpcom.ac_if.if_unit, 0);
}
-
- return(len);
+ return (len);
}
-
+
/*
* Given a source and destination address, copy 'amount' of a packet from
* the ring buffer into a linear destination buffer. Takes into account
* ring-wrap.
*/
static inline char *
-ed_ring_copy(sc,src,dst,amount)
+ed_ring_copy(sc, src, dst, amount)
struct ed_softc *sc;
- char *src;
- char *dst;
- u_short amount;
+ char *src;
+ char *dst;
+ u_short amount;
{
- u_short tmp_amount;
+ u_short tmp_amount;
/* does copy wrap to lower addr in ring buffer? */
if (src + amount > sc->mem_end) {
@@ -2414,21 +2622,20 @@ ed_ring_copy(sc,src,dst,amount)
/* copy amount up to end of NIC memory */
if (sc->mem_shared)
- bcopy(src,dst,tmp_amount);
+ bcopy(src, dst, tmp_amount);
else
- ed_pio_readmem(sc,src,dst,tmp_amount);
+ ed_pio_readmem(sc, src, dst, tmp_amount);
amount -= tmp_amount;
src = sc->mem_ring;
dst += tmp_amount;
}
-
if (sc->mem_shared)
bcopy(src, dst, amount);
else
ed_pio_readmem(sc, src, dst, amount);
- return(src + amount);
+ return (src + amount);
}
/*
@@ -2441,9 +2648,9 @@ ed_ring_copy(sc,src,dst,amount)
* amount = amount of data to copy
*/
struct mbuf *
-ed_ring_to_mbuf(sc,src,dst,total_len)
+ed_ring_to_mbuf(sc, src, dst, total_len)
struct ed_softc *sc;
- char *src;
+ char *src;
struct mbuf *dst;
u_short total_len;
{
@@ -2452,18 +2659,19 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
while (total_len) {
register u_short amount = min(total_len, M_TRAILINGSPACE(m));
- if (amount == 0) { /* no more data in this mbuf, alloc another */
+ if (amount == 0) { /* no more data in this mbuf, alloc
+ * another */
+
/*
- * If there is enough data for an mbuf cluster, attempt
- * to allocate one of those, otherwise, a regular
- * mbuf will do.
- * Note that a regular mbuf is always required, even if
- * we get a cluster - getting a cluster does not
- * allocate any mbufs, and one is needed to assign
- * the cluster to. The mbuf that has a cluster
- * extension can not be used to contain data - only
- * the cluster can contain data.
- */
+ * If there is enough data for an mbuf cluster,
+ * attempt to allocate one of those, otherwise, a
+ * regular mbuf will do. Note that a regular mbuf is
+ * always required, even if we get a cluster - getting
+ * a cluster does not allocate any mbufs, and one is
+ * needed to assign the cluster to. The mbuf that has
+ * a cluster extension can not be used to contain data
+ * - only the cluster can contain data.
+ */
dst = m;
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0)
@@ -2476,7 +2684,6 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
dst->m_next = m;
amount = min(total_len, M_TRAILINGSPACE(m));
}
-
src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
m->m_len += amount;
@@ -2485,4 +2692,62 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
}
return (m);
}
+#ifdef MULTICAST
+/*
+ * Compute crc for ethernet address
+ */
+u_long
+ds_crc(ep)
+ u_char *ep;
+{
+#define POLYNOMIAL 0x04c11db6
+ register u_long crc = 0xffffffffL;
+ register int carry, i, j;
+ register u_char b;
+
+ for (i = 6; --i >= 0;) {
+ b = *ep++;
+ for (j = 8; --j >= 0;) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry)
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ return crc;
+#undef POLYNOMIAL
+}
+
+/*
+ * Compute the multicast address filter from the
+ * list of multicast addresses we need to listen to.
+ */
+void
+ds_getmcaf(sc, mcaf)
+ struct ed_softc *sc;
+ u_long *mcaf;
+{
+ register u_int index;
+ register u_char *af = (u_char *) mcaf;
+ register struct ether_multi *enm;
+ register struct ether_multistep step;
+
+ mcaf[0] = 0;
+ mcaf[1] = 0;
+
+ ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ mcaf[0] = 0xffffffff;
+ mcaf[1] = 0xffffffff;
+ return;
+ }
+ index = ds_crc(enm->enm_addrlo, 6) >> 26;
+ af[index >> 3] |= 1 << (index & 7);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+}
+#endif
#endif
diff --git a/sys/i386/isa/if_edreg.h b/sys/i386/isa/if_edreg.h
index 49f7816a4d4e..d2a03f5b508b 100644
--- a/sys/i386/isa/if_edreg.h
+++ b/sys/i386/isa/if_edreg.h
@@ -1,7 +1,7 @@
/*
* National Semiconductor DS8390 NIC register definitions
*
- * $Id: if_edreg.h,v 1.13.2.1 1994/04/17 06:07:24 rgrimes Exp $
+ * $Id: if_edreg.h,v 1.14 1994/04/10 20:06:28 davidg Exp $
*
* Modification history
*
diff --git a/sys/i386/isa/if_el.c b/sys/i386/isa/if_el.c
new file mode 100644
index 000000000000..d0de274baf73
--- /dev/null
+++ b/sys/i386/isa/if_el.c
@@ -0,0 +1,800 @@
+/* Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
+ * to use, copy, modify and distribute this software 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.
+ *
+ * Questions, comments, bug reports and fixes to kimmel@cs.umass.edu.
+ */
+/* Except of course for the portions of code lifted from other FreeBSD
+ * drivers (mainly elread, elget and el_ioctl)
+ */
+/* 3COM Etherlink 3C501 device driver for FreeBSD */
+/* Yeah, I know these cards suck, but you can also get them for free
+ * really easily...
+ */
+/* Bugs/possible improvements:
+ * - Does not currently support DMA
+ * - Does not currently support multicasts
+ */
+#include "el.h"
+#if NEL > 0
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_elreg.h"
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+
+/* For debugging convenience */
+#ifdef EL_DEBUG
+#define dprintf(x) printf x
+#else
+#define dprintf(x)
+#endif
+
+/* el_softc: per line info and status */
+struct el_softc {
+ struct arpcom arpcom; /* Ethernet common */
+ u_short el_base; /* Base I/O addr */
+ caddr_t bpf; /* BPF magic cookie */
+ char el_pktbuf[EL_BUFSIZ]; /* Frame buffer */
+} el_softc[NEL];
+
+/* Prototypes */
+int el_attach(struct isa_device *);
+void el_init(int);
+void elintr(int);
+int el_ioctl(struct ifnet *,int,caddr_t);
+int el_probe(struct isa_device *);
+void el_start(struct ifnet *);
+void el_reset(int,int);
+void el_watchdog(int);
+
+static void el_stop(int);
+static int el_xmit(struct el_softc *,int);
+static inline void elread(struct el_softc *,caddr_t,int);
+static struct mbuf *elget(caddr_t,int,int,struct ifnet *);
+static inline void el_hardreset(int);
+
+/* isa_driver structure for autoconf */
+struct isa_driver eldriver = {
+ el_probe, el_attach, "el"
+};
+
+/* Probe routine. See if the card is there and at the right place. */
+int el_probe(struct isa_device *idev)
+{
+ struct el_softc *sc;
+ u_short base; /* Just for convenience */
+ u_char station_addr[ETHER_ADDR_LEN];
+ int i;
+
+ /* Grab some info for our structure */
+ sc = &el_softc[idev->id_unit];
+ sc->el_base = idev->id_iobase;
+ base = sc->el_base;
+
+ /* First check the base */
+ if((base < 0x280) || (base > 0x3f0)) {
+ printf("el%d: ioaddr must be between 0x280 and 0x3f0\n",
+ idev->id_unit);
+ return(0);
+ }
+
+ /* Now attempt to grab the station address from the PROM
+ * and see if it contains the 3com vendor code.
+ */
+ dprintf(("Probing 3c501 at 0x%x...\n",base));
+
+ /* Reset the board */
+ dprintf(("Resetting board...\n"));
+ outb(base+EL_AC,EL_AC_RESET);
+ DELAY(5);
+ outb(base+EL_AC,0);
+ dprintf(("Reading station address...\n"));
+ /* Now read the address */
+ for(i=0;i<ETHER_ADDR_LEN;i++) {
+ outb(base+EL_GPBL,i);
+ station_addr[i] = inb(base+EL_EAW);
+ }
+ dprintf(("Address is %s\n",ether_sprintf(station_addr)));
+
+ /* If the vendor code is ok, return a 1. We'll assume that
+ * whoever configured this system is right about the IRQ.
+ */
+ if((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
+ || (station_addr[2] != 0x8c)) {
+ dprintf(("Bad vendor code.\n"));
+ return(0);
+ } else {
+ dprintf(("Vendor code ok.\n"));
+ /* Copy the station address into the arpcom structure */
+ bcopy(station_addr,sc->arpcom.ac_enaddr,ETHER_ADDR_LEN);
+ return(1);
+ }
+}
+
+/* Attach the interface to the kernel data structures. By the time
+ * this is called, we know that the card exists at the given I/O address.
+ * We still assume that the IRQ given is correct.
+ */
+int el_attach(struct isa_device *idev)
+{
+ struct el_softc *sc;
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+ u_short base;
+ int t;
+
+ dprintf(("Attaching el%d...\n",idev->id_unit));
+
+ /* Get things pointing to the right places. */
+ sc = &el_softc[idev->id_unit];
+ ifp = &sc->arpcom.ac_if;
+ base = sc->el_base;
+
+ /* Now reset the board */
+ dprintf(("Resetting board...\n"));
+ el_hardreset(idev->id_unit);
+
+ /* Initialize ifnet structure */
+ ifp->if_unit = idev->id_unit;
+ ifp->if_name = "el";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = el_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = el_start;
+ ifp->if_ioctl = el_ioctl;
+ ifp->if_reset = el_reset;
+ ifp->if_watchdog = el_watchdog;
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /* Now we can attach the interface */
+ dprintf(("Attaching interface...\n"));
+ if_attach(ifp);
+
+ /* Put the station address in the ifa address list's AF_LINK
+ * entry, if any.
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != NULL) && (ifa->ifa_addr != NULL) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ if((ifa != NULL) && (ifa->ifa_addr != NULL)) {
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr,LLADDR(sdl),ETHER_ADDR_LEN);
+ }
+
+ /* Print out some information for the user */
+ printf("el%d: 3c501 address %s\n",idev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr));
+
+ /* Finally, attach to bpf filter if it is present. */
+#if NBPFILTER > 0
+ dprintf(("Attaching to BPF...\n"));
+ bpfattach(&sc->bpf,ifp,DLT_EN10MB,sizeof(struct ether_header));
+#endif
+
+ dprintf(("el_attach() finished.\n"));
+ return(1);
+}
+
+/* This routine resets the interface. */
+void el_reset(int unit,int uban)
+{
+ int s;
+
+ dprintf(("elreset()\n"));
+ s = splimp();
+ el_stop(unit);
+ el_init(unit);
+ splx(s);
+}
+
+static void el_stop(int unit)
+{
+ struct el_softc *sc;
+
+ sc = &el_softc[unit];
+ outb(sc->el_base+EL_AC,0);
+}
+
+/* Do a hardware reset of the 3c501. Do not call until after el_probe()! */
+static inline void el_hardreset(int unit)
+{
+ register struct el_softc *sc;
+ register int base;
+ register int j;
+
+ sc = &el_softc[unit];
+ base = sc->el_base;
+
+ /* First reset the board */
+ outb(base+EL_AC,EL_AC_RESET);
+ DELAY(5);
+ outb(base+EL_AC,0);
+
+ /* Then give it back its ethernet address. Thanks to the mach
+ * source code for this undocumented goodie...
+ */
+ for(j=0;j<ETHER_ADDR_LEN;j++)
+ outb(base+j,sc->arpcom.ac_enaddr[j]);
+}
+
+/* Initialize interface. */
+void el_init(int unit)
+{
+ struct el_softc *sc;
+ struct ifnet *ifp;
+ int s;
+ u_short base;
+
+ /* Set up pointers */
+ sc = &el_softc[unit];
+ ifp = &sc->arpcom.ac_if;
+ base = sc->el_base;
+
+ /* If address not known, do nothing. */
+ if(ifp->if_addrlist == (struct ifaddr *)0)
+ return;
+
+ s = splimp();
+
+ /* First, reset the board. */
+ dprintf(("Resetting board...\n"));
+ el_hardreset(unit);
+
+ /* Configure rx */
+ dprintf(("Configuring rx...\n"));
+ if(ifp->if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ outb(base+EL_RBC,0);
+
+ /* Configure TX */
+ dprintf(("Configuring tx...\n"));
+ outb(base+EL_TXC,0);
+
+ /* Start reception */
+ dprintf(("Starting reception...\n"));
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+
+ /* Set flags appropriately */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* And start output. */
+ el_start(ifp);
+
+ splx(s);
+}
+
+/* Start output on interface. Get datagrams from the queue and output
+ * them, giving the receiver a chance between datagrams. Call only
+ * from splimp or interrupt level!
+ */
+void el_start(struct ifnet *ifp)
+{
+ struct el_softc *sc;
+ u_short base;
+ struct mbuf *m, *m0;
+ int s, i, len, retries, done;
+
+ /* Get things pointing in the right directions */
+ sc = &el_softc[ifp->if_unit];
+ base = sc->el_base;
+
+ dprintf(("el_start()...\n"));
+ s = splimp();
+
+ /* Don't do anything if output is active */
+ if(sc->arpcom.ac_if.if_flags & IFF_OACTIVE)
+ return;
+ sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+
+ /* The main loop. They warned me against endless loops, but
+ * would I listen? NOOO....
+ */
+ while(1) {
+ /* Dequeue the next datagram */
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd,m0);
+
+ /* If there's nothing to send, return. */
+ if(m0 == NULL) {
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ splx(s);
+ return;
+ }
+
+ /* Disable the receiver */
+ outb(base+EL_AC,EL_AC_HOST);
+ outb(base+EL_RBC,0);
+
+ /* Copy the datagram to the buffer. */
+ len = 0;
+ for(m = m0; m != NULL; m = m->m_next) {
+ if(m->m_len == 0)
+ continue;
+ bcopy(mtod(m,caddr_t),sc->el_pktbuf+len,m->m_len);
+ len += m->m_len;
+ }
+ m_freem(m0);
+
+ len = MAX(len,ETHER_MIN_LEN);
+
+ /* Give the packet to the bpf, if any */
+#if NBPFILTER > 0
+ if(sc->bpf)
+ bpf_tap(sc->bpf,sc->el_pktbuf,len);
+#endif
+
+ /* Transfer datagram to board */
+ dprintf(("el: xfr pkt length=%d...\n",len));
+ i = EL_BUFSIZ - len;
+ outb(base+EL_GPBL,(i & 0xff));
+ outb(base+EL_GPBH,((i>>8)&0xff));
+ outsb(base+EL_BUF,sc->el_pktbuf,len);
+
+ /* Now transmit the datagram */
+ retries=0;
+ done=0;
+ while(!done) {
+ if(el_xmit(sc,len)) { /* Something went wrong */
+ done = -1;
+ break;
+ }
+ /* Check out status */
+ i = inb(base+EL_TXS);
+ dprintf(("tx status=0x%x\n",i));
+ if(!(i & EL_TXS_READY)) {
+ dprintf(("el: err txs=%x\n",i));
+ sc->arpcom.ac_if.if_oerrors++;
+ if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {
+ if((!(i & EL_TXC_DCOLL16)) && retries < 15) {
+ retries++;
+ outb(base+EL_AC,EL_AC_HOST);
+ }
+ }
+ else
+ done = 1;
+ }
+ else {
+ sc->arpcom.ac_if.if_opackets++;
+ done = 1;
+ }
+ }
+ if(done == -1) /* Packet not transmitted */
+ continue;
+
+ /* Now give the card a chance to receive.
+ * Gotta love 3c501s...
+ */
+ (void)inb(base+EL_AS);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ splx(s);
+ /* Interrupt here */
+ s = splimp();
+ }
+}
+
+/* This function actually attempts to transmit a datagram downloaded
+ * to the board. Call at splimp or interrupt, after downloading data!
+ * Returns 0 on success, non-0 on failure
+ */
+static int el_xmit(struct el_softc *sc,int len)
+{
+ int gpl;
+ int i;
+
+ gpl = EL_BUFSIZ - len;
+ dprintf(("el: xmit..."));
+ outb((sc->el_base)+EL_GPBL,(gpl & 0xff));
+ outb((sc->el_base)+EL_GPBH,((gpl>>8)&0xff));
+ outb((sc->el_base)+EL_AC,EL_AC_TXFRX);
+ i = 20000;
+ while((inb((sc->el_base)+EL_AS) & EL_AS_TXBUSY) && (i>0))
+ i--;
+ if(i == 0) {
+ dprintf(("tx not ready\n"));
+ sc->arpcom.ac_if.if_oerrors++;
+ return(-1);
+ }
+ dprintf(("%d cycles.\n",(20000-i)));
+ return(0);
+}
+
+/* controller interrupt */
+void elintr(int unit)
+{
+ register struct el_softc *sc;
+ register base;
+ int stat, rxstat, len, done;
+
+ /* Get things pointing properly */
+ sc = &el_softc[unit];
+ base = sc->el_base;
+
+ dprintf(("elintr: "));
+
+ /* Check board status */
+ stat = inb(base+EL_AS);
+ if(stat & EL_AS_RXBUSY) {
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ done = 0;
+ while(!done) {
+ rxstat = inb(base+EL_RXS);
+ if(rxstat & EL_RXS_STALE) {
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ /* If there's an overflow, reinit the board. */
+ if(!(rxstat & EL_RXS_NOFLOW)) {
+ dprintf(("overflow.\n"));
+ el_hardreset(unit);
+ /* Put board back into receive mode */
+ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ (void)inb(base+EL_AS);
+ outb(base+EL_RBC,0);
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ /* Incoming packet */
+ len = inb(base+EL_RBL);
+ len |= inb(base+EL_RBH) << 8;
+ dprintf(("receive len=%d rxstat=%x ",len,rxstat));
+ outb(base+EL_AC,EL_AC_HOST);
+
+ /* If packet too short or too long, restore rx mode and return
+ */
+ if((len <= sizeof(struct ether_header)) || (len > ETHER_MAX_LEN)) {
+ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ (void)inb(base+EL_AS);
+ outb(base+EL_RBC,0);
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ sc->arpcom.ac_if.if_ipackets++;
+
+ /* Copy the data into our buffer */
+ outb(base+EL_GPBL,0);
+ outb(base+EL_GPBH,0);
+ insb(base+EL_BUF,sc->el_pktbuf,len);
+ outb(base+EL_RBC,0);
+ outb(base+EL_AC,EL_AC_RX);
+ dprintf(("%s-->",ether_sprintf(sc->el_pktbuf+6)));
+ dprintf(("%s\n",ether_sprintf(sc->el_pktbuf)));
+
+ /* Pass data up to upper levels */
+ len -= sizeof(struct ether_header);
+ elread(sc,(caddr_t)(sc->el_pktbuf),len);
+
+ /* Is there another packet? */
+ stat = inb(base+EL_AS);
+
+ /* If so, do it all again (i.e. don't set done to 1) */
+ if(!(stat & EL_AS_RXBUSY))
+ dprintf(("<rescan> "));
+ else
+ done = 1;
+ }
+
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+}
+
+/* Pass a packet up to the higher levels. Deal with trailer protocol. */
+static inline void elread(struct el_softc *sc,caddr_t buf,int len)
+{
+ register struct ether_header *eh;
+ struct mbuf *m;
+ int off, resid;
+
+ /* Deal with trailer protocol: if type is trailer type
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+ eh = (struct ether_header *)buf;
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+#define eldataaddr(eh,off,type) ((type)(((caddr_t)((eh)+1)+(off))))
+ if(eh->ether_type >= ETHERTYPE_TRAIL &&
+ eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
+ if(off >= ETHERMTU)
+ return;
+ eh->ether_type = ntohs(*eldataaddr(eh,off,u_short *));
+ resid = ntohs(*(eldataaddr(eh,off+2,u_short *)));
+ if((off+resid) > len)
+ return;
+ len = off + resid;
+ }
+ else
+ off = 0;
+
+ if(len <= 0)
+ return;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a bpf filter listening on this interface.
+ * If so, hand off the raw packet to bpf, which must deal with
+ * trailers in its own way.
+ */
+ if(sc->bpf) {
+ eh->ether_type = htons((u_short)eh->ether_type);
+ bpf_tap(sc->bpf,buf,len+sizeof(struct ether_header));
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no bpf listeners. And if el are in promiscuous
+ * mode, el have to check if this packet is really ours.
+ *
+ * This test does not support multicasts.
+ */
+ if((sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ && bcmp(eh->ether_dhost,sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0
+ && bcmp(eh->ether_dhost,etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0)
+ return;
+ }
+#endif
+
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; neget will then force this header
+ * information to be at the front, but we still have to drop
+ * the type and length which are at the front of any trailer data.
+ */
+ m = elget(buf,len,off,&sc->arpcom.ac_if);
+ if(m == 0)
+ return;
+
+ ether_input(&sc->arpcom.ac_if,eh,m);
+}
+
+/*
+ * Pull read data off a interface.
+ * Len is length of data, with local net header stripped.
+ * Off is non-zero if a trailer protocol was used, and
+ * gives the offset of the trailer information.
+ * We copy the trailer information and then all the normal
+ * data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+struct mbuf *
+elget(buf, totlen, off0, ifp)
+ caddr_t buf;
+ int totlen, off0;
+ struct ifnet *ifp;
+{
+ struct mbuf *top, **mp, *m, *p;
+ int off = off0, len;
+ register caddr_t cp = buf;
+ char *epkt;
+
+ buf += sizeof(struct ether_header);
+ cp = buf;
+ epkt = cp + totlen;
+
+
+ if (off) {
+ cp += off + 2 * sizeof(u_short);
+ totlen -= 2 * sizeof(u_short);
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ m->m_len = MHLEN;
+ top = 0;
+ mp = &top;
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return (0);
+ }
+ m->m_len = MLEN;
+ }
+ len = min(totlen, epkt - cp);
+ if (len >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = len = min(len, MCLBYTES);
+ else
+ len = m->m_len;
+ } else {
+ /*
+ * Place initial small packet/header at end of mbuf.
+ */
+ if (len < m->m_len) {
+ if (top == 0 && len + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = len;
+ } else
+ len = m->m_len;
+ }
+ bcopy(cp, mtod(m, caddr_t), (unsigned)len);
+ cp += len;
+ *mp = m;
+ mp = &m->m_next;
+ totlen -= len;
+ if (cp == epkt)
+ cp = buf;
+ }
+ return (top);
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+el_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct el_softc *sc = &el_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ el_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ el_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ el_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)&ifr->ifr_data;
+ bcopy((caddr_t)sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ el_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ el_init(ifp->if_unit);
+ }
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/* Device timeout routine */
+void el_watchdog(int unit)
+{
+ struct el_softc *sc;
+
+ sc = &el_softc[unit];
+
+ log(LOG_ERR,"el%d: device timeout\n",unit);
+ sc->arpcom.ac_if.if_oerrors++;
+ el_reset(unit,0);
+}
+#endif
diff --git a/sys/i386/isa/if_elreg.h b/sys/i386/isa/if_elreg.h
new file mode 100644
index 000000000000..806d6ff68d1b
--- /dev/null
+++ b/sys/i386/isa/if_elreg.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
+ * to use, copy, modify and distribute this software 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.
+ */
+/* 3COM Etherlink 3C501 Register Definitions */
+
+/* I/O Ports */
+#define EL_RXS 0x6 /* Receive status register */
+#define EL_RXC 0x6 /* Receive command register */
+#define EL_TXS 0x7 /* Transmit status register */
+#define EL_TXC 0x7 /* Transmit command register */
+#define EL_GPBL 0x8 /* GP buffer ptr low byte */
+#define EL_GPBH 0x9 /* GP buffer ptr high byte */
+#define EL_RBL 0xa /* Receive buffer ptr low byte */
+#define EL_RBC 0xa /* Receive buffer clear */
+#define EL_RBH 0xb /* Receive buffer ptr high byte */
+#define EL_EAW 0xc /* Ethernet address window */
+#define EL_AS 0xe /* Auxillary status register */
+#define EL_AC 0xe /* Auxillary command register */
+#define EL_BUF 0xf /* Data buffer */
+
+/* Receive status register bits */
+#define EL_RXS_OFLOW 0x01 /* Overflow error */
+#define EL_RXS_FCS 0x02 /* FCS error */
+#define EL_RXS_DRIB 0x04 /* Dribble error */
+#define EL_RXS_SHORT 0x08 /* Short frame */
+#define EL_RXS_NOFLOW 0x10 /* No overflow */
+#define EL_RXS_GOOD 0x20 /* Received good frame */
+#define EL_RXS_STALE 0x80 /* Stale receive status */
+
+/* Receive command register bits */
+#define EL_RXC_DISABLE 0x00 /* Receiver disabled */
+#define EL_RXC_DOFLOW 0x01 /* Detect overflow */
+#define EL_RXC_DFCS 0x02 /* Detect FCS errs */
+#define EL_RXC_DDRIB 0x04 /* Detect dribble errors */
+#define EL_RXC_DSHORT 0x08 /* Detect short frames */
+#define EL_RXC_DNOFLOW 0x10 /* Detect frames w/o overflow ??? */
+#define EL_RXC_AGF 0x20 /* Accept Good Frames */
+#define EL_RXC_PROMISC 0x40 /* Promiscuous mode */
+#define EL_RXC_ABROAD 0x80 /* Accept address, broadcast */
+#define EL_RXC_AMULTI 0xc0 /* Accept address, multicast */
+
+/* Transmit status register bits */
+#define EL_TXS_UFLOW 0x01 /* Underflow */
+#define EL_TXS_COLL 0x02 /* Collision */
+#define EL_TXS_COLL16 0x04 /* Collision 16 */
+#define EL_TXS_READY 0x08 /* Ready for new frame */
+
+/* Transmit command register bits */
+#define EL_TXC_DUFLOW 0x01 /* Detect underflow */
+#define EL_TXC_DCOLL 0x02 /* Detect collisions */
+#define EL_TXC_DCOLL16 0x04 /* Detect collision 16 */
+#define EL_TXC_DSUCCESS 0x08 /* Detect success */
+
+/* Auxillary status register bits */
+#define EL_AS_RXBUSY 0x01 /* Receive busy */
+#define EL_AS_DMADONE 0x10 /* DMA finished */
+#define EL_AS_TXBUSY 0x80 /* Transmit busy */
+
+/* Auxillary command register bits */
+#define EL_AC_HOST 0x00 /* System bus can access buffer */
+#define EL_AC_IRQE 0x01 /* IRQ enable */
+#define EL_AC_TXBAD 0x02 /* Transmit frames with bad FCS */
+#define EL_AC_TXFRX 0x04 /* Transmit followed by receive */
+#define EL_AC_RX 0x08 /* Receive */
+#define EL_AC_LB 0x0c /* Loopback */
+#define EL_AC_DRQ 0x20 /* DMA request */
+#define EL_AC_RIDE 0x40 /* DRQ and IRQ enabled */
+#define EL_AC_RESET 0x80 /* Reset */
+
+/* Packet buffer size */
+#define EL_BUFSIZ 2048
+
+#define ETHER_ADDR_LEN 6
diff --git a/sys/i386/isa/if_ep.c b/sys/i386/isa/if_ep.c
index 43edd4529485..44e9c9fc0d58 100644
--- a/sys/i386/isa/if_ep.c
+++ b/sys/i386/isa/if_ep.c
@@ -8,7 +8,7 @@
* 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
+ * 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
@@ -22,62 +22,56 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
- * $Id: if_ep.c,v 1.7 1994/02/03 11:51:06 davidg Exp $
- */
-/*
- * TODO:
- * Multi-509 configs.
- * don't pass unit into epstop.
- * epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows?
- * deallocate mbufs when ifconfig'd down.
+ * $Id: if_ep.c,v 1.9 1994/05/02 22:27:33 ats Exp $
*/
+
#include "ep.h"
#if NEP > 0
#include "bpfilter.h"
-#include "sys/param.h"
+#include <sys/param.h>
#if defined(__FreeBSD__)
-#include "sys/systm.h"
-#include "sys/kernel.h"
+#include <sys/systm.h>
+#include <sys/kernel.h>
#endif
-#include "sys/mbuf.h"
-#include "sys/socket.h"
-#include "sys/ioctl.h"
-#include "sys/errno.h"
-#include "sys/syslog.h"
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
#if defined(__NetBSD__)
-#include "sys/select.h"
+#include <sys/select.h>
#endif
-#include "net/if.h"
-#include "net/if_dl.h"
-#include "net/if_types.h"
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
#ifdef INET
-#include "netinet/in.h"
-#include "netinet/in_systm.h"
-#include "netinet/in_var.h"
-#include "netinet/ip.h"
-#include "netinet/if_ether.h"
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
#endif
#ifdef NS
-#include "netns/ns.h"
-#include "netns/ns_if.h"
+#include <netns/ns.h>
+#include <netns/ns_if.h>
#endif
#if NBPFILTER > 0
-#include "net/bpf.h"
-#include "net/bpfdesc.h"
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
#endif
-#include "machine/pio.h"
+#include <machine/pio.h>
-#include "i386/isa/isa.h"
-#include "i386/isa/isa_device.h"
-#include "i386/isa/icu.h"
-#include "i386/isa/if_epreg.h"
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/if_epreg.h>
#define ETHER_MIN_LEN 64
#define ETHER_MAX_LEN 1518
@@ -90,12 +84,13 @@ struct ep_softc {
struct arpcom arpcom; /* Ethernet common part */
short ep_io_addr; /* i/o bus address */
char ep_connectors; /* Connectors on this card. */
-#define MAX_MBS 4 /* # of mbufs we keep around */
+#define MAX_MBS 8 /* # of mbufs we keep around */
struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
int next_mb; /* Which mbuf to use next. */
int last_mb; /* Last mbuf. */
int tx_start_thresh; /* Current TX_start_thresh. */
caddr_t bpf; /* BPF "magic cookie" */
+ char bus32bit; /* 32bit access possible */
} ep_softc[NEP];
static int epprobe __P((struct isa_device *));
@@ -104,7 +99,8 @@ static int epioctl __P((struct ifnet * ifp, int, caddr_t));
void epinit __P((int));
void epintr __P((int));
-void epmbufqueue __P((caddr_t, int));
+void epmbuffill __P((caddr_t, int));
+void epmbufempty __P((struct ep_softc *));
void epread __P((struct ep_softc *));
void epreset __P((int));
void epstart __P((struct ifnet *));
@@ -274,7 +270,7 @@ epinit(unit)
return;
s = splimp();
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
GO_WINDOW(0);
@@ -350,7 +346,7 @@ epinit(unit)
*/
sc->last_mb = 0;
sc->next_mb = 0;
- epmbufqueue((caddr_t)sc, 0);
+ epmbuffill((caddr_t)sc, 0);
epstart(ifp);
@@ -421,10 +417,19 @@ startagain:
outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
for (top = m; m != 0; m = m->m_next) {
- outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
- if (m->m_len & 1)
- outb(BASE + EP_W1_TX_PIO_WR_1,
- *(mtod(m, caddr_t) + m->m_len - 1));
+ if (sc->bus32bit) {
+ outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
+ m->m_len/4);
+ if (m->m_len & 3)
+ outsb(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t) + m->m_len/4,
+ m->m_len & 3);
+ } else {
+ outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
+ if (m->m_len & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1,
+ *(mtod(m, caddr_t) + m->m_len - 1));
+ }
}
while (pad--)
outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
@@ -658,7 +663,7 @@ epread(sc)
if (m == 0)
goto out;
} else {
- timeout(epmbufqueue, (caddr_t)sc, 0);
+ timeout(epmbuffill, (caddr_t)sc, 0);
sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
}
if (totlen >= MINCLSIZE)
@@ -667,11 +672,22 @@ epread(sc)
mcur->m_next = m;
lenthisone = min(totlen, M_TRAILINGSPACE(m));
}
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
- lenthisone / 2);
- m->m_len += lenthisone;
- if (lenthisone & 1)
- *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ if (sc->bus32bit) {
+ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 4);
+ m->m_len += (lenthisone & ~3);
+ if (lenthisone & 3)
+ insb(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m, caddr_t) + m->m_len,
+ lenthisone & 3);
+ m->m_len += (lenthisone & 3);
+ } else {
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 2);
+ m->m_len += lenthisone;
+ if (lenthisone & 1)
+ *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ }
totlen -= lenthisone;
}
if (off) {
@@ -679,15 +695,17 @@ epread(sc)
sc->mb[sc->next_mb] = 0;
if (top == 0) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (top == 0)
+ if (top == 0) {
+ top = m0;
goto out;
+ }
} else {
/* Convert one of our saved mbuf's */
sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
top->m_data = top->m_pktdat;
top->m_flags = M_PKTHDR;
}
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t),
sizeof(struct ether_header));
top->m_next = m0;
top->m_len = sizeof(struct ether_header);
@@ -700,7 +718,7 @@ epread(sc)
top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
++sc->arpcom.ac_if.if_ipackets;
#if NBPFILTER > 0
@@ -728,12 +746,11 @@ epread(sc)
return;
out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
if (top)
m_freem(top);
- return;
}
@@ -773,7 +790,7 @@ epioctl(ifp, cmd, data)
else {
ifp->if_flags &= ~IFF_RUNNING;
bcopy((caddr_t) ina->x_host.c_host,
- (caddr_t)sc->arpcom.ns_addr
+ (caddr_t)sc->arpcom.ac_enaddr,
sizeof(sc->arpcom.ac_enaddr));
}
epinit(ifp->if_unit);
@@ -789,6 +806,7 @@ epioctl(ifp, cmd, data)
if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
ifp->if_flags &= ~IFF_RUNNING;
epstop(ifp->if_unit);
+ epmbufempty(sc);
break;
}
if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
@@ -815,7 +833,6 @@ epreset(unit)
epstop(unit);
epinit(unit);
splx(s);
- return;
}
void
@@ -838,7 +855,7 @@ epstop(unit)
outw(BASE + EP_COMMAND, RX_DISABLE);
outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
outw(BASE + EP_COMMAND, TX_DISABLE);
outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
@@ -848,7 +865,6 @@ epstop(unit)
outw(BASE + EP_COMMAND, SET_RD_0_MASK);
outw(BASE + EP_COMMAND, SET_INTR_MASK);
outw(BASE + EP_COMMAND, SET_RX_FILTER);
- return;
}
@@ -937,24 +953,42 @@ is_eeprom_busy(is)
}
void
-epmbufqueue(sp, dummy_arg)
+epmbuffill(sp, dummy_arg)
caddr_t sp;
int dummy_arg;
{
struct ep_softc *sc = (struct ep_softc *)sp;
- int i;
+ int s, i;
- if (sc->mb[sc->last_mb])
- return;
+ s = splimp();
i = sc->last_mb;
do {
- MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
- if (!sc->mb[i])
+ if(sc->mb[i] == NULL)
+ MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
+ if(sc->mb[i] == NULL)
break;
i = (i + 1) % MAX_MBS;
} while (i != sc->next_mb);
sc->last_mb = i;
- return;
+ splx(s);
+}
+
+static void
+epmbufempty(sc)
+ struct ep_softc *sc;
+{
+ int s, i;
+
+ s = splimp();
+ for (i = 0; i<MAX_MBS; i++) {
+ if (sc->mb[i]) {
+ m_freem(sc->mb[i]);
+ sc->mb[i] = NULL;
+ }
+ }
+ sc->last_mb = sc->next_mb = 0;
+ untimeout(epmbuffill, sc);
+ splx(s);
}
#endif /* NEP > 0 */
diff --git a/sys/i386/isa/if_ie507.h b/sys/i386/isa/if_ie507.h
new file mode 100644
index 000000000000..4bf87fcbb597
--- /dev/null
+++ b/sys/i386/isa/if_ie507.h
@@ -0,0 +1,19 @@
+/*
+ * $Id: if_ie507.h,v 1.1 1994/05/25 20:06:49 ats Exp $
+ * Definitions for 3C507
+ */
+
+#define IE507_CTRL 6 /* control port */
+#define IE507_ICTRL 10 /* interrupt control */
+#define IE507_ATTN 11 /* any write here sends a chan attn */
+#define IE507_MADDR 14 /* shared memory configuration */
+#define IE507_IRQ 15 /* IRQ configuration */
+
+#define EL_CTRL_BNK1 0x01 /* register bank 1 */
+#define EL_CTRL_IEN 0x04 /* interrupt enable */
+#define EL_CTRL_INTL 0x08 /* interrupt active latch */
+#define EL_CTRL_16BIT 0x10 /* bus width; clear = 8-bit, set = 16-bit */
+#define EL_CTRL_LOOP 0x20 /* loopback mode */
+#define EL_CTRL_NRST 0x80 /* turn off to reset */
+#define EL_CTRL_RESET (EL_CTRL_LOOP)
+#define EL_CTRL_NORMAL (EL_CTRL_NRST | EL_CTRL_IEN | EL_CTRL_BNK1)
diff --git a/sys/i386/isa/if_is.c b/sys/i386/isa/if_is.c
index 341885f36ed1..234a0d937c1f 100644
--- a/sys/i386/isa/if_is.c
+++ b/sys/i386/isa/if_is.c
@@ -332,15 +332,15 @@ is_attach(isa_dev)
* are only 16 bits wide!
*/
-#define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) \
+#define ISMAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) \
+ sizeof(struct init_block) + 8)
- is->init_block = (struct init_block *)malloc(MAXMEM,M_TEMP,M_NOWAIT);
+ is->init_block = (struct init_block *)malloc(ISMAXMEM,M_TEMP,M_NOWAIT);
if (!is->init_block) {
printf("is%d : Couldn't allocate memory for card\n",unit);
}
/*
* XXX -- should take corrective action if not
- * quadword alilgned, the 8 byte slew factor in MAXMEM
+ * quadword alilgned, the 8 byte slew factor in ISMAXMEM
* allows for this.
*/
@@ -483,7 +483,7 @@ is_init(unit)
/* Address not known */
if (ifp->if_addrlist == (struct ifaddr *)0) return;
- s = splnet();
+ s = splimp();
/*
* Lance must be stopped
@@ -984,7 +984,7 @@ is_ioctl(ifp, cmd, data)
struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
- s = splnet();
+ s = splimp();
switch (cmd) {
diff --git a/sys/i386/isa/if_ze.c b/sys/i386/isa/if_ze.c
new file mode 100644
index 000000000000..6ffb96c96dbc
--- /dev/null
+++ b/sys/i386/isa/if_ze.c
@@ -0,0 +1,1951 @@
+/*-
+ * TODO:
+ * [1] integrate into current if_ed.c
+ * [2] parse tuples to find out where to map the shared memory buffer,
+ * and what to write into the configuration register
+ * [3] move pcic-specific code into a separate module.
+ *
+ * Device driver for IBM PCMCIA Credit Card Adapter for Ethernet,
+ * if_ze.c
+ *
+ * Based on the Device driver for National Semiconductor DS8390 ethernet
+ * adapters by David Greenman. Modifications for PCMCIA by Keith Moore.
+ * Adapted for FreeBSD 1.1.5 by Jordan Hubbard.
+ *
+ * Currently supports only the IBM Credit Card Adapter for Ethernet, but
+ * could probably work with other PCMCIA cards also, if it were modified
+ * to get the locations of the PCMCIA configuration option register (COR)
+ * by parsing the configuration tuples, rather than by hard-coding in
+ * the value expected by IBM's card.
+ *
+ * Sources for data on the PCMCIA/IBM CCAE specific portions of the driver:
+ *
+ * [1] _Local Area Network Credit Card Adapters Technical Reference_,
+ * IBM Corp., SC30-3585-00, part # 33G9243.
+ * [2] "pre-alpha" PCMCIA support code for Linux by Barry Jaspan.
+ * [3] Intel 82536SL PC Card Interface Controller Data Sheet, Intel
+ * Order Number 290423-002
+ * [4] National Semiconductor DP83902A ST-NIC (tm) Serial Network
+ * Interface Controller for Twisted Pair data sheet.
+ *
+ *
+ * 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.
+ */
+
+#include "ze.h"
+#if NZE > 0
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+#include "net/netisr.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_zereg.h"
+
+#include "i386/include/pio.h"
+
+
+
+/*****************************************************************************
+ * pcmcia controller chip (PCIC) support *
+ * (eventually, move this to a separate file) *
+ *****************************************************************************/
+#include "ic/i82365.h"
+
+/*
+ * Each PCIC chip (82365SL or clone) can handle two card slots, and there
+ * can be up to four PCICs in a system. (On some machines, not all of the
+ * address lines are decoded, so a card may appear to be in more than one
+ * slot.)
+ */
+#define MAXSLOT 8
+
+/*
+ * To access a register on the PCIC for a particular slot, you
+ * first write the correct OFFSET value for that slot in the
+ * INDEX register for the PCIC controller. You then read or write
+ * the value from or to the DATA register for that controller.
+ *
+ * The first pair of chips shares I/O addresss for DATA and INDEX,
+ * as does the second pair. (To the programmer, it looks like each
+ * pair is a single chip.) The i/o port addresses are hard-wired
+ * into the PCIC; so the following addresses should be valid for
+ * any machine that uses this chip.
+ */
+
+#define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */
+#define PCIC_DATA_0 0x3E1 /* data register, chips 0 and 1 */
+#define PCIC_INDEX_1 0x3E2 /* index reg, chips 1 and 2 */
+#define PCIC_DATA_1 0x3E3 /* data register, chips 1 and 2 */
+
+/*
+ * Given a slot number, calculate the INDEX and DATA registers
+ * to talk to that slot. OFFSET is added to the register number
+ * to address the registers for a particular slot.
+ */
+#define INDEX(slot) ((slot) < 4 ? PCIC_INDEX_0 : PCIC_INDEX_1)
+#define DATA(slot) ((slot) < 4 ? PCIC_DATA_0 : PCIC_DATA_1)
+#define OFFSET(slot) ((slot) % 4 * 0x40)
+
+/*
+ * There are 5 sets (windows) of memory mapping registers on the PCIC chip
+ * for each slot, numbered 0..4.
+ *
+ * They start at 10/50 hex within the chip's register space (not system
+ * I/O space), and are eight addresses apart. These are actually pairs of
+ * 8-bit-wide registers (low byte first, then high byte) since the
+ * address fields are actually 12 bits long. The upper bits are used
+ * for other things like 8/16-bit select and wait states.
+ *
+ * Memory mapping registers include start/stop addresses to define the
+ * region to be mapped (in terms of system memory addresses), and
+ * an offset register to allow for translation from system space
+ * to card space. The lower 12 bits aren't included in these, so memory is
+ * mapped in 4K chunks.
+ */
+#define MEM_START_ADDR(window) (((window) * 0x08) + 0x10)
+#define MEM_STOP_ADDR(window) (((window) * 0x08) + 0x12)
+#define MEM_OFFSET(window) (((window) * 0x08) + 0x14)
+/*
+ * this bit gets set in the address window enable register (PCIC_ADDRWINE)
+ * to enable a particular address window.
+ */
+#define MEM_ENABLE_BIT(window) ((1) << (window))
+
+/*
+ * There are two i/o port addressing windows. I/O ports cannot be
+ * relocated within system i/o space (unless the card doesn't decode
+ * all of the address bits); unlike card memory, there is no address
+ * translation offset.
+ */
+#define IO_START_ADDR(window) ((window) ? PCIC_IO1_STL : PCIC_IO0_STL)
+#define IO_STOP_ADDR(window) ((window) ? PCIC_IO1_SPL : PCIC_IO0_SPL)
+#define IO_ENABLE_BIT(window) ((window) ? PCIC_IO1_EN : PCIC_IO0_EN)
+#define IO_CS16_BIT(window) ((window) ? PCIC_IO1_CS16 : PCIC_IO0_CS16)
+
+/*
+ * read a byte from a pcic register for a particular slot
+ */
+static inline unsigned char
+pcic_getb (int slot, int reg)
+{
+ outb (INDEX(slot), OFFSET (slot) + reg);
+ return inb (DATA (slot));
+}
+
+/*
+ * write a byte to a pcic register for a particular slot
+ */
+static inline void
+pcic_putb (int slot, int reg, unsigned char val)
+{
+ outb (INDEX(slot), OFFSET (slot) + reg);
+ outb (DATA (slot), val);
+}
+
+/*
+ * read a word from a pcic register for a particular slot
+ */
+static inline unsigned short
+pcic_getw (int slot, int reg)
+{
+ return pcic_getb (slot, reg) | (pcic_getb (slot, reg+1) << 8);
+}
+
+/*
+ * write a word to a pcic register at a particular slot
+ */
+static inline void
+pcic_putw (int slot, int reg, unsigned short val)
+{
+ pcic_putb (slot, reg, val & 0xff);
+ pcic_putb (slot, reg + 1, (val >> 8) & 0xff);
+}
+
+static void
+pcic_print_regs (int slot)
+{
+ int i, j;
+
+ for (i = 0; i < 0x40; i += 16) {
+ for (j = 0; j < 16; ++j)
+ printf ("%02x ", pcic_getb (slot, i + j));
+ printf ("\n");
+ }
+}
+
+/*
+ * map a portion of the card's memory space into system memory
+ * space.
+ *
+ * slot = # of the slot the card is plugged into
+ * window = which pcic memory map registers to use (0..4)
+ * sys_addr = base system PHYSICAL memory address where we want it. must
+ * be on an appropriate boundary (lower 12 bits are zero).
+ * card_addr = the base address of the card's memory to correspond
+ * to sys_addr
+ * length = length of the segment to map (may be rounded up as necessary)
+ * type = which card memory space to map (attribute or shared)
+ * width = 1 for byte-wide mapping; 2 for word (16-bit) mapping.
+ */
+
+enum memtype { COMMON, ATTRIBUTE };
+
+static void
+pcic_map_memory (int slot, int window, unsigned long sys_addr,
+ unsigned long card_addr, unsigned long length,
+ enum memtype type, int width)
+{
+ unsigned short offset;
+ unsigned short mem_start_addr;
+ unsigned short mem_stop_addr;
+
+ sys_addr >>= 12;
+ card_addr >>= 12;
+ length >>= 12;
+ /*
+ * compute an offset for the chip such that
+ * (sys_addr + offset) = card_addr
+ * but the arithmetic is done modulo 2^14
+ */
+ offset = (card_addr - sys_addr) & 0x3FFF;
+ /*
+ * now OR in the bit for "attribute memory" if necessary
+ */
+ if (type == ATTRIBUTE) {
+ offset |= (PCIC_REG << 8);
+ /* REG == "region active" pin on card */
+ }
+ /*
+ * okay, set up the chip memory mapping registers, and turn
+ * on the enable bit for this window.
+ * if we are doing 16-bit wide accesses (width == 2),
+ * turn on the appropriate bit.
+ *
+ * XXX for now, we set all of the wait state bits to zero.
+ * Not really sure how they should be set.
+ */
+ mem_start_addr = sys_addr & 0xFFF;
+ if (width == 2)
+ mem_start_addr |= (PCIC_DATA16 << 8);
+ mem_stop_addr = (sys_addr + length) & 0xFFF;
+
+ pcic_putw (slot, MEM_START_ADDR(window), mem_start_addr);
+ pcic_putw (slot, MEM_STOP_ADDR(window), mem_stop_addr);
+ pcic_putw (slot, MEM_OFFSET(window), offset);
+ /*
+ * Assert the bit (PCIC_MEMCS16) that says to decode all of
+ * the address lines.
+ */
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) |
+ MEM_ENABLE_BIT(window) | PCIC_MEMCS16);
+}
+
+static void
+pcic_unmap_memory (int slot, int window)
+{
+ /*
+ * seems like we need to turn off the enable bit first, after which
+ * we can clear the registers out just to be sure.
+ */
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) & ~MEM_ENABLE_BIT(window));
+ pcic_putw (slot, MEM_START_ADDR(window), 0);
+ pcic_putw (slot, MEM_STOP_ADDR(window), 0);
+ pcic_putw (slot, MEM_OFFSET(window), 0);
+}
+
+/*
+ * map a range of addresses into system i/o space
+ * (no translation of i/o addresses is possible)
+ *
+ * 'width' is:
+ * + 0 to tell the PCIC to generate the ISA IOCS16* signal from
+ * the PCMCIA IOIS16* signal.
+ * + 1 to select 8-bit width
+ * + 2 to select 16-bit width
+ */
+
+static void
+pcic_map_io (int slot, int window, unsigned short base, unsigned short length,
+ unsigned short width)
+{
+ unsigned char x;
+
+ pcic_putw (slot, IO_START_ADDR(window), base);
+ pcic_putw (slot, IO_STOP_ADDR(window), base+length-1);
+ /*
+ * select the bits that determine whether
+ * an i/o operation is 8 or 16 bits wide
+ */
+ x = pcic_getb (slot, PCIC_IOCTL);
+ switch (width) {
+ case 0: /* PCMCIA card decides */
+ if (window)
+ x = (x & 0xf0) | PCIC_IO1_CS16;
+ else
+ x = (x & 0x0f) | PCIC_IO0_CS16;
+ break;
+ case 1: /* 8 bits wide */
+ break;
+ case 2: /* 16 bits wide */
+ if (window)
+ x = (x & 0xf0) | PCIC_IO1_16BIT;
+ else
+ x = (x & 0x0f) | PCIC_IO0_16BIT;
+ break;
+ }
+ pcic_putb (slot, PCIC_IOCTL, x);
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) | IO_ENABLE_BIT(window));
+}
+
+#ifdef TEST
+static void
+pcic_unmap_io (int slot, int window)
+{
+ pcic_putb (slot, PCIC_ADDRWINE,
+ pcic_getb (slot, PCIC_ADDRWINE) & ~IO_ENABLE_BIT(window));
+ pcic_putw (slot, IO_START_ADDR(window), 0);
+ pcic_putw (slot, IO_STOP_ADDR(window), 0);
+}
+#endif /* TEST */
+
+/*
+ * tell the PCIC which irq we want to use. only the following are legal:
+ * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15
+ *
+ * NB: 'irq' is an interrupt NUMBER, not a MASK as in struct isa_device.
+ */
+
+static void
+pcic_map_irq (int slot, int irq)
+{
+ if (irq < 3 || irq == 6 || irq == 8 || irq == 13 || irq > 15) {
+ printf ("ze: pcic_map_irq (slot %d): illegal irq %d\n", slot, irq);
+ return;
+ }
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) | (irq & 0x0F));
+}
+
+static void
+pcic_power_on (int slot)
+{
+ pcic_putb (slot, PCIC_POWER,
+ pcic_getb (slot, PCIC_POWER) | PCIC_DISRST | PCIC_PCPWRE);
+ DELAY (50000);
+ pcic_putb (slot, PCIC_POWER,
+ pcic_getb (slot, PCIC_POWER) | PCIC_OUTENA);
+}
+
+static void
+pcic_reset (int slot)
+{
+ /* assert RESET (by clearing a bit!), wait a bit, and de-assert it */
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) & ~PCIC_CARDRESET);
+ DELAY (50000);
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDRESET);
+}
+
+
+/*****************************************************************************
+ * Driver for Ethernet Adapter *
+ *****************************************************************************/
+/*
+ * ze_softc: per line info and status
+ */
+struct ze_softc {
+ struct arpcom arpcom; /* ethernet common */
+
+ char *type_str; /* pointer to type string */
+ char *mau; /* type of media access unit */
+#if 0
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
+#endif
+
+#if 0
+ u_short vector; /* interrupt vector */
+#endif
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
+
+ caddr_t smem_start; /* shared memory start address */
+ caddr_t smem_end; /* shared memory end address */
+ u_long smem_size; /* total shared memory size */
+ caddr_t smem_ring; /* start of RX ring-buffer (in smem) */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+
+ u_char memwidth; /* width of access to card mem 8 or 16 */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* Number of transmit buffers */
+ u_char txb_next; /* Pointer to next buffer ready to xmit */
+ u_short txb_next_len; /* next xmit buffer length */
+ u_char data_buffered; /* data has been buffered in interface memory */
+ u_char tx_page_start; /* first page of TX buffer area */
+
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ze_softc[NZE];
+
+int ze_attach(), ze_ioctl(), ze_probe();
+void ze_init(), ze_start(), ze_stop(), ze_intr();
+void ze_reset(), ze_watchdog(), ze_get_packet();
+
+static inline void ze_rint();
+static inline void ze_xmit();
+static inline char *ze_ring_copy();
+
+extern int ether_output();
+
+struct isa_driver zedriver = {
+ ze_probe,
+ ze_attach,
+ "ze"
+};
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+#define ETHER_HDR_SIZE 14
+
+static unsigned char enet_addr[6];
+static unsigned char card_info[256];
+
+#define CARD_INFO "IBM Corp.~Ethernet~0933495"
+
+/*
+ * scan the card information structure looking for the version/product info
+ * tuple. when we find it, compare it to the string we are looking for.
+ * return 1 if we find it, 0 otherwise.
+ */
+
+static int
+ze_check_cis (unsigned char *scratch)
+{
+ int i,j,k;
+
+ card_info[0] = '\0';
+ i = 0;
+ while (scratch[i] != 0xff && i < 1024) {
+ unsigned char link = scratch[i+2];
+
+#if 0
+ printf ("[%02x] %02x ", i, link);
+ for (j = 4; j < 2 * link + 4 && j < 32; j += 2)
+ printf ("%02x ", scratch[j + i]);
+ printf ("\n");
+#endif
+ if (scratch[i] == 0x15) {
+ /*
+ * level 1 version/product info
+ * copy to card_info, translating '\0' to '~'
+ */
+ k = 0;
+ for (j = i+8; scratch[j] != 0xff; j += 2)
+ card_info[k++] = scratch[j] == '\0' ? '~' : scratch[j];
+ card_info[k++] = '\0';
+ return (memcmp (card_info, CARD_INFO, sizeof(CARD_INFO)-1) == 0);
+ }
+ i += 4 + 2 * link;
+ }
+ return 0;
+}
+
+/*
+ * Probe each slot looking for an IBM Credit Card Adapter for Ethernet
+ * For each card that we find, map its card information structure
+ * into system memory at 'scratch' and see whether it's one of ours.
+ * Return the slot number if we find a card, or -1 otherwise.
+ *
+ * Side effects:
+ * + On success, leaves CIS mapped into memory at 'scratch';
+ * caller must free it.
+ * + On success, leaves ethernet address in enet_addr.
+ * + Leaves product/vendor id of last card probed in 'card_info'
+ */
+
+static int
+ze_find_adapter (unsigned char *scratch)
+{
+ int slot;
+
+ for (slot = 0; slot < MAXSLOT; ++slot) {
+ /*
+ * see if there's a PCMCIA controller here
+ * Intel PCMCIA controllers use 0x82 and 0x83
+ * IBM clone chips use 0x88 and 0x89, apparently
+ */
+ unsigned char idbyte = pcic_getb (slot, PCIC_ID_REV);
+
+ if (idbyte != 0x82 && idbyte != 0x83 &&
+ idbyte != 0x88 && idbyte != 0x89) {
+#if 0
+ printf ("ibmccae: pcic slot %d: wierd id/rev code 0x%02x\n",
+ slot, idbyte);
+#endif
+ continue;
+ }
+ if ((pcic_getb (slot, PCIC_STATUS) & PCIC_CD) != PCIC_CD) {
+ printf ("ze: slot %d: no card in slot\n", slot);
+ /* no card in slot */
+ continue;
+ }
+ pcic_power_on (slot);
+ pcic_reset (slot);
+ /*
+ * map the card's attribute memory and examine its
+ * card information structure tuples for something
+ * we recognize.
+ */
+ pcic_map_memory (slot, 0, kvtop (scratch), 0L,
+ 0xFFFL, ATTRIBUTE, 1);
+
+ if ((ze_check_cis (scratch)) > 0) {
+ /* found it */
+ printf ("ze: found card in slot %d\n", slot);
+ return slot;
+ }
+ else
+ printf ("ze: pcmcia slot %d: %s\n", slot, card_info);
+ pcic_unmap_memory (slot, 0);
+ }
+ return -1;
+}
+
+
+/*
+ * macros to handle casting unsigned long to (char *) so we can
+ * read/write into physical memory space.
+ */
+
+#define PEEK(addr) (*((unsigned char *)(addr)))
+#define POKE(addr,val) do { PEEK(addr) = (val); } while (0)
+
+/*
+ * Determine if the device is present
+ *
+ * on entry:
+ * a pointer to an isa_device struct
+ * on exit:
+ * NULL if device not found
+ * or # of i/o addresses used (if found)
+ */
+int
+ze_probe(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ze_softc *sc = &ze_softc[isa_dev->id_unit];
+ int i, x;
+ u_int memsize;
+ u_char iptr, memwidth, sum, tmp;
+ int slot;
+
+ if ((slot = ze_find_adapter (isa_dev->id_maddr)) < 0)
+ return NULL;
+
+ /*
+ * okay, we found a card, so set it up
+ */
+ /*
+ * Inhibit 16 bit memory delay.
+ * POINTETH.SYS apparently does this, for what reason I don't know.
+ */
+ pcic_putb (slot, PCIC_CDGC,
+ pcic_getb (slot, PCIC_CDGC) | PCIC_16_DL_INH);
+ /*
+ * things to map
+ * (1) card's EEPROM is already mapped by the find_adapter routine
+ * but we still need to get the card's ethernet address.
+ * after that we unmap that part of attribute memory.
+ * (2) card configuration registers need to be mapped in so we
+ * can set the configuration and socket # registers.
+ * (3) shared memory packet buffer
+ * (4) i/o ports
+ * (5) IRQ
+ */
+ /*
+ * Sigh. Location of the ethernet address isn't documented in [1].
+ * It was derived by doing a hex dump of all of attribute memory
+ * and looking for the IBM vendor prefix.
+ */
+ enet_addr[0] = PEEK(isa_dev->id_maddr+0xff0);
+ enet_addr[1] = PEEK(isa_dev->id_maddr+0xff2);
+ enet_addr[2] = PEEK(isa_dev->id_maddr+0xff4);
+ enet_addr[3] = PEEK(isa_dev->id_maddr+0xff6);
+ enet_addr[4] = PEEK(isa_dev->id_maddr+0xff8);
+ enet_addr[5] = PEEK(isa_dev->id_maddr+0xffa);
+ pcic_unmap_memory (slot, 0);
+
+ /*
+ * (2) map card configuration registers. these are offset
+ * in card memory space by 0x20000. normally we could get
+ * this offset from the card information structure, but I'm
+ * too lazy and am not quite sure if I understand the CIS anyway.
+ *
+ * XXX IF YOU'RE TRYING TO PORT THIS DRIVER FOR A DIFFERENT
+ * PCMCIA CARD, the most likely thing to change is the constant
+ * 0x20000 in the next statement. Oh yes, also change the
+ * card id string that we probe for.
+ */
+ pcic_map_memory (slot, 0, kvtop (isa_dev->id_maddr), 0x20000, 8L,
+ ATTRIBUTE, 1);
+ POKE(isa_dev->id_maddr, 0x80); /* reset the card (how long?) */
+ DELAY (10000);
+ /*
+ * Set the configuration index. According to [1], the adapter won't
+ * respond to any i/o signals until we do this; it uses the
+ * Memory Only interface (whatever that is; it's not documented).
+ * Also turn on "level" (not pulse) interrupts.
+ *
+ * XXX probably should init the socket and copy register also,
+ * so that we can deal with multiple instances of the same card.
+ */
+ POKE(isa_dev->id_maddr, 0x41);
+ pcic_unmap_memory (slot, 0);
+
+ /*
+ * (3) now map in the shared memory buffer. This has to be mapped
+ * as words, not bytes, and on a 16k boundary. The offset value
+ * was derived by installing IBM's POINTETH.SYS under DOS and
+ * looking at the PCIC registers; it's not documented in IBM's
+ * tech ref manual ([1]).
+ */
+ pcic_map_memory (slot, 0, kvtop (isa_dev->id_maddr), 0x4000L, 0x4000L,
+ COMMON, 2);
+
+ /*
+ * (4) map i/o ports.
+ *
+ * XXX is it possible that the config file leaves this unspecified,
+ * in which case we have to pick one?
+ *
+ * At least one PCMCIA device driver I'v seen maps a block
+ * of 32 consecutive i/o ports as two windows of 16 ports each.
+ * Maybe some other pcic chips are restricted to 16-port windows;
+ * the 82365SL doesn't seem to have that problem. But since
+ * we have an extra window anyway...
+ */
+#ifdef SHARED_MEMORY
+ pcic_map_io (slot, 0, isa_dev->id_iobase, 32, 1);
+#else
+ pcic_map_io (slot, 0, isa_dev->id_iobase, 16, 1);
+ pcic_map_io (slot, 1, isa_dev->id_iobase+16, 16, 2);
+#endif /* SHARED_MEMORY */
+
+ /*
+ * (5) configure the card for the desired interrupt
+ *
+ * XXX is it possible that the config file leaves this unspecified?
+ */
+ pcic_map_irq (slot, ffs (isa_dev->id_irq) - 1);
+
+ /* tell the PCIC that this is an I/O card (not memory) */
+ pcic_putb (slot, PCIC_INT_GEN,
+ pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDTYPE);
+
+#if 0
+ /* tell the PCIC to use level-mode interrupts */
+ /* XXX this register may not be present on all controllers */
+ pcic_putb (slot, PCIC_GLO_CTRL,
+ pcic_getb (slot, PCIC_GLO_CTRL) | PCIC_LVL_MODE);
+#endif
+
+#if 0
+ pcic_print_regs (slot);
+#endif
+ /*
+ * Setup i/o addresses
+ */
+ sc->nic_addr = isa_dev->id_iobase;
+#if 0
+ sc->vector = isa_dev->id_irq;
+#endif
+ sc->smem_start = (caddr_t)isa_dev->id_maddr;
+
+#if 0
+ sc->vendor = ZE_VENDOR_IBM;
+ sc->type = xxx;
+#endif
+
+ /* reset card to force it into a known state */
+ tmp = inb (isa_dev->id_iobase + ZE_RESET);
+ DELAY(5000);
+ outb (isa_dev->id_iobase + ZE_RESET, tmp);
+ DELAY(5000);
+
+ /*
+ * query MAM bit in misc register for 10base2
+ */
+ tmp = inb (isa_dev->id_iobase + ZE_MISC);
+ sc->mau = tmp & 0x09 ? "10base2" : "10baseT";
+
+ /* set width/size */
+ sc->type_str = "IBM PCMCIA";
+ memsize = 16*1024;
+ sc->memwidth = 16;
+
+ /* allocate 1 xmit buffer */
+ sc->smem_ring = sc->smem_start + (ZE_PAGE_SIZE * ZE_TXBUF_SIZE);
+ sc->txb_cnt = 1;
+ sc->rec_page_start = ZE_TXBUF_SIZE + ZE_PAGE_OFFSET;
+ sc->smem_size = memsize;
+ sc->smem_end = sc->smem_start + memsize;
+ sc->rec_page_stop = memsize / ZE_PAGE_SIZE + ZE_PAGE_OFFSET;
+ sc->tx_page_start = ZE_PAGE_OFFSET;
+
+ /* get station address */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = enet_addr[i];
+
+ isa_dev->id_msize = memsize;
+ return 32;
+}
+
+/*
+ * Install interface into kernel networking data structures
+ */
+int
+ze_attach(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ze_softc *sc = &ze_softc[isa_dev->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ /*
+ * Set interface to stopped condition (reset)
+ */
+ ze_stop(isa_dev->id_unit);
+
+ /*
+ * Initialize ifnet structure
+ */
+ ifp->if_unit = isa_dev->id_unit;
+ ifp->if_name = "ze" ;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = ze_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = ze_start;
+ ifp->if_ioctl = ze_ioctl;
+ ifp->if_reset = ze_reset;
+ ifp->if_watchdog = ze_watchdog;
+
+ /*
+ * Set default state for LLC0 flag (used to disable the tranceiver
+ * for AUI operation), based on compile-time config option.
+ */
+ if (isa_dev->id_flags & ZE_FLAGS_DISABLE_TRANCEIVER)
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS
+ | IFF_LLC0);
+ else
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+
+ /*
+ * Search down the ifa address list looking for the AF_LINK type entry
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ /*
+ * If we find an AF_LINK type entry we fill in the hardware address.
+ * This is useful for netstat(1) to keep track of which interface
+ * is which.
+ */
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ /*
+ * Fill in the link-level address for this interface
+ */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+
+ /*
+ * Print additional info when attached
+ */
+ printf("ze%d: address %s, type %s (%dbit)%s, MAU %s\n",
+ isa_dev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str,
+ sc->memwidth,
+ (ifp->if_flags & IFF_LLC0 ? " [tranceiver disabled]" : ""),
+ sc->mau);
+
+ /*
+ * If BPF is in the kernel, call the attach for it
+ */
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+/*
+ * Reset interface.
+ */
+void
+ze_reset(unit)
+ int unit;
+{
+ int s;
+
+ s = splnet();
+
+ /*
+ * Stop interface and re-initialize.
+ */
+ ze_stop(unit);
+ ze_init(unit);
+
+ (void) splx(s);
+}
+
+/*
+ * Take interface offline.
+ */
+void
+ze_stop(unit)
+ int unit;
+{
+ struct ze_softc *sc = &ze_softc[unit];
+ int n = 5000;
+
+ /*
+ * Stop everything on the interface, and select page 0 registers.
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STP);
+
+ /*
+ * Wait for interface to enter stopped state, but limit # of checks
+ * to 'n' (about 5ms). It shouldn't even take 5us on modern
+ * DS8390's, but just in case it's an old one.
+ */
+ while (((inb(sc->nic_addr + ZE_P0_ISR) & ZE_ISR_RST) == 0) && --n);
+
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to
+ * generate an interrupt after a transmit has been started on it.
+ */
+void
+ze_watchdog(unit)
+ int unit;
+{
+#if 1
+ struct ze_softc *sc = &ze_softc[unit];
+ u_char isr, imr;
+ u_short imask;
+
+ /* select page zero */
+ outb (sc->nic_addr + ZE_P0_CR,
+ (inb (sc->nic_addr + ZE_P0_CR) & 0x3f) | ZE_CR_PAGE_0);
+
+ /* read interrupt status register */
+ isr = inb (sc->nic_addr + ZE_P0_ISR) & 0xff;
+
+ /* select page two */
+ outb (sc->nic_addr + ZE_P0_CR,
+ (inb (sc->nic_addr + ZE_P0_CR) & 0x3f) | ZE_CR_PAGE_2);
+
+ /* read interrupt mask register */
+ imr = inb (sc->nic_addr + ZE_P2_IMR) & 0xff;
+
+ imask = inb(IO_ICU2) << 8 | inb(IO_ICU1);
+
+ log (LOG_ERR, "ze%d: device timeout, isr=%02x, imr=%02x, imask=%04x\n",
+ unit, isr, imr, imask);
+#else
+ log(LOG_ERR, "ze%d: device timeout\n", unit);
+#endif
+
+ ze_reset(unit);
+}
+
+/*
+ * Initialize device.
+ */
+void
+ze_init(unit)
+ int unit;
+{
+ struct ze_softc *sc = &ze_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i, s;
+ u_char command;
+
+
+ /* address not known */
+ if (ifp->if_addrlist == (struct ifaddr *)0) return;
+
+ /*
+ * Initialize the NIC in the exact order outlined in the NS manual.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
+ */
+ s = splnet();
+
+ /* reset transmitter flags */
+ sc->data_buffered = 0;
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_timer = 0;
+
+ sc->txb_next = 0;
+
+ /* This variable is used below - don't move this assignment */
+ sc->next_packet = sc->rec_page_start + 1;
+
+ /*
+ * Set interface for page 0, Remote DMA complete, Stopped
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STP);
+
+ if (sc->memwidth == 16) {
+ /*
+ * Set FIFO threshold to 8, No auto-init Remote DMA,
+ * byte order=80x86, word-wide DMA xfers
+ */
+ outb(sc->nic_addr + ZE_P0_DCR, ZE_DCR_FT1|ZE_DCR_WTS);
+ } else {
+ /*
+ * Same as above, but byte-wide DMA xfers
+ */
+ outb(sc->nic_addr + ZE_P0_DCR, ZE_DCR_FT1);
+ }
+
+ /*
+ * Clear Remote Byte Count Registers
+ */
+ outb(sc->nic_addr + ZE_P0_RBCR0, 0);
+ outb(sc->nic_addr + ZE_P0_RBCR1, 0);
+
+ /*
+ * Enable reception of broadcast packets
+ */
+ outb(sc->nic_addr + ZE_P0_RCR, ZE_RCR_AB);
+
+ /*
+ * Place NIC in internal loopback mode
+ */
+ outb(sc->nic_addr + ZE_P0_TCR, ZE_TCR_LB0);
+
+ /*
+ * Initialize transmit/receive (ring-buffer) Page Start
+ */
+ outb(sc->nic_addr + ZE_P0_TPSR, sc->tx_page_start);
+ outb(sc->nic_addr + ZE_P0_PSTART, sc->rec_page_start);
+
+ /*
+ * Initialize Receiver (ring-buffer) Page Stop and Boundry
+ */
+ outb(sc->nic_addr + ZE_P0_PSTOP, sc->rec_page_stop);
+ outb(sc->nic_addr + ZE_P0_BNRY, sc->rec_page_start);
+
+ /*
+ * Clear all interrupts. A '1' in each bit position clears the
+ * corresponding flag.
+ */
+ outb(sc->nic_addr + ZE_P0_ISR, 0xff);
+
+ /*
+ * Enable the following interrupts: receive/transmit complete,
+ * receive/transmit error, and Receiver OverWrite.
+ *
+ * Counter overflow and Remote DMA complete are *not* enabled.
+ */
+ outb(sc->nic_addr + ZE_P0_IMR,
+ ZE_IMR_PRXE|ZE_IMR_PTXE|ZE_IMR_RXEE|ZE_IMR_TXEE|ZE_IMR_OVWE);
+
+ /*
+ * Program Command Register for page 1
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_PAGE_1|ZE_CR_RD2|ZE_CR_STP);
+
+ /*
+ * Copy out our station address
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ outb(sc->nic_addr + ZE_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+
+#if NBPFILTER > 0
+ /*
+ * Initialize multicast address hashing registers to accept
+ * all multicasts (only used when in promiscuous mode)
+ */
+ for (i = 0; i < 8; ++i)
+ outb(sc->nic_addr + ZE_P1_MAR0 + i, 0xff);
+#endif
+
+ /*
+ * Set Current Page pointer to next_packet (initialized above)
+ */
+ outb(sc->nic_addr + ZE_P1_CURR, sc->next_packet);
+
+ /*
+ * Set Command Register for page 0, Remote DMA complete,
+ * and interface Start.
+ */
+ outb(sc->nic_addr + ZE_P1_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * Take interface out of loopback
+ */
+ outb(sc->nic_addr + ZE_P0_TCR, 0);
+
+#if 0
+ /*
+ * If this is a 3Com board, the tranceiver must be software enabled
+ * (there is no settable hardware default).
+ */
+ if (sc->vendor == ZE_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_LLC0) {
+ outb(sc->asic_addr + ZE_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ZE_3COM_CR, ZE_3COM_CR_XSEL);
+ }
+ }
+#endif
+
+ /*
+ * Set 'running' flag, and clear output active flag.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * ...and attempt to start output
+ */
+ ze_start(ifp);
+
+ (void) splx(s);
+}
+
+/*
+ * This routine actually starts the transmission on the interface
+ */
+static inline void
+ze_xmit(ifp)
+ struct ifnet *ifp;
+{
+ struct ze_softc *sc = &ze_softc[ifp->if_unit];
+ u_short len = sc->txb_next_len;
+
+ /*
+ * Set NIC for page 0 register access
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * Set TX buffer start page
+ */
+ outb(sc->nic_addr + ZE_P0_TPSR, sc->tx_page_start +
+ sc->txb_next * ZE_TXBUF_SIZE);
+
+ /*
+ * Set TX length
+ */
+ outb(sc->nic_addr + ZE_P0_TBCR0, len & 0xff);
+ outb(sc->nic_addr + ZE_P0_TBCR1, len >> 8);
+
+ /*
+ * Set page 0, Remote DMA complete, Transmit Packet, and *Start*
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_TXP|ZE_CR_STA);
+
+ sc->xmit_busy = 1;
+ sc->data_buffered = 0;
+
+ /*
+ * Switch buffers if we are doing double-buffered transmits
+ */
+ if ((sc->txb_next == 0) && (sc->txb_cnt > 1))
+ sc->txb_next = 1;
+ else
+ sc->txb_next = 0;
+
+ /*
+ * Set a timer just in case we never hear from the board again
+ */
+ ifp->if_timer = 2;
+}
+
+/*
+ * Start output on interface.
+ * We make two assumptions here:
+ * 1) that the current priority is set to splnet _before_ this code
+ * is called *and* is returned to the appropriate priority after
+ * return
+ * 2) that the IFF_OACTIVE flag is checked before this code is called
+ * (i.e. that the output part of the interface is idle)
+ */
+void
+ze_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ze_softc *sc = &ze_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ caddr_t buffer;
+ int len;
+ u_char laar_tmp;
+
+outloop:
+ /*
+ * See if there is room to send more data (i.e. one or both of the
+ * buffers is empty).
+ */
+ if (sc->data_buffered)
+ if (sc->xmit_busy) {
+ /*
+ * No room. Indicate this to the outside world
+ * and exit.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ } else {
+ /*
+ * Data is buffered, but we're not transmitting, so
+ * start the xmit on the buffered data.
+ * Note that ze_xmit() resets the data_buffered flag
+ * before returning.
+ */
+ ze_xmit(ifp);
+ }
+
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == NULL) {
+ /*
+ * The following isn't pretty; we are using the !OACTIVE flag to
+ * indicate to the outside world that we can accept an additional
+ * packet rather than that the transmitter is _actually_
+ * active. Indeed, the transmitter may be active, but if we haven't
+ * filled the secondary buffer with data then we still want to
+ * accept more.
+ * Note that it isn't necessary to test the data_buffered flag -
+ * we wouldn't have tried to de-queue the packet in the first place
+ * if it was set.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ return;
+ }
+
+ /*
+ * Copy the mbuf chain into the transmit buffer
+ */
+#if 0
+ /*
+ * Enable 16bit access to shared memory on WD/SMC boards
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ laar_tmp = inb(sc->asic_addr + ZE_WD_LAAR);
+ outb(sc->asic_addr + ZE_WD_LAAR, laar_tmp | ZE_WD_LAAR_M16EN);
+ }
+#endif
+
+ buffer = sc->smem_start + (sc->txb_next * ZE_TXBUF_SIZE * ZE_PAGE_SIZE);
+ len = 0;
+ for (m0 = m; m != 0; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+#if 0
+ /*
+ * Restore previous shared mem access type
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ outb(sc->asic_addr + ZE_WD_LAAR, laar_tmp);
+ }
+#endif
+
+ sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
+
+ if (sc->txb_cnt > 1)
+ /*
+ * only set 'buffered' flag if doing multiple buffers
+ */
+ sc->data_buffered = 1;
+
+ if (sc->xmit_busy == 0)
+ ze_xmit(ifp);
+ /*
+ * If there is BPF support in the configuration, tap off here.
+ * The following has support for converting trailer packets
+ * back to normal.
+ */
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+ } trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(m0, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(m0, off, sizeof(struct trailer_header),
+ &trailer_header.ether_type);
+
+ /* copy residual data */
+ m_copydata(m0, off+sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
+ sizeof(struct trailer_header), ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(m0, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, m0);
+ }
+#endif
+
+ m_freem(m0);
+
+ /*
+ * If we are doing double-buffering, a buffer might be free to
+ * fill with another packet, so loop back to the top.
+ */
+ if (sc->txb_cnt > 1)
+ goto outloop;
+ else {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ */
+static inline void /* only called from one place, so may as well integrate */
+ze_rint(unit)
+ int unit;
+{
+ register struct ze_softc *sc = &ze_softc[unit];
+ u_char boundry, current;
+ u_short len;
+ struct ze_ring *packet_ptr;
+
+ /*
+ * Set NIC to page 1 registers to get 'current' pointer
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_PAGE_1|ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
+ * it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer
+ * - i.e. it points to where additional new data will be added.
+ * We loop here until the logical beginning equals the logical
+ * end (or in other words, until the ring-buffer is empty).
+ */
+ while (sc->next_packet != inb(sc->nic_addr + ZE_P1_CURR)) {
+
+ /* get pointer to this buffer header structure */
+ packet_ptr = (struct ze_ring *)(sc->smem_ring +
+ (sc->next_packet - sc->rec_page_start) * ZE_PAGE_SIZE);
+
+ /*
+ * The byte count includes the FCS - Frame Check Sequence (a
+ * 32 bit CRC).
+ */
+ len = packet_ptr->count;
+ if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+ /*
+ * Go get packet. len - 4 removes CRC from length.
+ * (packet_ptr + 1) points to data just after the packet ring
+ * header (+4 bytes)
+ */
+ ze_get_packet(sc, (caddr_t)(packet_ptr + 1), len - 4);
+ ++sc->arpcom.ac_if.if_ipackets;
+ } else {
+ /*
+ * Really BAD...probably indicates that the ring pointers
+ * are corrupted. Also seen on early rev chips under
+ * high load - the byte order of the length gets switched.
+ */
+ log(LOG_ERR,
+ "ze%d: shared memory corrupt - invalid packet length %d\n",
+ unit, len);
+ ze_reset(unit);
+ return;
+ }
+
+ /*
+ * Update next packet pointer
+ */
+ sc->next_packet = packet_ptr->next_packet;
+
+ /*
+ * Update NIC boundry pointer - being careful to keep it
+ * one buffer behind. (as recommended by NS databook)
+ */
+ boundry = sc->next_packet - 1;
+ if (boundry < sc->rec_page_start)
+ boundry = sc->rec_page_stop - 1;
+
+ /*
+ * Set NIC to page 0 registers to update boundry register
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ outb(sc->nic_addr + ZE_P0_BNRY, boundry);
+
+ /*
+ * Set NIC to page 1 registers before looping to top (prepare to
+ * get 'CURR' current pointer)
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_PAGE_1|ZE_CR_RD2|ZE_CR_STA);
+ }
+}
+
+/*
+ * Ethernet interface interrupt processor
+ */
+void
+zeintr(unit)
+ int unit;
+{
+ struct ze_softc *sc = &ze_softc[unit];
+ u_char isr;
+
+ /*
+ * Set NIC to page 0 registers
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * loop until there are no more new interrupts
+ */
+ while (isr = inb(sc->nic_addr + ZE_P0_ISR)) {
+
+ /*
+ * reset all the bits that we are 'acknowleging'
+ * by writing a '1' to each bit position that was set
+ * (writing a '1' *clears* the bit)
+ */
+ outb(sc->nic_addr + ZE_P0_ISR, isr);
+
+ /*
+ * Transmit error. If a TX completed with an error, we end up
+ * throwing the packet away. Really the only error that is
+ * possible is excessive collisions, and in this case it is
+ * best to allow the automatic mechanisms of TCP to backoff
+ * the flow. Of course, with UDP we're screwed, but this is
+ * expected when a network is heavily loaded.
+ */
+ if (isr & ZE_ISR_TXE) {
+ u_char tsr = inb(sc->nic_addr + ZE_P0_TSR);
+ u_char ncr = inb(sc->nic_addr + ZE_P0_NCR);
+
+ /*
+ * Excessive collisions (16)
+ */
+ if ((tsr & ZE_TSR_ABT) && (ncr == 0)) {
+ /*
+ * When collisions total 16, the P0_NCR will
+ * indicate 0, and the TSR_ABT is set.
+ */
+ sc->arpcom.ac_if.if_collisions += 16;
+ } else
+ sc->arpcom.ac_if.if_collisions += ncr;
+
+ /*
+ * update output errors counter
+ */
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+ }
+
+
+ /*
+ * Receiver Error. One or more of: CRC error, frame alignment error
+ * FIFO overrun, or missed packet.
+ */
+ if (isr & ZE_ISR_RXE) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef ZE_DEBUG
+#if 0
+ printf("ze%d: receive error %x\n", unit,
+ inb(sc->nic_addr + ZE_P0_RSR));
+#else
+ printf("ze%d: receive error %b\n", unit,
+ inb(sc->nic_addr + ZE_P0_RSR),
+ "\20\8DEF\7REC DISAB\6PHY/MC\5MISSED\4OVR\3ALIGN\2FCS\1RCVD");
+#endif
+#endif
+ }
+
+ /*
+ * Overwrite warning. In order to make sure that a lockup
+ * of the local DMA hasn't occurred, we reset and
+ * re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some
+ * chips seem to want more. The DMA lockup has been
+ * seen only with early rev chips - Methinks this
+ * bug was fixed in later revs. -DG
+ */
+ if (isr & ZE_ISR_OVW) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#if 0
+ /* sigh. this happens too often on our net */
+ log(LOG_WARNING,
+ "ze%d: warning - receiver ring buffer overrun\n",
+ unit);
+#endif
+ /*
+ * Stop/reset/re-init NIC
+ */
+ ze_reset(unit);
+ }
+
+ /*
+ * Transmission completed normally.
+ */
+ if (isr & ZE_ISR_PTX) {
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+
+ /*
+ * Update total number of successfully transmitted
+ * packets.
+ */
+ ++sc->arpcom.ac_if.if_opackets;
+
+ /*
+ * Add in total number of collisions on last
+ * transmission.
+ */
+ sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr +
+ ZE_P0_TBCR0);
+ }
+
+ /*
+ * Receive Completion. Go and get the packet.
+ * XXX - Doing this on an error is dubious because there
+ * shouldn't be any data to get (we've configured the
+ * interface to not accept packets with errors).
+ */
+ if (isr & (ZE_ISR_PRX|ZE_ISR_RXE)) {
+#if 0
+ /*
+ * Enable access to shared memory on WD/SMC boards
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ outb(sc->asic_addr + ZE_WD_LAAR,
+ inb(sc->asic_addr + ZE_WD_LAAR)
+ | ZE_WD_LAAR_M16EN);
+ }
+#endif
+ ze_rint (unit);
+
+#if 0
+ /*
+ * Disable access to shared memory
+ */
+ if (sc->memwidth == 16)
+ if (sc->vendor == ZE_VENDOR_WD_SMC) {
+ outb(sc->asic_addr + ZE_WD_LAAR,
+ inb(sc->asic_addr + ZE_WD_LAAR)
+ & ~ZE_WD_LAAR_M16EN);
+ }
+#endif
+ }
+
+ /*
+ * If it looks like the transmitter can take more data,
+ * attempt to start output on the interface. If data is
+ * already buffered and ready to go, send it first.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) {
+ if (sc->data_buffered)
+ ze_xmit(&sc->arpcom.ac_if);
+ ze_start(&sc->arpcom.ac_if);
+ }
+
+ /*
+ * return NIC CR to standard state: page 0, remote DMA complete,
+ * start (toggling the TXP bit off, even if was just set
+ * in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
+ */
+ outb(sc->nic_addr + ZE_P0_CR, ZE_CR_RD2|ZE_CR_STA);
+
+ /*
+ * If the Network Talley Counters overflow, read them to
+ * reset them. It appears that old 8390's won't
+ * clear the ISR flag otherwise - resulting in an
+ * infinite loop.
+ */
+ if (isr & ZE_ISR_CNT) {
+ (void) inb(sc->nic_addr + ZE_P0_CNTR0);
+ (void) inb(sc->nic_addr + ZE_P0_CNTR1);
+ (void) inb(sc->nic_addr + ZE_P0_CNTR2);
+ }
+ }
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+ze_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ze_softc *sc = &ze_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ze_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ ze_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ ze_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ze_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ ze_init(ifp->if_unit);
+ }
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC) {
+ /*
+ * Set promiscuous mode on interface.
+ * XXX - for multicasts to work, we would need to
+ * write 1's in all bits of multicast
+ * hashing array. For now we assume that
+ * this was done in ze_init().
+ */
+ outb(sc->nic_addr + ZE_P0_RCR,
+ ZE_RCR_PRO|ZE_RCR_AM|ZE_RCR_AB);
+ } else {
+ /*
+ * XXX - for multicasts to work, we would need to
+ * rewrite the multicast hashing array with the
+ * proper hash (would have been destroyed above).
+ */
+ outb(sc->nic_addr + ZE_P0_RCR, ZE_RCR_AB);
+ }
+#endif
+#if 0
+ /*
+ * An unfortunate hack to provide the (required) software control
+ * of the tranceiver for 3Com boards. The LLC0 flag disables
+ * the tranceiver if set.
+ */
+ if (sc->vendor == ZE_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_LLC0) {
+ outb(sc->asic_addr + ZE_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ZE_3COM_CR, ZE_3COM_CR_XSEL);
+ }
+ }
+#endif
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/*
+ * Macro to calculate a new address within shared memory when given an offset
+ * from an address, taking into account ring-wrap.
+ */
+#define ringoffset(sc, start, off, type) \
+ ((type)( ((caddr_t)(start)+(off) >= (sc)->smem_end) ? \
+ (((caddr_t)(start)+(off))) - (sc)->smem_end \
+ + (sc)->smem_ring: \
+ ((caddr_t)(start)+(off)) ))
+
+/*
+ * Retreive packet from shared memory and send to the next level up via
+ * ether_input(). If there is a BPF listener, give a copy to BPF, too.
+ */
+void
+ze_get_packet(sc, buf, len)
+ struct ze_softc *sc;
+ char *buf;
+ u_short len;
+{
+ struct ether_header *eh;
+ struct mbuf *m, *head = NULL, *ze_ring_to_mbuf();
+ u_short off;
+ int resid;
+ u_short etype;
+ struct trailer_header {
+ u_short trail_type;
+ u_short trail_residual;
+ } trailer_header;
+
+ /* Allocate a header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ goto bad;
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ m->m_pkthdr.len = len;
+ m->m_len = 0;
+ head = m;
+
+ eh = (struct ether_header *)buf;
+
+ /* The following sillines is to make NFS happy */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+
+ /*
+ * The following assumes there is room for
+ * the ether header in the header mbuf
+ */
+ head->m_data += EOFF;
+ bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
+ buf += sizeof(struct ether_header);
+ head->m_len += sizeof(struct ether_header);
+ len -= sizeof(struct ether_header);
+
+ etype = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Deal with trailer protocol:
+ * If trailer protocol, calculate the datasize as 'off',
+ * which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the
+ * trailer header.
+ * Finally, copy residual data into mbuf chain.
+ */
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+
+ off = (etype - ETHERTYPE_TRAIL) << 9;
+ if ((off + sizeof(struct trailer_header)) > len)
+ goto bad; /* insanity */
+
+ eh->ether_type = *ringoffset(sc, buf, off, u_short *);
+ resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+
+ if ((off + resid) > len) goto bad; /* insanity */
+
+ resid -= sizeof(struct trailer_header);
+ if (resid < 0) goto bad; /* insanity */
+
+ m = ze_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid);
+ if (m == NULL) goto bad;
+
+ len = off;
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
+ }
+
+ /*
+ * Pull packet off interface. Or if this was a trailer packet,
+ * the data portion is appended.
+ */
+ m = ze_ring_to_mbuf(sc, buf, m, len);
+ if (m == NULL) goto bad;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, head);
+
+ /*
+ * 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.
+ *
+ * XXX This test does not support multicasts.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+
+ m_freem(head);
+ return;
+ }
+ }
+#endif
+
+ /*
+ * Fix up data start offset in mbuf to point past ether header
+ */
+ m_adj(head, sizeof(struct ether_header));
+
+ /*
+ * silly ether_input routine needs 'type' in host byte order
+ */
+ eh->ether_type = ntohs(eh->ether_type);
+
+ ether_input(&sc->arpcom.ac_if, eh, head);
+ return;
+
+bad: if (head)
+ m_freem(head);
+ return;
+}
+
+/*
+ * Supporting routines
+ */
+
+/*
+ * Given a source and destination address, copy 'amount' of a packet from
+ * the ring buffer into a linear destination buffer. Takes into account
+ * ring-wrap.
+ */
+static inline char *
+ze_ring_copy(sc,src,dst,amount)
+ struct ze_softc *sc;
+ char *src;
+ char *dst;
+ u_short amount;
+{
+ u_short tmp_amount;
+
+ /* does copy wrap to lower addr in ring buffer? */
+ if (src + amount > sc->smem_end) {
+ tmp_amount = sc->smem_end - src;
+ bcopy(src,dst,tmp_amount); /* copy amount up to end of smem */
+ amount -= tmp_amount;
+ src = sc->smem_ring;
+ dst += tmp_amount;
+ }
+
+ bcopy(src, dst, amount);
+
+ return(src + amount);
+}
+
+/*
+ * Copy data from receive buffer to end of mbuf chain
+ * allocate additional mbufs as needed. return pointer
+ * to last mbuf in chain.
+ * sc = ze info (softc)
+ * src = pointer in ze ring buffer
+ * dst = pointer to last mbuf in mbuf chain to copy to
+ * amount = amount of data to copy
+ */
+struct mbuf *
+ze_ring_to_mbuf(sc,src,dst,total_len)
+ struct ze_softc *sc;
+ char *src;
+ struct mbuf *dst;
+ u_short total_len;
+{
+ register struct mbuf *m = dst;
+
+ while (total_len) {
+ register u_short amount = min(total_len, M_TRAILINGSPACE(m));
+
+ if (amount == 0) { /* no more data in this mbuf, alloc another */
+ /*
+ * If there is enough data for an mbuf cluster, attempt
+ * to allocate one of those, otherwise, a regular
+ * mbuf will do.
+ * Note that a regular mbuf is always required, even if
+ * we get a cluster - getting a cluster does not
+ * allocate any mbufs, and one is needed to assign
+ * the cluster to. The mbuf that has a cluster
+ * extension can not be used to contain data - only
+ * the cluster can contain data.
+ */
+ dst = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (0);
+
+ if (total_len >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+
+ m->m_len = 0;
+ dst->m_next = m;
+ amount = min(total_len, M_TRAILINGSPACE(m));
+ }
+
+ src = ze_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
+
+ m->m_len += amount;
+ total_len -= amount;
+
+ }
+ return (m);
+}
+#endif
+
diff --git a/sys/i386/isa/if_zereg.h b/sys/i386/isa/if_zereg.h
new file mode 100644
index 000000000000..3cd501f682cb
--- /dev/null
+++ b/sys/i386/isa/if_zereg.h
@@ -0,0 +1,859 @@
+/*
+ * National Semiconductor DS8390 NIC register definitions
+ *
+ * if_edreg.h,v
+ * Revision 1.1.2.1 1993/07/21 13:50:04 cgd
+ * from davidg:
+ * Added config file override for memory size and added flags to force
+ * 8bit or 16bit operation, and a flag to disable transmitter double buffering.
+ * See the updated "ed.relnotes" file for information about how to set
+ * the flags.
+ * This should be considered the first "production" release. It still
+ * needs a manual page, though.
+ *
+ * Revision 1.1 1993/07/03 12:21:07 cgd
+ * add support for David Greenman "ed" driver
+ *
+ * Revision 1.2 93/06/23 03:03:05 davidg
+ * added some additional definitions for the 83C584 bus interface
+ * chip (SMC/WD boards)
+ *
+ * Revision 1.1 93/06/23 03:01:07 davidg
+ * Initial revision
+ *
+ */
+
+/*
+ * Page 0 register offsets
+ */
+#define ZE_P0_CR 0x00 /* Command Register */
+
+#define ZE_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */
+#define ZE_P0_PSTART 0x01 /* Page Start register (write) */
+
+#define ZE_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */
+#define ZE_P0_PSTOP 0x02 /* Page Stop register (write) */
+
+#define ZE_P0_BNRY 0x03 /* Boundary Pointer */
+
+#define ZE_P0_TSR 0x04 /* Transmit Status Register (read) */
+#define ZE_P0_TPSR 0x04 /* Transmit Page Start (write) */
+
+#define ZE_P0_NCR 0x05 /* Number of Collisions Reg (read) */
+#define ZE_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */
+
+#define ZE_P0_FIFO 0x06 /* FIFO register (read) */
+#define ZE_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */
+
+#define ZE_P0_ISR 0x07 /* Interrupt Status Register */
+
+#define ZE_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */
+#define ZE_P0_RSAR0 0x08 /* Remote Start Address low (write) */
+
+#define ZE_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */
+#define ZE_P0_RSAR1 0x09 /* Remote Start Address high (write) */
+
+#define ZE_P0_RBCR0 0x0a /* Remote Byte Count low (write) */
+
+#define ZE_P0_RBCR1 0x0b /* Remote Byte Count high (write) */
+
+#define ZE_P0_RSR 0x0c /* Receive Status (read) */
+#define ZE_P0_RCR 0x0c /* Receive Configuration Reg (write) */
+
+#define ZE_P0_CNTR0 0x0d /* frame alignment error counter (read) */
+#define ZE_P0_TCR 0x0d /* Transmit Configuration Reg (write) */
+
+#define ZE_P0_CNTR1 0x0e /* CRC error counter (read) */
+#define ZE_P0_DCR 0x0e /* Data Configuration Reg (write) */
+
+#define ZE_P0_CNTR2 0x0f /* missed packet counter (read) */
+#define ZE_P0_IMR 0x0f /* Interrupt Mask Register (write) */
+
+/*
+ * Page 1 register offsets
+ */
+#define ZE_P1_CR 0x00 /* Command Register */
+#define ZE_P1_PAR0 0x01 /* Physical Address Register 0 */
+#define ZE_P1_PAR1 0x02 /* Physical Address Register 1 */
+#define ZE_P1_PAR2 0x03 /* Physical Address Register 2 */
+#define ZE_P1_PAR3 0x04 /* Physical Address Register 3 */
+#define ZE_P1_PAR4 0x05 /* Physical Address Register 4 */
+#define ZE_P1_PAR5 0x06 /* Physical Address Register 5 */
+#define ZE_P1_CURR 0x07 /* Current RX ring-buffer page */
+#define ZE_P1_MAR0 0x08 /* Multicast Address Register 0 */
+#define ZE_P1_MAR1 0x09 /* Multicast Address Register 1 */
+#define ZE_P1_MAR2 0x0a /* Multicast Address Register 2 */
+#define ZE_P1_MAR3 0x0b /* Multicast Address Register 3 */
+#define ZE_P1_MAR4 0x0c /* Multicast Address Register 4 */
+#define ZE_P1_MAR5 0x0d /* Multicast Address Register 5 */
+#define ZE_P1_MAR6 0x0e /* Multicast Address Register 6 */
+#define ZE_P1_MAR7 0x0f /* Multicast Address Register 7 */
+
+/*
+ * Page 2 register offsets
+ */
+#define ZE_P2_CR 0x00 /* Command Register */
+#define ZE_P2_PSTART 0x01 /* Page Start (read) */
+#define ZE_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */
+#define ZE_P2_PSTOP 0x02 /* Page Stop (read) */
+#define ZE_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */
+#define ZE_P2_RNPP 0x03 /* Remote Next Packet Pointer */
+#define ZE_P2_TPSR 0x04 /* Transmit Page Start (read) */
+#define ZE_P2_LNPP 0x05 /* Local Next Packet Pointer */
+#define ZE_P2_ACU 0x06 /* Address Counter Upper */
+#define ZE_P2_ACL 0x07 /* Address Counter Lower */
+#define ZE_P2_RCR 0x0c /* Receive Configuration Register (read) */
+#define ZE_P2_TCR 0x0d /* Transmit Configuration Register (read) */
+#define ZE_P2_DCR 0x0e /* Data Configuration Register (read) */
+#define ZE_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 ZE_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 ZE_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 ZE_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 ZE_CR_RD0 0x08
+#define ZE_CR_RD1 0x10
+#define ZE_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 ZE_CR_PS0 0x40
+#define ZE_CR_PS1 0x80
+/* bit encoded aliases */
+#define ZE_CR_PAGE_0 0x00 /* (for consistency) */
+#define ZE_CR_PAGE_1 0x40
+#define ZE_CR_PAGE_2 0x80
+
+/*
+ * Interrupt Status Register (ISR) definitions
+ */
+
+/*
+ * PRX: Packet Received. Indicates packet received with no errors.
+ */
+#define ZE_ISR_PRX 0x01
+
+/*
+ * PTX: Packet Transmitted. Indicates packet transmitted with no errors.
+ */
+#define ZE_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 ZE_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 ZE_ISR_TXE 0x08
+
+/*
+ * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network
+ * would exceed (has exceeded?) the boundry pointer, resulting in data
+ * that was previously received and not yet read from the buffer to be
+ * overwritten.
+ */
+#define ZE_ISR_OVW 0x10
+
+/*
+ * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley
+ * Counters has been set.
+ */
+#define ZE_ISR_CNT 0x20
+
+/*
+ * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed.
+ */
+#define ZE_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 ZE_ISR_RST 0x80
+
+/*
+ * Interrupt Mask Register (IMR) definitions
+ */
+
+/*
+ * PRXE: Packet Received interrupt Enable. If set, a received packet will cause
+ * an interrupt.
+ */
+#define ZE_IMR_PRXE 0x01
+
+/*
+ * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when
+ * a packet transmission completes.
+ */
+#define ZE_IMR_PTXE 0x02
+
+/*
+ * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a
+ * packet is received with an error.
+ */
+#define ZE_IMR_RXEE 0x04
+
+/*
+ * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever
+ * a transmission results in an error.
+ */
+#define ZE_IMR_TXEE 0x08
+
+/*
+ * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever
+ * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded.
+ */
+#define ZE_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 ZE_IMR_CNTE 0x20
+
+/*
+ * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated
+ * when a remote DMA transfer has completed.
+ */
+#define ZE_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 ZE_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 ZE_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 ZE_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 ZE_DCR_LS 0x08
+
+/*
+ * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer
+ * under program control. When 1, remote DMA is automatically initiated
+ * and the boundry pointer is automatically updated
+ */
+#define ZE_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 ZE_DCR_FT0 0x20
+#define ZE_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 ZE_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 ZE_TCR_LB0 0x02
+#define ZE_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 ZE_TCR_ATD 0x08
+
+/*
+ * OFST: Collision Offset enable. This bit when set modifies the backoff
+ * algorithm to allow prioritization of nodes.
+ */
+#define ZE_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 ZE_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 ZE_TSR_COL 0x04
+
+/*
+ * ABT: Transmit aborted. Indicates that the transmission was aborted due to
+ * excessive collisions.
+ */
+#define ZE_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 ZE_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 ZE_TSR_FU 0x20
+
+/*
+ * CDH: CD Heartbeat. Indicates that the collision detection circuitry
+ * isn't working correctly during a collision heartbeat test.
+ */
+#define ZE_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 ZE_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 ZE_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 ZE_RCR_AR 0x02
+
+/*
+ * AB: Accept Broadcast. If set, packets sent to the broadcast address will be
+ * accepted.
+ */
+#define ZE_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 ZE_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 ZE_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 ZE_RCR_MON 0x20
+
+/*
+ * bits 6 and 7 are unused/reserved.
+ */
+
+/*
+ * Receiver Status Register (RSR) definitions
+ */
+
+/*
+ * PRX: Packet Received without error.
+ */
+#define ZE_RSR_PRX 0x01
+
+/*
+ * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame
+ * alignment errors.
+ */
+#define ZE_RSR_CRC 0x02
+
+/*
+ * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on
+ * a byte boundry and the CRC did not match at the last byte boundry.
+ */
+#define ZE_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 ZE_RSR_FO 0x08
+
+/*
+ * MPA: Missed Packet. Indicates that the received packet couldn't be stored in
+ * the ring-buffer because of insufficient buffer space (exceeding the
+ * boundry pointer), or because the transfer to the ring-buffer was inhibited
+ * by RCR_MON - monitor mode.
+ */
+#define ZE_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 ZE_RSR_PHY 0x20
+
+/*
+ * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor
+ * mode. Cleared when the receiver exits monitor mode.
+ */
+#define ZE_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 ZE_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.
+ */
+struct ze_ring {
+ struct edr_status { /* received packet status */
+ u_char rs_prx:1, /* packet received intack */
+ rs_crc:1, /* crc error */
+ rs_fae:1, /* frame alignment error */
+ rs_fo:1, /* fifo overrun */
+ rs_mpa:1, /* packet received intack */
+ rs_phy:1, /* packet received intack */
+ rs_dis:1, /* packet received intack */
+ rs_dfr:1; /* packet received intack */
+ } ze_rcv_status; /* received packet status */
+ u_char next_packet; /* pointer to next packet */
+ u_short count; /* bytes in packet (length + 4) */
+};
+
+/*
+ * Common constants
+ */
+#define ZE_PAGE_SIZE 256 /* Size of RAM pages in bytes */
+#define ZE_TXBUF_SIZE 6 /* Size of TX buffer in pages */
+#define ZE_PAGE_OFFSET 0x40 /* mem buffer starts at 0x4000 */
+
+/*
+ * Vendor types
+ */
+#define ZE_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */
+#define ZE_VENDOR_3COM 0x01 /* 3Com */
+
+/*
+ * Compile-time config flags
+ */
+/*
+ * this sets the default for enabling/disablng the tranceiver
+ */
+#define ZE_FLAGS_DISABLE_TRANCEIVER 0x01
+
+/*
+ * This forces the board to be used in 8/16bit mode even if it
+ * autoconfigs differently
+ */
+#define ZE_FLAGS_FORCE_8BIT_MODE 0x02
+#define ZE_FLAGS_FORCE_16BIT_MODE 0x04
+
+/*
+ * This disables the use of double transmit buffers.
+ */
+#define ZE_FLAGS_NO_DOUBLE_BUFFERING 0x08
+
+/*
+ * definitions for IBM credit card adapter for ethernet
+ */
+
+#define ZE_DATA_IO 0x10
+#define ZE_MISC 0x18
+#define ZE_RESET 0x1F
+
+#if 0
+/*
+ * Definitions for Western digital/SMC WD80x3 series ASIC
+ */
+/*
+ * Memory Select Register (MSR)
+ */
+#define ZE_WD_MSR 0
+
+#define ZE_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */
+#define ZE_WD_MSR_MENB 0x40 /* Memory enable */
+#define ZE_WD_MSR_RST 0x80 /* Reset board */
+
+/*
+ * Interface Configuration Register (ICR)
+ */
+#define ZE_WD_ICR 1
+
+#define ZE_WD_ICR_16BIT 0x01 /* 16-bit interface */
+#define ZE_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */
+#define ZE_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */
+#define ZE_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */
+#define ZE_WD_ICR_RLA 0x10 /* recall LAN address */
+#define ZE_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */
+#define ZE_WD_ICR_RIO 0x40 /* recall i/o address */
+#define ZE_WD_ICR_STO 0x80 /* store to non-volatile memory */
+
+/*
+ * IO Address Register (IAR)
+ */
+#define ZE_WD_IAR 2
+
+/*
+ * EEROM Address Register
+ */
+#define ZE_WD_EAR 3
+
+/*
+ * Interrupt Request Register (IRR)
+ */
+#define ZE_WD_IRR 4
+
+#define ZE_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */
+#define ZE_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */
+#define ZE_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */
+#define ZE_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */
+#define ZE_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */
+
+/*
+ * The three bit of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 2/9
+ * 0 0 1 3
+ * 0 1 0 5
+ * 0 1 1 7
+ * 1 0 0 10
+ * 1 0 1 11
+ * 1 1 0 15
+ * 1 1 1 4
+ */
+#define ZE_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */
+#define ZE_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */
+#define ZE_WD_IRR_IEN 0x80 /* Interrupt enable */
+
+/*
+ * LA Address Register (LAAR)
+ */
+#define ZE_WD_LAAR 5
+
+#define ZE_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */
+#define ZE_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */
+#define ZE_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */
+#define ZE_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */
+
+/* i/o base offset to station address/card-ID PROM */
+#define ZE_WD_PROM 8
+
+/* i/o base offset to CARD ID */
+#define ZE_WD_CARD_ID ZE_WD_PROM+6
+
+#define ZE_TYPE_WD8003S 0x02
+#define ZE_TYPE_WD8003E 0x03
+#define ZE_TYPE_WD8013EBT 0x05
+#define ZE_TYPE_WD8013EB 0x27
+#define ZE_TYPE_WD8013EBP 0x2c
+#define ZE_TYPE_WD8013EPC 0x29
+
+/* Bit definitions in card ID */
+#define ZE_WD_REV_MASK 0x1f /* Revision mask */
+#define ZE_WD_SOFTCONFIG 0x20 /* Soft config */
+#define ZE_WD_LARGERAM 0x40 /* Large RAM */
+#define ZE_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */
+
+/*
+ * Checksum total. All 8 bytes in station address PROM will add up to this
+ */
+#define ZE_WD_ROM_CHECKSUM_TOTAL 0xFF
+
+#define ZE_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */
+#define ZE_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */
+#define ZE_WD_IO_PORTS 32 /* # of i/o addresses used */
+
+#define ZE_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */
+
+/*
+ * Definitions for 3Com 3c503
+ */
+#define ZE_3COM_NIC_OFFSET 0
+#define ZE_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */
+
+/*
+ * XXX - The I/O address range is fragmented in the 3c503; this is the
+ * number of regs at iobase.
+ */
+#define ZE_3COM_IO_PORTS 16 /* # of i/o addresses used */
+
+#define ZE_3COM_PAGE_OFFSET 0x20 /* memory starts in second bank */
+
+/*
+ * Page Start Register. Must match PSTART in NIC
+ */
+#define ZE_3COM_PSTR 0
+
+/*
+ * Page Stop Register. Must match PSTOP in NIC
+ */
+#define ZE_3COM_PSPR 1
+
+/*
+ * Drq Timer Register. Determines number of bytes to be transfered during
+ * a DMA burst.
+ */
+#define ZE_3COM_DQTR 2
+
+/*
+ * Base Configuration Register. Read-only register which contains the
+ * board-configured I/O base address of the adapter. Bit encoded.
+ */
+#define ZE_3COM_BCFR 3
+
+#define ZE_3COM_BCFR_2E0 0x01
+#define ZE_3COM_BCFR_2A0 0x02
+#define ZE_3COM_BCFR_280 0x04
+#define ZE_3COM_BCFR_250 0x08
+#define ZE_3COM_BCFR_350 0x10
+#define ZE_3COM_BCFR_330 0x20
+#define ZE_3COM_BCFR_310 0x40
+#define ZE_3COM_BCFR_300 0x80
+
+/*
+ * EPROM Configuration Register. Read-only register which contains the
+ * board-configured memory base address. Bit encoded.
+ */
+#define ZE_3COM_PCFR 4
+
+#define ZE_3COM_PCFR_C8000 0x10
+#define ZE_3COM_PCFR_CC000 0x20
+#define ZE_3COM_PCFR_D8000 0x40
+#define ZE_3COM_PCFR_DC000 0x80
+
+/*
+ * GA Configuration Register. Gate-Array Configuration Register.
+ */
+#define ZE_3COM_GACFR 5
+
+/*
+ * mbs2 mbs1 mbs0 start address
+ * 0 0 0 0x0000
+ * 0 0 1 0x2000
+ * 0 1 0 0x4000
+ * 0 1 1 0x6000
+ *
+ * Note that with adapters with only 8K, the setting for 0x2000 must
+ * always be used.
+ */
+#define ZE_3COM_GACFR_MBS0 0x01
+#define ZE_3COM_GACFR_MBS1 0x02
+#define ZE_3COM_GACFR_MBS2 0x04
+
+#define ZE_3COM_GACFR_RSEL 0x08 /* enable shared memory */
+#define ZE_3COM_GACFR_TEST 0x10 /* for GA testing */
+#define ZE_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */
+#define ZE_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */
+#define ZE_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */
+
+/*
+ * Control Register. Miscellaneous control functions.
+ */
+#define ZE_3COM_CR 6
+
+#define ZE_3COM_CR_RST 0x01 /* Reset GA and NIC */
+#define ZE_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */
+#define ZE_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */
+#define ZE_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */
+#define ZE_3COM_CR_SHARE 0x10 /* select interrupt sharing option */
+#define ZE_3COM_CR_DBSEL 0x20 /* Double buffer select */
+#define ZE_3COM_CR_DDIR 0x40 /* DMA direction select */
+#define ZE_3COM_CR_START 0x80 /* Start DMA controller */
+
+/*
+ * Status Register. Miscellaneous status information.
+ */
+#define ZE_3COM_STREG 7
+
+#define ZE_3COM_STREG_REV 0x07 /* GA revision */
+#define ZE_3COM_STREG_DIP 0x08 /* DMA in progress */
+#define ZE_3COM_STREG_DTC 0x10 /* DMA terminal count */
+#define ZE_3COM_STREG_OFLW 0x20 /* Overflow */
+#define ZE_3COM_STREG_UFLW 0x40 /* Underflow */
+#define ZE_3COM_STREG_DPRDY 0x80 /* Data port ready */
+
+/*
+ * Interrupt/DMA Configuration Register
+ */
+#define ZE_3COM_IDCFR 8
+
+#define ZE_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */
+#define ZE_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */
+#define ZE_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */
+#define ZE_3COM_IDCFR_UNUSED 0x08 /* not used */
+#define ZE_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */
+#define ZE_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */
+#define ZE_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */
+#define ZE_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */
+
+/*
+ * DMA Address Register MSB
+ */
+#define ZE_3COM_DAMSB 9
+
+/*
+ * DMA Address Register LSB
+ */
+#define ZE_3COM_DALSB 0x0a
+
+/*
+ * Vector Pointer Register 2
+ */
+#define ZE_3COM_VPTR2 0x0b
+
+/*
+ * Vector Pointer Register 1
+ */
+#define ZE_3COM_VPTR1 0x0c
+
+/*
+ * Vector Pointer Register 0
+ */
+#define ZE_3COM_VPTR0 0x0d
+
+/*
+ * Register File Access MSB
+ */
+#define ZE_3COM_RFMSB 0x0e
+
+/*
+ * Register File Access LSB
+ */
+#define ZE_3COM_RFLSB 0x0f
+#endif
diff --git a/sys/i386/isa/ipl.h b/sys/i386/isa/ipl.h
new file mode 100644
index 000000000000..248ca5666d67
--- /dev/null
+++ b/sys/i386/isa/ipl.h
@@ -0,0 +1,7 @@
+#ifndef _ISA_IPL_H_
+#define _ISA_IPL_H_
+
+#define NHWI 16 /* number of h/w interrupts */
+#define HWI_MASK 0xffff /* bits corresponding to h/w interrupts */
+
+#endif /* _ISA_IPL_H_ */
diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c
index 3dbc748d9d55..588be2cccc7f 100644
--- a/sys/i386/isa/isa.c
+++ b/sys/i386/isa/isa.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
- * $Id: isa.c,v 1.14 1994/01/22 21:52:04 rgrimes Exp $
+ * $Id: isa.c,v 1.19 1994/06/22 05:52:39 jkh Exp $
*/
/*
@@ -124,9 +124,11 @@ haveseen(dvp, tmpdvp)
if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
(dvp->id_iobase <=
(tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
+#ifndef ALLOW_CONFLICT_IOADDR
conflict(dvp, tmpdvp, dvp->id_iobase,
"I/O address", "0x%x");
status = 1;
+#endif
}
}
/*
@@ -143,12 +145,14 @@ haveseen(dvp, tmpdvp)
if((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
(KERNBASE + dvp->id_maddr <=
(tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
+#ifndef ALLOW_CONFLICT_MEMADDR
conflict(dvp, tmpdvp, dvp->id_maddr, "maddr",
"0x%x");
status = 1;
+#endif
}
}
-#ifndef COM_MULTIPORT
+#ifndef ALLOW_CONFLICT_IRQ
/*
* Check for IRQ conflicts.
*/
@@ -160,6 +164,7 @@ haveseen(dvp, tmpdvp)
}
}
#endif
+#ifndef ALLOW_CONFLICT_DRQ
/*
* Check for DRQ conflicts.
*/
@@ -170,6 +175,7 @@ haveseen(dvp, tmpdvp)
status = 1;
}
}
+#endif
}
return (status);
}
@@ -213,38 +219,45 @@ isa_configure() {
printf("Probing for devices on the ISA bus:\n");
for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
- config_isadev(dvp,&ttymask);
+ config_isadev(dvp,&tty_imask);
}
for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
- config_isadev(dvp,&biomask);
+ config_isadev(dvp,&bio_imask);
}
for (dvp = isa_devtab_net; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
- config_isadev(dvp,&netmask);
+ config_isadev(dvp,&net_imask);
}
for (dvp = isa_devtab_null; dvp->id_driver; dvp++) {
if (!haveseen_isadev(dvp))
config_isadev(dvp,(u_int *) NULL);
}
+ bio_imask |= SWI_CLOCK_MASK;
+ net_imask |= SWI_NET_MASK;
+ tty_imask |= SWI_TTY_MASK;
+
/*
- * XXX We should really add the tty device to netmask when the line is
+ * XXX we should really add the tty device to net_imask when the line is
* switched to SLIPDISC, and then remove it when it is switched away from
- * SLIPDISC. No need to block out ALL ttys during a splnet when only one
+ * SLIPDISC. No need to block out ALL ttys during a splimp when only one
* of them is running slip.
+ *
+ * XXX actually, blocking all ttys during a splimp doesn't matter so much
+ * with sio because the serial interrupt layer doesn't use tty_imask. Only
+ * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked
+ * during spltty.
*/
#include "sl.h"
#if NSL > 0
- netmask |= ttymask;
- ttymask |= netmask;
+ net_imask |= tty_imask;
+ tty_imask = net_imask;
+#endif
+ /* bio_imask |= tty_imask ; can some tty devices use buffers? */
+#ifdef DIAGNOSTIC
+ printf("bio_imask %x tty_imask %x net_imask %x\n",
+ bio_imask, tty_imask, net_imask);
#endif
- /* if netmask == 0, then the loopback code can do some really
- * bad things.
- */
- if (netmask == 0)
- netmask = 0x10000;
- /* biomask |= ttymask ; can some tty devices use buffers? */
- printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask);
splnone();
}
@@ -337,15 +350,12 @@ extern inthand_t
IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
-static inthand_func_t defvec[16] = {
+static inthand_func_t defvec[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
-/* out of range default interrupt vector gate entry */
-extern inthand_t IDTVEC(intrdefault);
-
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
@@ -356,12 +366,8 @@ isa_defaultirq()
int i;
/* icu vectors */
- for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
- setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
-
- /* out of range vectors */
- for (i = NRSVIDT; i < NIDT; i++)
- setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
+ for (i = 0; i < ICU_LEN; i++)
+ setidt(ICU_OFFSET + i, defvec[i], SDT_SYS386IGT, SEL_KPL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
@@ -530,7 +536,7 @@ isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
#define ISARAM_END RAM_END
if (phys == 0)
panic("isa_dmacheck: no physical page present");
- if (phys > ISARAM_END)
+ if (phys >= ISARAM_END)
return (1);
if (priorpage) {
if (priorpage + NBPG != phys)
@@ -588,14 +594,18 @@ isa_freephysmem(caddr_t va, unsigned length) {
/*
* Handle a NMI, possibly a machine check.
+ * This is generally one of two things, either an memory parity error
+ * or a bus master timeout failure. A bus-master timeout is indicated
+ * by bit 4 of port 0x461 going high.
+ *
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
-
- log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
+ log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x, port 461 %x\n",
+ inb(0x61), inb(0x70), inb(0x461));
return(0);
}
@@ -627,165 +637,6 @@ isa_strayintr(d)
}
/*
- * Wait "n" microseconds.
- * Relies on timer 1 counting down from (TIMER_FREQ / hz) at
- * (1 * TIMER_FREQ) Hz.
- * Note: timer had better have been programmed before this is first used!
- * (The standard programming causes the timer to generate a square wave and
- * the counter is decremented twice every cycle.)
- */
-#define CF (1 * TIMER_FREQ)
-#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */
-
-void
-DELAY(n)
- int n;
-{
- int counter_limit;
- int prev_tick;
- int tick;
- int ticks_left;
- int sec;
- int usec;
-
-#ifdef DELAYDEBUG
- int getit_calls = 1;
- int n1;
- static int state = 0;
-
- if (state == 0) {
- state = 1;
- for (n1 = 1; n1 <= 10000000; n1 *= 10)
- DELAY(n1);
- state = 2;
- }
- if (state == 1)
- printf("DELAY(%d)...", n);
-#endif
-
- /*
- * Read the counter first, so that the rest of the setup overhead is
- * counted. Guess the initial overhead is 20 usec (on most systems it
- * takes about 1.5 usec for each of the i/o's in getit(). The loop
- * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
- * multiplications and divisions to scale the count take a while).
- */
- prev_tick = getit(0, 0);
- n -= 20;
-
- /*
- * Calculate (n * (CF / 1e6)) without using floating point and without
- * any avoidable overflows.
- */
- sec = n / 1000000;
- usec = n - sec * 1000000;
- ticks_left = sec * CF
- + usec * (CF / 1000000)
- + usec * ((CF % 1000000) / 1000) / 1000
- + usec * (CF % 1000) / 1000000;
-
- counter_limit = TIMER_FREQ / hz;
- while (ticks_left > 0) {
- tick = getit(0, 0);
-#ifdef DELAYDEBUG
- ++getit_calls;
-#endif
- if (tick > prev_tick)
- ticks_left -= prev_tick - (tick - counter_limit);
- else
- ticks_left -= prev_tick - tick;
- prev_tick = tick;
- }
-#ifdef DELAYDEBUG
- if (state == 1)
- printf(" %d calls to getit() at %d usec each\n",
- getit_calls, (n + 5) / getit_calls);
-#endif
-}
-
-int
-getit(unit, timer)
- int unit;
- int timer;
-{
- int high;
- int low;
-
- /*
- * XXX - isa.h defines bogus timers. There's no such timer as
- * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but
- * its interface is quite different. Neither timer is an 8252.
- * We actually only call this with unit = 0 and timer = 0. It
- * could be static...
- */
- /*
- * Protect ourself against interrupts.
- * XXX - sysbeep() and sysbeepstop() need protection.
- */
- disable_intr();
- /*
- * Latch the count for 'timer' (cc00xxxx, c = counter, x = any).
- */
- outb(IO_TIMER1 + 3, timer << 6);
-
- low = inb(IO_TIMER1 + timer);
- high = inb(IO_TIMER1 + timer);
- enable_intr();
- return ((high << 8) | low);
-}
-
-static int beeping;
-
-static void
-sysbeepstop(f, dummy)
- caddr_t f;
- int dummy;
-{
- /* disable counter 2 */
- outb(0x61, inb(0x61) & 0xFC);
- if (f)
- timeout(sysbeepstop, (caddr_t)0, (int)f);
- else
- beeping = 0;
-}
-
-void
-sysbeep(int pitch, int period)
-{
-
- outb(0x61, inb(0x61) | 3); /* enable counter 2 */
- /*
- * XXX - move timer stuff to clock.c.
- * Program counter 2:
- * ccaammmb, c counter, a = access, m = mode, b = BCD
- * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave.
- */
- outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
-
- outb(0x42, pitch);
- outb(0x42, (pitch>>8));
-
- if (!beeping) {
- beeping = period;
- timeout(sysbeepstop, (caddr_t)(period/2), period);
- }
-}
-
-/*
- * Pass command to keyboard controller (8042)
- */
-unsigned
-kbc_8042cmd(val)
- int val;
-{
-
- while (inb(KBSTATP)&KBS_IBF);
- if (val) outb(KBCMDP, val);
- while (inb(KBSTATP)&KBS_IBF);
- return (inb(KBDATAP));
-}
-
-/*
* find an ISA device in a given isa_devtab_* table, given
* the table to search, the expected id_driver entry, and the unit number.
*
diff --git a/sys/i386/isa/isa.h b/sys/i386/isa/isa.h
index cb083fdcf4cb..32786e6008c1 100644
--- a/sys/i386/isa/isa.h
+++ b/sys/i386/isa/isa.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.h 5.7 (Berkeley) 5/9/91
- * $Id: isa.h,v 1.4 1994/01/05 15:03:28 rgrimes Exp $
+ * $Id: isa.h,v 1.5 1994/04/21 14:20:54 sos Exp $
*/
#ifndef _I386_ISA_ISA_H_
@@ -47,12 +47,8 @@
#ifndef LOCORE
#include <sys/cdefs.h>
-unsigned char rtcin __P((int));
extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
-void sysbeep __P((int, int));
-unsigned kbd_8042cmd __P((int));
-struct isa_device;
-int isa_irq_pending __P((struct isa_device *dvp));
+unsigned char rtcin __P((int));
#endif
@@ -69,6 +65,7 @@ int isa_irq_pending __P((struct isa_device *dvp));
#define IO_TIMER1 0x040 /* 8253 Timer #1 */
#define IO_TIMER2 0x048 /* 8253 Timer #2 */
#define IO_KBD 0x060 /* 8042 Keyboard */
+#define IO_PPI 0x061 /* Programmabel Peripheral Interface */
#define IO_RTC 0x070 /* RTC */
#define IO_NMI IO_RTC /* NMI Control */
#define IO_DMAPG 0x080 /* DMA Page Registers */
diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h
index 6299f89912a4..670dacf4dfa6 100644
--- a/sys/i386/isa/isa_device.h
+++ b/sys/i386/isa/isa_device.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
- * $Id: isa_device.h,v 1.5 1994/01/04 20:06:30 nate Exp $
+ * $Id: isa_device.h,v 1.7 1994/06/08 14:01:04 davidg Exp $
*/
#ifndef _I386_ISA_ISA_DEVICE_H_
@@ -46,7 +46,7 @@
*/
struct isa_device {
struct isa_driver *id_driver;
- short id_iobase; /* base i/o address */
+ int id_iobase; /* base i/o address */
u_short id_irq; /* interrupt request */
short id_drq; /* DMA request */
caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
diff --git a/sys/i386/isa/kbdtables.h b/sys/i386/isa/kbdtables.h
index 011bc2cd1879..1fbd3215f367 100644
--- a/sys/i386/isa/kbdtables.h
+++ b/sys/i386/isa/kbdtables.h
@@ -14,7 +14,7 @@
* DK9210 Aalborg SO Phone: +45 9814 8076
*
* @(#)kbdtables.h 1.3 940123
- * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ * $Id: kbdtables.h,v 1.13 1994/05/27 01:09:16 ache Exp $
*/
#define SET8 0x80 /* eight bit for emacs SET8-key */
@@ -374,17 +374,17 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
-/* sc=03 */ '2', '"', NOP, NOP, NOP, '@', NOP, NOP, 0x3B, 0x00,
-/* sc=04 */ '3', 0xA3, NOP, NOP, NOP, '#', NOP, NOP, 0x3B, 0x00,
-/* sc=05 */ '4', '$', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
-/* sc=07 */ '6', '&', 0x1E, NOP, NOP, '^', 0x1E, NOP, 0x19, 0x00,
-/* sc=08 */ '7', '/', NOP, NOP, NOP, '&', NOP, NOP, 0x3B, 0x00,
-/* sc=09 */ '8', '(', NOP, NOP, NOP, '*', NOP, NOP, 0x3B, 0x00,
-/* sc=0a */ '9', ')', NOP, NOP, NOP, '(', NOP, NOP, 0x3B, 0x00,
-/* sc=0b */ '0', '=', NOP, NOP, NOP, ')', NOP, NOP, 0x3B, 0x00,
-/* sc=0c */ '+', '?', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
-/* sc=0d */ 0xB4, '`', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
@@ -397,8 +397,8 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
-/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '[', '{', 0x1B, NOP, 0x31, 0x01,
-/* sc=1b */ 0xA8, '^', NOP, NOP, ']', '}', 0x1D, NOP, 0x31, 0x00,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
@@ -410,11 +410,11 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
-/* sc=27 */ 0xF8, 0xD8, NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x01,
-/* sc=28 */ 0xE6, 0xC6, NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x01,
-/* sc=29 */ '<', '>', NOP, NOP, '\\', '|', 0x1C, NOP, 0x31, 0x00,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
-/* sc=2b */ '\'', '*', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
@@ -457,7 +457,7 @@ keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
-/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
@@ -569,7 +569,7 @@ keymap_t key_map = { 0xe9, /* keys number */
/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
-/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, RBT, 0x83, 0x02,
/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
@@ -698,7 +698,7 @@ keymap_t key_map = { 0xe9, /* keys number */
/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
-/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, RBT, 0x83, 0x02,
/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
diff --git a/sys/i386/isa/lpa.c b/sys/i386/isa/lpa.c
index 89434cbf3da7..8d4aa3f7470f 100644
--- a/sys/i386/isa/lpa.c
+++ b/sys/i386/isa/lpa.c
@@ -45,7 +45,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: lpa.c,v 1.5 1994/02/22 09:04:08 rgrimes Exp $
+ * $Id: lpa.c,v 1.6 1994/04/11 07:57:36 csgr Exp $
*/
/*
@@ -178,6 +178,18 @@ lpaprobe(struct isa_device *dvp)
u_char data;
u_char mask;
int i;
+ static int warned = 0;
+
+
+ /* Warn users that the lpa driver should no longer be used */
+ if(!warned) {
+ printf("*************************************************\n");
+ printf("WARNING: The lpa driver is now obsolete, and will\n");
+ printf("WARNING: be removed soon.\n");
+ printf("WARNING: Please change your config to use lpt\n");
+ printf("*************************************************\n");
+ warned = 1;
+ }
status = IO_LPTSIZE;
diff --git a/sys/i386/isa/lpt.c b/sys/i386/isa/lpt.c
index 42f92c74f8d0..2715ea8b193f 100644
--- a/sys/i386/isa/lpt.c
+++ b/sys/i386/isa/lpt.c
@@ -46,7 +46,7 @@
* SUCH DAMAGE.
*
* from: unknown origin, 386BSD 0.1
- * $Id: lpt.c,v 1.9 1994/02/22 09:05:13 rgrimes Exp $
+ * $Id: lpt.c,v 1.13 1994/06/08 14:34:54 davidg Exp $
*/
/*
@@ -66,11 +66,14 @@
#include "ioctl.h"
#include "tty.h"
#include "uio.h"
+#include "syslog.h"
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/lptreg.h"
+#include "i386/include/lpt.h"
+
#define LPINITRDY 4 /* wait up to 4 seconds for a ready */
#define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
#define LPPRI (PZERO+8)
@@ -90,15 +93,6 @@
int lptflag = 1;
#endif
-void lptout();
-
-int lptprobe(), lptattach();
-void lptintr();
-
-struct isa_driver lptdriver = {
- lptprobe, lptattach, "lpt"
-};
-
#define LPTUNIT(s) ((s)&0x03)
#define LPTFLAGS(s) ((s)&0xfc)
@@ -122,6 +116,8 @@ struct lpt_softc {
u_char sc_irq ; /* IRQ status of port */
#define LP_HAS_IRQ 0x01 /* we have an irq available */
#define LP_USE_IRQ 0x02 /* we are using our irq */
+#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */
+
} lpt_sc[NLPT] ;
/* bits for state */
@@ -149,12 +145,21 @@ struct lpt_softc {
#define MAX_SPIN 20 /* Max delay for device ready in usecs */
+static void lptout (struct lpt_softc * sc);
+int lptprobe (struct isa_device *dvp);
+int lptattach (struct isa_device *isdp);
+void lptintr (int unit);
+
+struct isa_driver lptdriver = {
+ lptprobe, lptattach, "lpt"
+};
+
/*
* Internal routine to lptprobe to do port tests of one byte value
*/
-int
+static int
lpt_port_test(short port, u_char data, u_char mask)
{
int temp, timeout;
@@ -279,8 +284,7 @@ end_probe:
/* XXX Todo - try and detect if interrupt is working */
int
-lptattach(isdp)
- struct isa_device *isdp;
+lptattach(struct isa_device *isdp)
{
struct lpt_softc *sc;
@@ -292,7 +296,7 @@ lptattach(isdp)
/* check if we can use interrupt */
lprintf("oldirq %x\n", sc->sc_irq);
if(isdp->id_irq) {
- sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ;
+ sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
printf("lpt%d: Interrupt-driven port\n", isdp->id_unit);
} else {
sc->sc_irq = 0;
@@ -308,9 +312,7 @@ lptattach(isdp)
*/
int
-lptopen(dev, flag)
- dev_t dev;
- int flag;
+lptopen(dev_t dev, int flag)
{
struct lpt_softc *sc;
int s;
@@ -321,7 +323,6 @@ lptopen(dev, flag)
if ((unit >= NLPT) || (sc->sc_port == 0))
return (ENXIO);
- /* Only check open bit */
if (sc->sc_state) {
lprintf("lp: still open\n") ;
lprintf("still open %x\n", sc->sc_state);
@@ -333,6 +334,13 @@ lptopen(dev, flag)
lprintf("lp flags 0x%x\n", sc->sc_flags);
port = sc->sc_port;
+ /* set IRQ status according to ENABLE_IRQ flag */
+ if(sc->sc_irq & LP_ENABLE_IRQ)
+ sc->sc_irq |= LP_USE_IRQ;
+ else
+ sc->sc_irq &= ~LP_USE_IRQ;
+
+
/* init printer */
if((sc->sc_flags & LP_NO_PRIME) == 0) {
if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
@@ -384,20 +392,19 @@ lptopen(dev, flag)
lprintf("irq %x\n", sc->sc_irq);
if(sc->sc_irq & LP_USE_IRQ) {
sc->sc_state |= TOUT;
- timeout (lptout, (caddr_t)sc, hz/2);
+ timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
}
lprintf("opened.\n");
return(0);
}
-void
-lptout (sc)
- struct lpt_softc *sc;
+static void
+lptout (struct lpt_softc * sc)
{ int pl;
lprintf ("T %x ", inb(sc->sc_port+lpt_status));
if (sc->sc_state&OPEN)
- timeout (lptout, (caddr_t)sc, hz/2);
+ timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
else sc->sc_state &= ~TOUT;
if (sc->sc_state & ERROR)
@@ -423,9 +430,7 @@ lptout (sc)
*/
int
-lptclose(dev, flag)
- dev_t dev;
- int flag;
+lptclose(dev_t dev, int flag)
{
struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
int port = sc->sc_port;
@@ -458,13 +463,13 @@ lptclose(dev, flag)
* This code is only used when we are polling the port
*/
static int
-pushbytes(sc)
- struct lpt_softc *sc;
+pushbytes(struct lpt_softc * sc)
{
int spin, err, tic;
char ch;
int port = sc->sc_port;
+ lprintf("p");
/* loop for every character .. */
while (sc->sc_xfercnt > 0) {
/* printer data */
@@ -518,9 +523,7 @@ pushbytes(sc)
*/
int
-lptwrite(dev, uio)
- dev_t dev;
- struct uio *uio;
+lptwrite(dev_t dev, struct uio * uio)
{
register unsigned n;
int pl, err;
@@ -531,26 +534,26 @@ lptwrite(dev, uio)
sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
uiomove(sc->sc_cp, n, uio);
sc->sc_xfercnt = n ;
- if(sc->sc_irq & LP_USE_IRQ)
- while (sc->sc_xfercnt > 0) {
- lprintf("i");
- /* if the printer is ready for a char, */
- /* give it one */
- if ((sc->sc_state & OBUSY) == 0){
- lprintf("\nC %d. ", sc->sc_xfercnt);
- pl = spltty();
- lptintr(sc - lpt_sc);
- (void) splx(pl);
- }
- lprintf("W ");
- if (sc->sc_state & OBUSY)
- if (err = tsleep ((caddr_t)sc,
- LPPRI|PCATCH, "lpwrite", 0)) {
- sc->sc_state |= INTERRUPTED;
- return(err);
- }
+ while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
+ lprintf("i");
+ /* if the printer is ready for a char, */
+ /* give it one */
+ if ((sc->sc_state & OBUSY) == 0){
+ lprintf("\nC %d. ", sc->sc_xfercnt);
+ pl = spltty();
+ lptintr(sc - lpt_sc);
+ (void) splx(pl);
}
- else { /* polled write */
+ lprintf("W ");
+ if (sc->sc_state & OBUSY)
+ if (err = tsleep ((caddr_t)sc,
+ LPPRI|PCATCH, "lpwrite", 0)) {
+ sc->sc_state |= INTERRUPTED;
+ return(err);
+ }
+ }
+ /* check to see if we must do a polled write */
+ if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
lprintf("p");
if((err = pushbytes(sc)))
return(err);
@@ -567,8 +570,7 @@ lptwrite(dev, uio)
*/
void
-lptintr(unit)
- int unit;
+lptintr(int unit)
{
struct lpt_softc *sc = lpt_sc + unit;
int port = sc->sc_port, sts;
@@ -607,22 +609,40 @@ lptintr(unit)
}
int
-lptioctl(dev, cmd, data, flag)
- dev_t dev;
- int cmd;
- caddr_t data;
- int flag;
+lptioctl(dev_t dev, int cmd, caddr_t data, int flag)
{
- int error;
+ int error = 0;
+ struct lpt_softc *sc;
+ u_int unit = LPTUNIT(minor(dev));
+ u_char old_sc_irq; /* old printer IRQ status */
+
+ sc = lpt_sc + unit;
- error = 0;
switch (cmd) {
-#ifdef THISISASAMPLE
- case XXX:
- dothis; andthis; andthat;
- error=x;
- break;
-#endif /* THISISASAMPLE */
+ case LPT_IRQ :
+ if(sc->sc_irq & LP_HAS_IRQ) {
+ /*
+ * NOTE:
+ * If the IRQ status is changed,
+ * this will only be visible on the
+ * next open.
+ *
+ * If interrupt status changes,
+ * this gets syslog'd.
+ */
+ old_sc_irq = sc->sc_irq;
+ if(*(int*)data == 0)
+ sc->sc_irq &= (~LP_ENABLE_IRQ);
+ else
+ sc->sc_irq |= LP_ENABLE_IRQ;
+ if (old_sc_irq != sc->sc_irq )
+ log(LOG_NOTICE, "lpt%c switched to %s mode\n",
+ (char)unit+'0',
+ (sc->sc_irq & LP_ENABLE_IRQ)?
+ "interrupt-driven":"polled");
+ } else /* polled port */
+ error = EOPNOTSUPP;
+ break;
default:
error = ENODEV;
}
diff --git a/sys/i386/isa/mcd.c b/sys/i386/isa/mcd.c
index 190d42be3b75..3245dadc4097 100644
--- a/sys/i386/isa/mcd.c
+++ b/sys/i386/isa/mcd.c
@@ -39,7 +39,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: mcd.c,v 1.10.2.2 1994/03/23 23:51:39 rgrimes Exp $
+ * $Id: mcd.c,v 1.16 1994/04/30 17:03:33 gclarkii Exp $
*/
static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
@@ -350,6 +350,9 @@ MCD_TRACE("strategy: drive not valid\n",0,0,0,0);
if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) {
goto done;
}
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
}
/* queue it */
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index 2979e0cfd7ab..e83a503feeed 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -32,7 +32,7 @@
* SUCH DAMAGE.
*
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91
- * $Id: npx.c,v 1.6 1994/01/03 07:55:43 davidg Exp $
+ * $Id: npx.c,v 1.9 1994/06/11 02:36:32 davidg Exp $
*/
#include "npx.h"
@@ -114,7 +114,7 @@ struct isa_driver npxdriver = {
npxprobe, npxattach, "npx",
};
-u_int npx0mask;
+u_int npx0_imask = SWI_CLOCK_MASK;
struct proc *npxproc;
static bool_t npx_ex16;
@@ -292,7 +292,7 @@ npxprobe1(dvp)
* Bad, we are stuck with IRQ13.
*/
npx_irq13 = 1;
- npx0mask = dvp->id_irq; /* npxattach too late */
+ npx0_imask = dvp->id_irq; /* npxattach too late */
return (IO_NPXSIZE);
}
/*
@@ -321,10 +321,12 @@ npxattach(dvp)
struct isa_device *dvp;
{
if (!npx_ex16 && !npx_irq13) {
- if (npx_exists)
+ if (npx_exists) {
printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
- else
+ npx_exists = 0;
+ } else {
printf("npx%d: 387 Emulator\n",dvp->id_unit);
+ }
}
npxinit(__INITIAL_NPXCW__);
return (1); /* XXX unused */
@@ -528,8 +530,8 @@ npxsave(addr)
old_icu1_mask = inb(IO_ICU1 + 1);
old_icu2_mask = inb(IO_ICU2 + 1);
save_idt_npxintr = idt[npx_intrno];
- outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask));
- outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8));
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
idt[npx_intrno] = npx_idt_probeintr;
enable_intr();
stop_emulating();
@@ -541,10 +543,10 @@ npxsave(addr)
icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
icu2_mask = inb(IO_ICU2 + 1);
outb(IO_ICU1 + 1,
- (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask));
+ (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
outb(IO_ICU2 + 1,
- (icu2_mask & ~(npx0mask >> 8))
- | (old_icu2_mask & (npx0mask >> 8)));
+ (icu2_mask & ~(npx0_imask >> 8))
+ | (old_icu2_mask & (npx0_imask >> 8)));
idt[npx_intrno] = save_idt_npxintr;
enable_intr(); /* back to usual state */
}
diff --git a/sys/i386/isa/pcaudio.c b/sys/i386/isa/pcaudio.c
new file mode 100644
index 000000000000..0c48e407a7be
--- /dev/null
+++ b/sys/i386/isa/pcaudio.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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 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.
+ *
+ * $Id: pcaudio.c,v 1.5 1994/05/27 08:51:03 sos Exp $
+ */
+
+#include "systm.h"
+#include "uio.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "file.h"
+#include "sound/ulaw.h"
+#include "machine/cpufunc.h"
+#include "machine/pio.h"
+#include "machine/pcaudioio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+
+#include "pca.h"
+#if NPCA > 0
+
+#define BUF_SIZE 4*8192
+#define SAMPLE_RATE 8000
+#define INTERRUPT_RATE 16000
+
+static struct pca_status {
+ char open; /* device open */
+ char queries; /* did others try opening */
+ unsigned char *buf[2]; /* double buffering */
+ unsigned char *buffer; /* current buffer ptr */
+ unsigned in_use[2]; /* buffers fill */
+ unsigned index; /* index in current buffer */
+ unsigned counter; /* sample counter */
+ unsigned scale; /* sample counter scale */
+ unsigned sample_rate; /* sample rate */
+ unsigned processed; /* samples processed */
+ unsigned volume; /* volume for pc-speaker */
+ char encoding; /* Ulaw, Alaw or linear */
+ char current; /* current buffer */
+ unsigned char oldval; /* old timer port value */
+ char timer_on; /* is playback running */
+ char coll; /* select collision */
+ pid_t wsel; /* pid of select'ing proc */
+} pca_status;
+
+static char buffer1[BUF_SIZE];
+static char buffer2[BUF_SIZE];
+static char volume_table[256];
+
+static int pca_sleep = 0;
+static int pca_initialized = 0;
+
+void pcaintr(int regs);
+int pcaprobe(struct isa_device *dvp);
+int pcaattach(struct isa_device *dvp);
+int pcaclose(dev_t dev, int flag);
+int pcaopen(dev_t dev, int flag);
+int pcawrite(dev_t dev, struct uio *uio, int flag);
+int pcaioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+int pcaselect(dev_t dev, int rw, struct proc *p);
+
+struct isa_driver pcadriver = {
+ pcaprobe, pcaattach, "pca",
+};
+
+
+inline void conv(const void *table, void *buff, unsigned long n)
+{
+ __asm__("1:\tmovb (%2), %3\n"
+ "\txlatb\n"
+ "\tmovb %3, (%2)\n"
+ "\tinc %2\n"
+ "\tdec %1\n"
+ "\tjnz 1b\n"
+ :
+ :"b" ((long)table), "c" (n), "D" ((long)buff), "a" ((char)n)
+ :"bx","cx","di","ax");
+}
+
+
+static void
+pca_volume(int volume)
+{
+ int i, j;
+
+ for (i=0; i<256; i++) {
+ j = ((i-128)*volume)/100;
+ if (j<-128)
+ j = -128;
+ if (j>127)
+ j = 127;
+ volume_table[i] = (((255-(j + 128))/4)+1);
+ }
+}
+
+
+static void
+pca_init()
+{
+ pca_status.open = 0;
+ pca_status.queries = 0;
+ pca_status.timer_on = 0;
+ pca_status.buf[0] = (unsigned char *)&buffer1[0];
+ pca_status.buf[1] = (unsigned char *)&buffer2[0];
+ pca_status.buffer = pca_status.buf[0];
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.current = 0;
+ pca_status.sample_rate = SAMPLE_RATE;
+ pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
+ pca_status.encoding = AUDIO_ENCODING_ULAW;
+ pca_status.volume = 100;
+
+ pca_volume(pca_status.volume);
+}
+
+
+static int
+pca_start(void)
+{
+ /* use the first buffer */
+ pca_status.current = 0;
+ pca_status.index = 0;
+ pca_status.counter = 0;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ pca_status.oldval = inb(IO_PPI) | 0x03;
+ /* acquire the timers */
+ if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT)) {
+ return -1;
+ }
+ if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
+ release_timer2();
+ return -1;
+ }
+ pca_status.timer_on = 1;
+ return 0;
+}
+
+
+static void
+pca_stop(void)
+{
+ /* release the timers */
+ release_timer0();
+ release_timer2();
+ /* reset the buffer */
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.index = 0;
+ pca_status.counter = 0;
+ pca_status.current = 0;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ pca_status.timer_on = 0;
+}
+
+
+static void
+pca_pause()
+{
+ release_timer0();
+ release_timer2();
+ pca_status.timer_on = 0;
+}
+
+
+static void
+pca_continue()
+{
+ pca_status.oldval = inb(IO_PPI) | 0x03;
+ acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
+ acquire_timer0(INTERRUPT_RATE, pcaintr);
+ pca_status.timer_on = 1;
+}
+
+
+static void
+pca_wait(void)
+{
+ while (pca_status.in_use[0] || pca_status.in_use[1]) {
+ pca_sleep = 1;
+ tsleep((caddr_t)&pca_sleep, PZERO|PCATCH, "pca_drain", 0);
+ }
+}
+
+
+int
+pcaprobe(struct isa_device *dvp)
+{
+ return(-1);
+}
+
+
+int
+pcaattach(struct isa_device *dvp)
+{
+ printf(" PCM audio driver\n", dvp->id_unit);
+ pca_init();
+ return 1;
+}
+
+
+int
+pcaopen(dev_t dev, int flag)
+{
+ /* audioctl device can always be opened */
+ if (minor(dev) == 128)
+ return 0;
+ if (minor(dev) > 0)
+ return ENXIO;
+
+ if (!pca_initialized) {
+ pca_init();
+ pca_initialized = 1;
+ }
+
+ /* audio device can only be open by one process */
+ if (pca_status.open) {
+ pca_status.queries = 1;
+ return EBUSY;
+ }
+ pca_status.buffer = pca_status.buf[0];
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.timer_on = 0;
+ pca_status.open = 1;
+ pca_status.processed = 0;
+ return 0;
+}
+
+
+int
+pcaclose(dev_t dev, int flag)
+{
+ /* audioctl device can always be closed */
+ if (minor(dev) == 128)
+ return 0;
+ if (minor(dev) > 0)
+ return ENXIO;
+ /* audio device close drains all output and restores timers */
+ pca_wait();
+ pca_stop();
+ pca_status.open = 0;
+ return 0;
+}
+
+
+int
+pcawrite(dev_t dev, struct uio *uio, int flag)
+{
+ int count, which;
+
+ /* only audio device can be written */
+ if (minor(dev) > 0)
+ return ENXIO;
+
+ while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
+ if (pca_status.in_use[0] && pca_status.in_use[1]) {
+ pca_sleep = 1;
+ tsleep((caddr_t)&pca_sleep, PZERO|PCATCH, "pca_wait",0);
+ }
+ which = pca_status.in_use[0] ? 1 : 0;
+ if (count && !pca_status.in_use[which]) {
+ uiomove(pca_status.buf[which], count, uio);
+ pca_status.processed += count;
+ switch (pca_status.encoding) {
+ case AUDIO_ENCODING_ULAW:
+ conv(ulaw_dsp, pca_status.buf[which], count);
+ break;
+
+ case AUDIO_ENCODING_ALAW:
+ break;
+
+ case AUDIO_ENCODING_RAW:
+ break;
+ }
+ pca_status.in_use[which] = count;
+ if (!pca_status.timer_on)
+ if (pca_start())
+ return EBUSY;
+ }
+ }
+ return 0;
+}
+
+
+int
+pcaioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ audio_info_t *auptr;
+
+ switch(cmd) {
+
+ case AUDIO_GETINFO:
+ auptr = (audio_info_t *)data;
+ auptr->play.sample_rate = pca_status.sample_rate;
+ auptr->play.channels = 1;
+ auptr->play.precision = 8;
+ auptr->play.encoding = pca_status.encoding;
+
+ auptr->play.gain = pca_status.volume;
+ auptr->play.port = 0;
+
+ auptr->play.samples = pca_status.processed;
+ auptr->play.eof = 0;
+ auptr->play.pause = !pca_status.timer_on;
+ auptr->play.error = 0;
+ auptr->play.waiting = pca_status.queries;
+
+ auptr->play.open = pca_status.open;
+ auptr->play.active = pca_status.timer_on;
+ return 0;
+
+ case AUDIO_SETINFO:
+ auptr = (audio_info_t *)data;
+ if (auptr->play.sample_rate != (unsigned int)~0) {
+ pca_status.sample_rate = auptr->play.sample_rate;
+ pca_status.scale =
+ (pca_status.sample_rate << 8) / INTERRUPT_RATE;
+ }
+ if (auptr->play.encoding != (unsigned int)~0) {
+ pca_status.encoding = auptr->play.encoding;
+ }
+ if (auptr->play.gain != (unsigned int)~0) {
+ pca_status.volume = auptr->play.gain;
+ pca_volume(pca_status.volume);
+ }
+ if (auptr->play.pause != (unsigned char)~0) {
+ if (auptr->play.pause)
+ pca_pause();
+ else
+ pca_continue();
+ }
+
+ return 0;
+
+ case AUDIO_DRAIN:
+ pca_wait();
+ return 0;
+
+ case AUDIO_FLUSH:
+ pca_stop();
+ return 0;
+
+ }
+ return ENXIO;
+}
+
+
+void
+pcaintr(int regs)
+{
+ if (pca_status.index < pca_status.in_use[pca_status.current]) {
+ disable_intr();
+ __asm__("outb %0,$0x61\n"
+ "andb $0xFE,%0\n"
+ "outb %0,$0x61"
+ : : "a" ((char)pca_status.oldval) );
+ __asm__("xlatb\n"
+ "outb %0,$0x42"
+ : : "a" ((char)pca_status.buffer[pca_status.index]),
+ "b" ((long)volume_table) );
+ enable_intr();
+ pca_status.counter += pca_status.scale;
+ pca_status.index = (pca_status.counter >> 8);
+ }
+ if (pca_status.index >= pca_status.in_use[pca_status.current]) {
+ pca_status.index = pca_status.counter = 0;
+ pca_status.in_use[pca_status.current] = 0;
+ pca_status.current ^= 1;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ if (pca_sleep) {
+ wakeup((caddr_t)&pca_sleep);
+ pca_sleep = 0;
+ }
+ if (pca_status.wsel) {
+ selwakeup(pca_status.wsel, pca_status.coll);
+ pca_status.wsel = 0;
+ pca_status.coll = 0;
+ }
+ }
+}
+
+
+int
+pcaselect(dev_t dev, int rw, struct proc *p)
+{
+ int s = spltty();
+ struct proc *p1;
+
+ switch (rw) {
+
+ case FWRITE:
+ if (!pca_status.in_use[0] || !pca_status.in_use[1]) {
+ splx(s);
+ return(1);
+ }
+ if (pca_status.wsel && (p1 = pfind(pca_status.wsel))
+ && p1->p_wchan == (caddr_t)&selwait)
+ pca_status.coll = 1;
+ else
+ pca_status.wsel = p->p_pid;
+ splx(s);
+ return 0;
+ default:
+ splx(s);
+ return(0);
+ }
+}
+#endif
diff --git a/sys/i386/isa/pccons.c b/sys/i386/isa/pccons.c
index 43fba38b1552..3d729da6dc54 100644
--- a/sys/i386/isa/pccons.c
+++ b/sys/i386/isa/pccons.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)pccons.c 5.11 (Berkeley) 5/21/91
- * $Id: pccons.c,v 1.13.2.1 1994/05/04 05:09:30 rgrimes Exp $
+ * $Id: pccons.c,v 1.17 1994/05/30 03:15:09 ache Exp $
*/
/*
@@ -63,7 +63,7 @@
int pc_xmode;
#endif /* XSERVER */
-struct tty pccons;
+struct tty *pccons;
struct pcconsoftc {
char cs_flags;
@@ -289,13 +289,12 @@ pcopen(dev, flag, mode, p)
if (minor(dev) != 0)
return (ENXIO);
- tp = &pccons;
+ tp = pccons = ttymalloc(pccons);
tp->t_oproc = pcstart;
tp->t_param = pcparam;
tp->t_dev = dev;
openf++;
if ((tp->t_state & TS_ISOPEN) == 0) {
- tp->t_state |= TS_WOPEN;
ttychars(tp);
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
@@ -316,8 +315,12 @@ pcclose(dev, flag, mode, p)
int flag, mode;
struct proc *p;
{
- (*linesw[pccons.t_line].l_close)(&pccons, flag);
- ttyclose(&pccons);
+ (*linesw[pccons->t_line].l_close)(pccons, flag);
+ ttyclose(pccons);
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ ttyfree(pccons);
+ pccons = (struct tty *)NULL;
+#endif
return(0);
}
@@ -328,7 +331,7 @@ pcread(dev, uio, flag)
struct uio *uio;
int flag;
{
- return ((*linesw[pccons.t_line].l_read)(&pccons, uio, flag));
+ return ((*linesw[pccons->t_line].l_read)(pccons, uio, flag));
}
/*ARGSUSED*/
@@ -338,7 +341,7 @@ pcwrite(dev, uio, flag)
struct uio *uio;
int flag;
{
- return ((*linesw[pccons.t_line].l_write)(&pccons, uio, flag));
+ return ((*linesw[pccons->t_line].l_write)(pccons, uio, flag));
}
/*
@@ -347,10 +350,8 @@ pcwrite(dev, uio, flag)
* Catch the character, and see who it goes to.
*/
void
-pcrint(dev, irq, cpl)
- dev_t dev;
- int irq; /* XXX ??? */
- int cpl;
+pcrint(unit)
+ int unit;
{
int c;
char *cp;
@@ -361,7 +362,7 @@ pcrint(dev, irq, cpl)
if (pcconsoftc.cs_flags & CSF_POLLING)
return;
#ifdef KDB
- if (kdbrintr(c, &pccons))
+ if (kdbrintr(c, pccons))
return;
#endif
if (!openf)
@@ -369,11 +370,11 @@ pcrint(dev, irq, cpl)
#ifdef XSERVER /* 15 Aug 92*/
/* send at least one character, because cntl-space is a null */
- (*linesw[pccons.t_line].l_rint)(*cp++ & 0xff, &pccons);
+ (*linesw[pccons->t_line].l_rint)(*cp++ & 0xff, pccons);
#endif /* XSERVER */
while (*cp)
- (*linesw[pccons.t_line].l_rint)(*cp++ & 0xff, &pccons);
+ (*linesw[pccons->t_line].l_rint)(*cp++ & 0xff, pccons);
}
#ifdef XSERVER /* 15 Aug 92*/
@@ -389,7 +390,7 @@ pcioctl(dev, cmd, data, flag)
caddr_t data;
int flag;
{
- register struct tty *tp = &pccons;
+ register struct tty *tp = pccons;
register error;
#ifdef XSERVER /* 15 Aug 92*/
@@ -436,12 +437,12 @@ pcxint(dev)
if (!pcconsintr)
return;
- pccons.t_state &= ~TS_BUSY;
+ pccons->t_state &= ~TS_BUSY;
pcconsoftc.cs_timo = 0;
- if (pccons.t_line)
- (*linesw[pccons.t_line].l_start)(&pccons);
+ if (pccons->t_line)
+ (*linesw[pccons->t_line].l_start)(pccons);
else
- pcstart(&pccons);
+ pcstart(pccons);
}
void
@@ -454,20 +455,11 @@ pcstart(tp)
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
goto out;
do {
- if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_out);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
- }
- if (RB_LEN(&tp->t_out) == 0)
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
+ if (RB_LEN(tp->t_out) == 0)
goto out;
- c = getc(&tp->t_out);
+ c = getc(tp->t_out);
tp->t_state |= TS_BUSY; /* 21 Aug 92*/
splx(s);
sput(c, 0);
@@ -491,7 +483,7 @@ pccnprobe(cp)
/* initialize required fields */
cp->cn_dev = makedev(maj, 0);
- cp->cn_tp = &pccons;
+ cp->cn_tp = pccons;
cp->cn_pri = CN_INTERNAL;
}
@@ -639,26 +631,13 @@ static u_char shift_down, ctrl_down, alt_down, caps, num, scroll;
/* translate ANSI color codes to standard pc ones */
static char fgansitopc[] =
{ FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
- FG_MAGENTA, FG_CYAN, FG_LIGHTGREY};
+ FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
+};
static char bgansitopc[] =
{ BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
- BG_MAGENTA, BG_CYAN, BG_LIGHTGREY};
-
-static void move_up(u_short *s, u_short *d, u_int len)
-{
- s += len;
- d += len;
- while (len-- > 0)
- *--d = *--s;
-}
-
-
-static void move_down(u_short *s, u_short *d, u_int len)
-{
- while (len-- > 0)
- *d++ = *s++;
-}
+ BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
+};
/*
* sput has support for emulation of the 'pc3' termcap entry.
@@ -872,7 +851,7 @@ sput(c, ka)
posy = (crtat - Crtat) / vs.ncol;
if (vs.cx > posy)
vs.cx = posy;
- bcopy(Crtat+vs.ncol*vs.cx, Crtat, vs.ncol*(vs.nrow-vs.cx)*CHR);
+ bcopyw(Crtat+vs.ncol*vs.cx, Crtat, vs.ncol*(vs.nrow-vs.cx)*CHR);
fillw((at <<8)+' ',
(Crtat + vs.ncol * (vs.nrow - vs.cx)),
vs.ncol * vs.cx);
@@ -884,7 +863,7 @@ sput(c, ka)
posy = (crtat - Crtat) / vs.ncol;
if (vs.cx > vs.nrow - posy)
vs.cx = vs.nrow - posy;
- bcopy(Crtat, Crtat+vs.ncol*vs.cx, vs.ncol*(vs.nrow-vs.cx)*CHR);
+ bcopyw(Crtat, Crtat+vs.ncol*vs.cx, vs.ncol*(vs.nrow-vs.cx)*CHR);
fillw((at <<8)+' ', Crtat, vs.ncol*vs.cx);
/* crtat += vs.ncol*vs.cx;*/ /* XXX */
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
@@ -897,7 +876,7 @@ sput(c, ka)
src = Crtat + posy * vs.ncol;
dst = src + vs.cx * vs.ncol;
count = vs.nrow - (posy + vs.cx);
- move_up(src, dst, count * vs.ncol);
+ bcopyw(src, dst, count * vs.ncol * CHR);
fillw((at <<8)+' ', src, vs.cx * vs.ncol);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
@@ -909,7 +888,7 @@ sput(c, ka)
dst = Crtat + posy * vs.ncol;
src = dst + vs.cx * vs.ncol;
count = vs.nrow - (posy + vs.cx);
- move_down(src, dst, count * vs.ncol);
+ bcopyw(src, dst, count * vs.ncol * CHR);
src = dst + count * vs.ncol;
fillw((at <<8)+' ', src, vs.cx * vs.ncol);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
@@ -999,7 +978,7 @@ sput(c, ka)
}
if (sc && crtat >= Crtat+vs.ncol*vs.nrow) { /* scroll check */
if (openf) do (void)sgetc(1); while (scroll);
- bcopy(Crtat+vs.ncol, Crtat, vs.ncol*(vs.nrow-1)*CHR);
+ bcopyw(Crtat+vs.ncol, Crtat, vs.ncol*(vs.nrow-1)*CHR);
fillw ((at << 8) + ' ', Crtat + vs.ncol*(vs.nrow-1),
vs.ncol);
crtat -= vs.ncol;
@@ -1557,6 +1536,12 @@ loop:
#endif /* !XSERVER*/
}
+ /*
+ * Check for cntl-alt-del
+ */
+ if ((dt == 83) && ctrl_down && alt_down)
+ cpu_reset();
+
#include "ddb.h"
#if NDDB > 0
/*
@@ -1564,7 +1549,7 @@ loop:
*/
if ((dt == 1) && ctrl_down && alt_down) {
Debugger("manual escape to debugger");
- dt |= 0x80; /* discard esc (ddb discarded ctrl-alt) */
+ goto loop;
}
#endif
@@ -1797,7 +1782,7 @@ void cons_normal()
int pcmmap(dev_t dev, int offset, int nprot)
{
- if (offset > 0x20000)
+ if (offset > 0x20000 - PAGE_SIZE)
return -1;
return i386_btop((0xa0000 + offset));
}
diff --git a/sys/i386/isa/psm.c b/sys/i386/isa/psm.c
new file mode 100644
index 000000000000..d12298727ca3
--- /dev/null
+++ b/sys/i386/isa/psm.c
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * Ported to 386bsd Oct 17, 1992
+ * Sandi Donno, Computer Science, University of Cape Town, South Africa
+ * Please send bug reports to sandi@cs.uct.ac.za
+ *
+ * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
+ * although I was only partially successful in getting the alpha release
+ * of his "driver for the Logitech and ATI Inport Bus mice for use with
+ * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
+ * found his code to be an invaluable reference when porting this driver
+ * to 386bsd.
+ *
+ * Further modifications for latest 386BSD+patchkit and port to NetBSD,
+ * Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
+ *
+ * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
+ * Andrew Herbert - 12 June 1993
+ *
+ * Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
+ * - 13 June 1993
+ *
+ * Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
+ * - 24 October 1993
+ */
+
+#include "psm.h"
+
+#if NPSM > 0
+
+#include "param.h"
+#include "kernel.h"
+#include "systm.h"
+#include "buf.h"
+#include "malloc.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "file.h"
+#include "proc.h"
+#include "vnode.h"
+
+#include "i386/include/mouse.h"
+#include "i386/include/pio.h" /* Julian's fast IO macros */
+#include "i386/isa/isa_device.h"
+
+#ifdef 0
+#include "syslog.h" /* For debugging */
+#endif
+
+#define DATA 0 /* Offset for data port, read-write */
+#define CNTRL 4 /* Offset for control port, write-only */
+#define STATUS 4 /* Offset for status port, read-only */
+
+/* status bits */
+#define PSM_OUTPUT_ACK 0x02 /* output acknowledge */
+
+/* controller commands */
+#define PSM_ENABLE 0xa8 /* enable auxiliary port */
+#define PSM_DISABLE 0xa7 /* disable auxiliary port */
+#define PSM_INT_ENABLE 0x47 /* enable controller interrupts */
+#define PSM_INT_DISABLE 0x65 /* disable controller interrupts */
+
+/* m+use commands */
+#define PSM_SET_SCALE11 0xe6 /* set 1:1 scaling */
+#define PSM_SET_SCALE21 0xe7 /* set 2:1 scaling */
+#define PSM_SET_RES 0xe8 /* set resolution */
+#define PSM_GET_SCALE 0xe9 /* set scaling factor */
+#define PSM_SET_STREAM 0xea /* set streaming mode */
+#define PSM_SET_SAMPLE 0xf3 /* set sampling rate */
+#define PSM_DEV_ENABLE 0xf4 /* mouse on */
+#define PSM_DEV_DISABLE 0xf5 /* mouse off */
+#define PSM_RESET 0xff /* reset */
+
+#define PSMUNIT(dev) (minor(dev) >> 1)
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif min
+
+int psmprobe (struct isa_device *);
+int psmattach (struct isa_device *);
+void psm_poll_status(void);
+
+static int psmaddr[NPSM]; /* Base I/O port addresses per unit */
+
+#define MSBSZ 1024 /* Output queue size (pwr of 2 is best) */
+
+struct ringbuf {
+ int count, first, last;
+ char queue[MSBSZ];
+};
+
+static struct psm_softc { /* Driver status information */
+ struct ringbuf inq; /* Input queue */
+ pid_t rsel; /* Process selecting for Input */
+ unsigned char state; /* Mouse driver state */
+ unsigned char status; /* Mouse button status */
+ unsigned char button; /* Previous mouse button status bits */
+ int x, y; /* accumulated motion in the X,Y axis */
+} psm_softc[NPSM];
+
+#define OPEN 1 /* Device is open */
+#define ASLP 2 /* Waiting for mouse data */
+
+struct isa_driver psmdriver = { psmprobe, psmattach, "psm" };
+
+#define AUX_PORT 0x60 /* AUX_PORT base (S.Yuen) */
+
+static void psm_write_dev(int inport, u_char value)
+{
+ psm_poll_status();
+ outb(inport+CNTRL, 0xd4);
+ psm_poll_status();
+ outb(inport+DATA,value);
+}
+
+static inline void psm_command(int ioport, u_char value)
+{
+ psm_poll_status();
+ outb(ioport+CNTRL, 0x60);
+ psm_poll_status();
+ outb(ioport+DATA, value);
+}
+
+int psmprobe(struct isa_device *dvp)
+{
+ /* XXX: Needs a real probe routine. */
+
+ int ioport,c,unit;
+
+ ioport=dvp->id_iobase;
+ unit=dvp->id_unit;
+ psm_write_dev(ioport,0xff); /* Reset aux device */
+ psm_poll_status();
+ outb(ioport+CNTRL,0xa9);
+ psm_poll_status();
+ outb(ioport+CNTRL,0xaa);
+ c = inb(ioport+DATA);
+ if(c&0x04) {
+/* printf("PS/2 AUX mouse is not found\n");*/
+ psm_command(ioport,0x65);
+ psmaddr[unit] = 0; /* Device not found */
+ return(0);}
+/* printf("PS/2 AUX mouse found. Installing driver\n");*/
+ return (4);
+}
+
+int psmattach(struct isa_device *dvp)
+{
+ int unit = dvp->id_unit;
+ int ioport = dvp->id_iobase;
+ struct psm_softc *sc = &psm_softc[unit];
+
+ /* Save I/O base address */
+
+ psmaddr[unit] = ioport;
+
+ /* Disable mouse interrupts */
+
+ psm_poll_status();
+ outb(ioport+CNTRL, PSM_ENABLE);
+#ifdef 0
+ psm_write(ioport, PSM_SET_RES);
+ psm_write(ioport, 0x03); /* 8 counts/mm */
+ psm_write(ioport, PSM_SET_SCALE);
+ psm_write(ioport, 0x02); /* 2:1 */
+ psm_write(ioport, PSM_SET_SCALE21);
+ psm_write(ioport, PSM_SET_SAMPLE);
+ psm_write(ioport, 0x64); /* 100 samples/sec */
+ psm_write(ioport, PSM_SET_STREAM);
+#endif
+ psm_poll_status();
+ outb(ioport+CNTRL, PSM_DISABLE);
+ psm_command(ioport, PSM_INT_DISABLE);
+
+ /* Setup initial state */
+
+ sc->state = 0;
+
+ /* Done */
+
+ return(0);
+}
+
+int psmopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = PSMUNIT(dev);
+ struct psm_softc *sc;
+ int ioport;
+
+ /* Validate unit number */
+
+ if (unit >= NPSM)
+ return(ENXIO);
+
+ /* Get device data */
+
+ sc = &psm_softc[unit];
+ ioport = psmaddr[unit];
+
+ /* If device does not exist */
+
+ if (ioport == 0)
+ return(ENXIO);
+
+ /* Disallow multiple opens */
+ if (sc->state & OPEN)
+ return(EBUSY);
+
+ /* Initialize state */
+
+ sc->state |= OPEN;
+ sc->rsel = 0;
+ sc->status = 0;
+ sc->button = 0;
+ sc->x = 0;
+ sc->y = 0;
+
+ /* Allocate and initialize a ring buffer */
+
+ sc->inq.count = sc->inq.first = sc->inq.last = 0;
+
+ /* Enable Bus Mouse interrupts */
+
+ psm_write_dev(ioport, PSM_DEV_ENABLE);
+ psm_poll_status();
+ outb(ioport+CNTRL, PSM_ENABLE);
+ psm_command(ioport, PSM_INT_ENABLE);
+
+ /* Successful open */
+
+ return(0);
+}
+
+void psm_poll_status(void)
+{
+
+ while(inb(AUX_PORT+STATUS)&0x03) {
+ if(inb(AUX_PORT+STATUS) & 0x2 == 0x2)
+ inb(AUX_PORT+DATA);}
+ return;
+}
+
+
+int psmclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit, ioport;
+ struct psm_softc *sc;
+
+ /* Get unit and associated info */
+
+ unit = PSMUNIT(dev);
+ sc = &psm_softc[unit];
+ ioport = psmaddr[unit];
+
+ /* Disable further mouse interrupts */
+
+ psm_command(ioport,PSM_INT_DISABLE);
+ psm_poll_status();
+ outb(ioport+CNTRL,PSM_DISABLE );
+
+ /* Complete the close */
+
+ sc->state &= ~OPEN;
+
+ /* close is almost always successful */
+
+ return(0);
+}
+
+int psmread(dev_t dev, struct uio *uio, int flag)
+{
+ int s;
+ int error = 0; /* keep compiler quiet, even though initialisation
+ is unnecessary */
+ unsigned length;
+ struct psm_softc *sc;
+ unsigned char buffer[100];
+
+ /* Get device information */
+
+ sc = &psm_softc[PSMUNIT(dev)];
+
+ /* Block until mouse activity occured */
+
+ s = spltty();
+ while (sc->inq.count == 0) {
+ if (minor(dev) & 0x1) {
+ splx(s);
+ return(EWOULDBLOCK);
+ }
+ sc->state |= ASLP;
+ error = tsleep((caddr_t)sc, PZERO | PCATCH, "psmrea", 0);
+ if (error != 0) {
+ splx(s);
+ return(error);
+ }
+ }
+
+ /* Transfer as many chunks as possible */
+
+ while (sc->inq.count > 0 && uio->uio_resid > 0) {
+ length = min(sc->inq.count, uio->uio_resid);
+ if (length > sizeof(buffer))
+ length = sizeof(buffer);
+
+ /* Remove a small chunk from input queue */
+
+ if (sc->inq.first + length >= MSBSZ) {
+ bcopy(&sc->inq.queue[sc->inq.first],
+ buffer, MSBSZ - sc->inq.first);
+ bcopy(sc->inq.queue, &buffer[MSBSZ-sc->inq.first],
+ length - (MSBSZ - sc->inq.first));
+ }
+ else
+ bcopy(&sc->inq.queue[sc->inq.first], buffer, length);
+
+ sc->inq.first = (sc->inq.first + length) % MSBSZ;
+ sc->inq.count -= length;
+
+ /* Copy data to user process */
+
+ error = uiomove(buffer, length, uio);
+ if (error)
+ break;
+ }
+
+ sc->x = sc->y = 0;
+
+ /* Allow interrupts again */
+
+ splx(s);
+ return(error);
+}
+
+int psmioctl(dev_t dev, caddr_t addr, int cmd, int flag, struct proc *p)
+{
+ struct psm_softc *sc;
+ struct mouseinfo info;
+ int s, error;
+
+ /* Get device information */
+
+ sc = &psm_softc[PSMUNIT(dev)];
+
+ /* Perform IOCTL command */
+
+ switch (cmd) {
+
+ case MOUSEIOCREAD:
+
+ /* Don't modify info while calculating */
+
+ s = spltty();
+
+ /* Build mouse status octet */
+
+ info.status = sc->status;
+ if (sc->x || sc->y)
+ info.status |= MOVEMENT;
+
+ /* Encode X and Y motion as good as we can */
+
+ if (sc->x > 127)
+ info.xmotion = 127;
+ else if (sc->x < -128)
+ info.xmotion = -128;
+ else
+ info.xmotion = sc->x;
+
+ if (sc->y > 127)
+ info.ymotion = 127;
+ else if (sc->y < -128)
+ info.ymotion = -128;
+ else
+ info.ymotion = sc->y;
+
+ /* Reset historical information */
+
+ sc->x = 0;
+ sc->y = 0;
+ sc->status &= ~BUTCHNGMASK;
+
+ /* Allow interrupts and copy result buffer */
+
+ splx(s);
+ error = copyout(&info, addr, sizeof(struct mouseinfo));
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ /* Return error code */
+
+ return(error);
+}
+
+void psmintr(unit)
+ int unit;
+{
+ struct psm_softc *sc = &psm_softc[unit];
+ int ioport = psmaddr[unit];
+
+ sc->inq.queue[sc->inq.last++ % MSBSZ] = inb(ioport+DATA);
+ sc->inq.count++;
+ if (sc -> state & ASLP) {
+ sc->state &= ~ASLP;
+ wakeup((caddr_t)sc);
+ }
+ if (sc->rsel) {
+ selwakeup(sc->rsel, 0);
+ sc->rsel = 0;
+ }
+}
+
+int psmselect(dev_t dev, int rw, struct proc *p)
+{
+ int s, ret;
+ struct psm_softc *sc = &psm_softc[PSMUNIT(dev)];
+
+ /* Silly to select for output */
+
+ if (rw == FWRITE)
+ return(0);
+
+ /* Return true if a mouse event available */
+
+ s = spltty();
+ if (sc->inq.count)
+ ret = 1;
+ else {
+ sc->rsel = p->p_pid;
+ ret = 0;
+ }
+ splx(s);
+
+ return(ret);
+}
+#endif
+
+
diff --git a/sys/i386/isa/seagate.c b/sys/i386/isa/seagate.c
new file mode 100644
index 000000000000..31c515166663
--- /dev/null
+++ b/sys/i386/isa/seagate.c
@@ -0,0 +1,2036 @@
+/*
+ * (Free/Net/386)BSD ST01/02, Future Domain TMC-885, TMC-950 SCSI driver for
+ * Julians SCSI-code
+ *
+ * Copyright 1994, Kent Palmkvist (kentp@isy.liu.se)
+ * Copyright 1994, Robert Knier (rknier@qgraph.com)
+ * Copyright 1992, 1994 Drew Eckhardt (drew@colorado.edu)
+ * Copyright 1994, Julian Elischer (julian@tfs.com)
+ *
+ * Others that has contributed by example code is
+ * Glen Overby (overby@cray.com)
+ * Tatu Yllnen
+ * Brian E Litzinger
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+/*
+ *
+ * kentp 940307 alpha version based on newscsi-03 version of Julians SCSI-code
+ * kentp 940314 Added possibility to not use messages
+ * rknier 940331 Added fast transfer code
+ * rknier 940407 Added assembler coded data transfers
+ *
+ * $Id: seagate.c,v 1.3 1994/06/16 13:26:14 sean Exp $
+ */
+
+/*
+ * What should really be done:
+ *
+ * Add missing tests for timeouts
+ * Restructure interrupt enable/disable code (runs to long with int disabled)
+ * Find bug? giving problem with tape status
+ * Add code to handle Future Domain 840, 841, 880 and 881
+ * adjust timeouts (startup is very slow)
+ * add code to use tagged commands in SCSI2
+ * Add code to handle slow devices better (sleep if device not disconnecting)
+ * Fix unnecessary interrupts
+ */
+
+/* Note to users trying to share a disk between DOS and unix:
+ * The ST01/02 is a translating host-adapter. It is not giving DOS
+ * the same number of heads/tracks/sectors as specified by the disk.
+ * It is therefore important to look at what numbers DOS thinks the
+ * disk has. Use these to disklabel your disk in an appropriate manner
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh.. look for main() */
+#include <sea.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <i386/isa/isa_device.h>
+#endif /* KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include "ddb.h"
+#include "kernel.h"
+#else /* KERNEL */
+#define NSEA 1
+#endif /* KERNEL */
+
+extern int hz;
+
+#define SEA_SCB_MAX 8 /* allow maximally 8 scsi control blocks */
+#define SCB_TABLE_SIZE 8 /* start with 8 scb entries in table */
+#define BLOCK_SIZE 512 /* size of READ/WRITE areas on SCSI card */
+
+/*
+ * defining PARITY causes parity data to be checked
+ */
+#define PARITY 1
+
+/*
+ * defining SEA_BLINDTRANSFER will make DATA IN and DATA OUT to be done with
+ * blind transfers, i.e. no check is done for scsi phase changes. This will
+ * result in data loss if the scsi device does not send its data using
+ * BLOCK_SIZE bytes at a time.
+ * If SEA_BLINDTRANSFER defined and SEA_ASSEMBLER also defined will result in
+ * the use of blind transfers coded in assembler. SEA_ASSEMBLER is no good
+ * without SEA_BLINDTRANSFER defined.
+ */
+#define SEA_BLINDTRANSFER 1 /* do blind transfers */
+#define SEA_ASSEMBLER 1 /* Use assembly code for fast transfers */
+
+/*
+ * defining SEANOMSGS causes messages not to be used (thereby disabling
+ * disconnects)
+ */
+/* #define SEANOMSGS 1 */
+
+/*
+ * defining SEA_NODATAOUT makes dataout phase being aborted
+ */
+/* #define SEA_NODATAOUT 1 */
+
+/*
+ * defining SEA_SENSEFIRST make REQUEST_SENSE opcode to be placed first
+ */
+/* #define SEA_SENSEFIRST 1 */
+
+#define SEA_FREEBSD11 1 /* intermediate def. for FreeBSD 1.1 BETA */
+ /* timeout function has changed */
+
+/* Debugging definitions. Should not be used unless you want a lot of
+ printouts even under normal conditions */
+
+/* #define SEADEBUG 1 */ /* General info about errors */
+/* #define SEADEBUG1 1 */ /* Info about internal results and errors */
+/* #define SEADEBUG2 1 */ /* Display a lot about timeouts etc */
+/* #define SEADEBUG3 1 */
+/* #define SEADEBUG4 1 */
+/* #define SEADEBUG5 1 */
+/* #define SEADEBUG6 1 */ /* Display info about queue-lengths */
+/* #define SEADEBUG7 1 */ /* Extra check on STATUS before phase check */
+/* #define SEADEBUG8 1 */ /* Disregard non-BSY state in
+ sea_information_transfer */
+/* #define SEADEBUG9 1 */ /* Enable printouts */
+/* #define SEADEBUG11 1 */ /* stop everything except access to scsi id 1 */
+/* #define SEADEBUG15 1 */ /* Display every byte sent/received */
+
+#define NUM_CONCURRENT 1 /* number of concurrent ops per board */
+
+/******************************* board definitions **************************/
+/*
+ * CONTROL defines
+ */
+
+#define CMD_RST 0x01 /* scsi reset */
+#define CMD_SEL 0x02 /* scsi select */
+#define CMD_BSY 0x04 /* scsi busy */
+#define CMD_ATTN 0x08 /* scsi attention */
+#define CMD_START_ARB 0x10 /* start arbitration bit */
+#define CMD_EN_PARITY 0x20 /* enable scsi parity generation */
+#define CMD_INTR 0x40 /* enable scsi interrupts */
+#define CMD_DRVR_ENABLE 0x80 /* scsi enable */
+
+/*
+ * STATUS
+ */
+
+#define STAT_BSY 0x01 /* scsi busy */
+#define STAT_MSG 0x02 /* scsi msg */
+#define STAT_IO 0x04 /* scsi I/O */
+#define STAT_CD 0x08 /* scsi C/D */
+#define STAT_REQ 0x10 /* scsi req */
+#define STAT_SEL 0x20 /* scsi select */
+#define STAT_PARITY 0x40 /* parity error bit */
+#define STAT_ARB_CMPL 0x80 /* arbitration complete bit */
+
+/*
+ * REQUESTS
+ */
+
+#define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG)
+#define REQ_DATAOUT 0
+#define REQ_DATAIN STAT_IO
+#define REQ_CMDOUT STAT_CD
+#define REQ_STATIN (STAT_CD | STAT_IO)
+#define REQ_MSGOUT (STAT_MSG | STAT_CD)
+#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
+
+#define REQ_UNKNOWN 0xff
+
+#define SEAGATERAMOFFSET 0x00001800
+
+#ifdef PARITY
+ #define BASE_CMD (CMD_EN_PARITY | CMD_INTR)
+#else
+ #define BASE_CMD (CMD_INTR)
+#endif
+
+#define SEAGATE 1
+#define FD 2
+
+/******************************************************************************
+ * This should be placed in a more generic file (presume in /sys/scsi)
+ * Message codes:
+ */
+#define MSG_ABORT 0x06
+#define MSG_NOP 0x08
+#define MSG_COMMAND_COMPLETE 0x00
+#define MSG_DISCONNECT 0x04
+#define MSG_IDENTIFY 0x80
+#define MSG_BUS_DEV_RESET 0x0c
+#define MSG_MESSAGE_REJECT 0x07
+#define MSG_SAVE_POINTERS 0x02
+#define MSG_RESTORE_POINTERS 0x03
+/******************************************************************************/
+
+#define IDENTIFY(can_disconnect,lun) (MSG_IDENTIFY | ((can_disconnect) ? \
+ 0x40 : 0) | ((lun) & 0x07))
+
+/* scsi control block used to keep info about a scsi command */
+struct sea_scb
+{
+ int flags; /* status of the instruction */
+#define SCB_FREE 0
+#define SCB_ACTIVE 1
+#define SCB_ABORTED 2
+#define SCB_TIMEOUT 4
+#define SCB_ERROR 8
+#define SCB_TIMECHK 16 /* We have set a timeout on this one */
+ struct sea_scb *next; /* in free list */
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ u_char * data; /* position in data buffer so far */
+ int32 datalen; /* bytes remaining to transfer */;
+};
+
+/*
+ * data structure describing current status of the scsi bus. One for each
+ * controller card.
+ */
+struct sea_data
+{
+ caddr_t basemaddr; /* Base address for card */
+ char ctrl_type; /* FD or SEAGATE */
+ caddr_t st0x_cr_sr; /* Address of control and status register */
+ caddr_t st0x_dr; /* Address of data register */
+ u_short vect; /* interrupt vector for this card */
+ int our_id; /* our scsi id */
+ int numscb; /* number of scsi control blocks */
+ struct scsi_link sc_link; /* struct connecting different data */
+ struct sea_scb *connected; /* currently connected command */
+ struct sea_scb *issue_queue; /* waiting to be issued */
+ struct sea_scb *disconnected_queue; /* waiting to reconnect */
+ struct sea_scb scbs[SCB_TABLE_SIZE];
+ struct sea_scb *free_scb; /* free scb list */
+ volatile unsigned char busy[8]; /* index=target, bit=lun, Keep track of
+ busy luns at device target */
+} *seadata[NSEA];
+
+/* flag showing if main routine is running. */
+static volatile int main_running = 0;
+
+#define STATUS (*(volatile unsigned char *) sea->st0x_cr_sr)
+#define CONTROL STATUS
+#define DATA (*(volatile unsigned char *) sea->st0x_dr)
+
+/*
+ * These are "special" values for the tag parameter passed to sea_select
+ * Not implemented right now.
+ */
+
+#define TAG_NEXT -1 /* Use next free tag */
+#define TAG_NONE -2 /*
+ * Establish I_T_L nexus instead of I_T_L_Q
+ * even on SCSI-II devices.
+ */
+
+typedef struct {
+ char *signature ;
+ unsigned offset;
+ unsigned length;
+ unsigned char type;
+} BiosSignature;
+
+/*
+ * Signatures for automatic recognition of board type
+ */
+
+static const BiosSignature signatures[] = {
+{"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
+{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
+
+/*
+ * The following two lines are NOT mistakes. One detects ROM revision
+ * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter,
+ * and this is not going to change, the "SEAGATE" and "SCSI" together
+ * are probably "good enough"
+ */
+
+{"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
+{"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
+
+ /*
+ * However, future domain makes several incompatible SCSI boards, so specific
+ * signatures must be used.
+ */
+
+ {"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 45, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90",5, 47, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90",5, 47, FD},
+ {"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
+ {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
+ {"FUTURE DOMAIN TMC-950", 5, 21, FD},
+ };
+
+#define NUM_SIGNATURES (sizeof(signatures) / sizeof(BiosSignature))
+
+static const char * seagate_bases[] = {
+ (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000,
+ (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000
+};
+
+#define NUM_BASES (sizeof(seagate_bases)/sizeof(char *))
+
+int sea_probe(struct isa_device *dev);
+int sea_attach(struct isa_device *dev);
+int seaintr(int unit);
+int32 sea_scsi_cmd(struct scsi_xfer *xs);
+#ifdef SEA_FREEBSD11
+void sea_timeout(caddr_t, int);
+#else
+void sea_timeout(struct sea_scb *scb);
+#endif
+void seaminphys(struct buf *bp);
+void sea_done(int unit, struct sea_scb *scb);
+u_int32 sea_adapter_info(int unit);
+struct sea_scb *sea_get_scb(int unit, int flags);
+void sea_free_scb(int unit, struct sea_scb *scb, int flags);
+static void sea_main(void);
+static void sea_information_transfer(struct sea_data *sea);
+int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb);
+int sea_init(int unit);
+int sea_send_scb(struct sea_data *sea, struct sea_scb *scb);
+int sea_reselect(struct sea_data *sea);
+int sea_select(struct sea_data *sea, struct sea_scb *scb);
+int sea_transfer_pio(struct sea_data *sea, u_char *phase, int32 *count,
+ u_char **data);
+int sea_abort(int unit, struct sea_scb *scb);
+
+static sea_unit = 0;
+static sea_slot = -1; /* last found board seagate_bases address index */
+#define FAIL 1
+#define SUCCESS 0
+
+#ifdef KERNEL
+struct scsi_adapter sea_switch =
+{
+ sea_scsi_cmd,
+ seaminphys,
+ 0,
+ 0,
+ sea_adapter_info,
+ "sea",
+ 0,0
+};
+
+/* the below structure is so we have a default dev struct for our link struct */
+struct scsi_device sea_dev =
+{
+ NULL, /* use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "sea",
+ 0,
+ 0,0
+};
+
+struct isa_driver seadriver =
+{
+ sea_probe,
+ sea_attach,
+ "sea"
+};
+
+#endif /* KERNEL */
+
+#ifdef SEADEBUG6
+void sea_queue_length()
+{
+ struct sea_scb *tmp;
+ int length = 0;
+
+ if(seadata[0]->connected)
+ length = 1;
+ for(tmp = seadata[0]->issue_queue; tmp != NULL; tmp = tmp->next, length++);
+ for(tmp = seadata[0]->disconnected_queue ; tmp != NULL; tmp->next, length++);
+ printf("length:%d ",length);
+}
+#endif
+
+/***********************************************************************\
+* Check if the device can be found at the port given and if so, detect *
+* the type of board. Set it up ready for further work. Takes the *
+* isa_dev structure from autoconf as an argument. *
+* Returns 1 if card recognized, 0 if errors *
+\***********************************************************************/
+int
+sea_probe(dev)
+struct isa_device *dev;
+{
+ int j;
+ int unit = sea_unit;
+ struct sea_data *sea;
+ dev->id_unit = unit;
+
+#ifdef SEADEBUG2
+ printf("sea_probe ");
+#endif
+
+ /* find unit and check we have that many defined */
+ if(unit >= NSEA) {
+ printf("sea%d: unit number too high\n",unit);
+ return(0);
+ }
+ dev->id_unit = unit;
+#ifdef SEADEBUG2
+ printf("unit: %d\n",unit);
+ printf("dev_addr: 0x%lx\n",dev->id_maddr);
+#endif
+ /* allocate a storage area for us */
+
+ if (seadata[unit]) {
+ printf("sea%d: memory already allocated\n", unit);
+ return(0);
+ }
+#ifdef SEADEBUG2
+ printf("Before malloc\n");
+#endif
+ sea = malloc(sizeof(struct sea_data), M_TEMP, M_NOWAIT);
+ if (!sea) {
+ printf("sea%d: cannot malloc!\n", unit);
+ return(0);
+ }
+
+#ifdef SEADEBUG2
+ printf("after malloc\n");
+ for(j=0;j<32767;j++);
+#endif
+ bzero(sea,sizeof(struct sea_data));
+ seadata[unit] = sea;
+
+ /* check for address if no one specified */
+ sea->basemaddr = NULL;
+
+ /* Could try to find a board by looking through all possible addresses */
+ /* This is not done the right way now, because I have not found a way */
+ /* to get a boards virtual memory address given its physical. There is */
+ /* a function that returns the physical address for a given virtual */
+ /* address, but not the other way around */
+
+ if(dev->id_maddr == 0) {
+/*
+ for(sea_slot++;sea_slot<NUM_BASES;sea_slot++)
+ for(j = 0; !sea->basemaddr && j < NUM_SIGNATURES; ++j)
+ if(!memcmp((void *)(seagate_bases[sea_slot]+signatures[j].offset),
+ (void *) signatures[j].signature, signatures[j].length)) {
+ sea->basemaddr = (void *)seagate_bases[sea_slot];
+ break;
+ }
+*/
+ } else {
+
+#ifdef SEADEBUG2
+ printf("id_maddr != 0\n");
+ for(j = 0; j < 32767 ; j++);
+ for(j = 0; j < 32767 ; j++);
+#endif
+ /* find sea_slot position for overridden memory address */
+ for(j = 0; ((char *)vtophys(dev->id_maddr) != seagate_bases[j]) &&
+ j<NUM_BASES; ++j);
+ if(j == NUM_BASES) {
+ printf("sea: board not expected at address 0x%lx\n",dev->id_maddr);
+ seadata[unit]=NULL;
+ free(sea, M_TEMP);
+ return(0);
+ } else if(sea_slot > j) {
+ printf("sea: board address 0x%lx already probed!\n", dev->id_maddr);
+ seadata[unit]=NULL;
+ free(sea, M_TEMP);
+ return(0);
+ } else {
+ sea->basemaddr = dev->id_maddr;
+ }
+
+ }
+#ifdef SEADEBUG2
+ printf("sea->basemaddr = %lx\n", sea->basemaddr);
+#endif
+
+ /* check board type */ /* No way to define this through config */
+ for(j = 0; j < NUM_SIGNATURES; j++)
+ if(!memcmp((void *) (sea->basemaddr + signatures[j].offset),
+ (void *) signatures[j].signature, signatures[j].length)) {
+ sea->ctrl_type = signatures[j].type;
+ break;
+ }
+ if(j == NUM_SIGNATURES) {
+ printf("sea: Board type unknown at address 0x%lx\n",
+ sea->basemaddr);
+ seadata[unit]=NULL;
+ free(sea, M_TEMP);
+ return(0);
+ }
+
+ /* Find controller and data memory addresses */
+ sea->st0x_cr_sr = (void *) (((unsigned char *) sea->basemaddr) +
+ ((sea->ctrl_type == SEAGATE) ? 0x1a00 : 0x1c00));
+ sea->st0x_dr = (void *) (((unsigned char *) sea->basemaddr) +
+ ((sea->ctrl_type == SEAGATE) ? 0x1c00 : 0x1e00));
+
+ /* Test controller RAM (works the same way on future domain cards?) */
+ *(sea->basemaddr + SEAGATERAMOFFSET) = 0xa5;
+ *(sea->basemaddr + SEAGATERAMOFFSET + 1) = 0x5a;
+
+ if((*(sea->basemaddr + SEAGATERAMOFFSET) != (char) 0xa5) ||
+ (*(sea->basemaddr + SEAGATERAMOFFSET + 1) != (char) 0x5a)) {
+ printf("sea%d: Board RAM failure\n",unit);
+ }
+
+ if(sea_init(unit) != 0) {
+ seadata[unit] = NULL;
+ free(sea,M_TEMP);
+ return(0);
+ }
+
+ /* if its there put in it's interrupt vector */
+ /* (Doesn't use dma, so no drq is set) */
+ sea->vect = dev->id_irq;
+
+ sea_unit++;
+ return(1);
+}
+
+/***********************************************\
+* Attach all sub-devices we can find *
+\***********************************************/
+int
+sea_attach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct sea_data *sea = seadata[unit];
+
+#ifdef SEADEBUG2
+ printf("sea_attach called\n");
+#endif
+
+ /* fill in the prototype scsi_link */
+ sea->sc_link.adapter_unit = unit;
+ sea->sc_link.adapter_targ = sea->our_id;
+ sea->sc_link.adapter = &sea_switch;
+ sea->sc_link.device = &sea_dev;
+
+ /*****************************************************\
+ * ask the adapter what subunits are present *
+ \*****************************************************/
+ scsi_attachdevs(&(sea->sc_link));
+ return 1;
+}
+
+/***********************************************\
+* Return some information to the caller about *
+* the adapter and its capabilities *
+\***********************************************/
+u_int32
+sea_adapter_info(unit)
+ int unit;
+{
+#ifdef SEADEBUG2
+ printf("sea_adapter_info called\n");
+#endif
+ return 1;
+}
+
+/***********************************************\
+* Catch an interrupt from the adaptor *
+\***********************************************/
+int
+seaintr(unit)
+ int unit;
+{
+ int done;
+ struct sea_data *sea = seadata[unit];
+ int oldpri;
+
+#if SEADEBUG2
+ printf(";");
+#endif
+
+ do {
+ done = 1;
+ /* dispatch to appropriate routine if found and done=0 */
+ /* should check to see that this card really caused the interrupt */
+ if ((STATUS & (STAT_SEL | STAT_IO)) == (STAT_SEL | STAT_IO)) {
+ /* Reselect interrupt */
+#ifdef SEADEBUG2
+ printf(";2");
+#endif
+ done = 0;
+/* enable_intr(); */ /* ?? How should this be done ?? */
+ sea_reselect(sea);
+ } else if (STATUS & STAT_PARITY) {
+ /* Parity error interrupt */
+#ifdef SEADEBUG2
+ printf(";3");
+#endif
+ printf("sea%d: PARITY interrupt\n", unit);
+ } else {
+#ifdef SEADEBUG2
+/* printf("sea%d: unknown interrupt\n",unit); */
+ printf(";4%x", STATUS);
+#endif
+ }
+ if (!done) {
+ oldpri = splbio(); /* disable_intr(); */
+ if (!main_running) {
+#ifdef SEADEBUG2
+ printf(";5");
+#endif
+ main_running = 1;
+ sea_main();
+ /* main_running is cleared in sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ splx(oldpri); /* enable_intr(); */
+ } else {
+ splx(oldpri); /* enable_intr(); */
+ }
+ }
+ } while (!done);
+ return 1;
+}
+
+/***********************************************\
+* Setup data structures, and reset the board *
+* and the scsi bus *
+\***********************************************/
+int
+sea_init(unit)
+ int unit;
+{
+ long l;
+ int i;
+ struct sea_data *sea = seadata[unit];
+
+#ifdef SEADEBUG2
+ printf("sea_init called\n");
+#endif
+/* Reset the scsi bus (I don't know if this is needed */
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_RST;
+ DELAY(25); /* hold reset for at least 25 microseconds */
+ CONTROL = BASE_CMD;
+ DELAY(10); /* wait a Bus Clear Delay (800 ns + bus free delay (800 ns) */
+ /* Set our id (don't know anything about this) */
+ if(sea->ctrl_type == SEAGATE)
+ sea->our_id = 7;
+ else
+ sea->our_id = 6;
+ /* init fields used by our routines */
+ sea->connected = NULL;
+ sea->issue_queue = NULL;
+ sea->disconnected_queue = NULL;
+ for (i=0; i<8 ; i++)
+ sea->busy[i] = 0;
+
+ /* link up the free list of scbs */
+ sea->numscb = SCB_TABLE_SIZE;
+ sea->free_scb = (struct sea_scb *) & (sea->scbs[0]);
+ for(i=1;i< SCB_TABLE_SIZE ; i++) {
+ sea->scbs[i-1].next = &(sea->scbs[i]);
+ }
+ sea->scbs[SCB_TABLE_SIZE - 1].next = NULL;
+
+ return(0);
+}
+
+/***********************************************\
+* *
+\***********************************************/
+void seaminphys(bp)
+ struct buf *bp;
+{
+#ifdef SEADEBUG2
+/* printf("seaminphys called\n"); */
+ printf(",");
+#endif
+}
+
+/***********************************************\
+* start a scsi operation given the command and *
+* the data address. Also needs the unit, target *
+* and lu *
+* get a free scb and set it up *
+* call send_scb *
+* either start timer or wait until done *
+\***********************************************/
+int32 sea_scsi_cmd(xs)
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1, *s2;
+ struct sea_scb *scb;
+ int i = 0;
+ int flags;
+ int unit = xs->sc_link->adapter_unit;
+ struct sea_data *sea = seadata[unit];
+ int s;
+ unsigned int stat;
+ int32 result;
+
+#ifdef SEADEBUG2
+ /* printf("scsi_cmd\n"); */
+ printf("=");
+#endif
+
+#ifdef SEADEBUG11
+ if(xs->sc_link->target != 1) {
+ xs->flags |= ITSDONE;
+ xs->error = XS_TIMEOUT;
+ return(HAD_ERROR);
+ }
+#endif
+
+ flags = xs->flags;
+ if(xs->bp) flags |= (SCSI_NOSLEEP);
+ if(flags & ITSDONE) {
+ printf("sea%d: Already done?", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if(!(flags & INUSE)) {
+ printf("sea%d: Not in use?", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(scb = sea_get_scb(unit, flags))) {
+#ifdef SEADEBUG2
+ printf("=2");
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Put all the arguments for the xfer in the scb
+ */
+ scb->xfer = xs;
+ scb->datalen = xs->datalen;
+ scb->data = xs->data;
+
+ if(flags & SCSI_RESET) {
+ /* Try to send a reset command to the card. This is done by calling the
+ * Reset function. Should then return COMPLETE. Need to take care of the
+ * possible current connected command.
+ * Not implemented right now.
+ */
+ printf("sea%d: Got a SCSI_RESET!\n",unit);
+ }
+
+ /* setup the scb to contain necessary values */
+ /* The interresting values can be read from the xs that is saved */
+ /* I therefore think that the structure can be kept very small */
+ /* the driver doesn't use DMA so the scatter/gather is not needed ? */
+#ifdef SEADEBUG6
+ sea_queue_length();
+#endif
+ if (sea_send_scb(sea, scb) == 0) {
+#ifdef SEADEBUG2
+ printf("=3");
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ sea_free_scb(unit, scb, flags);
+ return (TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if (!(flags & SCSI_NOMASK)) {
+ if(xs->flags & ITSDONE) { /* timout timer not started, already finished */
+ /* Tried to return COMPLETE but the machine hanged with this */
+#ifdef SEADEBUG2
+ printf("=6");
+#endif
+ return(SUCCESSFULLY_QUEUED);
+ }
+#ifdef SEA_FREEBSD11
+ timeout(sea_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000);
+#else
+ timeout(sea_timeout, scb, (xs->timeout * hz) / 1000);
+#endif
+ scb->flags |= SCB_TIMECHK;
+#ifdef SEADEBUG2
+ printf("=4");
+#endif
+ return(SUCCESSFULLY_QUEUED);
+ }
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+
+ result = sea_poll(unit, xs, scb);
+#ifdef SEADEBUG2
+ printf("=5 %lx", result);
+#endif
+ return result;
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new one. If so,
+ * put it in the hash table too, otherwise return an error or sleep.
+ */
+
+struct sea_scb *
+sea_get_scb(unit, flags)
+ int unit;
+ int flags;
+{
+ struct sea_data *sea = seadata[unit];
+ unsigned opri = 0;
+ struct sea_scb * scbp;
+ int hashnum;
+
+#ifdef SEADEBUG2
+/* printf("get_scb\n"); */
+ printf("(");
+#endif
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+#ifdef SEADEBUG3
+ printf("(2 %lx ", sea->free_scb);
+#endif
+
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can´t allocate a new one.
+ */
+ while (!(scbp = sea->free_scb)) {
+#ifdef SEADEBUG12
+ printf("(3");
+#endif
+ if (sea->numscb < SEA_SCB_MAX) {
+ printf("malloced new scbs\n");
+ if (scbp = (struct sea_scb *) malloc(sizeof(struct sea_scb),
+ M_TEMP, M_NOWAIT)) {
+ bzero(scbp, sizeof(struct sea_scb));
+ sea->numscb++;
+ scbp->flags = SCB_ACTIVE;
+ scbp->next = NULL;
+ } else {
+ printf("sea%d: Can't malloc SCB\n",unit);
+ }
+ goto gottit;
+ } else {
+#ifdef SEADEBUG12
+ printf("(4");
+#endif
+ if(!(flags & SCSI_NOSLEEP)) {
+#ifdef SEADEBUG2
+ printf("(5");
+#endif
+ tsleep(&sea->free_scb, PRIBIO, "seascb", 0);
+ }
+ }
+ }
+ if (scbp) {
+#ifdef SEADEBUG2
+ printf("(6");
+#endif
+ /* Get SCB from free list */
+ sea->free_scb = scbp->next;
+ scbp->next = NULL;
+ scbp->flags = SCB_ACTIVE;
+ }
+ gottit:
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return(scbp);
+}
+
+/*
+ * sea_send_scb
+ *
+ * Try to send this command to the board. Because this board does not use any
+ * mailboxes, this routine simply adds the command to the queue held by the
+ * sea_data structure.
+ * A check is done to see if the command contains a REQUEST_SENSE command, and
+ * if so the command is put first in the queue, otherwise the command is added
+ * to the end of the queue. ?? Not correct ??
+ */
+int
+sea_send_scb(struct sea_data *sea, struct sea_scb *scb)
+{
+ struct sea_scb *tmp;
+ int oldpri = 0;
+
+#ifdef SEADEBUG2
+ printf("+");
+#endif
+
+ if(!(scb->xfer->flags & SCSI_NOSLEEP)) {
+ oldpri = splbio();
+ }
+
+ /* add to head of queue if queue empty or command is REQUEST_SENSE */
+
+ if (!(sea->issue_queue)
+#ifdef SEA_SENSEFIRST
+ || (scb->xfer->cmd->opcode == (u_char) REQUEST_SENSE)
+#endif
+ ) {
+#ifdef SEADEBUG2
+ printf("+2");
+#endif
+ scb->next = sea->issue_queue;
+ sea->issue_queue = scb;
+ } else {
+#ifdef SEADEBUG2
+ printf("+3");
+#endif
+ for (tmp = sea->issue_queue; tmp->next; tmp = tmp->next);
+ tmp->next = scb;
+ scb->next = NULL; /* placed at the end of the queue */
+ }
+ /* Try to do some work on the card */
+ if (!main_running) {
+ main_running = 1;
+ sea_main();
+ /* main running is cleared in sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ }
+ if(!(scb->xfer->flags & SCSI_NOSLEEP)) {
+ splx(oldpri);
+ }
+ return (1); /* No possible errors right now */
+}
+
+/*
+ * sea_main(void)
+ *
+ * corroutine that runs as long as more work can be done on the seagate host
+ * adapter in a system. Both sea_scsi_cmd and sea_intr will try to start it in
+ * case it is not running.
+ */
+
+static void sea_main(void)
+{
+ struct sea_data *sea; /* This time we look at all cards */
+ struct sea_scb *tmp, *prev;
+ int done;
+ int unit;
+ int oldpri;
+
+#ifdef SEADEBUG2
+ printf(".");
+#endif
+
+ /*
+ * This should not be run with interrupts disabled, but use the splx code
+ * instead
+ */
+ do {
+ done = 1;
+ for (sea=seadata[unit=0]; (unit < NSEA) && seadata[unit] ;
+ sea=seadata[++unit]) {
+ oldpri = splbio();
+ if (!sea->connected) {
+#ifdef SEADEBUG2
+ printf(".2");
+#endif
+ /*
+ * Search through the issue_queue for a command destined for a
+ * target that's not busy.
+ */
+ for (tmp = sea->issue_queue, prev = NULL; tmp ;
+ prev = tmp, tmp = tmp->next)
+ /* When we find one, remove it from the issue queue. */
+ if (!(sea->busy[tmp->xfer->sc_link->target] &
+ (1 << tmp->xfer->sc_link->lun))) {
+ if (prev)
+ prev->next = tmp->next;
+ else
+ sea->issue_queue = tmp->next;
+ tmp->next = NULL;
+
+ /* re-enable interrupts after finding one */
+ splx(oldpri);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, sea->connected is set.
+ * On failure, we must add the command back to
+ * the issue queue so we can keep trying.
+ */
+#ifdef SEADEBUG2
+ printf(".3");
+#endif
+
+ /* REQUEST_SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent alligence condition exists for the
+ * entire unit.
+ */
+
+ /* First check that if any device has tried a reconnect while
+ * we have done other things with interrupts disabled
+ */
+
+ if ((STATUS & (STAT_SEL | STAT_IO)) == (STAT_SEL | STAT_IO)) {
+#ifdef SEADEBUG2
+ printf(".7");
+#endif
+ sea_reselect(sea);
+ break;
+ }
+ if (!sea_select(sea, tmp)) {
+#ifdef SEADEBUG2
+ /* printf("Select returned ok\n"); */
+ printf(".4");
+#endif
+ break;
+ } else {
+ oldpri = splbio();
+ tmp->next = sea->issue_queue;
+ sea->issue_queue = tmp;
+ splx(oldpri);
+ printf("sea_main: select failed\n");
+ }
+ } /* if target/lun is not busy */
+ } /* if (!sea->connected) */
+
+ if (sea->connected) { /* we are connected. Do the task */
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("sea_main: starting information transfer!\n"); */
+ printf(".5");
+#endif
+ sea_information_transfer(sea);
+#ifdef SEADEBUG2
+/* printf("sea_main: sea->connected:%lx\n", sea->connected); */
+ printf(".6%lx ", sea->connected);
+#endif
+ done = 0;
+ } else
+ break;
+ } /* for instance */
+ } while (!done);
+ main_running = 0;
+}
+
+void
+sea_free_scb(unit, scb, flags)
+ int unit;
+ struct sea_scb *scb;
+ int flags;
+{
+ struct sea_data *sea = seadata[unit];
+ unsigned int opri = 0;
+
+#ifdef SEADEBUG2
+/* printf("free_scb\n"); */
+ printf(")");
+#endif
+
+ if(!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ scb->next = sea->free_scb;
+ sea->free_scb = scb;
+ scb->flags = SCB_FREE;
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if(!scb->next) {
+#ifdef SEADEBUG2
+/* printf("free_scb waking up sleep\n"); */
+ printf(")2");
+#endif
+#ifdef SEA_FREEBSD11
+ wakeup((caddr_t)&sea->free_scb);
+#else
+ wakeup(&sea->free_scb);
+#endif
+ }
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+#ifdef SEA_FREEBSD11
+void
+sea_timeout(caddr_t arg1, int arg2)
+#else
+void
+sea_timeout(struct sea_scb *scb)
+#endif
+{
+#ifdef SEA_FREEBSD11
+ struct sea_scb *scb = (struct sea_scb *)arg1;
+#endif
+ int unit;
+ struct sea_data *sea;
+ int s=splbio();
+
+#ifdef SEADEBUG2
+/* printf("sea_timeout called\n"); */
+ printf(":");
+#endif
+
+ unit = scb->xfer->sc_link->adapter_unit;
+ sea = seadata[unit];
+#ifndef SEADEBUG /* print message only if not waiting unless debug */
+ if(!(scb->xfer->flags & SCSI_NOMASK))
+#endif
+ printf("sea%d:%d:%d (%s%d) timed out ", unit,
+ scb->xfer->sc_link->target,
+ scb->xfer->sc_link->lun,
+ scb->xfer->sc_link->device->name,
+ scb->xfer->sc_link->dev_unit);
+
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (/* (sea_abort(unit, scb) != 1) ||*/ (scb->flags & SCB_ABORTED)) {
+ /*
+ * abort timed out
+ */
+#ifdef SEADEBUG2
+/* printf("sea%d: Abort Operation has timed out\n", unit); */
+ printf(":2");
+#endif
+ scb->xfer->retries = 0;
+ scb->flags |= SCB_ABORTED;
+ sea_done(unit, scb);
+ } else {
+ #ifdef SEADEBUG2
+ /* printf("sea%d: Try to abort\n", unit); */
+ printf(":3");
+ #endif
+ sea_abort(unit, scb);
+ /* sea_send_scb(sea, ~SCSI_NOMASK, SEA_SCB_ABORT, scb); */
+ /* 2 seconds for the abort */
+ #ifdef SEA_FREEBSD11
+ timeout(sea_timeout, (caddr_t)scb, 2*hz);
+ #else
+ timeout(sea_timeout, scb, 2*hz);
+ #endif
+ scb->flags |= (SCB_ABORTED | SCB_TIMECHK);
+ }
+ splx(s);
+}
+
+int
+sea_reselect(sea)
+ struct sea_data *sea;
+{
+ unsigned char target_mask;
+ long l;
+ unsigned char lun, phase;
+ unsigned char msg[3];
+ int32 len;
+ u_char *data;
+ struct sea_scb *tmp = 0, *prev = 0;
+ int abort = 0;
+
+#if SEADEBUG2
+/* printf("sea_reselect called\n"); */
+ printf("}");
+#endif
+
+ if (!((target_mask = STATUS) & STAT_SEL)) {
+ printf("sea: wrong state 0x%x\n", target_mask);
+ return(0);
+ }
+ /* wait for a device to win the reselection phase */
+ /* signals this by asserting the I/O signal */
+ for(l=10; l && (STATUS & (STAT_SEL | STAT_IO | STAT_BSY))
+ != (STAT_SEL | STAT_IO | 0);l--);
+ /* !! Check for timeout here */
+ /* the data bus contains original initiator id ORed with target id */
+ target_mask = DATA;
+ /* see that we really are the initiator */
+ if (!(target_mask & ((sea->ctrl_type == SEAGATE) ? 0x80 : 0x40))) {
+ printf("sea: polled reselection was not for me: %x\n",target_mask);
+ return(0);
+ }
+ /* find target who won */
+ target_mask &= ((sea->ctrl_type == SEAGATE) ? ~0x80 : ~0x40);
+ /* host responds by asserting the BSY signal */
+ CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
+ /* target should respond by deasserting the SEL signal */
+ for(l=50000;l && (STATUS & STAT_SEL);l++);
+ /* remove the busy status */
+ CONTROL = (BASE_CMD | CMD_DRVR_ENABLE);
+ /* we are connected. Now we wait for the MSGIN condition */
+ for(l=50000; l && !(STATUS & STAT_REQ);l--);
+ /* !! Add timeout check here */
+ /* hope we get an IDENTIFY message */
+ len = 3;
+ data = msg;
+ phase = REQ_MSGIN;
+ sea_transfer_pio(sea, &phase, &len, &data);
+
+ if (!(msg[0] & 0x80)) {
+ printf("sea: Expecting IDENTIFY message, got 0x%x\n", msg[0]);
+ abort = 1;
+ } else {
+ lun = (msg[0] & 0x07);
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just restablished, and remove it from the disconnected queue.
+ */
+
+ for(tmp = sea->disconnected_queue, prev = NULL;
+ tmp; prev=tmp, tmp = tmp->next)
+ if((target_mask == (1 << tmp->xfer->sc_link->target)) &&
+ (lun == tmp->xfer->sc_link->lun)) {
+ if(prev) {
+#ifdef SEADEBUG2
+ printf("}2");
+#endif
+ prev->next = tmp->next;
+ } else {
+#ifdef SEADEBUG2
+ printf("}3");
+#endif
+ sea->disconnected_queue = tmp->next;
+ }
+ tmp->next = NULL;
+ break;
+ }
+ if (!tmp) {
+ printf("sea: warning : target %02x lun %d not in disconnect_queue\n",
+ target_mask, lun);
+ /*
+ * Since we have an established nexus that we can't do anything with,
+ * we must abort it.
+ */
+ abort = 1;
+ }
+ }
+
+ if(abort) {
+#ifdef SEADEBUG2
+ printf("}4");
+#endif
+ msg[0] = MSG_ABORT;
+ len = 1;
+ data = msg;
+ phase = REQ_MSGOUT;
+ CONTROL = (BASE_CMD | CMD_ATTN);
+ sea_transfer_pio(sea, &phase, &len, &data);
+ } else {
+#ifdef SEADEBUG2
+ printf("}5");
+#endif
+ sea->connected = tmp;
+ }
+ /* return value not used yet */
+ return 0;
+}
+
+/* Transfer data in given phase using polled I/O
+*/
+
+int sea_transfer_pio(struct sea_data *sea, u_char *phase, int32 *count,
+ u_char **data)
+{
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+ unsigned long int timeout;
+
+#if SEADEBUG2
+/* printf("sea_transfer_pio called: len:%x\n",c); */
+ printf("-1 %x %x", c, p);
+#endif
+
+ do {
+ /* wait for assertion of REQ, after which the phase bits will be valid */
+ for(timeout = 0; timeout < 5000000L ; timeout++)
+ if ((tmp = STATUS) & STAT_REQ)
+ break;
+ if (!(tmp & STAT_REQ)) {
+ printf("sea_transfer_pio: timeout waiting for STAT_REQ\n");
+ break;
+ }
+
+ /* check for phase mismatch */
+ /* Reached if the target decides that it has finished the transfer */
+ if ((tmp & REQ_MASK) != p) {
+#ifdef SEADEBUG1
+/* printf("-2 %x", tmp); */
+ printf("sea:pio phase mismatch:%x, want:%x, len:%x\n",tmp,p,c);
+#endif
+ break;
+ }
+
+ /* Do actual transfer from SCSI bus to/from memory */
+ if (!(p & STAT_IO))
+ DATA = *d;
+ else
+ *d = DATA;
+#ifdef SEADEBUG15
+ printf("-7%x", *d);
+#endif
+ ++d;
+
+ /* The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ * Don't know how to accomplish this on the ST01/02
+ */
+ /* We don't mind right now. */
+
+ /* The st01 code doesn't wait for STAT_REQ to be deasserted. Is this ok? */
+/* for(timeout=0;timeout<200000L;timeout++)
+ if(!(STATUS & STAT_REQ))
+ break;
+ if(STATUS & STAT_REQ)
+ printf("timeout on wait for !STAT_REQ"); */
+/* printf("*"); */
+ } while (--c);
+
+ *count = c;
+ *data = d;
+ tmp = STATUS;
+ if (tmp & STAT_REQ) {
+#if SEADEBUG2
+ printf("-3%x", tmp);
+#endif
+ *phase = tmp & REQ_MASK;
+ } else {
+#if SEADEBUG2
+ printf("-4%x", tmp);
+#endif
+ *phase = REQ_UNKNOWN;
+ }
+ if (!c || (*phase == p)) {
+#if SEADEBUG2
+ printf("-5%x %x", c, *phase);
+#endif
+ return 0;
+ } else {
+#if SEADEBUG2
+ printf("-6");
+#endif
+ return -1;
+ }
+}
+
+/* sea_select
+ * establish I_T_L or I_T_L_Q nexus for new or existing command
+ * including ARBITRATION, SELECTION, and initial message out for IDENTIFY and
+ * queue messages.
+ * return -1 if selection could not execute for some reason, 0 if selection
+ * succeded or failed because the taget did not respond
+ */
+int sea_select(struct sea_data *sea, struct sea_scb *scb)
+{
+ unsigned char tmp[3], phase;
+ u_char *data;
+ int32 len;
+ unsigned long timeout;
+
+#ifdef SEADEBUG2
+/* printf("sea_select called\n"); */
+ printf("{");
+#endif
+
+ CONTROL = BASE_CMD;
+ DATA = ((sea->ctrl_type == SEAGATE) ? 0x80 : 0x40);
+ CONTROL = (BASE_CMD & ~CMD_INTR) | CMD_START_ARB;
+ /* wait for arbitration to complete */
+ for (timeout = 0; timeout < 3000000L ; timeout++) {
+ if (STATUS & STAT_ARB_CMPL)
+ break;
+ }
+ if (!(STATUS & STAT_ARB_CMPL)) {
+ if (STATUS & STAT_SEL) {
+ printf("sea: arbitration lost\n");
+ scb->flags |= SCB_ERROR;
+ } else {
+ printf("sea: arbitration timeout.\n");
+ scb->flags |=SCB_TIMEOUT;
+ }
+ CONTROL = BASE_CMD;
+ return(-1);
+ }
+ DELAY(2);
+
+#if SEADEBUG2
+/* printf("after arbitration: STATUS=%x\n", STATUS); */
+ printf("{2 %x", STATUS);
+#endif
+
+ DATA = (unsigned char)((1 << scb->xfer->sc_link->target) |
+ ((sea->ctrl_type == SEAGATE) ? 0x80 : 0x40));
+#ifdef SEANOMSGS
+ CONTROL = (BASE_CMD & (~CMD_INTR))| CMD_DRVR_ENABLE | CMD_SEL;
+#else
+ CONTROL = (BASE_CMD & (~CMD_INTR)) | CMD_DRVR_ENABLE | CMD_SEL | CMD_ATTN;
+#endif
+ DELAY(1);
+ /* wait for a bsy from target */
+ for (timeout = 0; timeout < 2000000L; timeout++) {
+ if (STATUS & STAT_BSY)
+ break;
+ }
+
+#if SEADEBUG2
+/* printf("after wait for BSY: STATUS=%x,count=%lx\n", STATUS, timeout); */
+ printf("{3 %x %x", STATUS, timeout);
+#endif
+
+ if (!(STATUS & STAT_BSY)) {
+ /* should return some error to the higher level driver */
+ CONTROL = BASE_CMD;
+#if SEADEBUG2
+/* printf("sea: target did not respond\n"); */
+ printf("{4");
+#endif
+ scb->flags |= SCB_TIMEOUT;
+ return 0;
+ }
+
+ /* Try to make the target to take a message from us */
+#ifdef SEANOMSGS
+ CONTROL = (BASE_CMD & (~CMD_INTR)) | CMD_DRVR_ENABLE;
+#else
+ CONTROL = (BASE_CMD & (~CMD_INTR)) | CMD_DRVR_ENABLE | CMD_ATTN;
+#endif
+
+ DELAY(1);
+
+ /* should start a msg_out phase */
+ for (timeout = 0; timeout < 2000000L ; timeout++) {
+ if (STATUS & STAT_REQ)
+ break;
+ }
+
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+
+#if SEADEBUG2 || SEADEBUG9
+/* printf("after wait for STAT_REQ: STATUS=%x,count=%lx\n", STATUS, timeout);
+ printf("2:nd try after wait for STAT_REQ: STATUS=%x\n", STATUS); */
+ printf("{5%x", timeout);
+#endif
+
+ if (!(STATUS & STAT_REQ)) {
+ /* This should not be taken as an error, but more like an unsupported
+ * feature!
+ * Should set a flag indicating that the target don't support messages, and
+ * continue without failure. (THIS IS NOT AN ERROR!)
+ */
+#if SEADEBUG
+/* printf("{6"); */
+ printf("sea: WARNING: target %x don't support messages?\n",
+ scb->xfer->sc_link->target);
+#endif
+ } else {
+ tmp[0] = IDENTIFY(1, scb->xfer->sc_link->lun); /* allow disconnects */
+ len = 1;
+ data = tmp;
+ phase = REQ_MSGOUT;
+ /* Should do test on result of sea_transfer_pio */
+#if SEADEBUG2
+/* printf("Trying a msg out phase\n"); */
+ printf("{7");
+#endif
+ sea_transfer_pio(sea, &phase, &len, &data);
+ }
+ if (!(STATUS & STAT_BSY)) {
+ printf("sea: after successful arbitrate: No STAT_BSY!\n");
+ }
+
+#if SEADEBUG2
+ printf("{8");
+#endif
+ sea->connected = scb;
+ sea->busy[scb->xfer->sc_link->target] |= (1 << scb->xfer->sc_link->lun);
+ /* this assignment should depend on possibility to send a message to target */
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+ /* reset pointer in command ??? */
+ return 0;
+}
+
+/* sea_abort
+ send an abort to the target
+ return 1 success, 0 on failure
+ */
+int sea_abort(int unit, struct sea_scb *scb)
+{
+ struct sea_data *sea = seadata[unit];
+ struct sea_scb *tmp, **prev;
+ unsigned char msg, phase, *msgptr;
+ int32 len;
+ int oldpri;
+
+#ifdef SEADEBUG2
+/* printf("sea_abort called\n"); */
+ printf("\\");
+#endif
+
+ oldpri = splbio();
+
+ /* If the command hasn't been issued yet, we simply remove it from the
+ * issue queue
+ */
+ for (prev = (struct sea_scb **) &(sea->issue_queue),
+ tmp = sea->issue_queue; tmp;
+ prev = (struct sea_scb **) &(tmp->next), tmp = tmp->next)
+ if (scb == tmp) {
+ (*prev) = tmp->next;
+ tmp->next = NULL;
+ /* set some type of error result for this operation */
+ splx(oldpri);
+#ifdef SEADEBUG2
+ printf("\\2");
+#endif
+ return 1;
+ }
+
+ /* If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or issue a
+ * reset
+ */
+
+ if(sea->connected) {
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("sea:abort error connected\n"); */
+ printf("\\3");
+#endif
+ return 0;
+ }
+
+ /* If the command is currently disconnected from the bus, and there are
+ * no connected commands, we reconnect the I_T_L or I_T_L_Q nexus
+ * associated with it, go into message out, and send an abort message.
+ */
+
+ for (tmp = sea->disconnected_queue; tmp; tmp = tmp->next)
+ if (scb == tmp) {
+ splx(oldpri);
+#ifdef SEADEBUG2
+ printf("\\4");
+#endif
+ if (sea_select(sea,scb)) {
+#ifdef SEADEBUG2
+ printf("\\5");
+#endif
+ return 0;
+ }
+ msg = MSG_ABORT;
+ msgptr = &msg;
+ len = 1;
+ phase = REQ_MSGOUT;
+ CONTROL = BASE_CMD | CMD_ATTN;
+ sea_transfer_pio(sea, &phase, &len, &msgptr);
+
+ oldpri = splbio();
+ for (prev = (struct sea_scb **) &(sea->disconnected_queue),
+ tmp = sea->disconnected_queue; tmp ;
+ prev = (struct sea_scb **) &(tmp->next), tmp = tmp->next)
+ if (scb == tmp) {
+ *prev = tmp->next;
+ tmp->next = NULL;
+ /* set some type of error result for the operation */
+#ifdef SEADEBUG2
+ printf("\\6");
+#endif
+ splx(oldpri);
+ return 1;
+ }
+ }
+
+ /* command not found in any queue, race condition in the code ? */
+
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("sea: WARNING: SCSI command probably completed successfully\n"
+ " before abortion\n"); */
+ printf("\\7");
+#endif
+ return 1;
+
+}
+
+void sea_done(int unit, struct sea_scb *scb)
+{
+ struct sea_data *sea = seadata[unit];
+ struct scsi_xfer *xs = scb->xfer;
+
+
+#ifdef SEADEBUG2
+/* printf("sea_done called\n"); */
+ printf("&");
+#endif
+
+ if (scb->flags & SCB_TIMECHK) {
+#ifdef SEADEBUG2
+ printf("&2");
+#endif
+#ifdef SEA_FREEBSD11
+ untimeout(sea_timeout, (caddr_t)scb);
+#else
+ untimeout(sea_timeout, scb);
+#endif
+ }
+
+ xs->resid = scb->datalen; /* How much of the buffer was not touched */
+
+ if ((scb->flags == SCB_ACTIVE) || (xs->flags & SCSI_ERR_OK)) {
+#ifdef SEADEBUG2
+/* printf("sea_done:Report no err in xs\n"); */
+ printf("&3");
+#endif
+/* xs->resid = 0; */
+/* xs->error = 0; */
+ } else {
+
+ if (!(scb->flags == SCB_ACTIVE)) {
+ if ((scb->flags & SCB_TIMEOUT) || (scb->flags & SCB_ABORTED)) {
+#ifdef SEADEBUG2
+ printf("&6");
+#endif
+ xs->error = XS_TIMEOUT;
+ }
+ if (scb->flags & SCB_ERROR) {
+#ifdef SEADEBUG2
+ printf("&7");
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ } else {
+
+ /* !!! Add code to check for target status */
+ /* say all error now */
+ xs->error = XS_DRIVER_STUFFUP;
+#ifdef SEADEBUG2
+ printf("&4");
+#endif
+ }
+ }
+ xs->flags |= ITSDONE;
+ sea_free_scb(unit, scb, xs->flags);
+ scsi_done(xs);
+#ifdef SEADEBUG2
+/* printf("Leaving sea_done\n"); */
+ printf("&5");
+#endif
+}
+
+/* wait for completion of command in polled mode */
+
+int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb)
+{
+ int count = 500; /* xs->timeout; */
+ int oldpri;
+
+#ifdef SEADEBUG2
+/* printf("sea_poll called\n"); */
+ printf("?");
+#endif
+
+ while (count) {
+ /* try to do something */
+ oldpri = splbio();
+ if (!main_running) {
+ main_running = 1;
+ sea_main();
+ /* main_running is cleared in sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ splx(oldpri);
+ } else {
+ splx(oldpri);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(10);
+ count--;
+ }
+#ifdef SEADEBUG2
+ printf("?2 %x ", count);
+/* printf("sea_poll: count:%x\n",count); */
+#endif
+ if (count == 0) {
+ /* we timed out, so call the timeout handler manually,
+ * accounting for the fact that the clock is not running yet
+ * by taking out the clock queue entry it makes.
+ */
+#ifdef SEADEBUG2
+ printf("?3");
+#endif
+#ifdef SEA_FREEBSD11
+ sea_timeout((caddr_t)scb, 0);
+#else
+ sea_timeout(scb);
+#endif
+
+ /* because we are polling, take out the timeout entry
+ * sea_timeout made
+ */
+#ifdef SEADEBUG2
+ printf("?4");
+#endif
+#ifdef SEA_FREEBSD11
+ untimeout(sea_timeout, (caddr_t) scb);
+#else
+ untimeout(sea_timeout, scb);
+#endif
+ count = 50;
+ while (count) {
+ /* once again, wait for the int bit */
+ oldpri = splbio();
+ if (!main_running) {
+ main_running = 1;
+ sea_main();
+ /* main_running is cleared by sea_main once it can't
+ * do more work, and sea_main exits with interrupts
+ * disabled
+ */
+ splx(oldpri);
+ } else {
+ splx(oldpri);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(10);
+ count--;
+ }
+ if (count == 0) {
+ /* we timed out again... This is bad. Notice that
+ * this time there is no clock queue entry to remove
+ */
+#ifdef SEADEBUG2
+ printf("?5");
+#endif
+#ifdef SEA_FREEBSD11
+ sea_timeout((caddr_t)scb, 0);
+#else
+ sea_timeout(scb);
+#endif
+ }
+ }
+#ifdef SEADEBUG2
+/* printf("sea_poll: xs->error:%x\n",xs->error); */
+ printf("?6%x",xs->error);
+#endif
+ if (xs->error) {
+#ifdef SEADEBUG2
+/* printf("done return error\n"); */
+ printf("?7");
+#endif
+ return (HAD_ERROR);
+ }
+#ifdef SEADEBUG2
+/* printf("done return complete\n"); */
+ printf("?8");
+#endif
+ return (COMPLETE);
+}
+
+/*
+ * sea_information_transfer
+ * Do the transfer. We know we are connected. Update the flags,
+ * call sea_done when task accomplished. Dialog controlled by the
+ * target
+ */
+static void sea_information_transfer (struct sea_data *sea)
+{
+ long int timeout;
+ int unit = sea->sc_link.adapter_unit;
+ unsigned char msgout = MSG_NOP;
+ int32 len;
+ int oldpri;
+ u_char *data;
+ unsigned char phase, tmp, old_phase=REQ_UNKNOWN;
+ struct sea_scb *scb = sea->connected;
+ int loop;
+
+#if SEADEBUG2
+/* printf("sea_information_transfer called\n"); */
+ printf("!");
+#endif
+
+ for(timeout = 0; timeout < 10000000L ; timeout++) {
+ tmp = STATUS;
+ if (!(tmp & STAT_BSY)) {
+/* for(loop=0;loop < 20 ; loop++) {
+ if((tmp=STATUS) & STAT_BSY)
+ break;
+ } */
+#ifndef SEADEBUG8
+ if(!(tmp & STAT_BSY)) {
+ printf("sea: !STAT_BSY unit in data transfer!\n");
+ oldpri = splbio();
+ sea->connected = NULL;
+ scb->flags = SCB_ERROR;
+ splx(oldpri);
+ sea_done(unit, scb);
+ return;
+ }
+#endif
+ }
+
+ /* we only have a valid SCSI phase when REQ is asserted */
+ if (tmp & STAT_REQ) {
+ phase = (tmp & REQ_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+ }
+
+#ifdef SEADEBUG7
+ printf("!2%x", phase);
+ for(loop=0;loop < 20; loop++) {
+ phase = STATUS;
+ printf("!6%x",phase);
+ phase = phase & REQ_MASK;
+ }
+#endif
+
+ switch (phase) {
+ case REQ_DATAOUT:
+#ifdef SEA_NODATAOUT
+ printf("sea: SEA_NODATAOUT set, attempted DATAOUT aborted\n");
+ msgout = MSG_ABORT;
+ CONTROL = BASE_CMD | CMD_ATTN;
+ break;
+#endif
+ case REQ_DATAIN:
+/* data = scb->xfer->data;
+ len = scb->xfer->datalen;
+*/ if(!(scb->data)) {
+ printf("no data address!\n");
+ }
+#ifdef SEA_BLINDTRANSFER
+ if (scb->datalen && !(scb->datalen % BLOCK_SIZE)) {
+ while (scb->datalen) {
+ for(timeout = 0; timeout < 5000000L ; timeout++)
+ if((tmp = STATUS) & STAT_REQ)
+ break;
+ if(!(tmp & STAT_REQ)) {
+ printf("sea_transfer_pio: timeout waiting for STAT_REQ\n");
+ /* getchar(); */
+ }
+ if((tmp & REQ_MASK) != phase) {
+#ifdef SEADEBUG1
+ printf("sea:infotransfer phase mismatch:%x, want:%x, len:%x\n",
+ tmp,phase,scb->datalen);
+ /* getchar(); */
+#endif
+ break;
+ }
+ if(!(phase & STAT_IO)) {
+#ifdef SEA_ASSEMBLER
+ asm("
+ shr $2, %%ecx;
+ cld;
+ rep;
+ movsl; " : :
+ "D" (sea->st0x_dr), "S" (scb->data), "c" (BLOCK_SIZE) :
+ "cx", "si", "di" );
+ scb->data += BLOCK_SIZE;
+#else
+ for(count=0; count < BLOCK_SIZE; count++) {
+ DATA = *(scb->data);
+ scb->data++;
+ }
+#endif
+ } else {
+#ifdef SEA_ASSEMBLER
+ asm("
+ shr $2, %%ecx;
+ cld;
+ rep;
+ movsl; " : :
+ "S" (sea->st0x_dr), "D" (scb->data), "c" (BLOCK_SIZE) :
+ "cx", "si", "di" );
+ scb->data += BLOCK_SIZE;
+#else
+ for(count=0; count < BLOCK_SIZE; count++) {
+ *scb->data = DATA;
+ scb->data++;
+ }
+#endif
+ }
+ scb->datalen -= BLOCK_SIZE;
+ }
+ }
+
+ /* save current position into the command structure */
+/* scb->xfer->data = data;
+ scb->xfer->datalen = len; */
+#endif
+
+ sea_transfer_pio(sea, &phase, &(scb->datalen), &(scb->data));
+/* scb->xfer->data = data;
+ scb->xfer->datalen = len;
+*/ break;
+
+ case REQ_MSGIN:
+ /* don't handle multi-byte messages here, because they
+ * should not be present here
+ */
+ len = 1;
+ data = &tmp;
+ sea_transfer_pio(sea, &phase, &len, &data);
+ /* scb->MessageIn = tmp; */
+
+ switch (tmp) {
+
+ case MSG_ABORT:
+ scb->flags = SCB_ABORTED;
+ printf("sea:Command aborted by target\n");
+ CONTROL = BASE_CMD;
+ sea_done(unit, scb);
+ return;
+
+ case MSG_COMMAND_COMPLETE:
+ oldpri = splbio();
+ sea->connected = NULL;
+ splx(oldpri);
+#ifdef SEADEBUG2
+ printf("!3");
+#endif
+ sea->busy[scb->xfer->sc_link->target] &=
+ ~(1 << scb->xfer->sc_link->lun);
+
+ CONTROL = BASE_CMD;
+ sea_done(unit, scb);
+ return;
+ case MSG_MESSAGE_REJECT:
+ /* printf("sea: message_reject recieved\n"); */
+ printf("!4");
+ break;
+ case MSG_DISCONNECT:
+ oldpri = splbio();
+ scb->next = sea->disconnected_queue;
+ sea->disconnected_queue = scb;
+ sea->connected = NULL;
+ CONTROL = BASE_CMD;
+ splx(oldpri);
+#ifdef SEADEBUG2
+/* printf("msg_disconnect\n"); */
+ printf("!5");
+#endif
+ return;
+ /* save/restore of pointers are ignored */
+ case MSG_SAVE_POINTERS:
+ case MSG_RESTORE_POINTERS:
+#if SEADEBUG2
+ printf("sea: rec save/restore ptrs\n");
+#endif
+ break;
+ default:
+ /* this should be handled in the pio data transfer phase, as the
+ * ATN should be raised before ACK goes false when rejecting a message
+ */
+#ifdef SEADEBUG
+ printf("sea: Unknown message in:%x\n", tmp);
+#endif
+ break;
+ } /* switch (tmp) */
+ break;
+ case REQ_MSGOUT:
+ len = 1;
+ data = &msgout;
+ /* sea->last_message = msgout; */
+ sea_transfer_pio(sea, &phase, &len, &data);
+ if (msgout == MSG_ABORT) {
+ printf("sea: sent message abort to target\n");
+ oldpri = splbio();
+ sea->busy[scb->xfer->sc_link->target] &=
+ ~(1 << scb->xfer->sc_link->lun);
+ sea->connected = NULL;
+ scb->flags = SCB_ABORTED;
+ splx(oldpri);
+ /* enable interrupt from scsi */
+ sea_done(unit, scb);
+ return;
+ }
+ msgout = MSG_NOP;
+ break;
+ case REQ_CMDOUT:
+ len = scb->xfer->cmdlen;
+ data = (char *) scb->xfer->cmd;
+ sea_transfer_pio(sea, &phase, &len, &data);
+ break;
+ case REQ_STATIN:
+ len = 1;
+ data = &tmp;
+ sea_transfer_pio(sea, &phase, &len, &data);
+ scb->xfer->status = tmp;
+ break;
+ default:
+ printf("sea: unknown phase\n");
+ } /* switch (phase) */
+ } /* if (tmp & STAT_REQ) */
+ } /* for (...) */
+ /* if we get here we have got a timeout! */
+ printf("sea: Timeout in data transfer\n");
+ scb->flags = SCB_TIMEOUT;
+ /* should I clear scsi-bus state? */
+ sea_done(unit, scb);
+}
+
+
diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c
index 4cee4fe8c60f..6fa09247e5f3 100644
--- a/sys/i386/isa/sio.c
+++ b/sys/i386/isa/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.28 1994/02/07 18:37:21 ache Exp $
+ * $Id: sio.c,v 1.56 1994/06/16 08:08:44 ache Exp $
*/
#include "sio.h"
@@ -49,17 +49,19 @@
#include "proc.h"
#include "user.h"
#include "conf.h"
+#include "dkstat.h"
#include "file.h"
#include "uio.h"
#include "kernel.h"
+#include "malloc.h"
#include "syslog.h"
+#include "i386/isa/icu.h" /* XXX */
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/comreg.h"
#include "i386/isa/ic/ns16550.h"
-#define FAKE_DCD(unit) ((unit) == comconsole)
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
@@ -67,38 +69,27 @@
#define TTY_BI TTY_FE /* XXX */
#define TTY_OE TTY_PE /* XXX */
-#ifndef COM_BIDIR
-#define UNIT(x) (minor(x)) /* XXX */
-#else /* COM_BIDIR */
-#define COM_UNITMASK 0x7f
-#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
-#define UNIT(x) (minor(x) & COM_UNITMASK)
-#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
-#endif /* COM_BIDIR */
+#define CALLOUT_MASK 0x80
+#define CONTROL_MASK 0x60
+#define CONTROL_INIT_STATE 0x20
+#define CONTROL_LOCK_STATE 0x40
+#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
+#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
+#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
#ifdef COM_MULTIPORT
/* checks in flags for multiport and which is multiport "master chip"
* for a given card
*/
-#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
-#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOTAST4(dev) ((dev)->id_flags & 0x04)
#endif /* COM_MULTIPORT */
-#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
-#ifndef FIFO_TRIGGER
-/*
- * This driver is fast enough to work with any value and for high values
- * to be only slightly more efficient. Low values may be better because
- * they give lower latency.
- * TODO: always use low values for low speeds. Mouse movements are jerky
- * if more than one packet arrives at once. The low speeds used for
- * serial mice help avoid this, but not if (large) fifos are enabled.
- */
-#define FIFO_TRIGGER FIFO_TRIGGER_14
-#endif
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+#define COM_VERBOSE(dev) ((dev)->id_flags & 0x80)
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
-#define setsofttty() (ipending |= 1 << 4) /* XXX */
/*
* Input buffer watermarks.
@@ -124,17 +115,19 @@
* CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
* CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
* TS_FLUSH is not used.
- * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
*/
#define CS_BUSY 0x80 /* output in progress */
#define CS_TTGO 0x40 /* output not stopped by XOFF */
#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
#define CS_CHECKMSR 1 /* check of MSR scheduled */
#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_DTR_OFF 0x10 /* DTR held off */
#define CS_ODONE 4 /* output completed */
#define CS_RTS_IFLOW 8 /* use RTS input flow control */
-static char *error_desc[] = {
+static char const * const error_desc[] = {
#define CE_OVERRUN 0
"silo overflow",
#define CE_INTERRUPT_BUF_OVERFLOW 1
@@ -153,20 +146,19 @@ typedef u_char bool_t; /* boolean */
/* com device structure */
struct com_s {
u_char state; /* miscellaneous flag bits */
+ bool_t active_out; /* nonzero if the callout device is open */
u_char cfcr_image; /* copy of value written to CFCR */
+ u_char ftl; /* current rx fifo trigger level */
+ u_char ftl_init; /* ftl_max for next open() */
+ u_char ftl_max; /* maximum ftl for curent open() */
bool_t hasfifo; /* nonzero for 16550 UARTs */
u_char mcr_image; /* copy of value written to MCR */
-#ifdef COM_BIDIR
- bool_t bidir; /* is this unit bidirectional? */
- bool_t active; /* is the port active _at all_? */
- bool_t active_in; /* is the incoming port in use? */
- bool_t active_out; /* is the outgoing port in use? */
-#endif /* COM_BIDIR */
#ifdef COM_MULTIPORT
bool_t multiport; /* is this unit part of a multiport device? */
#endif /* COM_MULTIPORT */
- int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
u_int tx_fifo_size;
+ u_int wopeners; /* # processes waiting for DCD in open() */
/*
* The high level of the driver never reads status registers directly
@@ -177,6 +169,7 @@ struct com_s {
u_char last_modem_status; /* last MSR read by intr handler */
u_char prev_modem_status; /* last MSR handled by high level */
+ u_char hotchar; /* ldisc-specific char to be handled ASAP */
u_char *ibuf; /* start of input buffer */
u_char *ibufend; /* end of input buffer */
u_char *ihighwater; /* threshold in input buffer */
@@ -195,6 +188,19 @@ struct com_s {
struct tty *tp; /* cross reference */
+ /* Initial state. */
+ struct termios it_in; /* should be in struct tty */
+ struct termios it_out;
+
+ /* Lock state. */
+ struct termios lt_in; /* should be in struct tty */
+ struct termios lt_out;
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
u_long bytes_in; /* statistics */
u_long bytes_out;
u_int delta_error_counts[CE_NTYPES];
@@ -210,48 +216,56 @@ struct com_s {
};
/*
- * These functions in the com module ought to be declared (with a prototype)
- * in a com-driver system header. The void ones may need to be int to match
- * ancient devswitch declarations, but they don't actually return anything.
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
*/
#define Dev_t int /* promoted dev_t */
-struct consdev;
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
int sioclose __P((Dev_t dev, int fflag, int devtype,
struct proc *p));
-void siointr __P((int unit));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((Dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
int siocngetc __P((Dev_t dev));
+struct consdev;
void siocninit __P((struct consdev *cp));
void siocnprobe __P((struct consdev *cp));
void siocnputc __P((Dev_t dev, int c));
-int sioopen __P((Dev_t dev, int oflags, int devtype,
- struct proc *p));
-void siopoll __P((void));
-int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
-int sioselect __P((Dev_t dev, int rw, struct proc *p));
-void siostop __P((struct tty *tp, int rw));
-int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
-void softsio1 __P((void));
static int sioattach __P((struct isa_device *dev));
+static void siodtrwakeup __P((caddr_t chan, int ticks));
static void comflush __P((struct com_s *com));
static void comhardclose __P((struct com_s *com));
-static void cominit __P((int unit, int rate));
-static void comintr1 __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
static void commctl __P((struct com_s *com, int bits, int how));
static int comparam __P((struct tty *tp, struct termios *t));
static int sioprobe __P((struct isa_device *dev));
-static void comstart __P((struct tty *tp));
-static void comwakeup __P((caddr_t chan, int ticks));
+static void comstart __P((struct tty *tp));
+static void comwakeup __P((caddr_t chan, int ticks));
static int tiocm_xxx2mcr __P((int tiocm_xxx));
/* table and macro for fast conversion from a unit number to its com struct */
static struct com_s *p_com_addr[NSIO];
#define com_addr(unit) (p_com_addr[unit])
-static struct com_s com_structs[NSIO];
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
struct isa_driver siodriver = {
sioprobe, sioattach, "sio"
@@ -262,15 +276,11 @@ static int comconsole = COMCONSOLE;
#else
static int comconsole = -1;
#endif
-static bool_t comconsinit;
static speed_t comdefaultrate = TTYDEF_SPEED;
static u_int com_events; /* input chars + weighted output completions */
static int commajor;
-struct tty sio_tty[NSIO];
-extern struct tty *constty;
-extern u_int ipending; /* XXX */
-extern int tk_nin; /* XXX */
-extern int tk_rawcc; /* XXX */
+struct tty *sio_tty[NSIO];
+extern struct tty *constty; /* XXX */
#ifdef KGDB
#include "machine/remote-sl.h"
@@ -311,7 +321,11 @@ sioprobe(dev)
{
static bool_t already_init;
Port_t *com_ptr;
+ bool_t failures[10];
+ int fn;
+ struct isa_device *idev;
Port_t iobase;
+ u_char mcr_image;
int result;
if (!already_init) {
@@ -319,6 +333,7 @@ sioprobe(dev)
* Turn off MCR_IENABLE for all likely serial ports. An unused
* port with its MCR_IENABLE gate open will inhibit interrupts
* from any used port that shares the interrupt vector.
+ * XXX the gate enable is elsewhere for some multiports.
*/
for (com_ptr = likely_com_ports;
com_ptr < &likely_com_ports[sizeof likely_com_ports
@@ -327,8 +342,45 @@ sioprobe(dev)
outb(*com_ptr + com_mcr, 0);
already_init = TRUE;
}
+
+ /*
+ * If the port is on a multiport card and has a master port,
+ * initialize the common interrupt control register in the
+ * master and prepare to leave MCR_IENABLE clear in the mcr.
+ * Otherwise, prepare to set MCR_IENABLE in the mcr.
+ * Point idev to the device struct giving the correct id_irq.
+ * This is the struct for the master device if there is one.
+ */
+ idev = dev;
+ mcr_image = MCR_IENABLE;
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(dev)) {
+ idev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(dev));
+ if (idev == NULL) {
+ printf("sio%d: master device %d not found\n",
+ dev->id_unit, COM_MPMASTER(dev));
+ return (0);
+ }
+ if (idev->id_irq == 0) {
+ printf("sio%d: master device %d irq not configured\n",
+ dev->id_unit, COM_MPMASTER(dev));
+ return (0);
+ }
+ if (!COM_NOTAST4(dev)) {
+ outb(idev->id_iobase + com_scr, 0x80);
+ mcr_image = 0;
+ }
+ }
+ else
+#endif /* COM_MULTIPORT */
+ if (idev->id_irq == 0) {
+ printf("sio%d: irq not configured\n", dev->id_unit);
+ return (0);
+ }
+
+ bzero(failures, sizeof failures);
iobase = dev->id_iobase;
- result = IO_COMSIZE;
/*
* We don't want to get actual interrupts, just masked ones.
@@ -339,55 +391,115 @@ sioprobe(dev)
disable_intr();
/*
- * Initialize the speed so that any junk in the THR or output fifo will
- * be transmitted in a known time. (There may be lots of junk after a
- * soft reboot, and output interrupts don't work right after a master
- * reset, at least for 16550s. (The speed is undefined after MR, but
- * MR empties the THR and the TSR so it's not clear why this matters)).
- * Enable output interrupts (only) and check the following:
+ * XXX DELAY() reenables CPU interrupts. This is a problem for
+ * shared interrupts after the first device using one has been
+ * successfully probed - config_isadev() has enabled the interrupt
+ * in the ICU.
+ */
+ outb(IO_ICU1 + 1, 0xff);
+
+ /*
+ * Initialize the speed and the word size and wait long enough to
+ * drain the maximum of 16 bytes of junk in device output queues.
+ * The speed is undefined after a master reset and must be set
+ * before relying on anything related to output. There may be
+ * junk after a (very fast) soft reboot and (apparently) after
+ * master reset.
+ * XXX what about the UART bug avoided by waiting in comparam()?
+ * We don't want to to wait long enough to drain at 2 bps.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ DELAY((16 + 1) * 9600 / 10);
+
+ /*
+ * Enable the interrupt gate and disable device interupts. This
+ * should leave the device driving the interrupt line low and
+ * guarantee an edge trigger if an interrupt can be generated.
+ */
+ outb(iobase + com_mcr, mcr_image);
+ outb(iobase + com_ier, 0);
+
+ /*
+ * Attempt to set loopback mode so that we can send a null byte
+ * without annoying any external device.
+ */
+ outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
+
+ /*
+ * Attempt to generate an output interrupt. On 8250's, setting
+ * IER_ETXRDY generates an interrupt independent of the current
+ * setting and independent of whether the THR is empty. On 16450's,
+ * setting IER_ETXRDY generates an interrupt independent of the
+ * current setting. On 16550A's, setting IER_ETXRDY only
+ * generates an interrupt when IER_ETXRDY is not already set.
+ */
+ outb(iobase + com_ier, IER_ETXRDY);
+
+ /*
+ * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
+ * an interrupt. They'd better generate one for actually doing
+ * output. Loopback may be broken on the same incompatibles but
+ * it's unlikely to do more than allow the null byte out.
+ */
+ outb(iobase + com_data, 0);
+ DELAY((2 + 1) * 9600 / 10);
+
+ /*
+ * Turn off loopback mode so that the interrupt gate works again
+ * (MCR_IENABLE was hidden). This should leave the device driving
+ * an interrupt line high. It doesn't matter if the interrupt
+ * line oscillates while we are not looking at it, since interrupts
+ * are disabled.
+ */
+ outb(iobase + com_mcr, mcr_image);
+
+ /*
+ * Check that
* o the CFCR, IER and MCR in UART hold the values written to them
* (the values happen to be all distinct - this is good for
* avoiding false positive tests from bus echoes).
* o an output interrupt is generated and its vector is correct.
* o the interrupt goes away when the IIR in the UART is read.
*/
- outb(iobase + com_cfcr, CFCR_DLAB);
- outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
- outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
- outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
- outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
- outb(iobase + com_ier, 0); /* ensure edge on next intr */
- outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
- DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
- if ( inb(iobase + com_cfcr) != CFCR_8BITS
- || inb(iobase + com_ier) != IER_ETXRDY
- || inb(iobase + com_mcr) != MCR_IENABLE
-#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
- || !isa_irq_pending(dev)
-#endif
- || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
- || isa_irq_pending(dev)
- || !(inb(iobase + com_iir) & IIR_NOPEND))
- result = 0;
+ failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
+ failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
+ failures[2] = inb(iobase + com_mcr) - mcr_image;
+ if (idev->id_irq != 0)
+ failures[3] = isa_irq_pending(idev) ? 0 : 1;
+ failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
+ failures[5] = isa_irq_pending(idev) ? 1 : 0;
+ failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
/*
* Turn off all device interrupts and check that they go off properly.
- * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * Leave MCR_IENABLE alone. For ports without a master port, it gates
+ * the OUT2 output of the UART to
* the ICU input. Closing the gate would give a floating ICU input
* (unless there is another device driving at) and spurious interrupts.
* (On the system that this was first tested on, the input floats high
* and gives a (masked) interrupt as soon as the gate is closed.)
*/
outb(iobase + com_ier, 0);
- outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
- if ( inb(iobase + com_ier) != 0
- || isa_irq_pending(dev)
- || !(inb(iobase + com_iir) & IIR_NOPEND))
- result = 0;
- if (result == 0)
- outb(iobase + com_mcr, 0);
+ outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */
+ failures[7] = inb(iobase + com_ier);
+ failures[8] = isa_irq_pending(idev) ? 1 : 0;
+ failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
+ outb(IO_ICU1 + 1, imen); /* XXX */
enable_intr();
+
+ result = IO_COMSIZE;
+ for (fn = 0; fn < sizeof failures; ++fn)
+ if (failures[fn]) {
+ outb(iobase + com_mcr, 0);
+ result = 0;
+ if (COM_VERBOSE(dev))
+ printf("sio%d: probe test %d failed\n",
+ dev->id_unit, fn);
+ }
return (result);
}
@@ -403,9 +515,9 @@ sioattach(isdp)
iobase = isdp->id_iobase;
unit = isdp->id_unit;
- if (unit == comconsole)
- DELAY(1000); /* XXX */
- s = spltty();
+ com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
+ if (com == NULL)
+ return (0);
/*
* sioprobe() has initialized the device registers as follows:
@@ -414,15 +526,13 @@ sioattach(isdp)
* data port is not hidden when we enable interrupts.
* o ier = 0.
* Interrupts are only enabled when the line is open.
- * o mcr = MCR_IENABLE.
+ * o mcr = MCR_IENABLE, or 0 if the port has a master port.
* Keeping MCR_DTR and MCR_RTS off might stop the external
* device from sending before we are ready.
*/
-
- com = &com_structs[unit];
+ bzero(com, sizeof *com);
com->cfcr_image = CFCR_8BITS;
- com->mcr_image = MCR_IENABLE;
- com->dtr_wait = 200;
+ com->dtr_wait = 3 * hz;
com->tx_fifo_size = 1;
com->iptr = com->ibuf = com->ibuf1;
com->ibufend = com->ibuf1 + RS_IBUFSIZE;
@@ -431,9 +541,30 @@ sioattach(isdp)
com->data_port = iobase + com_data;
com->int_id_port = iobase + com_iir;
com->modem_ctl_port = iobase + com_mcr;
+ com->mcr_image = inb(com->modem_ctl_port);
com->line_status_port = iobase + com_lsr;
com->modem_status_port = iobase + com_msr;
- com->tp = &sio_tty[unit];
+
+ /*
+ * We don't use all the flags from <sys/ttydefaults.h> since they
+ * are only relevant for logins. It's important to have echo off
+ * initially so that the line doesn't start blathering before the
+ * echo flag can be turned off.
+ */
+ com->it_in.c_iflag = 0;
+ com->it_in.c_oflag = 0;
+ com->it_in.c_cflag = TTYDEF_CFLAG;
+ com->it_in.c_lflag = 0;
+ if (unit == comconsole) {
+ com->it_in.c_iflag = TTYDEF_IFLAG;
+ com->it_in.c_oflag = TTYDEF_OFLAG;
+ com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
+ com->it_in.c_lflag = TTYDEF_LFLAG;
+ com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
+ }
+ termioschars(&com->it_in);
+ com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
+ com->it_out = com->it_in;
/* attempt to determine UART type */
printf("sio%d: type", unit);
@@ -470,10 +601,11 @@ sioattach(isdp)
break;
case FIFO_TRIGGER_14:
printf(" 16550A");
- if (COM_NOFIFO(isdp)) {
- printf(" fifo software disabled");
- } else {
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
com->hasfifo = TRUE;
+ com->ftl_init = FIFO_TRIGGER_14;
com->tx_fifo_size = 16;
}
break;
@@ -483,31 +615,36 @@ determined_type: ;
#ifdef COM_MULTIPORT
if (COM_ISMULTIPORT(isdp)) {
- struct isa_device *masterdev;
-
com->multiport = TRUE;
- printf(" (multiport)");
-
- /* set the master's common-interrupt-enable reg.,
- * as appropriate. YYY See your manual
- */
- /* enable only common interrupt for port */
- outb(com->modem_ctl_port, com->mcr_image = 0);
-
- masterdev = find_isadev(isa_devtab_tty, &siodriver,
- COM_MPMASTER(isdp));
- outb(masterdev->id_iobase + com_scr, 0x80);
- } else
- com->multiport = FALSE;
+ printf(" (multiport");
+ if (unit == COM_MPMASTER(isdp))
+ printf(" master");
+ printf(")");
+ }
#endif /* COM_MULTIPORT */
printf("\n");
#ifdef KGDB
if (kgdb_dev == makedev(commajor, unit)) {
- if (comconsole == unit)
+ if (unit == comconsole)
kgdb_dev = -1; /* can't debug over console port */
else {
- cominit(unit, kgdb_rate);
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
if (kgdb_debug_init) {
/*
* Print prefix of device name,
@@ -521,16 +658,11 @@ determined_type: ;
}
#endif
- /*
- * Need to reset baud rate, etc. of next print so reset comconsinit.
- */
- if (unit == comconsole)
- comconsinit = FALSE;
-
+ s = spltty();
com_addr(unit) = com;
splx(s);
if (!comwakeup_started) {
- comwakeup((caddr_t) NULL, 0);
+ comwakeup((caddr_t)NULL, 0);
comwakeup_started = TRUE;
}
return (1);
@@ -544,207 +676,127 @@ sioopen(dev, flag, mode, p)
int mode;
struct proc *p;
{
-#ifdef COM_BIDIR
- bool_t callout;
-#endif /* COM_BIDIR */
struct com_s *com;
- int error = 0;
+ int error;
Port_t iobase;
+ int mynor;
int s;
struct tty *tp;
int unit;
- unit = UNIT(dev);
+ mynor = minor(dev);
+ unit = MINOR_TO_UNIT(mynor);
if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
return (ENXIO);
-#ifdef COM_BIDIR
- /* if it's a callout device, and bidir not possible on that dev, die */
- callout = CALLOUT(dev);
- if (callout && !(com->bidir))
- return (ENXIO);
-#endif /* COM_BIDIR */
-
- tp = com->tp;
+ if (mynor & CONTROL_MASK)
+ return (0);
+ tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
s = spltty();
-
-#ifdef COM_BIDIR
-
-bidir_open_top:
- /* if it's bidirectional, we've gotta deal with it... */
- if (com->bidir) {
- if (callout) {
- if (com->active_in) {
- /* it's busy. die */
- splx(s);
- return (EBUSY);
- } else {
- /* it's ours. lock it down, and set it up */
- com->active_out = TRUE;
+ /*
+ * We jump to this label after all non-interrupted sleeps to pick
+ * up any changes of the device state.
+ */
+open_top:
+ while (com->state & CS_DTR_OFF) {
+ error = tsleep((caddr_t)&com->dtr_wait, TTIPRI | PCATCH,
+ "siodtr", 0);
+ if (error != 0)
+ goto out;
+ }
+ if (tp->t_state & TS_ISOPEN) {
+ /*
+ * The device is open, so everything has been initialized.
+ * Handle conflicts.
+ */
+ if (mynor & CALLOUT_MASK) {
+ if (!com->active_out) {
+ error = EBUSY;
+ goto out;
}
} else {
if (com->active_out) {
- /* it's busy, outgoing. wait, if possible */
if (flag & O_NONBLOCK) {
- /* can't wait; bail */
- splx(s);
- return (EBUSY);
- } else {
- /* wait for it... */
- error = tsleep((caddr_t)&com->active_out,
- TTIPRI|PCATCH,
- "siooth",
- 0);
- /* if there was an error, take off. */
- if (error != 0) {
- splx(s);
- return (error);
- }
- /* else take it from the top */
- goto bidir_open_top;
- }
- } else if (com->prev_modem_status & MSR_DCD
- || FAKE_DCD(unit)) {
- /* there's a carrier on the line; we win */
- com->active_in = TRUE;
- } else {
- /* there is no carrier on the line */
- if (flag & O_NONBLOCK) {
- /* can't wait; let it open */
- com->active_in = TRUE;
- } else {
- /* put DTR & RTS up */
- /* XXX - bring up RTS earlier? */
- commctl(com, MCR_DTR | MCR_RTS, DMSET);
- outb(com->iobase + com_ier, IER_EMSC);
-
- /* wait for it... */
- error = tsleep((caddr_t)&com->active_in,
- TTIPRI|PCATCH,
- "siodcd",
- 0);
-
- /* if not active, turn intrs and DTR off */
- if (!com->active) {
- outb(com->iobase + com_ier, 0);
- commctl(com, MCR_DTR, DMBIC);
- }
-
- /* if there was an error, take off. */
- if (error != 0) {
- splx(s);
- return (error);
- }
- /* else take it from the top */
- goto bidir_open_top;
+ error = EBUSY;
+ goto out;
}
+ error = tsleep((caddr_t)&com->active_out,
+ TTIPRI | PCATCH, "siobi", 0);
+ if (error != 0)
+ goto out;
+ goto open_top;
}
}
- }
-
- com->active = TRUE;
-#endif /* COM_BIDIR */
-
- tp->t_oproc = comstart;
- tp->t_param = comparam;
- tp->t_dev = dev;
- if (!(tp->t_state & TS_ISOPEN)) {
- tp->t_state |= TS_WOPEN;
- ttychars(tp);
- if (tp->t_ispeed == 0) {
- /*
- * We no longer use the flags from <sys/ttydefaults.h>
- * since those are only relevant for logins. It's
- * important to have echo off initially so that the
- * line doesn't start blathering before the echo flag
- * can be turned off.
- */
- tp->t_iflag = 0;
- tp->t_oflag = 0;
-#ifdef COMCONSOLE
- if (unit == comconsole)
- tp->t_oflag = TTYDEF_OFLAG;
-#endif
- tp->t_cflag = CREAD | CS8 | HUPCL;
- tp->t_lflag = 0;
- tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ error = EBUSY;
+ goto out;
}
-
+ } else {
/*
- * XXX the full state after a first open() needs to be
- * programmable and separate for callin and callout.
+ * The device isn't open, so there are no conflicts.
+ * Initialize it. Initialization is done twice in many
+ * cases: to preempt sleeping callin opens if we are
+ * callout, and to complete a callin open after DCD rises.
*/
-#ifdef COM_BIDIR
- if (com->bidir) {
- if (callout)
- tp->t_cflag |= CLOCAL;
- else
- tp->t_cflag &= ~CLOCAL;
- }
-#endif
-
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ tp->t_termios = mynor & CALLOUT_MASK
+ ? com->it_out : com->it_in;
commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ com->ftl_max = com->ftl_init;
+ ++com->wopeners;
error = comparam(tp, &tp->t_termios);
+ --com->wopeners;
if (error != 0)
goto out;
+ /*
+ * XXX we should goto open_top if comparam() slept.
+ */
ttsetwater(tp);
iobase = com->i