patch-2.1.25 linux/drivers/net/wic.c
Next file: linux/drivers/net/znet.c
Previous file: linux/drivers/net/wavelan.p.h
Back to the patch index
Back to the overall index
- Lines: 1441
- Date:
Thu Jan 1 02:00:00 1970
- Orig file:
v2.1.24/linux/drivers/net/wic.c
- Orig date:
Thu Jan 23 21:06:49 1997
diff -u --recursive --new-file v2.1.24/linux/drivers/net/wic.c linux/drivers/net/wic.c
@@ -1,1440 +0,0 @@
-/* $Id: wic.c,v 1.0 1995/02/11 10:26:05 hayes Exp $ */
-/* WIC: A parallel port "network" driver for Linux. */
-/* based on the plip network driver */
-/* Modified for Linux 1.3.x by Alan Cox <Alan.Cox@linux.org> */
-
-char *version = "NET3 WIC version 0.9 hayes@netplumbing.com";
-
-/*
- Sources:
- Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>
- "parallel.asm" parallel port packet driver and from the plip.c
- parallel networking linux driver from the 1.2.13 Linux
- distribution.
-
- The packet is encapsulated as if it were ethernet.
-
-*/
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/if_ether.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/lp.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_wic.h>
-
-#include <linux/tqueue.h>
-#include <linux/ioport.h>
-#include <asm/bitops.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-#include <linux/string.h>
-
-#define NET_DEBUG 1
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-unsigned int net_debug = NET_DEBUG;
-
-/* Connection time out = WIC_TRIGGER_WAIT * WIC_DELAY_UNIT usec */
-#define WIC_TRIGGER_WAIT 500
-
-/* Nibble time out = WIC_NIBBLE_WAIT * WIC_DELAY_UNIT usec */
-#define WIC_NIBBLE_WAIT 3000
-
-#define PAR_DATA(dev) ((dev)->base_addr+0)
-#define PAR_STATUS(dev) ((dev)->base_addr+1)
-#define PAR_CONTROL(dev) ((dev)->base_addr+2)
-
-/* Bottom halfs */
-void wic_kick_bh(struct device *dev);
-void wic_bh(struct device *dev);
-
-/* Interrupt handler */
-void wic_interrupt(int irq, void *dev_ptr, struct pt_regs *regs);
-
-/* Functions for DEV methods */
-int wic_rebuild_header(struct sk_buff *skb);
-int wic_tx_packet(struct sk_buff *skb, struct device *dev);
-int wic_open(struct device *dev);
-int wic_close(struct device *dev);
-struct enet_statistics *wic_get_stats(struct device *dev);
-int wic_config(struct device *dev, struct ifmap *map);
-int wic_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-int send_cmd(struct device *dev, unsigned char *cmd, char len);
-int recv_cmd_resp(struct device *dev, unsigned char *cmd);
-int send_byte(struct device *dev, unsigned char c);
-int get_byte(struct device *dev, unsigned char *c);
-int ack_resp(struct device *dev);
-int check_bfr(struct device *dev);
-void wic_reset(struct device *dev);
-void wic_set_multicast_list(struct device *dev);
-
-#define LOOPCNT 30000
-unsigned char tog = 3;
-unsigned char save = 0;
-
-enum wic_connection_state {
- WIC_CN_NONE=0,
- WIC_CN_RECEIVE,
- WIC_CN_SEND,
- WIC_CN_CLOSING,
- WIC_CN_ERROR
-};
-
-enum wic_packet_state {
- WIC_PK_DONE=0,
- WIC_PK_TRIGGER,
- WIC_PK_LENGTH_LSB,
- WIC_PK_LENGTH_MSB,
- WIC_PK_DATA,
- WIC_PK_CHECKSUM
-};
-
-enum wic_nibble_state {
- WIC_NB_BEGIN,
- WIC_NB_1,
- WIC_NB_2,
-};
-
-struct wic_local {
- enum wic_packet_state state;
- enum wic_nibble_state nibble;
- union {
- struct {
-#if defined(__LITTLE_ENDIAN)
- unsigned char lsb;
- unsigned char msb;
-#elif defined(__BIG_ENDIAN)
- unsigned char msb;
- unsigned char lsb;
-#else
-#error "Please fix the endianness defines in <asm/byteorder.h>"
-#endif
- } b;
- unsigned short h;
- } length;
- unsigned short byte;
- unsigned char checksum;
- unsigned char data;
- struct sk_buff *skb;
-};
-
-struct net_local {
- struct enet_statistics enet_stats;
- struct tq_struct immediate;
- struct tq_struct deferred;
- struct wic_local snd_data;
- struct wic_local rcv_data;
- unsigned long trigger;
- unsigned long nibble;
- enum wic_connection_state connection;
- unsigned short timeout_count;
- char is_deferred;
- int (*orig_rebuild_header)(struct sk_buff *skb);
-};
-
-/* Entry point of WIC driver.
- Probe the hardware, and register/initialize the driver. */
-
-int wic_init(struct device *dev)
-{
- struct net_local *nl;
- struct wicconf wc;
- int i;
-
- /* Check region before the probe */
- if (check_region(PAR_DATA(dev), 3) < 0)
- return -ENODEV;
-
- /* Check that there is something at base_addr. */
- outb(0, PAR_DATA(dev));
- udelay(1000);
- if (inb(PAR_DATA(dev)) != 0)
- return -ENODEV;
-
- printk("%s\n",version);
- printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
- if (dev->irq) {
- printk("using assigned IRQ %d.\n", dev->irq);
- } else {
- int irq = 0;
-#ifdef MODULE
- /* dev->irq==0 means autoprobe, but we don't try to do so
- with module. We can change it by ifconfig */
-#else
- unsigned int irqs = probe_irq_on();
-
- outb(0x00, PAR_CONTROL(dev));
- udelay(1000);
- udelay(1000);
- irq = probe_irq_off(irqs);
-#endif
- if (irq > 0) {
- dev->irq = irq;
- printk("using probed IRQ %d.\n", dev->irq);
- } else
- printk("failed to detect IRQ(%d) --"
- " Please set IRQ by ifconfig.\n", irq);
- }
-
- request_region(PAR_DATA(dev), 3, dev->name);
-
- /* Fill in the generic fields of the device structure. */
- ether_setup(dev);
-
- /* Then, override parts of it */
- dev->hard_start_xmit = wic_tx_packet;
- dev->open = wic_open;
- dev->stop = wic_close;
- dev->get_stats = wic_get_stats;
- dev->set_config = wic_config;
- dev->do_ioctl = wic_ioctl;
- dev->mtu = 1514;
- dev->set_multicast_list = wic_set_multicast_list;
- dev->flags = IFF_BROADCAST | IFF_RUNNING | IFF_NOTRAILERS;
-
- /* get the MAC address from the controller */
- wc.len = 1;
- wc.pcmd = WIC_GETNET;
- check_bfr(dev);
- send_cmd(dev, (unsigned char *)&wc, 1);
- wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
- while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
- wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-
- printk("%s:MAC address: ",dev->name);
- for (i=0; i < ETH_ALEN ; i++) {
- dev->dev_addr[i] = wc.data[i];
- printk("%2x ",dev->dev_addr[i]);
- }
- printk("\n");
-
- /* Set the private structure */
- dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
- if (dev->priv == NULL)
- return EAGAIN;
- memset(dev->priv, 0, sizeof(struct net_local));
- nl = (struct net_local *) dev->priv;
-
- nl->orig_rebuild_header = dev->rebuild_header;
- dev->rebuild_header = wic_rebuild_header;
-
- /* Initialize constants */
- nl->trigger = WIC_TRIGGER_WAIT;
- nl->nibble = WIC_NIBBLE_WAIT;
-
- /* Initialize task queue structures */
- nl->immediate.next = NULL;
- nl->immediate.sync = 0;
- nl->immediate.routine = (void *)(void *)wic_bh;
- nl->immediate.data = dev;
-
- nl->deferred.next = NULL;
- nl->deferred.sync = 0;
- nl->deferred.routine = (void *)(void *)wic_kick_bh;
- nl->deferred.data = dev;
-
- return 0;
-}
-
-/* Bottom half handler for the delayed request.
- This routine is kicked by do_timer().
- Request `wic_bh' to be invoked. */
-void wic_kick_bh(struct device *dev)
-{
- struct net_local *nl = (struct net_local *)dev->priv;
-
- if (nl->is_deferred) {
- queue_task(&nl->immediate, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- }
-}
-
-/* Forward declarations of internal routines */
-int wic_none(struct device *, struct net_local *,
- struct wic_local *, struct wic_local *);
-int wic_receive_packet(struct device *, struct net_local *,
- struct wic_local *, struct wic_local *);
-int wic_send_packet(struct device *, struct net_local *,
- struct wic_local *, struct wic_local *);
-int wic_connection_close(struct device *, struct net_local *,
- struct wic_local *, struct wic_local *);
-int wic_error(struct device *, struct net_local *,
- struct wic_local *, struct wic_local *);
-int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
- struct wic_local *snd,
- struct wic_local *rcv,
- int error);
-
-#define OK 0
-#define TIMEOUT 1
-#define ERROR 2
-
-typedef int (*wic_func)(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv);
-
-wic_func connection_state_table[] =
-{
- wic_none,
- wic_receive_packet,
- wic_send_packet,
- wic_connection_close,
- wic_error
-};
-
-void wic_set_multicast_list(struct device *dev)
-{
- struct wicconf wc;
- struct wic_net *wn;
-
- disable_irq(dev->irq);
- save &= 0xef; /* disable */
- outb(save, PAR_CONTROL(dev));
-
- wc.len = 1;
- wc.pcmd = WIC_GETNET;
- check_bfr(dev);
- tog = 3;
- send_cmd(dev, (unsigned char *)&wc, 1);
- wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
- while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
- wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
- wn = (struct wic_net *)&wc.data;
- if(dev->flags&IFF_PROMISC)
- {
- /* promiscuous mode */
- wn->mode |= (NET_MODE_ME | NET_MODE_BCAST |
- NET_MODE_MCAST | NET_MODE_PROM);
- printk("%s: Setting promiscuous mode\n", dev->name);
- }
- else if((dev->flags&IFF_ALLMULTI) || dev->mc_count)
- {
- wn->mode &= ~NET_MODE_PROM;
- wn->mode |= (NET_MODE_MCAST | NET_MODE_ME | NET_MODE_BCAST);
- }
- else
- {
- wn->mode &= ~(NET_MODE_PROM | NET_MODE_MCAST);
- wn->mode |= (NET_MODE_ME | NET_MODE_BCAST);
- }
- wc.len = 23;
- wc.pcmd = WIC_SETNET;
- check_bfr(dev);
- tog = 3;
- send_cmd(dev, (unsigned char *)&wc, wc.len);
-
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return;
-}
-
-/* Bottom half handler of WIC. */
-void wic_bh(struct device *dev)
-{
- struct net_local *nl = (struct net_local *)dev->priv;
- struct wic_local *snd = &nl->snd_data;
- struct wic_local *rcv = &nl->rcv_data;
- wic_func f;
- int r;
-
- nl->is_deferred = 0;
- f = connection_state_table[nl->connection];
- if ((r = (*f)(dev, nl, snd, rcv)) != OK
- && (r = wic_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
- nl->is_deferred = 1;
- queue_task(&nl->deferred, &tq_timer);
- }
-}
-
-int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv,
- int error)
-{
- unsigned char c0;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (nl->connection == WIC_CN_SEND) {
-
- if (error != ERROR) { /* Timeout */
- nl->timeout_count++;
- if ((snd->state == WIC_PK_TRIGGER
- && nl->timeout_count <= 10)
- || nl->timeout_count <= 3) {
- restore_flags(flags);
- /* Try again later */
- return TIMEOUT;
- }
- c0 = inb(PAR_STATUS(dev));
- printk("%s: transmit timeout(%d,%02x)\n",
- dev->name, snd->state, c0);
- }
- nl->enet_stats.tx_errors++;
- nl->enet_stats.tx_aborted_errors++;
- } else if (nl->connection == WIC_CN_RECEIVE) {
- if (rcv->state == WIC_PK_TRIGGER) {
- /* Transmission was interrupted. */
- restore_flags(flags);
- return OK;
- }
- if (error != ERROR) { /* Timeout */
- if (++nl->timeout_count <= 3) {
- restore_flags(flags);
- /* Try again later */
- return TIMEOUT;
- }
- c0 = inb(PAR_STATUS(dev));
- printk("%s: receive timeout(%d,%02x)\n",
- dev->name, rcv->state, c0);
- }
- nl->enet_stats.rx_dropped++;
- }
- rcv->state = WIC_PK_DONE;
- if (rcv->skb) {
- kfree_skb(rcv->skb, FREE_READ);
- rcv->skb = NULL;
- }
- snd->state = WIC_PK_DONE;
- if (snd->skb) {
- dev_kfree_skb(snd->skb, FREE_WRITE);
- snd->skb = NULL;
- }
-#if (0)
- disable_irq(dev->irq);
- save &= 0xef; /* disable */
- outb(save, PAR_CONTROL(dev));
- dev->tbusy = 1;
- outb(0x00, PAR_DATA(dev));
-#endif /* (0) */
- nl->connection = WIC_CN_ERROR;
- restore_flags(flags);
-
- return TIMEOUT;
-}
-
-int wic_none(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv)
-{
- return OK;
-}
-
-/* WIC_RECEIVE --- receive a byte(two nibbles)
- Returns OK on success, TIMEOUT on timeout */
-extern inline int wic_receive(unsigned short nibble_timeout,
- unsigned short status_addr, enum wic_nibble_state *ns_p, unsigned char *data_p)
-{
- unsigned int cx;
-
- cx = LOOPCNT;
- while ((inb(status_addr) & 0x08) != ((tog<<3) & 0x08)) {
- if (--cx == 0) {
- return TIMEOUT;
- }
- }
- *data_p = inb(status_addr-1);
- tog ^= 0x01;
- outb(tog| save, status_addr+1);
- return OK;
-}
-
-/* WIC_RECEIVE_PACKET --- receive a packet */
-
-int wic_receive_packet(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv)
-{
- unsigned short status_addr = PAR_STATUS(dev);
- unsigned short nibble_timeout = nl->nibble;
- unsigned char *lbuf;
- unsigned char junk;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- switch (rcv->state) {
- case WIC_PK_TRIGGER:
- disable_irq(dev->irq);
- save &= 0xef; /* disable */
- outb(save, PAR_CONTROL(dev));
-
- dev->interrupt = 0;
-
- tog &= 0xfe;
- ack_resp(dev);
- if (net_debug > 2)
- printk("%s: receive start\n", dev->name);
- rcv->state = WIC_PK_LENGTH_LSB;
- rcv->nibble = WIC_NB_BEGIN;
-
- case WIC_PK_LENGTH_LSB:
- if (net_debug > 2)
- printk("%s: WIC_PK_LENGTH_LSB\n", dev->name);
- if (snd->state != WIC_PK_DONE) {
- if (wic_receive(nl->trigger, status_addr,
- &rcv->nibble, &rcv->length.b.lsb)) {
- /* collision, here dev->tbusy == 1 */
- rcv->state = WIC_PK_DONE;
- nl->is_deferred = 1;
- nl->connection = WIC_CN_SEND;
- restore_flags(flags);
- queue_task(&nl->deferred, &tq_timer);
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return OK;
- }
- } else {
- if (wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &rcv->length.b.lsb)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- }
- rcv->state = WIC_PK_LENGTH_MSB;
-
- case WIC_PK_LENGTH_MSB:
- if (net_debug > 2)
- printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
- if (wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &rcv->length.b.msb)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- if (rcv->length.h > dev->mtu || rcv->length.h < 8) {
- printk("%s: bad packet size %d.\n", dev->name, rcv->length.h);
- restore_flags(flags);
- return ERROR;
- }
- /* Malloc up new buffer. */
- rcv->skb = dev_alloc_skb(rcv->length.h);
- if (rcv->skb == NULL) {
- printk("%s: Memory squeeze.\n", dev->name);
- restore_flags(flags);
- return ERROR;
- }
- skb_put(rcv->skb,rcv->length.h);
- rcv->skb->dev = dev;
-
- rcv->state = WIC_PK_DATA;
- rcv->byte = 0;
- rcv->checksum = 0;
-
- /* sequence numbers */
- if (net_debug > 2)
- printk("%s: WIC_PK_SEQ\n", dev->name);
- if (wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &junk)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- if (wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &junk)) {
- restore_flags(flags);
- return TIMEOUT;
- }
-
- case WIC_PK_DATA:
- if (net_debug > 2)
- printk("%s: WIC_PK_DATA: length %i\n", dev->name,
- rcv->length.h);
- lbuf = rcv->skb->data;
- do {
- if (wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &lbuf[rcv->byte])) {
- restore_flags(flags);
- return TIMEOUT;
- }
- } while (++rcv->byte < (rcv->length.h - 4));
-
- /* receive pad byte */
- if (rcv->length.h & 0x01)
- wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &lbuf[rcv->byte]);
-
- do {
- rcv->checksum += lbuf[--rcv->byte];
- } while (rcv->byte);
-
- rcv->state = WIC_PK_CHECKSUM;
-
- case WIC_PK_CHECKSUM:
- if (net_debug > 2)
- printk("%s: WIC_PK_CHECKSUM\n", dev->name);
- if (wic_receive(nibble_timeout, status_addr,
- &rcv->nibble, &junk)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- outb(0, PAR_DATA(dev));
- rcv->state = WIC_PK_DONE;
-
- case WIC_PK_DONE:
- if (net_debug > 2)
- printk("%s: WIC_PK_DONE\n", dev->name);
- /* Inform the upper layer for the arrival of a packet. */
- netif_rx(rcv->skb);
- nl->enet_stats.rx_packets++;
- rcv->skb = NULL;
- if (net_debug > 2)
- printk("%s: receive end\n", dev->name);
-
- /* Close the connection. */
- if (snd->state != WIC_PK_DONE) {
- nl->connection = WIC_CN_SEND;
- restore_flags(flags);
- queue_task(&nl->immediate, &tq_immediate);
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return OK;
- } else {
- nl->connection = WIC_CN_NONE;
- restore_flags(flags);
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return OK;
- }
- }
- restore_flags(flags);
- return OK;
-}
-
-/* WIC_SEND --- send a byte (two nibbles)
- Returns OK on success, TIMEOUT when timeout */
-extern inline int wic_send(unsigned short nibble_timeout,
- unsigned short data_addr, enum wic_nibble_state *ns_p,
- unsigned char data)
-{
- unsigned int cx;
-
- cx = LOOPCNT;
- while ((inb(data_addr+1) & 0x80) == ((tog<<7) & 0x80)) {
- if (--cx == 0) {
- return -TIMEOUT;
- }
- }
- outb(data, data_addr);
- outb(tog | save, data_addr+2);
- tog ^= 0x01;
- return OK;
-}
-
-/* WIC_SEND_PACKET --- send a packet */
-int wic_send_packet(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv)
-{
- unsigned short data_addr = PAR_DATA(dev);
- unsigned short nibble_timeout = nl->nibble;
- unsigned char *lbuf;
- unsigned int cx;
- unsigned int pad = 2;
- unsigned long flags;
-
- if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
- printk("%s: send skb lost\n", dev->name);
- snd->state = WIC_PK_DONE;
- snd->skb = NULL;
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return ERROR;
- }
-
- save_flags(flags);
- cli();
- switch (snd->state) {
- case WIC_PK_TRIGGER:
-
- if (nl->connection == WIC_CN_RECEIVE) {
- /* interrupted */
- nl->enet_stats.collisions++;
- restore_flags(flags);
- if (net_debug > 1)
- printk("%s: collision.\n", dev->name);
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return OK;
- }
-
- disable_irq(dev->irq);
- save &= 0xef; /* disable */
- outb(save, PAR_CONTROL(dev));
-
- /* interrupt controller */
- tog = 3;
- outb(0x06 | save, PAR_CONTROL(dev));
-
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
- if (--cx == 0) {
- restore_flags(flags);
- return TIMEOUT;
- }
- if (cx == 10)
- outb(0x02, PAR_CONTROL(dev));
- }
-
- if (net_debug > 2)
- printk("%s: send start\n", dev->name);
- snd->state = WIC_PK_LENGTH_LSB;
- snd->nibble = WIC_NB_BEGIN;
- nl->timeout_count = 0;
-
- case WIC_PK_LENGTH_LSB:
- if (snd->length.h & 0x01)
- pad = 3;
- else
- pad = 2;
- snd->length.h += (4 + pad); /* len + seq + data + pad */
- if (net_debug > 2)
- printk("%s: WIC_PK_LENGTH_LSB: length = %i\n",
- dev->name, snd->length.h);
-
- if (wic_send(nibble_timeout, data_addr,
- &snd->nibble, snd->length.b.lsb)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- snd->state = WIC_PK_LENGTH_MSB;
-
- case WIC_PK_LENGTH_MSB:
- if (net_debug > 2)
- printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
- if (wic_send(nibble_timeout, data_addr,
- &snd->nibble, snd->length.b.msb)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- snd->state = WIC_PK_DATA;
- snd->byte = 0;
- snd->checksum = 0;
-
- case WIC_PK_DATA:
- /* adjust length back to data only */
- snd->length.h -= (4 + pad); /* len + seq + data + pad */
- /* send 2 byte sequence number */
- if (net_debug > 2)
- printk("%s: WIC_SEQ\n", dev->name);
- if (wic_send(nibble_timeout, data_addr,
- &snd->nibble, 0)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- if (wic_send(nibble_timeout, data_addr,
- &snd->nibble, 0)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- if (net_debug > 2)
- printk("%s: WIC_PK_DATA\n", dev->name);
-
- do {
- if (wic_send(nibble_timeout, data_addr,
- &snd->nibble, lbuf[snd->byte])) {
- restore_flags(flags);
- return TIMEOUT;
- }
- }
- while (++snd->byte < snd->length.h);
-
- do
- snd->checksum += lbuf[--snd->byte];
- while (snd->byte);
-
- snd->state = WIC_PK_CHECKSUM;
-
- case WIC_PK_CHECKSUM:
- /* send pad bytes */
- if (net_debug > 2)
- printk("%s: WIC_PK_PAD: %i bytes\n",
- dev->name, pad);
- while(pad--)
- if (wic_send(nibble_timeout, data_addr,
- &snd->nibble, 0)) {
- restore_flags(flags);
- return TIMEOUT;
- }
- dev_kfree_skb(snd->skb, FREE_WRITE);
- nl->enet_stats.tx_packets++;
- snd->state = WIC_PK_DONE;
-
- case WIC_PK_DONE:
- if (net_debug > 2)
- printk("%s: WIC_PK_DONE\n", dev->name);
- /* Close the connection */
- outb (0x00, PAR_DATA(dev));
- outb(save, PAR_CONTROL(dev));
-
- snd->skb = NULL;
- if (net_debug > 2)
- printk("%s: send end\n", dev->name);
- nl->connection = WIC_CN_CLOSING;
- nl->is_deferred = 1;
- restore_flags(flags);
- queue_task(&nl->deferred, &tq_timer);
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return OK;
- }
- restore_flags(flags);
- return OK;
-}
-
-int wic_connection_close(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (nl->connection == WIC_CN_CLOSING) {
- nl->connection = WIC_CN_NONE;
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
- restore_flags(flags);
- return OK;
-}
-
-/* WIC_ERROR --- wait till other end settled */
-int wic_error(struct device *dev, struct net_local *nl,
- struct wic_local *snd, struct wic_local *rcv)
-{
- unsigned char status;
-
- status = inb(PAR_STATUS(dev));
- if ((status & 0xf8) == 0x80) {
- if (net_debug > 2)
- printk("%s: reset interface.\n", dev->name);
- nl->connection = WIC_CN_NONE;
- dev->tbusy = 0;
- dev->interrupt = 0;
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- mark_bh(NET_BH);
- } else {
- nl->is_deferred = 1;
- queue_task(&nl->deferred, &tq_timer);
- }
-
- return OK;
-}
-
-/* Handle the parallel port interrupts. */
-void wic_interrupt(int irq, void *dev_ptr, struct pt_regs * regs)
-{
- struct device *dev = (struct device *) irq2dev_map[irq];
- struct net_local *nl = (struct net_local *)dev->priv;
- struct wic_local *rcv = &nl->rcv_data;
- unsigned long flags;
-
- if (dev == NULL) {
- printk ("wic_interrupt: irq %d for unknown device.\n", irq);
- return;
- }
-
- if (dev->interrupt) {
- return;
- }
-
- if (check_bfr(dev) < 0) {
- return;
- }
-
- dev->interrupt = 1;
- if (net_debug > 3)
- printk("%s: interrupt.\n", dev->name);
-
- save_flags(flags);
- cli();
- switch (nl->connection) {
- case WIC_CN_CLOSING:
- dev->tbusy = 0;
- case WIC_CN_NONE:
- case WIC_CN_SEND:
- dev->last_rx = jiffies;
- rcv->state = WIC_PK_TRIGGER;
- nl->connection = WIC_CN_RECEIVE;
- nl->timeout_count = 0;
- restore_flags(flags);
- queue_task(&nl->immediate, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- break;
-
- case WIC_CN_RECEIVE:
- printk("%s: receive interrupt when receiving packet\n", dev->name);
- restore_flags(flags);
- break;
-
- case WIC_CN_ERROR:
- printk("%s: receive interrupt in error state\n", dev->name);
- restore_flags(flags);
- break;
- }
-}
-
-int wic_rebuild_header(struct sk_buff *skb)
-{
- struct device *dev = skb->dev;
- struct net_local *nl = (struct net_local *)dev->priv;
- struct ethhdr *eth = (struct ethhdr *)skb->data;
- int i;
-
- if ((dev->flags & IFF_NOARP)==0)
- return nl->orig_rebuild_header(skb);
-
- if (eth->h_proto != htons(ETH_P_IP)) {
- printk("wic_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return 0;
- }
-
- for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
- eth->h_dest[i] = 0xfc;
- memcpy(&(eth->h_dest[i]), &skb->daddr, 4);
- return 0;
-}
-
-int wic_tx_packet(struct sk_buff *skb, struct device *dev)
-{
- struct net_local *nl = (struct net_local *)dev->priv;
- struct wic_local *snd = &nl->snd_data;
- unsigned long flags;
-
- if (dev->tbusy)
- return 1;
-
- /* If some higher layer thinks we've missed an tx-done interrupt
- we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- itself. */
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
-
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
-
- if (skb->len > dev->mtu) {
- printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
- dev->tbusy = 0;
- return 0;
- }
-
- if (net_debug > 2)
- printk("%s: send request\n", dev->name);
-
- save_flags(flags);
- cli();
- dev->trans_start = jiffies;
- snd->skb = skb;
- snd->length.h = skb->len;
- snd->state = WIC_PK_TRIGGER;
- if (nl->connection == WIC_CN_NONE) {
- nl->connection = WIC_CN_SEND;
- nl->timeout_count = 0;
- }
- restore_flags(flags);
- queue_task(&nl->immediate, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-
- return 0;
-}
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine gets exclusive access to the parallel port by allocating
- its IRQ line.
- */
-
-int wic_open(struct device *dev)
-{
- struct net_local *nl = (struct net_local *)dev->priv;
- unsigned long flags;
-
- if (dev->irq == 0) {
- printk("%s: IRQ is not set. Please set it by ifconfig.\n", dev->name);
- return -EAGAIN;
- }
- save_flags(flags);
- cli();
- check_bfr(dev);
- if (request_irq(dev->irq , wic_interrupt, 0, dev->name, NULL) != 0) {
- sti();
- printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- irq2dev_map[dev->irq] = dev;
- restore_flags(flags);
-
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- /* Initialize the state machine. */
- nl->rcv_data.state = nl->snd_data.state = WIC_PK_DONE;
- nl->rcv_data.skb = nl->snd_data.skb = NULL;
- nl->connection = WIC_CN_NONE;
- nl->is_deferred = 0;
-
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/* The inverse routine to wic_open (). */
-int wic_close(struct device *dev)
-{
- struct net_local *nl = (struct net_local *)dev->priv;
- struct wic_local *snd = &nl->snd_data;
- struct wic_local *rcv = &nl->rcv_data;
-
- dev->tbusy = 1;
- dev->start = 0;
- cli();
- free_irq(dev->irq, NULL);
- irq2dev_map[dev->irq] = NULL;
- nl->is_deferred = 0;
- nl->connection = WIC_CN_NONE;
- sti();
- outb(0x00, PAR_DATA(dev));
-
- snd->state = WIC_PK_DONE;
- if (snd->skb) {
- dev_kfree_skb(snd->skb, FREE_WRITE);
- snd->skb = NULL;
- }
- rcv->state = WIC_PK_DONE;
- if (rcv->skb) {
- kfree_skb(rcv->skb, FREE_READ);
- rcv->skb = NULL;
- }
-
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-struct enet_statistics *
-wic_get_stats(struct device *dev)
-{
- struct net_local *nl = (struct net_local *)dev->priv;
- struct enet_statistics *r = &nl->enet_stats;
-
- return r;
-}
-
-int
-wic_config(struct device *dev, struct ifmap *map)
-{
- if (dev->flags & IFF_UP)
- return -EBUSY;
-
- if (map->base_addr != (unsigned long)-1
- && map->base_addr != dev->base_addr)
- printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
-
- if (map->irq != (unsigned char)-1)
- dev->irq = map->irq;
- return 0;
-}
-
-int
-wic_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-{
- struct wicconf wc;
- int err;
- char len = 0;
- unsigned long flags;
-
- err=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(struct wicconf));
- if (err)
- return err;
- copy_from_user(&wc, rq->ifr_data, sizeof(struct wicconf));
- switch(wc.pcmd) {
- case WIC_AYT:
- strcpy(wc.data, version);
- wc.len = strlen(wc.data);
- copy_to_user(rq->ifr_data, &wc, sizeof(struct wicconf));
- /* return 0; */
- break;
- case WIC_RESET:
- wic_reset(dev);
- return(0);
- /* break; */
- case WIC_SETSN:
- len = 17;
- break;
- case WIC_SETPS:
- len = 3;
- break;
- case WIC_SETAF:
- case WIC_SETGPF:
- len = 2;
- break;
- case WIC_SETNET:
- len = 23;
- break;
- case WIC_SETSYS:
- len = 15;
- break;
- case WIC_GETVERH:
- case WIC_GETNL:
- case WIC_GETSN:
- case WIC_CLRSTATS:
- case WIC_GETSTATS:
- case WIC_GETVERM:
- case WIC_GETNET:
- case WIC_GETSYS:
- len = 1;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- /* Wait for lock to free */
- while (set_bit(0, (void *)&dev->tbusy) != 0);
- save_flags(flags);
- cli();
-
- disable_irq(dev->irq);
- save &= 0xef; /* disable */
- outb(save, PAR_CONTROL(dev));
- err = check_bfr(dev);
- tog = 3;
- err = send_cmd(dev, (unsigned char *)&wc, len);
-
- if (wc.pcmd & 0x40) { /* response */
- len = (char)recv_cmd_resp(dev, wc.data);
- while ((len == 1) && (wc.data[0] == 0x7)) { /* controller int */
- len = (char)recv_cmd_resp(dev, wc.data);
- }
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- wc.len = (len <0) ? 0 : len;
- copy_to_user(rq->ifr_data, &wc, sizeof(struct wicconf));
- } else {
- save |= 0x10; /* enable */
- outb(save, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- }
- restore_flags(flags);
-
- outb(0, PAR_DATA(dev));
- dev->tbusy = 0;
- return 0;
-}
-
-int
-get_byte(struct device *dev, unsigned char *c)
-{
-unsigned int cx;
-
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0x08) != ((tog << 3)&0x08)) {
- if (--cx == 0) {
- return(-TIMEOUT);
- }
- }
- /* receive a byte of data */
- *c = inb(PAR_DATA(dev));
- tog ^= 0x01;
- /* ack reception of data */
- outb(tog| save, PAR_CONTROL(dev));
- return OK;
-}
-
-int
-ack_resp(struct device *dev)
-{
-unsigned int cx;
-
- outb(save | 0x27, PAR_CONTROL(dev));
-
- /* wait for controller to remove interrupt [Ack(low), Busy(low)] */
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0xc0) != 0x80) {
- if (--cx == 0) {
- return -TIMEOUT;
- }
- }
-
- outb(save | 0x22, PAR_CONTROL(dev));
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0x08) == 0x08) {
- if (--cx == 0) {
- return TIMEOUT;
- }
- }
- tog |= 0x20;
- tog &= 0xfe;
- return OK;
-}
-
-void
-wic_reset(struct device *dev)
-{
-unsigned char stat;
-
- stat = inb(PAR_CONTROL(dev));
- outb(0, PAR_DATA(dev));
- outb(stat | 0x08, PAR_CONTROL(dev));
- outb(stat & 0xf7, PAR_CONTROL(dev));
- dev->tbusy = 0;
- dev->interrupt = 0;
- tog = 3;
- save = 0;
- return;
-}
-
-int
-check_bfr(struct device *dev)
-{
-unsigned char c0, l;
-
- if ((inb(PAR_STATUS(dev)) & 0xc8) == 0x48) {
- save |= 0x80;
- outb(0x23| save, PAR_CONTROL(dev));
- ack_resp(dev);
- get_byte(dev, &l); /* len */
- while (l--) {
- get_byte(dev, &c0);
- }
- get_byte(dev, &c0);
- save &=0x7f;
- outb(0, PAR_DATA(dev));
- return -l;
- } else
- return (0);
-}
-
-
-int
-recv_cmd_resp(struct device *dev, unsigned char *buf)
-{
-unsigned char cksum = 0;
-int err;
-unsigned char c0 = 0;
-int len;
-int savelen;
-unsigned int cx;
-int i;
-
- tog &= 0xfe;
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0xc8) != 0x48) {
- if (--cx == 0) {
- /* clear Busy */
- outb(0, PAR_DATA(dev));
- printk("rcv_cmd_resp: timeout\n");
- return -TIMEOUT;
- }
- }
-
- /* acknowledge the interrupt */
- i = ack_resp(dev);
-
- /* get length */
- err = get_byte(dev, &c0);
- if (err < 0) {
- printk("get_byte1: failed\n");
- return(err);
- }
- len = c0;
- savelen = len;
-
- /* get data */
- while(len--) {
- err = get_byte(dev, &c0);
- if (err < 0) {
- printk("get_byte2: failed\n");
- return(err);
- }
- outb(0, PAR_DATA(dev));
- *buf = c0;
- cksum += c0;
- buf++;
- }
- /* get cksum */
- err = get_byte(dev, &c0);
- if (err < 0) {
- printk("get_byte3: failed\n");
- return(err);
- }
- if (cksum != c0) {
- printk("cksum failed\n");
- return(-3);
- }
- /* get trailing byte, if any... */
- get_byte(dev, &c0);
- return(savelen);
-}
-
-int
-send_byte(struct device *dev, unsigned char c)
-{
-unsigned int cx;
-
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog<<7) & 0x80)) {
- if (--cx == 0) {
- return(-TIMEOUT);
- }
- }
- outb(c, PAR_DATA(dev));
- outb(save |tog, PAR_CONTROL(dev));
- tog ^= 0x01;
- return OK;
-}
-
-
-int
-send_cmd(struct device *dev, unsigned char *cmd, char len)
-{
-unsigned char cksum = 0;
-int err = 0;
-unsigned int cx;
-
- /* interrupt controller */
- outb(save | 0x04, PAR_CONTROL(dev));
- /* wait for ACK */
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
- if (--cx == 0)
- return -TIMEOUT;
- if (cx == 10)
- outb(0x02, PAR_CONTROL(dev));
- }
- /* cmd coming... */
- outb(save | 0x02, PAR_CONTROL(dev));
- /* send length byte */
- err = send_byte(dev, (unsigned char)len);
-
- /* send data */
- while (len--) {
- err = send_byte(dev, *cmd);
- if (err < 0) {
- return err;
- }
- cksum += *cmd;
- cmd++;
- }
-
- /* send cksum byte */
- err = send_byte(dev, cksum);
- if (err < 0)
- return err;
-
- cx = LOOPCNT;
- while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog <<7)&0x80)) {
- if (--cx == 0)
- return -TIMEOUT;
- }
- save |= 0x80;
- outb(save | 0x23, PAR_CONTROL(dev));
- outb(0, PAR_DATA(dev));
- return OK;
-}
-
-#ifdef MODULE
-struct device dev_wic0 =
-{
- "wic0" /*"wic"*/,
- 0, 0, 0, 0, /* memory */
- 0x3BC, 5, /* base, irq */
- 0, 0, 0, NULL, wic_init
-};
-
-struct device dev_wic1 =
-{
- "wic1" /*"wic"*/,
- 0, 0, 0, 0, /* memory */
- 0x378, 7, /* base, irq */
- 0, 0, 0, NULL, wic_init
-};
-
-struct device dev_wic2 =
-{
- "wic2" /*"wic"*/,
- 0, 0, 0, 0, /* memory */
- 0x278, 2, /* base, irq */
- 0, 0, 0, NULL, wic_init
-};
-
-int
-init_module(void)
-{
- int devices=0;
-
- if (register_netdev(&dev_wic0) != 0)
- devices++;
- if (register_netdev(&dev_wic1) != 0)
- devices++;
- if (register_netdev(&dev_wic2) != 0)
- devices++;
- if (devices == 0)
- return -EIO;
- return 0;
-}
-
-void
-cleanup_module(void)
-{
- if (dev_wic0.priv) {
- unregister_netdev(&dev_wic0);
- release_region(PAR_DATA(&dev_wic0), 3);
- kfree_s(dev_wic0.priv, sizeof(struct net_local));
- dev_wic0.priv = NULL;
- }
- if (dev_wic1.priv) {
- unregister_netdev(&dev_wic1);
- release_region(PAR_DATA(&dev_wic1), 3);
- kfree_s(dev_wic1.priv, sizeof(struct net_local));
- dev_wic1.priv = NULL;
- }
- if (dev_wic2.priv) {
- unregister_netdev(&dev_wic2);
- release_region(PAR_DATA(&dev_wic2), 3);
- kfree_s(dev_wic2.priv, sizeof(struct net_local));
- dev_wic2.priv = NULL;
- }
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c wic.c"
- * End:
- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov