diff -u --recursive --new-file v1.1.21/linux/Makefile linux/Makefile --- v1.1.21/linux/Makefile Wed Jun 22 14:57:07 1994 +++ linux/Makefile Wed Jun 22 14:16:27 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 21 +SUBLEVEL = 22 all: Version zImage diff -u --recursive --new-file v1.1.21/linux/config.in linux/config.in --- v1.1.21/linux/config.in Wed Jun 22 14:57:07 1994 +++ linux/config.in Thu Jun 23 22:43:37 1994 @@ -70,10 +70,10 @@ bool 'Network device support?' CONFIG_NETDEVICES y if [ "$CONFIG_NETDEVICES" = "n" ]; then -comment 'Skipping ethercard configuration options...' +comment 'Skipping network driver configuration options...' else -bool 'Dummy net driver support' CONFIG_DUMMY y +bool 'Dummy net driver support' CONFIG_DUMMY n bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' SL_COMPRESSED y @@ -81,29 +81,49 @@ fi bool 'PPP (point-to-point) support' CONFIG_PPP n bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n +bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n +bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n +if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then + bool 'WD80*3 support' CONFIG_WD80x3 n + bool 'SMC Ultra support' CONFIG_ULTRA n +fi +bool '3COM cards' CONFIG_NET_VENDOR_3COM y +if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then + bool '3c501 support' CONFIG_EL1 n + bool '3c503 support' CONFIG_EL2 n + if [ "$CONFIG_NET_ALPHA" = "y" ]; then + bool '3c505 support' CONFIG_ELPLUS n + bool '3c507 support' CONFIG_EL16 n + fi + bool '3c509/3c579 support' CONFIG_EL3 y +fi +bool 'Other ISA cards' CONFIG_NET_ISA n +if [ "$CONFIG_NET_ISA" = "y" ]; then + bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE y + bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n + bool 'DEPCA support' CONFIG_DEPCA n + if [ "$CONFIG_NET_ALPHA" = "y" ]; then + bool 'EtherExpress support' CONFIG_EEXPRESS n + fi + bool 'HP PCLAN support' CONFIG_HPLAN n + bool 'NE2000/NE1000 support' CONFIG_NE2000 n +fi bool 'PLIP (parallel port) support' CONFIG_PLIP n -bool 'NE2000/NE1000 support' CONFIG_NE2000 n -bool 'WD80*3 support' CONFIG_WD80x3 n -bool 'SMC Ultra support' CONFIG_ULTRA n -bool '3c501 support' CONFIG_EL1 n -bool '3c503 support' CONFIG_EL2 n -#bool '3c505 support' CONFIG_ELPLUS n -#bool '3c507 support' CONFIG_EL16 n -bool '3c509/3c579 support' CONFIG_EL3 y -bool 'HP PCLAN support' CONFIG_HPLAN n -bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n -bool 'AT1700 support' CONFIG_AT1700 n -#bool 'Zenith Z-Note support' CONFIG_ZNET n -#bool 'EtherExpress support' CONFIG_EEXPRESS n -#bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n -bool 'DEPCA support' CONFIG_DEPCA n +bool 'EISA and on board controllers' CONFIG_NET_EISA n + if [ "$CONFIG_NET_ALPHA" = "y" ]; then + bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n + bool 'AT1700 support' CONFIG_AT1700 n + fi + bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n #bool 'NI52EE support' CONFIG_NI52 n #bool 'NI65EE support' CONFIG_NI65 n -#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n -#bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n -bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n -bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n -bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n +bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n +if [ "$CONFIG_NET_POCKET" = "y" ]; then + bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n + bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n + bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n + bool 'Zenith Z-Note support' CONFIG_ZNET n +fi fi fi diff -u --recursive --new-file v1.1.21/linux/drivers/block/hd.c linux/drivers/block/hd.c --- v1.1.21/linux/drivers/block/hd.c Wed Jun 22 14:57:07 1994 +++ linux/drivers/block/hd.c Thu Jun 23 23:09:19 1994 @@ -655,8 +655,10 @@ hd_info[drive].ctl = *(8+BIOS); hd_info[drive].lzone = *(unsigned short *) (12+BIOS); hd_info[drive].sect = *(14+BIOS); +#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp if (hd_info[drive].cyl && NR_HD == drive) NR_HD++; +#endif BIOS += 16; } diff -u --recursive --new-file v1.1.21/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.1.21/linux/drivers/char/console.c Tue May 24 00:34:47 1994 +++ linux/drivers/char/console.c Wed Jun 22 14:18:28 1994 @@ -133,6 +133,8 @@ /* mode flags */ unsigned long vc_charset : 1; /* Character set G0 / G1 */ unsigned long vc_s_charset : 1; /* Saved character set */ + unsigned long vc_disp_ctrl : 1; /* Display chars < 32? */ + unsigned long vc_toggle_meta : 1; /* Toggle high bit? */ unsigned long vc_decscnm : 1; /* Screen Mode */ unsigned long vc_decom : 1; /* Origin Mode */ unsigned long vc_decawm : 1; /* Autowrap Mode */ @@ -185,6 +187,8 @@ #define video_mem_start (vc_cons[currcons].vc_video_mem_start) #define video_mem_end (vc_cons[currcons].vc_video_mem_end) #define video_erase_char (vc_cons[currcons].vc_video_erase_char) +#define disp_ctrl (vc_cons[currcons].vc_disp_ctrl) +#define toggle_meta (vc_cons[currcons].vc_toggle_meta) #define decscnm (vc_cons[currcons].vc_decscnm) #define decom (vc_cons[currcons].vc_decom) #define decawm (vc_cons[currcons].vc_decawm) @@ -682,6 +686,33 @@ case 7: reverse = 1; break; + case 10: /* ANSI X3.64-1979 (SCO-ish?) + * Select primary font, don't display + * control chars if defined, don't set + * bit 8 on output. + */ + translate = (charset == 0 + ? G0_charset + : G1_charset); + disp_ctrl = 0; + toggle_meta = 0; + break; + case 11: /* ANSI X3.64-1979 (SCO-ish?) + * Select first alternate font, let's + * chars < 32 be displayed as ROM chars. + */ + translate = NULL_TRANS; + disp_ctrl = 1; + toggle_meta = 0; + break; + case 12: /* ANSI X3.64-1979 (SCO-ish?) + * Select second alternate font, toggle + * high bit before displaying as ROM char. + */ + translate = NULL_TRANS; + disp_ctrl = 1; + toggle_meta = 1; + break; case 21: case 22: intensity = 1; @@ -695,8 +726,21 @@ case 27: reverse = 0; break; - case 39: + case 38: /* ANSI X3.64-1979 (SCO-ish?) + * Enables underscore, white foreground + * with white underscore (Linux - use + * default foreground). + */ + color = (def_color & 0x0f) | background; + underline = 1; + break; + case 39: /* ANSI X3.64-1979 (SCO-ish?) + * Disable underline option. + * Reset colour to default? It did this + * before... + */ color = (def_color & 0x0f) | background; + underline = 0; break; case 49: color = (def_color & 0xf0) | foreground; @@ -957,6 +1001,9 @@ charset = 0; need_wrap = 0; + disp_ctrl = 0; + toggle_meta = 0; + decscnm = 0; decom = 0; decawm = 1; @@ -1026,7 +1073,11 @@ while (!tty->stopped && count) { c = from_user ? get_fs_byte(buf) : *buf; buf++; n++; count--; - if (vc_state == ESnormal && translate[c]) { + if (vc_state == ESnormal + && (c >= 32 || (disp_ctrl && (c&0x7f) != 27)) + && (toggle_meta ? translate[c|0x80] : translate[c])) { + if (toggle_meta) + c |= 0x80; if (need_wrap) { cr(currcons); lf(currcons); diff -u --recursive --new-file v1.1.21/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v1.1.21/linux/drivers/net/3c505.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/3c505.c Thu Jun 23 12:07:41 1994 @@ -0,0 +1,941 @@ +/* + * Linux ethernet device driver for the 3Com Etherlink Plus (3C505) + * By Craig Southeren + * + * 3c505.c This module implements an interface to the 3Com + * Etherlink Plus (3c505) ethernet card. Linux device + * driver interface reverse engineered from the Linux 3C509 + * device drivers. Vital 3C505 information gleaned from + * the Crynwr packet driver + * + * Version: @(#)3c505.c 0.1 23/09/93 + * + * Authors: Linux 3c505 device driver by: + * Craig Southeren, + * Linux 3C509 driver by: + * Donald Becker, + * Crynwr packet driver by + * Krishnan Gopalan and Gregg Stefancik, + * Clemson Univesity Engineering Computer Operations. + * Portions of the code have been adapted from the 3c505 + * driver for NCSA Telnet by Bruce Orchard and later + * modified by Warren Van Houten and krus@diku.dk. + * 3C505 technical information provided by + * Terry Murphy, of 3Com Network Adapter Division + * Special thanks to Juha Laiho, + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef port_read +#include "iow.h" +#endif + +#include +#include +#include + +#include "3c505.h" + +#ifdef ELP_DEBUG +static int elp_debug = ELP_DEBUG; +#else +static int elp_debug = 0; +#endif + +/* + * 0 = no messages + * 1 = messages when high level commands performed + * 2 = messages when low level commands performed + * 3 = messages when interrupts received + */ + +#define ELP_VERSION "0.1.0" + +extern struct device *irq2dev_map[16]; + +/***************************************************************** + * + * useful macros + * + *****************************************************************/ + +#define INB(port) inb((unsigned short)port) +#define OUTB(val,port) outb((unsigned char)val,(unsigned short)port); + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/***************************************************************** + * + * PCB structure + * + *****************************************************************/ + +typedef struct { + unsigned char command; /* PCB command code */ + unsigned char length; /* PCB data length */ + unsigned char data[MAX_PCB_DATA]; /* PCB data */ +} pcb_struct; + + +/***************************************************************** + * + * structure to hold context information for adapter + * + *****************************************************************/ + +typedef struct { + int io_addr; /* base I/O address */ + short got_configure; /* set to TRUE when configure response received */ + pcb_struct tx_pcb; /* PCB for foreground sending */ + pcb_struct rx_pcb; /* PCB for foreground receiving */ + pcb_struct itx_pcb; /* PCB for background sending */ + pcb_struct irx_pcb; /* PCB for background receiving */ + struct enet_statistics stats; +} elp_device; + +/***************************************************************** + * + * useful functions for accessing the adapter + * + *****************************************************************/ + +/* + * use this routine when accessing the ASF bits as they are + * changed asynchronously by the adapter + */ + +/* get adapter PCB status */ +#define GET_ASF() (get_status(adapter)&ASF_PCB_MASK) +#define GET_STATUS() (get_status(adapter)) + +static int get_status (elp_device * adapter) + +{ + register int stat1; + do { + stat1 = INB(adapter->io_addr+PORT_STATUS); + } while (stat1 != INB(adapter->io_addr+PORT_STATUS)); + return stat1; +} + +#define SET_HSF(hsf) (set_hsf(adapter,hsf)) + +static void set_hsf (elp_device * adapter, int hsf) + +{ + cli(); + OUTB((INB(adapter->io_addr+PORT_CONTROL)&(~HSF_PCB_MASK))|hsf, adapter->io_addr+PORT_CONTROL); + sti(); +} + +#define WAIT_HCRE(toval) (wait_hcre(adapter,toval)) + +static int wait_hcre(elp_device * adapter, int toval) + +{ + int timeout = jiffies + toval; + while(((INB(adapter->io_addr+PORT_STATUS)&STATUS_HCRE)==0) && + (jiffies <= timeout)) + ; + if (jiffies > timeout) { + printk("elp0: timeout waiting for HCRE\n"); + return FALSE; + } + return TRUE; +} + +/***************************************************************** + * + * send_pcb + * Send a PCB to the adapter. + * + * output byte to command reg --<--+ + * wait until HCRE is non zero | + * loop until all bytes sent -->--+ + * set HSF1 and HSF2 to 1 + * output pcb length + * wait until ASF give ACK or NAK + * set HSF1 and HSF2 to 0 + * + *****************************************************************/ + +static int send_pcb(elp_device * adapter, pcb_struct * pcb) + +{ + int i; + int cont; + int retry = 0; + int timeout; + + while (1) { + + cont = 1; + + /* + * load each byte into the command register and + * wait for the HCRE bit to indicate the adapter + * had read the byte + */ + SET_HSF(0); + OUTB(pcb->command, (adapter->io_addr)+PORT_COMMAND); + cont = WAIT_HCRE(5); + /* SET_HSF(0); */ + + if (cont) { + OUTB(pcb->length, (adapter->io_addr)+PORT_COMMAND); + cont = WAIT_HCRE(2); + } + + for (i = 0; cont && (i < pcb->length); i++) { + OUTB(pcb->data[i], (adapter->io_addr)+PORT_COMMAND); + cont = WAIT_HCRE(2); + } + + /* set the host status bits to indicate end of PCB */ + /* send the total packet length as well */ + /* wait for the adapter to indicate that it has read the PCB */ + if (cont) { + SET_HSF(HSF_PCB_END); + OUTB(2+pcb->length, adapter->io_addr+PORT_COMMAND); + timeout = jiffies + 6; + while (jiffies < timeout) { + i = GET_ASF(); + if ((i == ASF_PCB_ACK) || + (i == ASF_PCB_NAK)) + break; + } + if (i == ASF_PCB_ACK) { + SET_HSF(0); + return TRUE; + } else if (i = ASF_PCB_NAK) { + SET_HSF(0); + printk("elp0: PCB send was NAKed\n"); + { + int to = jiffies + 5; + while (jiffies < to) + ; + } + } + } + + if (elp_debug >= 6) + printk("elp0: NAK/timeout on send PCB\n"); + if ((retry++ & 7) == 0) + printk("elp0: retry #%i on send PCB\n", retry); + } +} + +/***************************************************************** + * + * receive_pcb + * Read a PCB to the adapter + * + * wait for ACRF to be non-zero ---<---+ + * input a byte | + * if ASF1 and ASF2 were not both one | + * before byte was read, loop --->---+ + * set HSF1 and HSF2 for ack + * + *****************************************************************/ + +static int receive_pcb(elp_device * adapter, pcb_struct * pcb) + +{ + int i; + int total_length; + int stat; + + /* get the command code */ + while (((stat = GET_STATUS())&STATUS_ACRF) == 0) + ; + SET_HSF(0); + pcb->command = INB(adapter->io_addr+PORT_COMMAND); + if ((stat & ASF_PCB_MASK) != ASF_PCB_END) { + + /* read the data length */ + while (((stat = GET_STATUS())&STATUS_ACRF) == 0) + ; + pcb->length = INB(adapter->io_addr+PORT_COMMAND); + if ((stat & ASF_PCB_MASK) != ASF_PCB_END) { + + /* read the data */ + i = 0; + do { + while (((stat = GET_STATUS())&STATUS_ACRF) == 0) + ; + pcb->data[i++] = INB(adapter->io_addr+PORT_COMMAND); + } while ((stat & ASF_PCB_MASK) != ASF_PCB_END); + + /* woops, the last "data" byte was really the length! */ + total_length = pcb->data[--i]; + + /* safety check total length vs data length */ + if (total_length != (pcb->length + 2)) { + if (elp_debug >= 6) + printk("elp0: mangled PCB received\n"); + SET_HSF(HSF_PCB_NAK); + return FALSE; + } + SET_HSF(HSF_PCB_ACK); + return TRUE; + } + } + + SET_HSF(HSF_PCB_NAK); + return FALSE; +} + +static void adapter_hard_reset(elp_device * adapter) + +{ + int timeout; + + /* + * take FLSH and ATTN high + */ + OUTB(CONTROL_ATTN|CONTROL_FLSH, adapter->io_addr+PORT_CONTROL); + + /* + * wait for a little bit + */ + for (timeout = jiffies + 20; jiffies <= timeout; ) + ; + + /* + * now take them low + */ + OUTB(0, adapter->io_addr+PORT_CONTROL); + + /* + * wait for a little bit + */ + for (timeout = jiffies + 20; jiffies <= timeout; ) + ; + + /* + * now hang around until the board gets it's act together + */ + for (timeout = jiffies + (100 * 15); jiffies <= timeout; ) + if (GET_ASF() != ASF_PCB_END) + break; +} + +static void adapter_reset(elp_device * adapter) + +{ + int timeout; + + cli(); + OUTB(CONTROL_ATTN|INB(adapter->io_addr+PORT_CONTROL), adapter->io_addr+PORT_CONTROL); + sti(); + + /* + * wait for a little bit + */ + for (timeout = jiffies + 20; jiffies <= timeout; ) + ; + + cli(); + OUTB(INB(adapter->io_addr+PORT_CONTROL)&~(CONTROL_ATTN), adapter->io_addr+PORT_CONTROL); + sti(); +} + +/****************************************************** + * + * queue a receive command on the adapter so we will get an + * interrupt when a packet is received. + * + ******************************************************/ + +static int start_receive(elp_device * adapter, pcb_struct * tx_pcb) + +{ + if (elp_debug > 3) + printk("elp0: restarting receiver\n"); + tx_pcb->command = CMD_RECEIVE_PACKET; + tx_pcb->length = 8; + tx_pcb->data[4] = 1600 & 0xff; + tx_pcb->data[5] = 1600 >> 8; + tx_pcb->data[6] = 0; /* set timeout to zero */ + tx_pcb->data[7] = 0; + return send_pcb(adapter, tx_pcb); +} + +/****************************************************** + * + * extract a packet from the adapter + * this routine is only called from within the interrupt + * service routine, so no cli/sti calls are needed + * note that the length is always assumed to be even + * + ******************************************************/ + +static void receive_packet(struct device * dev, + elp_device * adapter, + int len) + +{ + register int i; + unsigned short * ptr; + short d; + + /* + * allocate a buffer to put the packet into. + */ + struct sk_buff *skb; + skb = alloc_skb(len+3, GFP_ATOMIC); + + /* + * make sure the data register is going the right way + */ + OUTB(INB(adapter->io_addr+PORT_CONTROL)|CONTROL_DIR, adapter->io_addr+PORT_CONTROL); + + /* + * if buffer could not be allocated, swallow it + */ + if (skb == NULL) { + for (i = 0; i < (len/2); i++) { + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) + ; + d = inw(adapter->io_addr+PORT_DATA); + } + adapter->stats.rx_dropped++; + + } else { + + /* + * now read the data from the adapter + */ + ptr = (unsigned short *)(skb->data); + for (i = 0; i < (len/2); i++) { + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) { + ; + } + *ptr = inw(adapter->io_addr+PORT_DATA); + ptr++; + } + + /* + * the magic routine "dev_rint" passes the packet up the + * protocol chain. If it returns 0, we can assume the packet was + * swallowed up. If not, then we are responsible for freeing memory + */ + if (dev_rint((unsigned char *)skb, len, IN_SKBUFF, dev) != 0) { + printk("%s: receive buffers full.\n", dev->name); + kfree_skb(skb, FREE_READ); + } + } + + OUTB(INB(adapter->io_addr+PORT_CONTROL)&(~CONTROL_DIR), adapter->io_addr+PORT_CONTROL); +} + + +/****************************************************** + * + * interrupt handler + * + ******************************************************/ + +static void elp_interrupt(int reg_ptr) + +{ + int len; + int dlen; + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev; + elp_device * adapter; + + if (irq < 0 || irq > 15) { + printk ("elp0: illegal IRQ number found in interrupt routine (%i)\n", irq); + return; + } + + if (irq != 0xc) { + printk ("elp0: warning - interrupt routine has incorrect IRQ of %i\n", irq); + return; + } + + dev = irq2dev_map[irq]; + adapter = (elp_device *) dev->priv; + + if (dev == NULL) { + printk ("elp_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + if (dev->interrupt) + if (elp_debug >= 3) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + /* + * allow interrupts (we need timers!) + */ + sti(); + + /* + * receive a PCB from the adapter + */ + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) { + + if (receive_pcb(adapter, &adapter->irx_pcb)) { + + switch (adapter->irx_pcb.command) { + + /* + * 82586 configured correctly + */ + case CMD_CONFIGURE_82586_RESPONSE: + adapter->got_configure = 1; + if (elp_debug >= 3) + printk("%s: interrupt - configure response received\n", dev->name); + break; + + /* + * received a packet + */ + case CMD_RECEIVE_PACKET_COMPLETE: + len = adapter->irx_pcb.data[6] + (adapter->irx_pcb.data[7] << 8); + dlen = adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8); + if (adapter->irx_pcb.data[8] != 0) { + printk("%s: interrupt - packet not received correctly\n", dev->name); + } else { + if (elp_debug >= 3) + printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen); + receive_packet(dev, adapter, dlen); + if (elp_debug >= 3) + printk("%s: packet received\n", dev->name); + adapter->stats.rx_packets++; + } + if (dev->start && !start_receive(adapter, &adapter->itx_pcb)) + if (elp_debug >= 2) + printk("%s: interrupt - failed to send receive start PCB\n", dev->name); + if (elp_debug >= 3) + printk("%s: receive procedure complete\n", dev->name); + + break; + + /* + * sent a packet + */ + case CMD_TRANSMIT_PACKET_COMPLETE: + if (elp_debug >= 3) + printk("%s: interrupt - packet sent\n", dev->name); + if (adapter->irx_pcb.data[4] != 0) + if (elp_debug >= 2) + printk("%s: interrupt - error sending packet %4.4x\n", dev->name, + adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8)); + dev->tbusy = 0; + mark_bh(INET_BH); + adapter->stats.tx_packets++; + break; + + /* + * some unknown PCB + */ + default: + printk("%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command); + break; + } + } else + printk("%s: failed to read PCB on interrupt\n", dev->name); + } + + /* + * indicate no longer in interrupt routine + */ + dev->interrupt = 0; +} + + +/****************************************************** + * + * open the board + * + ******************************************************/ + +static int elp_open (struct device *dev) + +{ + elp_device * adapter = (elp_device *) dev->priv; + + if (elp_debug >= 1) + printk("%s: request to open device\n", dev->name); + + /* + * make sure we actually found the device + */ + if (adapter == NULL) { + printk("%s: Opening a non-existent physical device\n", dev->name); + return -EAGAIN; + } + + /* + * interrupt routine not entered + */ + dev->interrupt = 0; + + /* + * transmitter not busy + */ + dev->tbusy = 0; + + /* + * install our interrupt service routine + */ + if (request_irq(dev->irq, &elp_interrupt)) + return -EAGAIN; + + /* + * make sure we can find the device header given the interrupt number + */ + irq2dev_map[dev->irq] = dev; + + /* + * enable interrupts on the board + */ + OUTB(CONTROL_CMDE, adapter->io_addr+PORT_CONTROL); + + /* + * device is now offically open! + */ + dev->start = 1; + + /* + * configure adapter to receive broadcast messages and wait for response + */ + if (elp_debug >= 2) + printk("%s: sending 82586 configure command\n", dev->name); + adapter->tx_pcb.command = CMD_CONFIGURE_82586; + adapter->tx_pcb.data[0] = 1; + adapter->tx_pcb.data[1] = 0; + adapter->tx_pcb.length = 2; + adapter->got_configure = 0; + if (!send_pcb(adapter, &adapter->tx_pcb)) + printk("%s: couldn't send 82586 configure command\n", dev->name); + else + while (adapter->got_configure == 0) + ; + + /* + * queue a receive command to start things rolling + */ + if (!start_receive(adapter, &adapter->tx_pcb)) + printk("%s: start receive command failed \n", dev->name); + if (elp_debug >= 2) + printk("%s: start receive command sent\n", dev->name); + + return 0; /* Always succeed */ +} + +/****************************************************** + * + * close the board + * + ******************************************************/ + +static int elp_close (struct device *dev) + +{ + elp_device * adapter = (elp_device *) dev->priv; + + if (elp_debug >= 1) + printk("%s: request to close device\n", dev->name); + + /* + * disable interrupts on the board + */ + OUTB(0x00, adapter->io_addr+PORT_CONTROL); + + /* + * flag transmitter as busy (i.e. not available) + */ + dev->tbusy = 1; + + /* + * indicate device is closed + */ + dev->start = 0; + + /* + * release the IRQ + */ + free_irq(dev->irq); + + /* + * and we no longer have to map irq to dev either + */ + irq2dev_map[dev->irq] = 0; + + return 0; +} + + +/****************************************************** + * + * send a packet to the adapter + * + ******************************************************/ + +static int send_packet (elp_device * adapter, unsigned char * ptr, int len) + +{ + int i; + + /* + * make sure the length is even and no shorter than 60 bytes + */ + unsigned int nlen = (((len < 60) ? 60 : len) + 1) & (~1); + + /* + * send the adapter a transmit packet command. Ignore segment and offset + * and make sure the length is even + */ + adapter->tx_pcb.command = CMD_TRANSMIT_PACKET; + adapter->tx_pcb.length = 6; + adapter->tx_pcb.data[4] = nlen & 0xff; + adapter->tx_pcb.data[5] = nlen >> 8; + if (!send_pcb(adapter, &adapter->tx_pcb)) + return FALSE; + + /* + * make sure the data register is going the right way + */ + cli(); + OUTB(INB(adapter->io_addr+PORT_CONTROL)&(~CONTROL_DIR), adapter->io_addr+PORT_CONTROL); + sti(); + + /* + * write data to the adapter + */ + for (i = 0; i < (nlen/2);i++) { + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) + ; + outw(*(short *)ptr, adapter->io_addr+PORT_DATA); + ptr +=2; + } + + return TRUE; +} + +/****************************************************** + * + * start the transmitter + * return 0 if sent OK, else return 1 + * + ******************************************************/ + +static int elp_start_xmit(struct sk_buff *skb, struct device *dev) + +{ + elp_device * adapter = (elp_device *) dev->priv; + + /* + * not sure what this does, but the 3c609 driver does it, so... + */ + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* + * if we ended up with a munged length, don't send it + */ + if (skb->len <= 0) + return 0; + + if (elp_debug >= 1) + printk("%s: request to send packet of length %i\n", dev->name, skb->len); + + /* + * if the transmitter is still busy, we have a transmit timeout... + */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 500) + return 1; + printk("%s: transmit timed out, resetting adapter\n", dev->name); + if ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) + printk("%s: hmmm...seemed to have missed an interrupt!\n", dev->name); + adapter_reset(adapter); + dev->trans_start = jiffies; + dev->tbusy = 0; + } + + /* + * send the packet at (void *)(skb+1) for skb->len + */ + if (!send_packet(adapter, (unsigned char *)(skb->data), skb->len)) { + printk("%s: send packet PCB failed\n", dev->name); + return 1; + } + + if (elp_debug >= 2) + printk("%s: packet of length %i sent\n", dev->name, skb->len); + + + /* + * start the transmit timeout + */ + dev->trans_start = jiffies; + + /* + * the transmitter is now busy + */ + dev->tbusy = 1; + + /* + * if we have been asked to free the buffer, do so + */ + dev_kfree_skb(skb, FREE_WRITE); + + return 0; +} + +/****************************************************** + * + * return statistics on the board + * + ******************************************************/ + +static struct enet_statistics * elp_get_stats(struct device *dev) + +{ + if (elp_debug >= 1) + printk("%s: request for stats\n", dev->name); + + elp_device * adapter = (elp_device *) dev->priv; + return &adapter->stats; +} + +/****************************************************** + * + * initialise Etherlink Pus board + * + ******************************************************/ + +static void elp_init(struct device *dev) + +{ + int i; + elp_device * adapter; + + /* + * NULL out buffer pointers + */ + for (i = 0; i < DEV_NUMBUFFS; i++) + dev->buffs[i] = NULL; + + /* + * set ptrs to various functions + */ + dev->open = elp_open; /* local */ + dev->stop = elp_close; /* local */ + dev->get_stats = elp_get_stats; /* local */ + dev->hard_start_xmit = elp_start_xmit; /* local */ + + dev->hard_header = eth_header; /* eth.c */ + dev->add_arp = eth_add_arp; /* eth.c */ + dev->rebuild_header = eth_rebuild_header; /* eth.c */ + dev->type_trans = eth_type_trans; /* eth.c */ + + dev->queue_xmit = dev_queue_xmit; /* dev.c */ + + /* + * setup ptr to adapter specific information + */ + adapter = (elp_device *)(dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL)); + adapter->io_addr = dev->base_addr; + memset(&(adapter->stats), 0, sizeof(struct enet_statistics)); + + + /* + * Ethernet information + */ + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 1500; /* eth_mtu */ + dev->addr_len = ETH_ALEN; + for (i = 0; i < dev->addr_len; i++) + dev->broadcast[i] = 0xff; + + /* + * New-style flags. + */ + dev->flags = IFF_BROADCAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = sizeof(unsigned long); + + /* + * memory information + */ + dev->mem_start = dev->mem_end = dev->rmem_end = dev->mem_start = 0; +} + + +/****************************************************** + * + * probe for an Etherlink Plus board at the specified address + * by attempting to get the ethernet address. + * + ******************************************************/ + +int elp_probe(struct device *dev) + +{ + elp_device adapter; + int i; + + /* + * setup adapter structure + */ + adapter.io_addr = dev->base_addr; + + printk ("%s: probing for 3c505...", dev->name); + + /* + * get the adapter's undivided attention (if it's there!) + */ + adapter_hard_reset(&adapter); + + /* + * use ethernet address command to probe for board in polled mode + */ + adapter.tx_pcb.command = CMD_STATION_ADDRESS; + adapter.tx_pcb.length = 0; + if (!send_pcb (&adapter, &adapter.tx_pcb) || + !receive_pcb(&adapter, &adapter.rx_pcb) || + (adapter.rx_pcb.command != CMD_ADDRESS_RESPONSE) || + (adapter.rx_pcb.length != 6)) { + printk("not found\n"); + return -ENODEV; + } + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = adapter.rx_pcb.data[i]; + + printk("found at port 0x%x, address = %s\n", dev->base_addr, eth_print(dev->dev_addr)); + + elp_init(dev); + return 0; +} + diff -u --recursive --new-file v1.1.21/linux/drivers/net/3c505.h linux/drivers/net/3c505.h --- v1.1.21/linux/drivers/net/3c505.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/3c505.h Wed Jun 22 17:30:14 1994 @@ -0,0 +1,124 @@ +/***************************************************************** + * + * defines for 3Com Etherlink Plus adapter + * + *****************************************************************/ + +/* + * I/O register offsets + */ +#define PORT_COMMAND 0x00 /* read/write */ +#define PORT_STATUS 0x02 /* read only */ +#define PORT_AUXDMA 0x02 /* write only */ +#define PORT_DATA 0x04 /* read/write */ +#define PORT_CONTROL 0x06 /* read/write */ + +/* + * host control registers bits + */ +#define CONTROL_ATTN 0x80 /* attention */ +#define CONTROL_FLSH 0x40 /* flush data register */ +#define CONTROL_DMAE 0x20 /* DMA enable */ +#define CONTROL_DIR 0x10 /* direction */ +#define CONTROL_TCEN 0x08 /* terminal count interrupt enable */ +#define CONTROL_CMDE 0x04 /* command register interrupt enable */ +#define CONTROL_HSF2 0x02 /* host status flag 2 */ +#define CONTROL_HSF1 0x01 /* host status flag 1 */ + +/* + * combinations of HSF flags used for PCB transmission + */ +#define HSF_PCB_ACK (CONTROL_HSF1) +#define HSF_PCB_NAK (CONTROL_HSF2) +#define HSF_PCB_END (CONTROL_HSF2|CONTROL_HSF1) +#define HSF_PCB_MASK (CONTROL_HSF2|CONTROL_HSF1) + +/* + * host status register bits + */ +#define STATUS_HRDY 0x80 /* data register ready */ +#define STATUS_HCRE 0x40 /* command register empty */ +#define STATUS_ACRF 0x20 /* adapter command register full */ +#define STATUS_DIR 0x10 /* direction */ +#define STATUS_DONE 0x08 /* DMA done */ +#define STATUS_ASF3 0x04 /* adapter status flag 3 */ +#define STATUS_ASF2 0x02 /* adapter status flag 2 */ +#define STATUS_ASF1 0x01 /* adapter status flag 1 */ + +/* + * combinations of ASF flags used for PCB reception + */ +#define ASF_PCB_ACK (STATUS_ASF1) +#define ASF_PCB_NAK (STATUS_ASF2) +#define ASF_PCB_END (STATUS_ASF2|STATUS_ASF1) +#define ASF_PCB_MASK (STATUS_ASF2|STATUS_ASF1) + +/* + * host aux DMA register bits + */ +#define AUXDMA_BRST 0x01 /* DMA burst */ + +/* + * maximum amount of data data allowed in a PCB + */ +#define MAX_PCB_DATA 62 + +/***************************************************************** + * + * timeout value + * this is a rough value used for loops to stop them from + * locking up the whole machine in the case of failure or + * error conditions + * + *****************************************************************/ + +#define TIMEOUT 10000 + +/***************************************************************** + * + * PCB commands + * + *****************************************************************/ + +enum { + /* + * host PCB commands + */ + CMD_CONFIGURE_ADAPTER_MEMORY = 0x01, + CMD_CONFIGURE_82586 = 0x02, + CMD_STATION_ADDRESS = 0x03, + CMD_DMA_DOWNLOAD = 0x04, + CMD_DMA_UPLOAD = 0x05, + CMD_PIO_DOWNLOAD = 0x06, + CMD_PIO_UPLOAD = 0x07, + CMD_RECEIVE_PACKET = 0x08, + CMD_TRANSMIT_PACKET = 0x09, + CMD_NETWORK_STATISTICS = 0x0a, + CMD_LOAD_MULTICAST_LIST = 0x0b, + CMD_CLEAR_PROGRAM = 0x0c, + CMD_DOWNLOAD_PROGRAM = 0x0d, + CMD_EXECUTE_PROGRAM = 0x0e, + CMD_SELF_TEST = 0x0f, + CMD_SET_STATION_ADDRESS = 0x10, + CMD_ADAPTER_INFO = 0x11, + + /* + * adapter PCB commands + */ + CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31, + CMD_CONFIGURE_82586_RESPONSE = 0x32, + CMD_ADDRESS_RESPONSE = 0x33, + CMD_DOWNLOAD_DATA_REQUEST = 0x34, + CMD_UPLOAD_DATA_REQUEST = 0x35, + CMD_RECEIVE_PACKET_COMPLETE = 0x38, + CMD_TRANSMIT_PACKET_COMPLETE = 0x39, + CMD_NETWORK_STATISTICS_RESPONSE = 0x3a, + CMD_LOAD_MULTICAST_RESPONSE = 0x3b, + CMD_CLEAR_PROGRAM_RESPONSE = 0x3c, + CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d, + CMD_EXECUTE_RESPONSE = 0x3e, + CMD_SELF_TEST_RESPONSE = 0x3f, + CMD_SET_ADDRESS_RESPONSE = 0x40, + CMD_ADAPTER_INFO_RESPONSE = 0x41 +}; + diff -u --recursive --new-file v1.1.21/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.1.21/linux/drivers/net/3c509.c Tue Jun 21 14:16:20 1994 +++ linux/drivers/net/3c509.c Thu Jun 23 23:06:39 1994 @@ -94,7 +94,9 @@ /* First check for a board on the EISA bus. */ if (EISA_bus) { - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + static int eisa_addr; + for (ioaddr=0x1000 ; ioaddr < 0x9000; ioaddr += 0x1000) { + eisa_addr = ioaddr; /* Check the standard EISA ID register for an encoded '3Com'. */ if (inw(ioaddr + 0xC80) != 0x6d50) continue; diff -u --recursive --new-file v1.1.21/linux/drivers/net/ac32000.c linux/drivers/net/ac32000.c --- v1.1.21/linux/drivers/net/ac32000.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ac32000.c Wed Jun 22 17:36:53 1994 @@ -0,0 +1,275 @@ +/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */ +/* + Written 1993, 1994 by Donald Becker. + Copyright 1993 United States Government as represented by the Director, + National Security Agency. This software may only be used and distributed + according to the terms of the GNU Public License as modified by SRC, + incorporated herein by reference. + + The author may be reached as becker@cesdis.gsfc.nasa.gov, or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + + This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN + Adapter. The programming information is from the users manual, as related + by glee@ardnassak.math.clemson.edu. + */ + +static char *version = + "ac3200.c:v0.03 2/6/94 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "8390.h" + +/* Offsets from the base address. */ +#define AC_NIC_BASE 0x00 +#define AC_SA_PROM 0x16 /* The station address PROM. */ +#define AC_ADDR0 0x00 /* Prefix station address values. */ +#define AC_ADDR1 0x40 /* !!!!These are just guesses!!!! */ +#define AC_ADDR2 0x90 +#define AC_ID_PORT 0xC80 +#define AC_EISA_ID 0x0110d305 +#define AC_RESET_PORT 0xC84 +#define AC_RESET 0x00 +#define AC_ENABLE 0x01 +#define AC_CONFIG 0xC90 /* The configuration port. */ + +/* Decoding of the configuration register. */ +static unsigned char config2irqmap[8] = {15, 12, 11, 10, 9, 7, 5, 3}; +static int addrmap[8] = +{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000, 0xD0000, 0 }; +static char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"}; + +#define config2irq(configval) config2irqmap[((configval) >> 3) & 7] +#define config2mem(configval) addrmap[(configval) & 7] +#define config2name(configval) port_name[((configval) >> 6) & 3] + +/* First and last 8390 pages. */ +#define AC_START_PG 0x00 /* First page of 8390 TX buffer */ +#define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */ + +int ac3200_probe(struct device *dev); +static int ac_probe1(int ioaddr, struct device *dev); + +static int ac_open(struct device *dev); +static void ac_reset_8390(struct device *dev); +static int ac_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void ac_block_output(struct device *dev, const int count, + const unsigned char *buf, const int start_page); +static int ac_close_card(struct device *dev); + + +/* Probe for the AC3200. + + The AC3200 can be identified by either the EISA configuration registers, + or the unique value in the station address PROM. + */ + +int ac3200_probe(struct device *dev) +{ + unsigned short ioaddr = dev->base_addr; + + if (ioaddr > 0x1ff) /* Check a single specified location. */ + return ac_probe1(ioaddr, dev); + else if (ioaddr > 0) /* Don't probe at all. */ + return ENXIO; + + /* If you have a pre-pl15 machine you should delete this line. */ + if ( ! EISA_bus) + return ENXIO; + + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + if (ac_probe1(ioaddr, dev) == 0) + return 0; + + return ENODEV; +} + +static int ac_probe1(int ioaddr, struct device *dev) +{ + int i; + +#ifndef final_version + printk("AC3200 ethercard probe at %#3x:", ioaddr); + + for(i = 0; i < 6; i++) + printk(" %02x", inb(ioaddr + AC_SA_PROM + i)); +#endif + + /* !!!!The values of AC_ADDRn (see above) should be corrected when we + find out the correct station address prefix!!!! */ + if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0 + || inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1 + || inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) { +#ifndef final_version + printk(" not found (invalid prefix).\n"); +#endif + return ENODEV; + } + + /* The correct probe method is to check the EISA ID. */ + for (i = 0; i < 4; i++) + if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) { + printk("EISA ID mismatch, %8x vs %8x.\n", + inl(ioaddr + AC_EISA_ID), AC_EISA_ID); + return ENODEV; + } + + for(i = 0; i < ETHER_ADDR_LEN; i++) + dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i); + +#ifndef final_version + printk("\nAC3200 ethercard configuration register is %#02x," + " EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG), + inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1), + inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3)); +#endif + + /* Assign and snarf the interrupt now. */ + if (dev->irq == 0) + dev->irq = config2irq(inb(ioaddr + AC_CONFIG)); + else if (dev->irq == 2) + dev->irq = 9; + + if (irqaction (dev->irq, &ei_sigaction)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return 0; + } + + dev->base_addr = ioaddr; + +#ifdef notyet + if (dev->mem_start) { /* Override the value from the board. */ + for (i = 0; i < 7; i++) + if (addrmap[i] == dev->mem_start) + break; + if (i >= 7) + i = 0; + outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG); + } +#endif + + dev->if_port = inb(ioaddr + AC_CONFIG) >> 6; + dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG)); + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->mem_end = dev->rmem_end = dev->mem_start + + (AC_STOP_PG - AC_START_PG)*256; + + ethdev_init(dev); + + ei_status.name = "AC3200"; + ei_status.tx_start_page = AC_START_PG; + ei_status.rx_start_page = AC_START_PG + TX_PAGES; + ei_status.stop_page = AC_STOP_PG; + ei_status.word16 = 1; + + printk("\n%s: AC3200 at %#x, IRQ %d, %s port, shared memory at %#x-%#x.\n", + dev->name, ioaddr, dev->irq, port_name[dev->if_port], + dev->mem_start, dev->mem_end-1); + + if (ei_debug > 0) + printk(version); + + ei_status.reset_8390 = &ac_reset_8390; + ei_status.block_input = &ac_block_input; + ei_status.block_output = &ac_block_output; + + dev->open = &ac_open; + dev->stop = &ac_close_card; + NS8390_init(dev, 0); + return 0; +} + +static int ac_open(struct device *dev) +{ +#ifdef notyet + /* Someday we may enable the IRQ and shared memory here. */ + int ioaddr = dev->base_addr; + + if (irqaction(dev->irq, &ei_sigaction)) + return -EAGAIN; +#endif + + return ei_open(dev); +} + +static void ac_reset_8390(struct device *dev) +{ + ushort ioaddr = dev->base_addr; + + outb(AC_RESET, ioaddr + AC_RESET_PORT); + if (ei_debug > 1) printk("resetting AC3200, t=%d...", jiffies); + + ei_status.txing = 0; + outb(AC_ENABLE, ioaddr + AC_RESET_PORT); + if (ei_debug > 1) printk("reset done\n"); + + return; +} + +/* Block input and output are easy on shared memory ethercards, the only + complication is when the ring buffer wraps. */ + +static int ac_block_input(struct device *dev, int count, char *buf, + int ring_offset) +{ + long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8); + + if (xfer_start + count > dev->rmem_end) { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy(buf, (char*)xfer_start, semi_count); + count -= semi_count; + memcpy(buf + semi_count, (char *)dev->rmem_start, count); + return dev->rmem_start + count; + } + memcpy(buf, (char*)xfer_start, count); + + return ring_offset + count; +} + +static void ac_block_output(struct device *dev, int count, + const unsigned char *buf, int start_page) +{ + long shmem = dev->mem_start + ((start_page - AC_START_PG)<<8); + + memcpy((unsigned char *)shmem, buf, count); +} + +static int ac_close_card(struct device *dev) +{ + dev->start = 0; + dev->tbusy = 1; + + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + +#ifdef notyet + /* We should someday disable shared memory and interrupts. */ + outb(0x00, ioaddr + 6); /* Disable interrupts. */ + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; +#endif + + NS8390_init(dev, 0); + + return 0; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ac3200.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v1.1.21/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v1.1.21/linux/drivers/net/depca.c Tue Jun 21 14:16:21 1994 +++ linux/drivers/net/depca.c Wed Jun 22 21:39:50 1994 @@ -21,15 +21,17 @@ DE201 Turbo DE202 Turbo (TP BNC) DE210 + DE422 (EISA) The driver has been tested on DE100, DE200 and DE202 cards in a - relatively busy network. + relatively busy network. The DE422 has been tested a little. - This driver will not work for the DE203, DE204 and DE205 series of - cards, since they have a new custom ASIC in place of the AMD LANCE chip. + This driver will NOT work for the DE203, DE204 and DE205 series of + cards, since they have a new custom ASIC in place of the AMD LANCE + chip. The author may be reached as davies@wanton.lkg.dec.com or - Digital Equipment Corporation, 146 Main Street, Maynard MA 01754. + Digital Equipment Corporation, 550 King Street, Littleton MA 01460. ========================================================================= The driver was based on the 'lance.c' driver from Donald Becker which is @@ -59,14 +61,15 @@ the filter bit positions correctly. Hash filtering is not yet implemented in the current driver set. - The original DEPCA card requires that the ethernet ROM address counter + The original DEPCA card requires that the ethernet ROM address counter be enabled to count and has an 8 bit NICSR. The ROM counter enabling is - only done when a 0x08 is read as the first address octet (to minimise - the chances of writing over some other hardware's I/O register). The - size of the NICSR is tested by a word read: if both bytes are the same, - the register is 8 bits wide. Also, there is a maximum of only 48kB - network RAM for this card. My thanks to Torbjorn Lindh for help - debugging all this (and holding my feet to the fire until I got it + only done when a 0x08 is read as the first address octet (to minimise + the chances of writing over some other hardware's I/O register). The + NICSR accesses have been changed to byte accesses for all the cards + supported by this driver, since there is only one useful bit in the MSB + (remote boot timeout) and it is not used. Also, there is a maximum of + only 48kB network RAM for this card. My thanks to Torbjorn Lindh for + help debugging all this (and holding my feet to the fire until I got it right). The DE200 series boards have on-board 64kB RAM for use as a shared @@ -74,22 +77,26 @@ mode which has not been implemented in this driver (only the 32kB and 64kB modes are supported [16kB/48kB for the original DEPCA]). - At the most only 2 DEPCA cards can be supported because there is only - provision for two I/O base addresses on the cards (0x300 and 0x200). The - base address is 'autoprobed' by looking for the self test PROM and - detecting the card name. The shared memory base address is decoded by - 'autoprobing' the Ethernet PROM address information. The second DEPCA is - detected and information placed in the base_addr variable of the next - device structure (which is created if necessary), thus enabling - ethif_probe initialization for the device. + At the most only 2 DEPCA cards can be supported on the ISA bus because + there is only provision for two I/O base addresses on each card (0x300 + and 0x200). The I/O address is detected by searching for a byte sequence + in the Ethernet station address PROM at the expected I/O address for the + Ethernet PROM. The shared memory base address is 'autoprobed' by + looking for the self test PROM and detecting the card name. When a + second DEPCA is detected, information is placed in the base_addr + variable of the next device structure (which is created if necessary), + thus enabling ethif_probe initialization for the device. More than 2 + EISA cards can be supported, but care will be needed assigning the + shared memory to ensure that each slot has the correct IRQ, I/O address + and shared memory address assigned. ************************************************************************ - NOTE: If you are using two DEPCAs, it is important that you assign the - base memory addresses correctly. The driver autoprobes I/O 0x300 then - 0x200. The base memory address for the first device must be less than - that of the second so that the auto probe will correctly assign the I/O - and memory addresses on the same card. I can't think of a way to do + NOTE: If you are using two ISA DEPCAs, it is important that you assign + the base memory addresses correctly. The driver autoprobes I/O 0x300 + then 0x200. The base memory address for the first device must be less + than that of the second so that the auto probe will correctly assign the + I/O and memory addresses on the same card. I can't think of a way to do this unambiguously at the moment, since there is nothing on the cards to tie I/O and memory information together. @@ -126,12 +133,14 @@ Add jabber packet fix from murf@perftech.com and becker@super.org 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access. - 0.35 8-mar-94 Added DE201 recognition. + 0.35 8-mar-94 Added DE201 recognition. Tidied up. + 0.351 30-apr-94 Added EISA support. Added DE422 recognition. + 0.36 16-may-94 DE422 fix released. ========================================================================= */ -static char *version = "depca.c:v0.35 3/8/94 davies@wanton.lkg.dec.com\n"; +static char *version = "depca.c:v0.36 5/16/94 davies@wanton.lkg.dec.com\n"; #include #include @@ -148,7 +157,6 @@ #include #include -#include "iow.h" /* left in for pl13/14 compatibility... */ #include #include #include "depca.h" @@ -159,11 +167,6 @@ int depca_debug = 1; #endif -#ifndef DEPCA_IRQ -/*#define DEPCA_IRQ {5,9,10,11,15,0}*/ -#define DEPCA_IRQ 5 -#endif - #ifndef PROBE_LENGTH #define PROBE_LENGTH 32 #endif @@ -173,7 +176,10 @@ #endif #ifndef DEPCA_SIGNATURE -#define DEPCA_SIGNATURE {"DEPCA","DE100","DE200","DE201","DE202","DE210",""} +#define DEPCA_SIGNATURE {"DEPCA","DE100",\ + "DE200","DE201","DE202","DE210",\ + "DE422",\ + ""} #define DEPCA_NAME_LENGTH 8 #endif @@ -195,6 +201,14 @@ #define MAX_NUM_DEPCAS 2 #endif +#ifndef DEPCA_EISA_IO_PORTS +#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ +#endif + +#ifndef MAX_EISA_SLOTS +#define MAX_EISA_SLOTS 8 +#endif + /* ** Set the number of Tx and Rx buffers. */ @@ -230,8 +244,8 @@ short misc; /* Errors and TDR info */ }; -struct depca_ring_info { -}; +#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM + to LANCE memory address space */ /* ** The Lance initialization block, described in databook, in common memory. @@ -249,6 +263,7 @@ struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */ struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */ struct depca_init init_block;/* Initialization block */ + long bus_offset; /* (E)ISA bus address offset vs LANCE */ long dma_buffs; /* Start address of Rx and Tx buffers. */ int cur_rx, cur_tx; /* The next free ring entry */ int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ @@ -287,8 +302,10 @@ #ifdef HAVE_MULTICAST static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table); #endif +static struct device *isa_probe(struct device *dev); +static struct device *eisa_probe(struct device *dev); +static struct device *alloc_device(struct device *dev, int ioaddr); -static int depca_na; static int num_depcas = 0, num_eth = 0;; /* @@ -298,96 +315,26 @@ outw(CSR0, DEPCA_ADDR);\ outw(STOP, DEPCA_DATA) -#define GET_NICSR(a,b) \ - if (depca_na) { \ - (a) = inw((b)); \ - } else { \ - (a) = inb((b)); \ - } - -#define PUT_NICSR(a,b) \ - if (depca_na) { \ - outw((a), (b)); \ - } else { \ - outb((a), (b)); \ - } - int depca_probe(struct device *dev) { - int *port, ports[] = DEPCA_IO_PORTS; int base_addr = dev->base_addr; - int status; - struct device *eth0 = (struct device *) NULL; + int status = -ENODEV; + struct device *eth0; if (base_addr > 0x1ff) { /* Check a single specified location. */ - status = -ENODEV; if (DevicePresent(base_addr) == 0) { /* Is DEPCA really here? */ status = depca_probe1(dev, base_addr); } } else if (base_addr > 0) { /* Don't probe at all. */ - status = -ENXIO; + status = -ENXIO; } else { /* First probe for the DEPCA test */ /* pattern in ROM */ - - for (status = -ENODEV, port = &ports[0]; - *port && (num_depcas < MAX_NUM_DEPCAS); port++) { - int ioaddr = *port; - -#ifdef HAVE_PORTRESERVE - if (check_region(ioaddr, DEPCA_TOTAL_SIZE)) - continue; -#endif - if (DevicePresent(ioaddr) == 0) { - if (num_depcas > 0) { /* only gets here in autoprobe */ - - /* - ** Check the device structures for an end of list or unused device - */ - while (dev->next != (struct device *)NULL) { - if (dev->next->base_addr == 0xffe0) break; - dev = dev->next; /* walk through eth device list */ - num_eth++; /* increment eth device number */ - } - - /* - ** If no more device structures, malloc one up. If memory could - ** not be allocated, print an error message. - ** - */ - if (dev->next == (struct device *)NULL) { - dev->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - } else { - printk("eth%d: Device not initialised, insufficient memory\n", - num_eth); - } - - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ - if ((dev->next != (struct device *)NULL) && - (num_eth > 0) && (num_eth < 9999)) { - dev = dev->next; /* point to the new device */ - dev->name = (char *)(dev + sizeof(struct device)); - sprintf(dev->name,"eth%d", num_eth); /* New device name */ - dev->base_addr = ioaddr; /* assign the io address */ - dev->next = (struct device *)NULL; /* mark the end of list */ - dev->init = &depca_probe;/* initialisation routine */ - } - } else { - eth0 = dev; /* remember the first device */ - status = depca_probe1(dev, ioaddr); - } - num_depcas++; - num_eth++; - } - } - if (eth0) dev = eth0; /* restore the first device */ + eth0=isa_probe(dev); + eth0=eisa_probe(eth0); + if (dev->priv) status=0; } if (status) dev->base_addr = base_addr; @@ -406,14 +353,13 @@ /* - ** Stop the DEPCA. Enable the DBR ROM and the ethernet ROM address counter - ** (for the really old DEPCAs). Disable interrupts and remote boot. + ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot. */ STOP_DEPCA; - GET_NICSR(nicsr, DEPCA_NICSR); - nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | AAC | IM); - PUT_NICSR(nicsr, DEPCA_NICSR); + nicsr = inb(DEPCA_NICSR); + nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM); + outb(nicsr, DEPCA_NICSR); if (inw(DEPCA_DATA) == STOP) { @@ -436,11 +382,16 @@ } } - if (*name != (char)NULL) { /* found a DEPCA device */ + if (*name != (char)NULL) { /* found a DEPCA device */ mem_start = mem_base[i]; dev->base_addr = ioaddr; - printk("%s: DEPCA at %#3x is a %s, ", dev->name, ioaddr, name); + if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */ + printk("%s: %s at %#3x (EISA slot %d)", + dev->name, name, ioaddr, ((ioaddr>>12)&0x0f)); + } else { /* ISA port address */ + printk("%s: %s at %#3x", dev->name, name, ioaddr); + } /* There is a 32 byte station address PROM at DEPCA_PROM address. The first six bytes are the station address. They can be read @@ -457,7 +408,7 @@ j = 0; } - printk("ethernet address "); + printk(", h/w address "); for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */ printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j)); } @@ -481,27 +432,32 @@ } /* - ** Determine the base address for the DEPCA RAM from the NI-CSR - ** and make up a DEPCA-specific-data structure. + ** Determine the base address for the DEPCA RAM from the NI-CSR + ** and make up a DEPCA-specific-data structure. */ if (nicsr & BUF) { offset = 0x8000; /* 32kbyte RAM offset*/ nicsr &= ~BS; /* DEPCA RAM in top 32k */ - printk(",\n with %dkB RAM", netRAM-(offset >> 10)); + printk(",\n has %dkB RAM", netRAM - 32); + } else if ((nicsr & _128KB) && (netRAM!=48)) { + offset = 0x0000; + printk(",\n has 128kB RAM"); } else { offset = 0x0000; /* 64k/48k bytes RAM */ - printk(",\n with %dkB RAM", netRAM); + printk(",\n has %dkB RAM", netRAM); } - mem_start += offset; - printk(" starting at 0x%.5lx", mem_start); + mem_start += offset; /* (E)ISA start address */ + printk(" at 0x%.5lx", mem_start); /* - ** Enable the shadow RAM. + ** Enable the shadow RAM. */ - nicsr |= SHE; - PUT_NICSR(nicsr, DEPCA_NICSR); + if (strstr(name,"DEPCA")==(char *)NULL) { + nicsr |= SHE; + outb(nicsr, DEPCA_NICSR); + } /* ** Calculate the ring size based on the available RAM @@ -551,12 +507,15 @@ lp->tx_ring = (struct depca_tx_head *)mem_start; mem_start += (sizeof(struct depca_tx_head) * j); - lp->dma_buffs = mem_start & 0x00ffffff; + lp->bus_offset = mem_start & 0x00ff0000; + mem_start &= LA_MASK; /* LANCE re-mapped start address */ + + lp->dma_buffs = mem_start; mem_start += (PKT_BUF_SZ * j); /* (mem_start now points to the start of the Tx buffers) */ - /* Initialise the data structures */ + /* Initialise the data structures wrt CPU */ memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j); memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j); @@ -593,15 +552,10 @@ LoadCSRs(dev); /* - ** Store the NICSR width for this DEPCA - */ - lp->depca_na = depca_na; - - /* ** Enable DEPCA board interrupts for autoprobing */ nicsr = ((nicsr & ~IM)|IEN); - PUT_NICSR(nicsr, DEPCA_NICSR); + outb(nicsr, DEPCA_NICSR); /* The DMA channel may be passed in on this parameter. */ dev->dma = 0; @@ -616,13 +570,13 @@ dev->irq = autoirq_report(1); if (dev->irq) { - printk(" and probed IRQ%d.\n", dev->irq); + printk(" and uses IRQ%d.\n", dev->irq); } else { - printk(". Failed to detect IRQ line.\n"); + printk(" and failed to detect IRQ line.\n"); status = -EAGAIN; } } else { - printk(". Assigned IRQ%d.\n", dev->irq); + printk(" and assigned IRQ%d.\n", dev->irq); } } else { status = -ENXIO; @@ -644,7 +598,7 @@ dev->mem_start = 0; /* Fill in the generic field of the device structure. */ - ether_setup(dev); + ether_setup(dev); } } else { status = -ENXIO; @@ -670,9 +624,8 @@ /* ** Stop the DEPCA & get the board status information. */ - depca_na=lp->depca_na; STOP_DEPCA; - GET_NICSR(nicsr, DEPCA_NICSR); + nicsr = inb(DEPCA_NICSR); /* ** Re-initialize the DEPCA... @@ -723,7 +676,7 @@ ** Enable DEPCA board interrupts */ nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN); - PUT_NICSR(nicsr, DEPCA_NICSR); + outb(nicsr, DEPCA_NICSR); outw(CSR0,DEPCA_ADDR); dev->tbusy = 0; @@ -734,8 +687,7 @@ if (depca_debug > 1){ printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA)); - GET_NICSR(nicsr, DEPCA_NICSR); - printk("nicsr: 0x%4.4x\n",nicsr); + printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR)); } return 0; /* Always succeed */ @@ -767,8 +719,8 @@ for (i = 0; i < 4; i++) { lp->init_block.filter[i] = 0x0000; } - lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen; - lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen; + lp->init_block.rx_ring = ((unsigned long)lp->rx_ring & LA_MASK) | lp->rlen; + lp->init_block.tx_ring = ((unsigned long)lp->tx_ring & LA_MASK) | lp->rlen; lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */ } @@ -789,10 +741,10 @@ if (tickssofar < 10) { status = -1; } else { - STOP_DEPCA; - printk("%s: transmit timed out, status %4.4x, resetting.\n", + printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA)); + STOP_DEPCA; depca_init_ring(dev); LoadCSRs(dev); InitRestartDepca(dev); @@ -835,7 +787,8 @@ char *p = (char *) skb->data; entry &= lp->rmask; /* Ring around buffer number. */ - buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); + buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) & + 0x00ffffff); /* Wait for a full ring to free up */ while (lp->tx_ring[entry].base < 0); @@ -870,7 +823,8 @@ /* Get new buffer pointer */ entry = lp->cur_tx++; entry &= lp->rmask; /* Ring around buffer number. */ - buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); + buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) & + 0x00ffffff); /* Wait for a full ring to free up */ while (lp->tx_ring[entry].base < 0); @@ -898,7 +852,8 @@ if (depca_debug > 4) { unsigned char *pkt = - (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); + (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) & + 0x00ffffff); printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n", dev->name, entry, (unsigned long) &lp->tx_ring[entry], @@ -933,54 +888,52 @@ if (dev == NULL) { printk ("depca_interrupt(): irq %d for unknown device.\n", irq); - return; } else { lp = (struct depca_private *)dev->priv; ioaddr = dev->base_addr; - depca_na = lp->depca_na; - } - if (dev->interrupt) + if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = MASK_INTERRUPTS; + dev->interrupt = MASK_INTERRUPTS; - /* mask the DEPCA board interrupts and turn on the LED */ - GET_NICSR(nicsr, DEPCA_NICSR); - nicsr |= (IM|LED); - PUT_NICSR(nicsr, DEPCA_NICSR); + /* mask the DEPCA board interrupts and turn on the LED */ + nicsr = inb(DEPCA_NICSR); + nicsr |= (IM|LED); + outb(nicsr, DEPCA_NICSR); - outw(CSR0, DEPCA_ADDR); - csr0 = inw(DEPCA_DATA); + outw(CSR0, DEPCA_ADDR); + csr0 = inw(DEPCA_DATA); - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA); + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA); - if (depca_debug > 5) + if (depca_debug > 5) printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", dev->name, csr0, inw(DEPCA_DATA)); - if (csr0 & RINT) /* Rx interrupt (packet arrived) */ + if (csr0 & RINT) /* Rx interrupt (packet arrived) */ depca_rx(dev); - if (csr0 & TINT) /* Tx interrupt (packet sent) */ + if (csr0 & TINT) /* Tx interrupt (packet sent) */ depca_tx(dev); - /* Clear the interrupts we've handled. */ - outw(CSR0, DEPCA_ADDR); - outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA); + /* Clear the interrupts we've handled. */ + outw(CSR0, DEPCA_ADDR); + outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA); - if (depca_debug > 4) { - printk("%s: exiting interrupt, csr%d=%#4.4x.\n", - dev->name, inw(DEPCA_ADDR), - inw(DEPCA_DATA)); - } + if (depca_debug > 4) { + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", + dev->name, inw(DEPCA_ADDR), + inw(DEPCA_DATA)); + } - /* Unmask the DEPCA board interrupts and turn off the LED */ - nicsr = (nicsr & ~IM & ~LED); - PUT_NICSR(nicsr, DEPCA_NICSR); + /* Unmask the DEPCA board interrupts and turn off the LED */ + nicsr = (nicsr & ~IM & ~LED); + outb(nicsr, DEPCA_NICSR); + dev->interrupt = UNMASK_INTERRUPTS; + } - dev->interrupt = UNMASK_INTERRUPTS; return; } @@ -1036,7 +989,8 @@ skb->len = pkt_len; skb->dev = dev; memcpy(skb->data, - (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), + (unsigned char *)((lp->rx_ring[entry].base+lp->bus_offset) & + 0x00ffffff), pkt_len); /* ** Notify the upper protocol layers that there is another @@ -1146,9 +1100,11 @@ int ioaddr = dev->base_addr; outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ - outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA); + outw((unsigned short)((unsigned long)(&lp->init_block) & LA_MASK), + DEPCA_DATA); outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ - outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA); + outw((unsigned short)(((unsigned long)(&lp->init_block) & LA_MASK) >> 16), + DEPCA_DATA); outw(CSR3, DEPCA_ADDR); /* ALE control */ outw(ACON, DEPCA_DATA); outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ @@ -1274,6 +1230,118 @@ #endif /* HAVE_MULTICAST */ /* +** ISA bus I/O device probe +*/ +static struct device *isa_probe(dev) +struct device *dev; +{ + int *port, ports[] = DEPCA_IO_PORTS; + int status; + + for (status = -ENODEV, port = &ports[0]; + *port && (num_depcas < MAX_NUM_DEPCAS); port++) { + int ioaddr = *port; + +#ifdef HAVE_PORTRESERVE + if (check_region(ioaddr, DEPCA_TOTAL_SIZE)) + continue; +#endif + + if (DevicePresent(ioaddr) == 0) { + if (num_depcas > 0) { /* only gets here in autoprobe */ + dev = alloc_device(dev, ioaddr); + } else { + if ((status = depca_probe1(dev, ioaddr)) == 0) { + num_depcas++; + } + } + num_eth++; + } + } + return dev; +} + +/* +** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually +** the motherboard. +*/ +static struct device *eisa_probe(dev) +struct device *dev; +{ + int i, ioaddr = DEPCA_EISA_IO_PORTS; + int status; + + ioaddr+=0x1000; /* get the first slot address */ + for (status = -ENODEV, i=1; i 0) { /* only gets here in autoprobe */ + dev = alloc_device(dev, ioaddr); + } else { + if ((status = depca_probe1(dev, ioaddr)) == 0) { + num_depcas++; + } + } + num_eth++; + } + } + return dev; +} + +/* +** Allocate the device by pointing to the next available space in the +** device structure. Should one not be available, it is created. +*/ +static struct device *alloc_device(dev, ioaddr) +struct device *dev; +int ioaddr; +{ + /* + ** Check the device structures for an end of list or unused device + */ + while (dev->next != (struct device *)NULL) { + if (dev->next->base_addr == 0xffe0) break; + dev = dev->next; /* walk through eth device list */ + num_eth++; /* increment eth device number */ + } + + /* + ** If no more device structures, malloc one up. If memory could + ** not be allocated, print an error message. + */ + if (dev->next == (struct device *)NULL) { + dev->next = (struct device *)kmalloc(sizeof(struct device) + 8, + GFP_KERNEL); + if (dev->next == (struct device *)NULL) { + printk("eth%d: Device not initialised, insufficient memory\n", + num_eth); + } + } + + /* + ** If the memory was allocated, point to the new memory area + ** and initialize it (name, I/O address, next device (NULL) and + ** initialisation probe routine). + */ + if ((dev->next != (struct device *)NULL) && + (num_eth > 0) && (num_eth < 9999)) { + dev = dev->next; /* point to the new device */ + dev->name = (char *)(dev + sizeof(struct device)); + sprintf(dev->name,"eth%d", num_eth);/* New device name */ + dev->base_addr = ioaddr; /* assign the io address */ + dev->next = (struct device *)NULL; /* mark the end of list */ + dev->init = &depca_probe; /* initialisation routine */ + num_depcas++; + } + + return dev; +} + +/* ** Look for a particular board name in the on-board Remote Diagnostics ** and Boot (RDB) ROM. This will also give us a clue to the network RAM ** base address. @@ -1315,9 +1383,7 @@ ** messing around with some other hardware, but it assumes that this DEPCA ** card initialized itself correctly. It also assumes that all past and ** future DEPCA/EtherWORKS cards will have ethernet addresses beginning with -** a 0x08. The choice of byte or word addressing is made here based on whether -** word read of the NICSR returns two identical lower and upper bytes: if so -** the register is 8 bits wide. +** a 0x08. */ static int DevicePresent(short ioaddr) @@ -1325,7 +1391,6 @@ static short fp=1,sigLength=0; static char devSig[] = PROBE_SEQUENCE; char data; - unsigned char LSB,MSB; int i, j, nicsr, status = 0; static char asc2hex(char value); @@ -1337,26 +1402,12 @@ data = inb(DEPCA_PROM); /* read data */ /* -** Determine whether a byte or word access should be made on the NICSR. -** Since the I/O 'functions' are actually in-line code, the choice not to use -** pointers to functions vs. just set a conditional, is made for us. This code -** assumes that the NICSR has an asymmetric bit pattern already in it. -*/ - nicsr = inw(DEPCA_NICSR); - LSB = nicsr & 0xff; - MSB = (((unsigned) nicsr) >> 8) & 0xff; - if (MSB == LSB) { - depca_na = 0; /* byte accesses */ - } else { - depca_na = 1; /* word accesses */ - } - -/* ** Enable counter */ if (data == 0x08) { + nicsr = inb(DEPCA_NICSR); nicsr |= AAC; - PUT_NICSR(nicsr, DEPCA_NICSR); + outb(nicsr, DEPCA_NICSR); } /* @@ -1382,7 +1433,7 @@ /* ** Search the Ethernet address ROM for the signature. Since the ROM address ** counter can start at an arbitrary point, the search must include the entire -** probe sequence length plus the length of the (signature - 1). +** probe sequence length plus the (length_of_the_signature - 1). ** Stop the search IMMEDIATELY after the signature is found so that the ** PROM address counter is correctly positioned at the start of the ** ethernet address for later read out. diff -u --recursive --new-file v1.1.21/linux/drivers/net/depca.h linux/drivers/net/depca.h --- v1.1.21/linux/drivers/net/depca.h Tue Apr 19 10:52:45 1994 +++ linux/drivers/net/depca.h Wed Jun 22 21:39:50 1994 @@ -14,7 +14,9 @@ #define DEPCA_RBI ioaddr+0x02 /* RAM buffer index (2k buffer mode) */ #define DEPCA_DATA ioaddr+0x04 /* LANCE registers' data port */ #define DEPCA_ADDR ioaddr+0x06 /* LANCE registers' address port */ +#define DEPCA_HBASE ioaddr+0x08 /* EISA high memory base address reg. */ #define DEPCA_PROM ioaddr+0x0c /* Ethernet address ROM data port */ +#define DEPCA_CNFG ioaddr+0x0c /* EISA Configuration port */ #define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */ /* @@ -35,6 +37,7 @@ #define BUF 0x0020 /* BUFfer size (1->32k, 0->64k) */ #define RBE 0x0010 /* Remote Boot Enable (1->net boot) */ #define AAC 0x0008 /* Address ROM Address Counter (1->enable) */ +#define _128KB 0x0008 /* 128kB Network RAM (1->enable) */ #define IM 0x0004 /* Interrupt Mask (1->mask) */ #define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */ #define LED 0x0001 /* LED control */ @@ -119,6 +122,20 @@ #define TMD3_LCAR 0x0800 /* Loss of CARrier */ #define TMD3_RTRY 0x0400 /* ReTRY error */ +/* +** EISA configuration Register (CNFG) bit definitions +*/ + +#define TIMEOUT 0x0100 /* 0:2.5 mins, 1: 30 secs */ +#define REMOTE 0x0080 /* Remote Boot Enable -> 1 */ +#define IRQ11 0x0040 /* Enable -> 1 */ +#define IRQ10 0x0020 /* Enable -> 1 */ +#define IRQ9 0x0010 /* Enable -> 1 */ +#define IRQ5 0x0008 /* Enable -> 1 */ +#define BUFF 0x0004 /* 0: 64kB or 128kB, 1: 32kB */ +#define PADR16 0x0002 /* RAM on 64kB boundary */ +#define PADR17 0x0001 /* RAM on 128kB boundary */ + /* ** Miscellaneous */ @@ -126,3 +143,6 @@ #define MASK_INTERRUPTS 1 #define UNMASK_INTERRUPTS 0 +#define EISA_EN 0x0001 /* Enable EISA bus buffers */ +#define DEPCA_EISA_ID ioaddr+0x80 /* ID long word for EISA card */ +#define DEPCA_EISA_CTRL ioaddr+0x84 /* Control word for EISA card */ diff -u --recursive --new-file v1.1.21/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v1.1.21/linux/drivers/net/e2100.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/e2100.c Wed Jun 22 17:38:02 1994 @@ -0,0 +1,341 @@ +/* e2100.c: A Cabletron E2100 series ethernet driver for linux. */ +/* + Written 1993 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. This software may be used and + distributed according to the terms of the GNU Public License, + incorporated herein by reference. + + This is a driver for the Cabletron E2100 series ethercards. + + The Author may be reached as becker@cesdis.gsfc.nasa.gov, or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + + The E2100 series ethercard is a fairly generic shared memory 8390 + implementation. The only unusual aspect is the way the shared memory + registers are set: first you do an inb() in what is normally the + station address region, and the low four bits of next outb() is used + as the write value for that register. Either someone wasn't too used + to dem bit en bites, or they were trying to obfusicate the programming + interface. + + There is an additional complication when setting the window on the packet + buffer. You must first do a read into the packet buffer region with the + low 8 address bits the address setting the page for the start of the packet + buffer window, and then do the above operation. See mem_on() for details. + + One bug on the chip is that even a hard reset won't disable the memory + window, usually resulting in a hung machine if mem_off() isn't called. + If this happens, you must power down the machine for about 30 seconds. +*/ + +static char *version = + "e2100.c:v0.01 11/21/93 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include +#include +#ifndef PRE_PL13 +#include /* Delete if your kernel doesn't have it. */ +#endif + +#include +#include "8390.h" + +/* Compatibility definitions for earlier kernel versions. */ +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#endif +#ifndef HAVE_AUTOIRQ +/* From auto_irq.c, in ioport.h for later versions. */ +extern void autoirq_setup(int waittime); +extern int autoirq_report(int waittime); +/* The map from IRQ number (as passed to the interrupt handler) to + 'struct device'. */ +extern struct device *irq2dev_map[16]; +#endif + +/* Offsets from the base_addr. + Read from the ASIC register, and the low 3(?) bits of the next outb() address + is used to set the cooresponding register. */ +#define E21_NIC_OFFSET 0 /* Offset to the 8390 NIC. */ +#define E21_ASIC 0x10 +#define E21_MEM_ENABLE 0x10 +#define E21_MEM_ON 0x05 /* Enable memory in 16 bit mode. */ +#define E21_MEM_ON_8 0x07 /* Enable memory in 8 bit mode. */ +#define E21_MEM_BASE 0x11 +#define E21_IRQ_LOW 0x12 /* The low three bits of the IRQ number. */ +#define E21_IRQ_HIGH 0x14 /* The high IRQ bit, and ... */ +#define E21_ALT_IFPORT 0x02 /* Set to use the other (BNC,AUI) port. */ +#define E21_BIG_MEM 0x04 /* Use a bigger (64K) buffer (we don't) */ +#define E21_SAPROM 0x10 /* Offset to station address data. */ +#define ETHERCARD_TOTAL_SIZE 0x20 + +extern inline void mem_on(short port, volatile char *mem_base, + unsigned char start_page ) +{ + /* This is a little weird: set the shared memory window by doing a + read. The low address bits specify the starting page. */ + mem_base[start_page]; + inb(port + E21_MEM_ENABLE); + outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON); +} + +extern inline void mem_off(short port) +{ + inb(port + E21_MEM_ENABLE); + outb(0x00, port + E21_MEM_ENABLE); +} + +/* In other drivers I put the TX pages first, but the E2100 window circuitry + is designed to have a 4K Tx region last. The windowing circuitry wraps the + window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring + appear contiguously in the window. */ +#define E21_RX_START_PG 0x00 /* First page of RX buffer */ +#define E21_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ +#define E21_BIG_RX_STOP_PG 0xF0 /* Last page +1 of RX ring */ +#define E21_TX_START_PG E21_RX_STOP_PG /* First page of TX buffer */ + +int e2100_probe(struct device *dev); +int e21_probe1(struct device *dev, int ioaddr); + +static int e21_open(struct device *dev); +static void e21_reset_8390(struct device *dev); +static int e21_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void e21_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); +static int e21_close(struct device *dev); + + +/* Probe for the E2100 series ethercards. These cards have an 8390 at the + base address and the station address at both offset 0x10 and 0x18. I read + the station address from offset 0x18 to avoid the dataport of NE2000 + ethercards, and look for Ctron's unique ID (first three octets of the + station address). + */ + +int e2100_probe(struct device *dev) +{ + int *port, ports[] = {0x300, 0x280, 0x380, 0x220, 0}; + short base_addr = dev->base_addr; + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return e21_probe1(dev, base_addr); + else if (base_addr > 0) /* Don't probe at all. */ + return ENXIO; + + for (port = &ports[0]; *port; port++) { + ushort ioaddr = *port; + + if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE)) + continue; + if (inb(ioaddr + E21_SAPROM + 0) == 0x00 + && inb(ioaddr + E21_SAPROM + 1) == 0x00 + && inb(ioaddr + E21_SAPROM + 2) == 0x1d + && e21_probe1(dev, ioaddr) == 0) + return 0; + } + return -ENODEV; +} + +int e21_probe1(struct device *dev, int ioaddr) +{ + int i, status; + unsigned char *station_addr = dev->dev_addr; + + /* We've already checked the station address prefix, now verify by making + certain that there is a 8390 at the expected location. */ + outb(E8390_NODMA + E8390_STOP, ioaddr); + SLOW_DOWN_IO; + status = inb(ioaddr); + if (status != 0x21 && status != 0x23) + return -ENODEV; + +#ifdef testing_only + printk("%s: E21xx at %#3x (PAXI backwards): ", dev->name, ioaddr); + for (i = 0; i < 16; i++) + printk(" %02X", inb(ioaddr + 0x1f - i)); + printk("\n"); +#endif + + /* Read the station address PROM. */ + for (i = 0; i < 6; i++) + station_addr[i] = inb(ioaddr + E21_SAPROM + i); + + /* Grab the region so we can find another board if needed . */ + snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE); + + printk("%s: E21xx at %#3x, ", dev->name, ioaddr); + for (i = 0; i < 6; i++) + printk(" %02X", station_addr[i]); + + if (dev->irq < 2) { + int irqlist[] = {15,11,10,12,5,9,3,4}, i; + for (i = 0; i < 8; i++) + if (request_irq (irqlist[i], NULL) != -EBUSY) { + dev->irq = irqlist[i]; + break; + } + } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ + dev->irq = 9; + + /* Snarf the interrupt now. */ + if (irqaction (dev->irq, &ei_sigaction)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return -EBUSY; + } + + /* The 8390 is at the base address. */ + dev->base_addr = ioaddr; + + ethdev_init(dev); + + ei_status.name = "E2100"; + ei_status.word16 = 1; + ei_status.tx_start_page = E21_TX_START_PG; + ei_status.rx_start_page = E21_RX_START_PG; + ei_status.stop_page = E21_RX_STOP_PG; + + /* Check the media port used. The port can be passed in on the + low mem_end bits. */ + if (dev->mem_end & 15) + dev->if_port = dev->mem_end & 7; + else { + dev->if_port = 0; + inb_p(ioaddr + E21_IRQ_HIGH); /* Select if_port detect. */ + for(i = 0; i < 6; i++) + if (station_addr[i] != inb(ioaddr + E21_SAPROM)) + dev->if_port = 1; + } + + /* Never map in the E21 shared memory unless you are actively using it. + Also, the shared memory has effective only one setting -- spread all + over the 128K region! */ + if (dev->mem_start == 0) + dev->mem_start = 0xd0000; + +#ifdef notdef + /* These values are unused. The E2100 has a 2K window into the packet + buffer. The window can be set to start on any page boundary. */ + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024; +#endif + + printk(" IRQ %d, %s interface, memory at %#x-%#x.\n", dev->irq, + dev->if_port ? "secondary" : "primary", dev->mem_start, + dev->mem_start + 2*1024 - 1); + + if (ei_debug > 0) + printk(version); + + ei_status.reset_8390 = &e21_reset_8390; + ei_status.block_input = &e21_block_input; + ei_status.block_output = &e21_block_output; + dev->open = &e21_open; + dev->stop = &e21_close; + NS8390_init(dev, 0); + + return 0; +} + +static int +e21_open(struct device *dev) +{ + short ioaddr = dev->base_addr; + + /* Set the interrupt line and memory base on the hardware. */ + inb_p(ioaddr + E21_IRQ_LOW); + outb_p(0, ioaddr + E21_ASIC + (dev->irq & 7)); + inb_p(ioaddr + E21_IRQ_HIGH); /* High IRQ bit, and if_port. */ + outb_p(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0) + + (dev->if_port ? E21_ALT_IFPORT : 0)); + inb_p(ioaddr + E21_MEM_BASE); + outb_p(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7)); + + return ei_open(dev); +} + +static void +e21_reset_8390(struct device *dev) +{ + short ioaddr = dev->base_addr; + + outb(0x01, ioaddr); + if (ei_debug > 1) printk("resetting the E2180x3 t=%d...", jiffies); + ei_status.txing = 0; + + /* Set up the ASIC registers, just in case something changed them. */ + + if (ei_debug > 1) printk("reset done\n"); + return; +} + +/* Block input and output are easy on shared memory ethercards. The E21xx makes + block_input() especially easy by wrapping the top ring buffer to the bottom + automatically. */ +static int +e21_block_input(struct device *dev, int count, char *buf, int ring_offset) +{ + short ioaddr = dev->base_addr; + char *shared_mem = (char *)dev->mem_start; + int start_page = (ring_offset>>8); + + mem_on(ioaddr, shared_mem, start_page); + + /* We'll always get a 4 byte header read first. */ + if (count == 4) + ((int*)buf)[0] = ((int*)shared_mem)[0]; + else + memcpy(buf, shared_mem + (ring_offset & 0xff), count); + + /* Turn off memory access: we would need to reprogram the window anyway. */ + mem_off(ioaddr); + + return 0; +} + +static void +e21_block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) +{ + short ioaddr = dev->base_addr; + volatile char *shared_mem = (char *)dev->mem_start; + + /* Set the shared memory window start by doing a read, with the low address + bits specifing the starting page. */ + *(shared_mem + start_page); + mem_on(ioaddr, shared_mem, start_page); + + memcpy((char*)shared_mem, buf, count); + mem_off(ioaddr); +} + +static int +e21_close(struct device *dev) +{ + short ioaddr = dev->base_addr; + + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + NS8390_init(dev, 0); + + mem_off(ioaddr); + + return 0; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c" + * version-control: t + * tab-width: 4 + * kept-new-versions: 5 + * End: + */ diff -u --recursive --new-file v1.1.21/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v1.1.21/linux/drivers/net/loopback.c Tue Jun 21 14:16:21 1994 +++ linux/drivers/net/loopback.c Thu Jun 23 22:09:33 1994 @@ -128,7 +128,7 @@ #endif /* New-style flags. */ - dev->flags = IFF_LOOPBACK; + dev->flags = IFF_LOOPBACK|IFF_BROADCAST; dev->family = AF_INET; #ifdef CONFIG_INET dev->pa_addr = in_aton("127.0.0.1"); diff -u --recursive --new-file v1.1.21/linux/drivers/net/znote.c linux/drivers/net/znote.c --- v1.1.21/linux/drivers/net/znote.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/znote.c Thu Jun 23 22:51:47 1994 @@ -0,0 +1,947 @@ +/* znet.c: An Zenith Z-Note ethernet driver for linux. */ + +static char *version = "znet.c:v0.04 5/10/94 becker@cesdis.gsfc.nasa.gov\n"; + +/* + Written by Donald Becker. + + The author may be reached as becker@cesdis.gsfc.nasa.gov. + This driver is based on the Linux skeleton driver. The copyright of the + skeleton driver is held by the United States Government, as represented + by DIRNSA, and it is released under the GPL. + + Thanks to Mike Hollick for alpha testing and suggestions. + + References: + The Crynwr packet driver. + + "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992 + Intel Microcommunications Databook, Vol. 1, 1990. + As usual with Intel, the documentation is incomplete and inaccurate. + I had to read the Crynwr packet driver to figure out how to actually + use the i82593, and guess at what register bits matched the loosely + related i82586. + + Theory of Operation + + The i82593 used in the Zenith Z-Note series operates using two(!) slave + DMA channels, one interrupt, and one 8-bit I/O port. + + While there several ways to configure '593 DMA system, I chose the one + that seemed commesurate with the highest system performance in the face + of moderate interrupt latency: Both DMA channels are configued as + recirculating ring buffers, with one channel (#0) dedicated to Rx and + the other channel (#1) to Tx and configuration. (Note that this is + different than the Crynwr driver, where the Tx DMA channel is initialized + before each operation. That approach simplifies operation and Tx error + recovery, but requires additional I/O in normal operation and precludes + transmit buffer chaining.) + + Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides + a reasonable ring size for Rx, while simplifying DMA buffer allocation -- + DMA buffers must not cross a 128K boundary. (In truth the size selection + was influenced by my lack of '593 documentation. I thus was constrained + to use the Crynwr '593 initialization table, which sets the Rx ring size + to 8K.) + + Despite my usual low opinion about Intel-designed parts, I must admit + that the bulk data handling of the i82593 is a good design for + an integrated system, like a laptop, where using two slave DMA channels + doesn't pose a problem. I still take issue with using only a single I/O + port. In the same controlled environment there are essentially no + limitations on I/O space, and using multiple locations would eliminate + the need for multiple operations when looking at status registers, + setting the Rx ring boundary, or switching to promiscuous mode. + + I also question Zenith's selection of the '593: one of the advertised + advantages of earlier Intel parts was that if you figured out the magic + initialization incantation you could use the same part on many different + network types. Zenith's use of the "FriendlyNet" (sic) connector rather + than an on-board transceiver leads me to believe that they were planning + to take advantage of this. But, uhmmm, the '593 omits all but ethernet + functionality from the serial subsystem. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef HAVE_AUTOIRQ +/* From auto_irq.c, in ioport.h for later versions. */ +extern void autoirq_setup(int waittime); +extern int autoirq_report(int waittime); +/* The map from IRQ number (as passed to the interrupt handler) to + 'struct device'. */ +extern struct device *irq2dev_map[16]; +#endif + +#ifndef HAVE_ALLOC_SKB +#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) +#define kfree_skbmem(addr, size) kfree_s(addr,size); +#endif + +#ifndef ZNET_DEBUG +#define ZNET_DEBUG 3 +#endif +static unsigned int znet_debug = ZNET_DEBUG; + +/* The DMA modes we need aren't in . */ +#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */ +#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */ +#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17) +#define DMA_BUF_SIZE 8192 +#define RX_BUF_SIZE 8192 +#define TX_BUF_SIZE 8192 + +/* Commands to the i82593 channel 0. */ +#define CMD0_CHNL_0 0x00 +#define CMD0_CHNL_1 0x10 /* Switch to channel 1. */ +#define CMD0_NOP (CMD0_CHNL_0) +#define CMD0_PORT_1 CMD0_CHNL_1 +#define CMD1_PORT_0 1 +#define CMD0_IA_SETUP 1 +#define CMD0_CONFIGURE 2 +#define CMD0_MULTICAST_LIST 3 +#define CMD0_TRANSMIT 4 +#define CMD0_DUMP 6 +#define CMD0_DIAGNOSE 7 +#define CMD0_Rx_ENABLE 8 +#define CMD0_Rx_DISABLE 10 +#define CMD0_Rx_STOP 11 +#define CMD0_RETRANSMIT 12 +#define CMD0_ABORT 13 +#define CMD0_RESET 14 + +#define CMD0_ACK 0x80 + +#define CMD0_STAT0 (0 << 5) +#define CMD0_STAT1 (1 << 5) +#define CMD0_STAT2 (2 << 5) +#define CMD0_STAT3 (3 << 5) + +#define net_local znet_private +struct znet_private { + int rx_dma, tx_dma; + struct enet_statistics stats; + /* The starting, current, and end pointers for the packet buffers. */ + ushort *rx_start, *rx_cur, *rx_end; + ushort *tx_start, *tx_cur, *tx_end; + ushort tx_buf_len; /* Tx buffer lenght, in words. */ +}; + +/* Only one can be built-in;-> */ +static struct znet_private zn; +static ushort dma_buffer1[DMA_BUF_SIZE/2]; +static ushort dma_buffer2[DMA_BUF_SIZE/2]; +static ushort dma_buffer3[DMA_BUF_SIZE/2 + 8]; + +/* The configuration block. What an undocumented nightmare. The first + set of values are those suggested (without explaination) for ethernet + in the Intel 82586 databook. The rest appear to be completely undocumented, + except for cryptic notes in the Crynwr packet driver. This driver uses + the Crynwr values verbatim. */ + +static unsigned char i593_init[] = { + 0xAA, /* 0: 16-byte input & 80-byte output FIFO. */ + /* threshhold, 96-byte FIFO, 82593 mode. */ + 0x88, /* 1: Continuous w/interrupts, 128-clock DMA.*/ + 0x2E, /* 2: 8-byte preamble, NO address insertion, */ + /* 6-byte Ethernet address, loopback off.*/ + 0x00, /* 3: Default priorities & backoff methods. */ + 0x60, /* 4: 96-bit interframe spacing. */ + 0x00, /* 5: 512-bit slot time (low-order). */ + 0xF2, /* 6: Slot time (high-order), 15 COLL retries. */ + 0x00, /* 7: Promisc-off, broadcast-on, default CRC. */ + 0x00, /* 8: Default carrier-sense, collision-detect. */ + 0x40, /* 9: 64-byte minimum frame length. */ + 0x5F, /* A: Type/length checks OFF, no CRC input, + "jabber" termination, etc. */ + 0x00, /* B: Full-duplex disabled. */ + 0x3F, /* C: Default multicast addresses & backoff. */ + 0x07, /* D: Default IFS retriggering. */ + 0x31, /* E: Internal retransmit, drop "runt" packets, + synchr. DRQ deassertion, 6 status bytes. */ + 0x22, /* F: Receive ring-buffer size (8K), + receive-stop register enable. */ +}; + +struct netidblk { + char magic[8]; /* The magic number (string) "NETIDBLK" */ + unsigned char netid[8]; /* The physical station address */ + char nettype, globalopt; + char vendor[8]; /* The machine vendor and product name. */ + char product[8]; + char irq1, irq2; /* Interrupts, only one is currently used. */ + char dma1, dma2; + short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */ + short iobase1, iosize1; + short iobase2, iosize2; /* Second iobase unused. */ + char driver_options; /* Misc. bits */ + char pad; +}; + +int znet_probe(struct device *dev); +static int znet_open(struct device *dev); +static int znet_send_packet(struct sk_buff *skb, struct device *dev); +static void znet_interrupt(int reg_ptr); +static void znet_rx(struct device *dev); +static int znet_close(struct device *dev); +static struct enet_statistics *net_get_stats(struct device *dev); +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void hardware_init(struct device *dev); +static int do_command(short ioaddr, int command, int length, ushort *buffer); +static int wait_for_done(short ioaddr); +static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); + +#ifdef notdef +static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, }; +#endif + + +/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe + BIOS area. We just scan for the signature, and pull the vital parameters + out of the structure. */ + +int znet_probe(struct device *dev) +{ + int i; + struct netidblk *netinfo; + char *p; + + /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ + for(p = (char *)0xf0000; p < (char *)0x100000; p++) + if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) + break; + + if (p >= (char *)0x100000) { + if (znet_debug > 1) + printk("No Z-Note ethernet adaptor found.\n"); + return ENODEV; + } + netinfo = (struct netidblk *)p; + dev->base_addr = netinfo->iobase1; + dev->irq = netinfo->irq1; + + printk("%s: ZNET at %#3x,", dev->name, dev->base_addr); + + /* The station address is in the "netidblk" at 0x0f0000. */ + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]); + + printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1, + netinfo->dma2); + + if (znet_debug > 1) { + printk("%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n", + dev->name, netinfo->vendor, + netinfo->irq1, netinfo->irq2, + netinfo->dma1, netinfo->dma2); + printk("%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n", + dev->name, netinfo->iobase1, netinfo->iosize1, + netinfo->iobase2, netinfo->iosize2, netinfo->nettype); + } + + if (znet_debug > 0) + printk(version); + + dev->priv = (void *) &zn; + zn.rx_dma = netinfo->dma1; + zn.tx_dma = netinfo->dma2; + + /* These should never fail. You can't add devices to a sealed box! */ + if (request_irq(dev->irq, &znet_interrupt) + || request_dma(zn.rx_dma) + || request_dma(zn.tx_dma)) { + printk("Not opened -- resource busy?!?\n"); + return EBUSY; + } + irq2dev_map[dev->irq] = dev; + + /* Allocate buffer memory. We can cross a 128K boundary, so we + must be careful about the allocation. It's easiest to waste 8K. */ + if (dma_page_eq(dma_buffer1, &dma_buffer1[RX_BUF_SIZE/2-1])) + zn.rx_start = dma_buffer1; + else + zn.rx_start = dma_buffer2; + + if (dma_page_eq(dma_buffer3, &dma_buffer3[RX_BUF_SIZE/2-1])) + zn.tx_start = dma_buffer3; + else + zn.tx_start = dma_buffer2; + zn.rx_end = zn.rx_start + RX_BUF_SIZE/2; + zn.tx_buf_len = TX_BUF_SIZE/2; + zn.tx_end = zn.tx_start + zn.tx_buf_len; + + /* The ZNET-specific entries in the device structure. */ + dev->open = &znet_open; + dev->hard_start_xmit = &znet_send_packet; + dev->stop = &znet_close; + dev->get_stats = net_get_stats; +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_multicast_list; +#endif + + /* Fill in the generic field of the device structure. */ + for (i = 0; i < DEV_NUMBUFFS; i++) + dev->buffs[i] = NULL; + + dev->hard_header = eth_header; + dev->add_arp = eth_add_arp; + dev->queue_xmit = dev_queue_xmit; + dev->rebuild_header = eth_rebuild_header; + dev->type_trans = eth_type_trans; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 1500; /* eth_mtu */ + dev->addr_len = ETH_ALEN; + for (i = 0; i < ETH_ALEN; i++) { + dev->broadcast[i]=0xff; + } + + /* New-style flags. */ + dev->flags = IFF_BROADCAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = sizeof(unsigned long); + + return 0; +} + + +static int znet_open(struct device *dev) +{ + int ioaddr = dev->base_addr; + + if (znet_debug > 2) + printk("%s: znet_open() called.\n", dev->name); + + /* Turn on the 82501 SIA, using zenith-specific magic. */ + outb(0x10, 0xe6); /* Select LAN control register */ + outb(inb(0xe7) | 0x84, 0xe7); /* Turn on LAN power (bit 2). */ + /* According to the Crynwr driver we should wait 50 msec. for the + LAN clock to stabilize. My experiments indicates that the '593 can + be initialized immediately. The delay is probably needed for the + DC-to-DC converter to come up to full voltage, and for the oscillator + to be spot-on at 20Mhz before transmitting. + Until this proves to be a problem we rely on the higher layers for the + delay and save allocating a timer entry. */ + + /* This follows the packet driver's lead, and checks for success. */ + if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00) + printk("%s: Problem turning on the transceiver power.\n", dev->name); + + dev->tbusy = 0; + dev->interrupt = 0; + hardware_init(dev); + dev->start = 1; + + return 0; +} + +static int znet_send_packet(struct sk_buff *skb, struct device *dev) +{ + int ioaddr = dev->base_addr; + + if (znet_debug > 4) + printk("%s: ZNet_send_packet(%d).\n", dev->name, dev->tbusy); + + /* Transmitter timeout, could be a serious problems. */ + if (dev->tbusy) { + ushort event, tx_status, rx_offset, state; + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 10) + return 1; + outb(CMD0_STAT0, ioaddr); event = inb(ioaddr); + outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr); + outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr); + outb(CMD0_STAT3, ioaddr); state = inb(ioaddr); + printk("%s: transmit timed out, status %02x %04x %04x %02x," + " resetting.\n", dev->name, event, tx_status, rx_offset, state); + if (tx_status == 0x0400) + printk("%s: Tx carrier error, check transceiver cable.\n", + dev->name); + outb(CMD0_RESET, ioaddr); + hardware_init(dev); + } + + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* Fill in the ethernet header. */ + if (!skb->arp && dev->rebuild_header(skb+1, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + + /* Check that the part hasn't reset itself, probably from suspend. */ + outb(CMD0_STAT0, ioaddr); + if (inw(ioaddr) == 0x0010 + && inw(ioaddr) == 0x0000 + && inw(ioaddr) == 0x0010) + hardware_init(dev); + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = (void *)(skb+1); + ushort *tx_link = zn.tx_cur - 1; + ushort rnd_len = (length + 1)>>1; + + { + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + addr <<= 1; + if (((int)zn.tx_cur & 0x1ffff) != addr) + printk("Address mismatch at Tx: %#x vs %#x.\n", + (int)zn.tx_cur & 0xffff, addr); + zn.tx_cur = (ushort *)(((int)zn.tx_cur & 0xfe0000) | addr); + } + + if (zn.tx_cur >= zn.tx_end) + zn.tx_cur = zn.tx_start; + *zn.tx_cur++ = length; + if (zn.tx_cur + rnd_len + 1 > zn.tx_end) { + int semi_cnt = (zn.tx_end - zn.tx_cur)<<1; /* Cvrt to byte cnt. */ + memcpy(zn.tx_cur, buf, semi_cnt); + rnd_len -= semi_cnt>>1; + memcpy(zn.tx_start, buf + semi_cnt, length - semi_cnt); + zn.tx_cur = zn.tx_start + rnd_len; + } else { + memcpy(zn.tx_cur, buf, skb->len); + zn.tx_cur += rnd_len; + } + *zn.tx_cur++ = 0; + cli(); { + *tx_link = CMD0_TRANSMIT + CMD0_CHNL_1; + /* Is this always safe to do? */ + outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr); + } sti(); + + dev->trans_start = jiffies; + if (znet_debug > 4) + printk("%s: Transmitter queued, length %d.\n", dev->name, length); + } + dev_kfree_skb(skb, FREE_WRITE); + return 0; +} + +/* The ZNET interrupt handler. */ +static void znet_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = irq2dev_map[irq]; + int ioaddr; + int boguscnt = 20; + + if (dev == NULL) { + printk ("znet_interrupt(): IRQ %d for unknown device.\n", irq); + return; + } + + dev->interrupt = 1; + ioaddr = dev->base_addr; + + outb(CMD0_STAT0, ioaddr); + do { + ushort status = inb(ioaddr); + if (znet_debug > 5) { + ushort result, rx_ptr, running; + outb(CMD0_STAT1, ioaddr); + result = inw(ioaddr); + outb(CMD0_STAT2, ioaddr); + rx_ptr = inw(ioaddr); + outb(CMD0_STAT3, ioaddr); + running = inb(ioaddr); + printk("%s: interrupt, status %02x, %04x %04x %02x serial %d.\n", + dev->name, status, result, rx_ptr, running, boguscnt); + } + if ((status & 0x80) == 0) + break; + + if ((status & 0x0F) == 4) { /* Transmit done. */ + struct net_local *lp = (struct net_local *)dev->priv; + int tx_status; + outb(CMD0_STAT1, ioaddr); + tx_status = inw(ioaddr); + /* It's undocumented, but tx_status seems to match the i82586. */ + if (tx_status & 0x2000) { + lp->stats.tx_packets++; + lp->stats.collisions += tx_status & 0xf; + } else { + if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; + if (tx_status & 0x0100) lp->stats.tx_fifo_errors++; + if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++; + if (tx_status & 0x0020) lp->stats.tx_aborted_errors++; + /* ...and the catch-all. */ + if (tx_status | 0x0760 != 0x0760) + lp->stats.tx_errors++; + } + dev->tbusy = 0; + mark_bh(INET_BH); /* Inform upper layers. */ + } + + if ((status & 0x40) + || (status & 0x0f) == 11) { + znet_rx(dev); + } + /* Clear the interrupts we've handled. */ + outb(CMD0_ACK,ioaddr); + } while (boguscnt--); + + dev->interrupt = 0; + return; +} + +static void znet_rx(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int boguscount = 1; + short next_frame_end_offset = 0; /* Offset of next frame start. */ + short *cur_frame_end; + short cur_frame_end_offset; + + outb(CMD0_STAT2, ioaddr); + cur_frame_end_offset = inw(ioaddr); + + if (cur_frame_end_offset == zn.rx_cur - zn.rx_start) { + printk("%s: Interrupted, but nothing to receive, offset %03x.\n", + dev->name, cur_frame_end_offset); + return; + } + + /* Use same method as the Crynwr driver: construct a forward list in + the same area of the backwards links we now have. This allows us to + pass packets to the upper layers in the order they were received -- + important for fast-path sequential operations. */ + while (zn.rx_start + cur_frame_end_offset != zn.rx_cur + && ++boguscount < 5) { + unsigned short hi_cnt, lo_cnt, hi_status, lo_status; + int count, status; + + if (cur_frame_end_offset < 4) { + /* Oh no, we have a special case: the frame trailer wraps around + the end of the ring buffer. We've saved space at the end of + the ring buffer for just this problem. */ + memcpy(zn.rx_end, zn.rx_start, 8); + cur_frame_end_offset += (RX_BUF_SIZE/2); + } + cur_frame_end = zn.rx_start + cur_frame_end_offset - 4; + + lo_status = *cur_frame_end++; + hi_status = *cur_frame_end++; + status = ((hi_status & 0xff) << 8) + (lo_status & 0xff); + lo_cnt = *cur_frame_end++; + hi_cnt = *cur_frame_end++; + count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff); + + if (znet_debug > 5) + printk("Constructing trailer at location %03x, %04x %04x %04x %04x" + " count %#x status %04x.\n", + cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt, + count, status); + cur_frame_end[-4] = status; + cur_frame_end[-3] = next_frame_end_offset; + cur_frame_end[-2] = count; + next_frame_end_offset = cur_frame_end_offset; + cur_frame_end_offset -= ((count + 1)>>1) + 3; + if (cur_frame_end_offset < 0) + cur_frame_end_offset += RX_BUF_SIZE/2; + }; + + /* Now step forward through the list. */ + do { + ushort *this_rfp_ptr = zn.rx_start + next_frame_end_offset; + int status = this_rfp_ptr[-4]; + int pkt_len = this_rfp_ptr[-2]; + + if (znet_debug > 5) + printk("Looking at trailer ending at %04x status %04x length %03x" + " next %04x.\n", next_frame_end_offset<<1, status, pkt_len, + this_rfp_ptr[-3]<<1); + /* Once again we must assume that the i82586 docs apply. */ + if ( ! (status & 0x2000)) { /* There was an error. */ + lp->stats.rx_errors++; + if (status & 0x0800) lp->stats.rx_crc_errors++; + if (status & 0x0400) lp->stats.rx_frame_errors++; + if (status & 0x0200) lp->stats.rx_over_errors++; /* Wrong. */ + if (status & 0x0100) lp->stats.rx_fifo_errors++; + if (status & 0x0080) lp->stats.rx_length_errors++; + } else if (pkt_len > 1536) { + lp->stats.rx_length_errors++; + } else { + /* Malloc up new buffer. */ + int sksize = sizeof(struct sk_buff) + pkt_len; + struct sk_buff *skb; + + skb = alloc_skb(sksize, GFP_ATOMIC); + if (skb == NULL) { + if (znet_debug) + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + break; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + + if (&zn.rx_cur[(pkt_len+1)>>1] > zn.rx_end) { + int semi_cnt = (zn.rx_end - zn.rx_cur)<<1; + memcpy((unsigned char *) (skb + 1), zn.rx_cur, semi_cnt); + memcpy((unsigned char *) (skb + 1) + semi_cnt, zn.rx_start, + pkt_len - semi_cnt); + } else { + memcpy((unsigned char *) (skb + 1), zn.rx_cur, pkt_len); + if (znet_debug > 6) { + unsigned int *packet = (unsigned int *) (skb + 1); + printk("Packet data is %08x %08x %08x %08x.\n", packet[0], + packet[1], packet[2], packet[3]); + } + } + +#ifdef HAVE_NETIF_RX + netif_rx(skb); +#else + skb->lock = 0; + if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { + kfree_s(skb, sksize); + lp->stats.rx_dropped++; + break; + } +#endif + lp->stats.rx_packets++; + } + zn.rx_cur = this_rfp_ptr; + if (zn.rx_cur >= zn.rx_end) + zn.rx_cur -= RX_BUF_SIZE/2; + update_stop_hit(ioaddr, (zn.rx_cur - zn.rx_start)<<1); + next_frame_end_offset = this_rfp_ptr[-3]; + if (next_frame_end_offset == 0) /* Read all the frames? */ + break; /* Done for now */ + this_rfp_ptr = zn.rx_start + next_frame_end_offset; + } while (--boguscount); + + /* If any worth-while packets have been received, dev_rint() + has done a mark_bh(INET_BH) for us and will work on them + when we get to the bottom-half routine. */ + return; +} + +/* The inverse routine to znet_open(). */ +static int znet_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + + dev->tbusy = 1; + dev->start = 0; + + outb(CMD0_RESET, ioaddr); /* CMD0_RESET */ + + disable_dma(zn.rx_dma); + disable_dma(zn.tx_dma); + + free_irq(dev->irq); + + if (znet_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + /* Turn off transceiver power. */ + outb(0x10, 0xe6); /* Select LAN control register */ + outb(inb(0xe7) & ~0x84, 0xe7); /* Turn on LAN power (bit 2). */ + + return 0; +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct enet_statistics *net_get_stats(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + return &lp->stats; +} + +#ifdef HAVE_MULTICAST +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + As a side effect this routine must also initialize the device parameters. + This is taken advantage of in open(). + + N.B. that we change i593_init[] in place. This (properly) makes the + mode change persistent, but must be changed if this code is moved to + a multiple adaptor environment. + */ +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +{ + short ioaddr = dev->base_addr; + + if (num_addrs < 0) { + /* Enable promiscuous mode */ + i593_init[7] &= ~3; i593_init[7] |= 1; + i593_init[13] &= ~8; i593_init[13] |= 8; + } else if (num_addrs > 0) { + /* Enable accept-all-multicast mode */ + i593_init[7] &= ~3; i593_init[7] |= 0; + i593_init[13] &= ~8; i593_init[13] |= 8; + } else { /* Enable normal mode. */ + i593_init[7] &= ~3; i593_init[7] |= 0; + i593_init[13] &= ~8; i593_init[13] |= 0; + } + *zn.tx_cur++ = sizeof(i593_init); + memcpy(zn.tx_cur, i593_init, sizeof(i593_init)); + zn.tx_cur += sizeof(i593_init)/2; + outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr); +#ifdef not_tested + if (num_addrs > 0) { + int addrs_len = 6*num_addrs; + *zn.tx_cur++ = addrs_len; + memcpy(zn.tx_cur, addrs, addrs_len); + outb(CMD0_MULTICAST_LIST+CMD0_CHNL_1, ioaddr); + zn.tx_cur += addrs_len>>1; + } +#endif +} +#endif + +void show_dma(void) +{ + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + printk("Addr: %04x cnt:%3x...", addr<<1, + get_dma_residue(zn.tx_dma)); +} + +/* Initialize the hardware. We have to do this when the board is open()ed + or when we come out of suspend mode. */ +static void hardware_init(struct device *dev) +{ + short ioaddr = dev->base_addr; + + zn.rx_cur = zn.rx_start; + zn.tx_cur = zn.tx_start; + + /* Reset the chip, and start it up. */ + outb(CMD0_RESET, ioaddr); + + cli(); { /* Protect against a DMA flip-flop */ + disable_dma(zn.rx_dma); /* reset by an interrupting task. */ + clear_dma_ff(zn.rx_dma); + set_dma_mode(zn.rx_dma, DMA_RX_MODE); + set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start); + set_dma_count(zn.rx_dma, RX_BUF_SIZE); + enable_dma(zn.rx_dma); + /* Now set up the Tx channel. */ + disable_dma(zn.tx_dma); + clear_dma_ff(zn.tx_dma); + set_dma_mode(zn.tx_dma, DMA_TX_MODE); + set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start); + set_dma_count(zn.tx_dma, zn.tx_buf_len<<1); + enable_dma(zn.tx_dma); + } sti(); + + if (znet_debug > 1) + printk("%s: Initializing the i82593, tx buf %p... ", dev->name, + zn.tx_start); + /* Do an empty configure command, just like the Crynwr driver. This + resets to chip to its default values. */ + *zn.tx_cur++ = 0; + *zn.tx_cur++ = 0; + printk("stat:%02x ", inb(ioaddr)); show_dma(); + outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr); + *zn.tx_cur++ = sizeof(i593_init); + memcpy(zn.tx_cur, i593_init, sizeof(i593_init)); + zn.tx_cur += sizeof(i593_init)/2; + printk("stat:%02x ", inb(ioaddr)); show_dma(); + outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr); + *zn.tx_cur++ = 6; + memcpy(zn.tx_cur, dev->dev_addr, 6); + zn.tx_cur += 3; + printk("stat:%02x ", inb(ioaddr)); show_dma(); + outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr); + printk("stat:%02x ", inb(ioaddr)); show_dma(); + + update_stop_hit(ioaddr, 8192); + if (znet_debug > 1) printk("enabling Rx.\n"); + outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr); + dev->tbusy = 0; +} + +#ifdef notdef +foo() +{ + /*do_command(ioaddr, CMD0_CONFIGURE+CMD0_CHNL_1, sizeof(i593_init) + 2, + zn.tx_buffer);*/ + /*do_command(ioaddr, CMD0_CONFIGURE+CMD0_CHNL_1, 32, zn.tx_buffer);*/ + /*outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);*/ + + if (znet_debug > 1) printk("Set Address... "); + *zn.tx_cur++ = 6; + memcpy(zn.tx_cur, dev->dev_addr, 6); + zn.tx_cur += 3; + outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr); + { + unsigned stop_time = jiffies + 3; + while (jiffies < stop_time); + } + if (znet_debug > 2) { + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + printk("Terminal addr is %04x, cnt. %03x...", addr<<1, + get_dma_residue(zn.tx_dma)); + } + *zn.tx_cur++ = 6; + memcpy(zn.tx_cur, dev->dev_addr, 6); + zn.tx_cur += 3; + outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr); + { + unsigned stop_time = jiffies + 2; + while (jiffies < stop_time); + } + if (znet_debug > 2) { + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + printk("Terminal addr is %04x, cnt. %03x...", addr<<1, + get_dma_residue(zn.tx_dma)); + } + wait_for_done(ioaddr); + + if (znet_debug > 1) printk("Set Mode... "); + set_multicast_list(dev, 0, 0); + { + unsigned stop_time = jiffies + 3; + while (jiffies < stop_time); + } + if (znet_debug > 2) { + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + printk("Terminal addr is %04x, cnt. %03x...", addr<<1, + get_dma_residue(zn.tx_dma)); + } + if (znet_debug > 2) { + int i; + outb(CMD0_DUMP+CMD0_CHNL_0, ioaddr); + printk("Dumping state:"); + for (i = 0; i < 16; i++) + printk(" %04x", *zn.rx_cur++); + printk("\n :"); + for (;i < 32; i++) + printk(" %04x", *zn.rx_cur++); + printk("\n"); + wait_for_done(ioaddr); + } +} + +static int do_command(short ioaddr, int command, int length, ushort *buffer) +{ + /* This isn't needed, but is here for safety. */ + outb(CMD0_NOP+CMD0_STAT3,ioaddr); + if (inb(ioaddr) & 3) + printk("znet: do_command() while the i82593 is busy.\n"); + + cli(); + disable_dma(zn.tx_dma); + clear_dma_ff(zn.tx_dma); + set_dma_mode(zn.tx_dma,DMA_MODE_WRITE); + set_dma_addr(zn.tx_dma,(unsigned int) zn.tx_start); + set_dma_count(zn.tx_dma,length); + sti(); + enable_dma(zn.tx_dma); + outb(command, ioaddr); + return 0; +} + +/* wait_for_done - this is a blatent rip-off of the wait_for_done routine + ** from the Crynwr packet driver. It does not work correctly - doesn't + ** acknowledge the interrupts it gets or something. It does determine + ** when the command is done, or if there are none executing, though... + ** -Mike + */ +static int wait_for_done(short ioaddr) +{ + unsigned int stat; + unsigned stop_time = jiffies + 10; + int ticks = 0; + + /* check to see if we are busy */ + outb(CMD0_NOP+CMD0_STAT3,ioaddr); + stat = inb(ioaddr); + + /* check if busy */ + if ((stat&3)==0) { + if (znet_debug > 5) + printk("wait_for_done(): Not busy, status %02x.\n", stat); + return 0; + } + + while (jiffies < stop_time) { + /* now check */ + outb(CMD0_NOP+CMD0_STAT3,ioaddr); + stat = inb(ioaddr); + if ((stat&3)==0) { + if (znet_debug > 5) + printk("Command completed after %d ticks status %02x.\n", + ticks, stat); + outb((CMD0_NOP|CMD0_ACK),ioaddr); + return 0; + } + ticks++; + } + outb(CMD0_ABORT, ioaddr); + if (znet_debug) + printk("wait_for_done: command not ACK'd, status %02x after abort %02x.\n", + stat, inb(ioaddr)); + + /* should re-initialize here... */ + return 1; +} +#endif /* notdef */ + +static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset) +{ + outb(CMD0_PORT_1, ioaddr); + if (znet_debug > 5) + printk("Updating stop hit with value %02x.\n", + (rx_stop_offset >> 6) | 0x80); + outb((rx_stop_offset >> 6) | 0x80, ioaddr); + outb(CMD1_PORT_0, ioaddr); +} + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c znet.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v1.1.21/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.1.21/linux/drivers/scsi/scsi.c Fri Jun 17 15:20:06 1994 +++ linux/drivers/scsi/scsi.c Thu Jun 23 22:29:28 1994 @@ -142,6 +142,7 @@ {"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */ {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */ {"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */ + {"MAXTOR","XT-8760S","B6B"}, /* Locks-up when LUN > 0 is polled */ {"MAXTOR","XT-8760S","B7B"}, /* guess what? */ {"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */ {"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */ diff -u --recursive --new-file v1.1.21/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v1.1.21/linux/include/linux/if_arp.h Tue May 24 00:34:56 1994 +++ linux/include/linux/if_arp.h Thu Jun 23 22:09:41 1994 @@ -37,6 +37,7 @@ #define ARPHRD_CSLIP6 259 #define ARPHRD_RSRVD 260 /* Notional KISS type */ #define ARPHRD_ADAPT 264 +#define ARPHRD_PPP 512 /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request */ diff -u --recursive --new-file v1.1.21/linux/include/linux/route.h linux/include/linux/route.h --- v1.1.21/linux/include/linux/route.h Tue May 24 00:34:56 1994 +++ linux/include/linux/route.h Thu Jun 23 22:09:41 1994 @@ -22,6 +22,7 @@ /* This structure gets passed by the SIOCADDRTOLD and SIOCDELRTOLD calls. */ + struct old_rtentry { unsigned long rt_genmask; struct sockaddr rt_dst; @@ -44,7 +45,8 @@ struct ifnet *rt_ifp; short rt_metric; /* +1 for binary compatibility! */ char *rt_dev; /* forcing the device at add */ - unsigned long rt_mtu; /* per route MTU/Window */ + unsigned long rt_mss; /* per route MTU/Window */ + unsigned long rt_window; /* Window clamping */ }; @@ -54,5 +56,14 @@ #define RTF_REINSTATE 0x0008 /* re-instate route after tmout */ #define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ #define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ -#define RTF_MTU 0x0040 /* specific MSS for this route */ +#define RTF_MSS 0x0040 /* specific MSS for this route */ +#define RTF_WINDOW 0x0080 /* per route window clamping */ + +/* + * REMOVE THESE BY 1.2.0 !!!!!!!!!!!!!!!!! + */ + +#define RTF_MTU RTF_MSS +#define rt_mtu rt_mss + #endif /* _LINUX_ROUTE_H */ diff -u --recursive --new-file v1.1.21/linux/mm/memory.c linux/mm/memory.c --- v1.1.21/linux/mm/memory.c Wed Jun 22 14:57:10 1994 +++ linux/mm/memory.c Wed Jun 22 14:18:49 1994 @@ -45,6 +45,8 @@ #include #include #include +#include +#include /* * Define this if things work differently on a i386 and a i486: @@ -677,6 +679,13 @@ int verify_area(int type, const void * addr, unsigned long size) { struct vm_area_struct * vma; + + /* If the current user space is mapped to kernel space (for the + * case where we use a fake user buffer with get_fs/set_fs()) we + * don't expect to find the address in the user vm map. + */ + if (get_fs() == get_ds()) + return 0; for (vma = current->mm->mmap ; ; vma = vma->vm_next) { if (!vma) diff -u --recursive --new-file v1.1.21/linux/modules/NET_MODULES linux/modules/NET_MODULES --- v1.1.21/linux/modules/NET_MODULES Tue May 31 12:48:19 1994 +++ linux/modules/NET_MODULES Thu Jun 23 23:01:49 1994 @@ -1 +1 @@ -3c509.o de600.o 3c501.o plip.o +3c509.o de600.o de620.o 3c501.o plip.o diff -u --recursive --new-file v1.1.21/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.21/linux/net/inet/af_inet.c Wed Jun 22 14:57:11 1994 +++ linux/net/inet/af_inet.c Thu Jun 23 22:28:16 1994 @@ -839,7 +839,7 @@ int err; sock->conn = NULL; - if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) + if (sock->state == SS_CONNECTING && tcp_connected(sk->state)) { sock->state = SS_CONNECTED; /* Connection completing after a connect/EINPROGRESS/select/connect */ diff -u --recursive --new-file v1.1.21/linux/net/inet/icmp.c linux/net/inet/icmp.c --- v1.1.21/linux/net/inet/icmp.c Tue May 24 00:35:01 1994 +++ linux/net/inet/icmp.c Thu Jun 23 22:09:40 1994 @@ -308,7 +308,7 @@ */ #ifdef not_a_good_idea ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev,0); + ip, 0, icmph->un.gateway, dev,0, 0); break; #endif case ICMP_REDIR_HOST: @@ -324,7 +324,7 @@ break; printk("redirect from %08lx\n", source); ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev,0); + ip, 0, icmph->un.gateway, dev,0, 0); break; case ICMP_REDIR_NETTOS: case ICMP_REDIR_HOSTTOS: diff -u --recursive --new-file v1.1.21/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.21/linux/net/inet/ip.c Wed Jun 22 14:57:11 1994 +++ linux/net/inet/ip.c Thu Jun 23 22:09:40 1994 @@ -1523,8 +1523,8 @@ #ifdef CONFIG_IP_FORWARD ip_forward(skb, dev, is_frag); #else - printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", - iph->saddr,iph->daddr); +/* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", + iph->saddr,iph->daddr);*/ ip_statistics.IpInAddrErrors++; #endif /* diff -u --recursive --new-file v1.1.21/linux/net/inet/ipx.c linux/net/inet/ipx.c --- v1.1.21/linux/net/inet/ipx.c Tue Jun 21 14:16:28 1994 +++ linux/net/inet/ipx.c Thu Jun 23 22:09:40 1994 @@ -26,6 +26,7 @@ * identification, support for local net 0 and * multiple datalinks * Revision 0.26: Device drop kills IPX routes via it. (needed for modules) + * Revision 0.27: Autobind * * * @@ -640,18 +641,11 @@ static unsigned short first_free_socketnum(void) { static unsigned short socketNum = 0x4000; - unsigned short startNum, foundNum = 0; - startNum = socketNum; - do { - if (ipx_find_socket(htons(socketNum)) == NULL) { - foundNum = socketNum; - } - socketNum++; + while (ipx_find_socket(htons(socketNum)) != NULL) if (socketNum > 0x7ffc) socketNum = 0x4000; - } while (!foundNum && (socketNum != startNum)); - return htons(foundNum); + return htons(socketNum++); } static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) @@ -736,9 +730,17 @@ return(-EINVAL); addr=(struct sockaddr_ipx *)uaddr; - if(sk->ipx_source_addr.net==0) /* Must bind first - no autobinding in this */ - return -EINVAL; - + if(sk->ipx_source_addr.net==0) + /* put the autobinding in */ + { + struct sockaddr_ipx uaddr; + int ret; + + uaddr.sipx_port = 0; + uaddr.sipx_network = 0L; + ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); + if (ret != 0) return (ret); + } sk->ipx_dest_addr.net=addr->sipx_network; sk->ipx_dest_addr.sock=addr->sipx_port; @@ -970,6 +972,18 @@ if(usipx) { + if(sk->ipx_source_addr.net==0) + /* put the autobinding in */ + { + struct sockaddr_ipx uaddr; + int ret; + + uaddr.sipx_port = 0; + uaddr.sipx_network = 0L; + ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); + if (ret != 0) return (ret); + } + if(addr_len sipx_family != AF_IPX) diff -u --recursive --new-file v1.1.21/linux/net/inet/route.c linux/net/inet/route.c --- v1.1.21/linux/net/inet/route.c Tue May 24 00:35:03 1994 +++ linux/net/inet/route.c Thu Jun 23 22:09:40 1994 @@ -21,6 +21,8 @@ * Alan Cox : Added BSD route gw semantics * Alan Cox : Super /proc >4K * Alan Cox : MTU in route table + * Alan Cox : MSS actually. Also added the window + * clamper. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -195,7 +197,7 @@ */ void ip_rt_add(short flags, unsigned long dst, unsigned long mask, - unsigned long gw, struct device *dev, unsigned short mtu) + unsigned long gw, struct device *dev, unsigned short mtu, unsigned long window) { struct rtable *r, *rt; struct rtable **rp; @@ -267,12 +269,16 @@ rt->rt_dev = dev; rt->rt_gateway = gw; rt->rt_mask = mask; - rt->rt_mtu = dev->mtu; + rt->rt_mss = dev->mtu - HEADER_SIZE; + rt->rt_window = 0; /* Default is no clamping */ /* Are the MSS/Window valid ? */ - if(rt->rt_flags & RTF_MTU) - rt->rt_mtu = mtu; + if(rt->rt_flags & RTF_MSS) + rt->rt_mss = mtu; + + if(rt->rt_flags & RTF_WINDOW) + rt->rt_window = window; /* * What we have to do is loop though this until we have @@ -449,7 +455,7 @@ * Add the route */ - ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mtu); + ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mss, r->rt_window); return 0; } @@ -481,7 +487,7 @@ int size; len += sprintf(buffer, - "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\n"); + "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\n"); pos=len; /* @@ -490,10 +496,10 @@ for (r = rt_base; r != NULL; r = r->rt_next) { - size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\n", + size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\n", r->rt_dev->name, r->rt_dst, r->rt_gateway, r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, - r->rt_mask, (int)r->rt_mtu); + r->rt_mask, (int)r->rt_mss, r->rt_window); len+=size; pos+=size; if(pos #include -#define TCP_FASTPATH +#undef TCP_FASTPATH #define SEQ_TICK 3 unsigned long seq_offset; @@ -183,8 +186,6 @@ in order to get the data we are waiting for into the memory limit. Secondly we bin common duplicate forms at receive time - TODO: add sk->window_clamp to limit windows over the DE600 and AX.25 - Better heuristics welcome */ @@ -192,6 +193,8 @@ { int new_window = sk->prot->rspace(sk); + if(sk->window_clamp) + new_window=min(sk->window_clamp,new_window); /* * two things are going on here. First, we don't ever offer a * window less than min(sk->mss, MAX_WINDOW/2). This is the @@ -565,8 +568,7 @@ adcl $0, %%ebx movl %%edx, %%ecx 2: andl $28, %%ecx - cmpl $4, %%ecx - jb 4f + je 4f shrl $2, %%ecx clc 3: lodsl @@ -578,11 +580,13 @@ je 5f lodsw addl %%eax, %%ebx + adcl $0, %%ebx movw $0, %%ax 5: test $1, %%edx je 6f lodsb addl %%eax, %%ebx + adcl $0, %%ebx 6: movl %%ebx, %%eax shrl $16, %%eax addw %%ax, %%bx @@ -2024,10 +2028,16 @@ */ rt=ip_rt_route(saddr, NULL,NULL); + + if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) + sk->window_clamp=rt->rt_window; + else + sk->window_clamp=0; + if (sk->user_mss) newsk->mtu = sk->user_mss; - else if(rt!=NULL && (rt->rt_flags&RTF_MTU)) - newsk->mtu = rt->rt_mtu - HEADER_SIZE; + else if(rt!=NULL && (rt->rt_flags&RTF_MSS)) + newsk->mtu = rt->rt_mss - HEADER_SIZE; else { #ifdef CONFIG_INET_SNARL /* Sub Nets ARe Local */ @@ -2270,6 +2280,7 @@ sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); if (tmp < 0) { + sk->write_seq++; /* Very important 8) */ kfree_skb(buff,FREE_WRITE); /* @@ -2481,12 +2492,18 @@ if (sk->retransmits && sk->timeout == TIME_KEEPOPEN) sk->retransmits = 0; +#if 0 /* * Not quite clear why the +1 and -1 here, and why not +1 in next line */ if (after(ack, sk->sent_seq+1) || before(ack, sk->rcv_ack_seq-1)) +#else + if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq)) +#endif { + if(sk->debug) + printk("Ack ignored %lu %lu\n",ack,sk->sent_seq); if (after(ack, sk->sent_seq) || (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) { @@ -2841,6 +2858,7 @@ if (sk->state == TCP_FIN_WAIT1) { + if (!sk->dead) sk->state_change(sk); if (sk->rcv_ack_seq == sk->write_seq) @@ -2866,6 +2884,7 @@ if (sk->state == TCP_CLOSING) { + if (!sk->dead) sk->state_change(sk); if (sk->rcv_ack_seq == sk->write_seq) @@ -2974,10 +2993,12 @@ sk->state_change(sk); return(0); } +#if 0 /* Discard the frame here - we've already proved its a duplicate */ kfree_skb(skb, FREE_READ); return(0); +#endif } /* * Now we have to walk the chain, and figure out where this one @@ -3523,11 +3544,16 @@ t1->urg_ptr = 0; t1->doff = 6; /* use 512 or whatever user asked for */ + + if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) + sk->window_clamp=rt->rt_window; + else + sk->window_clamp=0; if (sk->user_mss) sk->mtu = sk->user_mss; - else if(rt!=NULL && rt->rt_flags&RTF_MTU) - sk->mtu = rt->rt_mtu; + else if(rt!=NULL && (rt->rt_flags&RTF_MTU)) + sk->mtu = rt->rt_mss; else { #ifdef CONFIG_INET_SNARL @@ -3779,7 +3805,7 @@ */ /* Im trusting gcc to optimise this sensibly... might need judicious application of a software mallet */ - if(!(sk->shutdown & RCV_SHUTDOWN) && sk->state==TCP_ESTABLISHED && !th->urg && !th->syn && !th->fin && !th->rst && !th->urg) + if(!(sk->shutdown & RCV_SHUTDOWN) && sk->state==TCP_ESTABLISHED && !th->urg && !th->syn && !th->fin && !th->rst) { /* Packets in order. Fits window */ if(th->seq == sk->acked_seq+1 && sk->window && tcp_clean_end(sk)) @@ -3804,7 +3830,7 @@ sk->window-=skb->len; /* We know its effect on the window */ else sk->window=0; - sk->acked_seq = th->ack_seq; /* Easy */ + sk->acked_seq = th->seq+skb->len; /* Easy */ skb->acked=1; /* Guaranteed true */ if(!sk->delay_acks || sk->ack_backlog >= sk->max_ack_backlog || sk->bytes_rcv > sk->max_unacked) @@ -3939,17 +3965,18 @@ return(0); } - if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } if (tcp_data(skb, sk, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } + + if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } release_sock(sk); return(0);