patch-2.3.17 linux/drivers/net/plip.c
Next file: linux/drivers/net/ppp_async.c
Previous file: linux/drivers/net/irda/toshoboe.c
Back to the patch index
Back to the overall index
- Lines: 794
- Date:
Tue Sep 7 10:14:37 1999
- Orig file:
v2.3.16/linux/drivers/net/plip.c
- Orig date:
Wed Aug 18 11:36:42 1999
diff -u --recursive --new-file v2.3.16/linux/drivers/net/plip.c linux/drivers/net/plip.c
@@ -2,17 +2,22 @@
/* PLIP: A parallel port "network" driver for Linux. */
/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
/*
- * Authors: Donald Becker, <becker@super.org>
- * Tommy Thorn, <thorn@daimi.aau.dk>
- * Tanabe Hiroyasu, <hiro@sanpo.t.u-tokyo.ac.jp>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Peter Bauer, <100136.3530@compuserve.com>
- * Niibe Yutaka, <gniibe@mri.co.jp>
+ * Authors: Donald Becker <becker@super.org>
+ * Tommy Thorn <thorn@daimi.aau.dk>
+ * Tanabe Hiroyasu <hiro@sanpo.t.u-tokyo.ac.jp>
+ * Alan Cox <gw4pts@gw4pts.ampr.org>
+ * Peter Bauer <100136.3530@compuserve.com>
+ * Niibe Yutaka <gniibe@mri.co.jp>
+ * Nimrod Zimerman <zimerman@mailandnews.com>
*
+ * Enhancements:
* Modularization and ifreq/ifmap support by Alan Cox.
* Rewritten by Niibe Yutaka.
- * parport-sharing awareness code by Philip Blundell.
+ * parport-sharing awareness code by Philip Blundell.
* SMP locking by Niibe Yutaka.
+ * Support for parallel ports with no IRQ (poll mode),
+ * Modifications to use the parallel port API
+ * by Nimrod Zimerman.
*
* Fixes:
* Niibe Yutaka
@@ -49,7 +54,7 @@
* To use with DOS box, please do (Turn on ARP switch):
* # ifconfig plip[0-2] arp
*/
-static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n";
+static const char *version = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n";
/*
Sources:
@@ -57,7 +62,7 @@
"parallel.asm" parallel port packet driver.
The "Crynwr" parallel port standard specifies the following protocol:
- Trigger by sending '0x08' (this cause interrupt on other end)
+ Trigger by sending nibble '0x8' (this causes interrupt on other end)
count-low octet
count-high octet
... data octets
@@ -93,7 +98,6 @@
#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>
@@ -105,6 +109,7 @@
#include <linux/inetdevice.h>
#include <linux/skbuff.h>
#include <linux/if_plip.h>
+#include <net/neighbour.h>
#include <linux/tqueue.h>
#include <linux/ioport.h>
@@ -112,6 +117,7 @@
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <asm/spinlock.h>
+#include <asm/semaphore.h>
#include <linux/parport.h>
@@ -124,8 +130,8 @@
#endif
static unsigned int net_debug = NET_DEBUG;
-#define ENABLE(irq) enable_irq(irq)
-#define DISABLE(irq) disable_irq(irq)
+#define ENABLE(irq) if (irq != -1) enable_irq(irq)
+#define DISABLE(irq) if (irq != -1) disable_irq(irq)
/* In micro second */
#define PLIP_DELAY_UNIT 1
@@ -136,22 +142,21 @@
/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
#define PLIP_NIBBLE_WAIT 3000
-#define PAR_INTR_ON (LP_PINITP|LP_PSELECP|LP_PINTEN)
-#define PAR_INTR_OFF (LP_PINITP|LP_PSELECP)
-#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 */
+/* Bottom halves */
static void plip_kick_bh(struct net_device *dev);
static void plip_bh(struct net_device *dev);
+static void plip_timer_bh(struct net_device *dev);
/* Interrupt handler */
static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/* Functions for DEV methods */
-static int plip_rebuild_header(struct sk_buff *skb);
static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
+static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len);
+static int plip_hard_header_cache(struct neighbour *neigh,
+ struct hh_cache *hh);
static int plip_open(struct net_device *dev);
static int plip_close(struct net_device *dev);
static struct net_device_stats *plip_get_stats(struct net_device *dev);
@@ -210,6 +215,7 @@
struct net_device_stats enet_stats;
struct tq_struct immediate;
struct tq_struct deferred;
+ struct tq_struct timer;
struct plip_local snd_data;
struct plip_local rcv_data;
struct pardevice *pardev;
@@ -220,10 +226,52 @@
int is_deferred;
int port_owner;
int should_relinquish;
- int (*orig_rebuild_header)(struct sk_buff *skb);
+ int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len);
+ int (*orig_hard_header_cache)(struct neighbour *neigh,
+ struct hh_cache *hh);
spinlock_t lock;
+ atomic_t kill_timer;
+ struct semaphore killed_timer_sem;
};
+inline static void enable_parport_interrupts (struct net_device *dev)
+{
+ if (dev->irq != -1)
+ {
+ struct parport *port =
+ ((struct net_local *)dev->priv)->pardev->port;
+ port->ops->enable_irq (port);
+ }
+}
+
+inline static void disable_parport_interrupts (struct net_device *dev)
+{
+ if (dev->irq != -1)
+ {
+ struct parport *port =
+ ((struct net_local *)dev->priv)->pardev->port;
+ port->ops->disable_irq (port);
+ }
+}
+
+inline static void write_data (struct net_device *dev, unsigned char data)
+{
+ struct parport *port =
+ ((struct net_local *)dev->priv)->pardev->port;
+
+ port->ops->write_data (port, data);
+}
+
+inline static unsigned char read_status (struct net_device *dev)
+{
+ struct parport *port =
+ ((struct net_local *)dev->priv)->pardev->port;
+
+ return port->ops->read_status (port);
+}
+
/* Entry point of PLIP driver.
Probe the hardware, and register/initialize the driver.
@@ -243,8 +291,8 @@
dev->base_addr = pb->base;
if (pb->irq == -1) {
- printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name);
- return -ENODEV;
+ printk(KERN_INFO "plip: %s has no IRQ. Using IRQ-less mode,"
+ "which is fairly inefficient!\n", pb->name);
}
pardev = parport_register_device(pb, dev->name, plip_preempt,
@@ -255,21 +303,26 @@
return -ENODEV;
printk(KERN_INFO "%s", version);
- printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
- dev->base_addr, dev->irq);
+ if (dev->irq != -1)
+ printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n",
+ dev->name, dev->base_addr, dev->irq);
+ else
+ printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n",
+ dev->name, dev->base_addr);
/* Fill in the generic fields of the device structure. */
ether_setup(dev);
/* Then, override parts of it */
- dev->hard_start_xmit = plip_tx_packet;
- dev->open = plip_open;
- dev->stop = plip_close;
- dev->get_stats = plip_get_stats;
- dev->set_config = plip_config;
- dev->do_ioctl = plip_ioctl;
- dev->tx_queue_len = 10;
- dev->flags = IFF_POINTOPOINT|IFF_NOARP;
+ dev->hard_start_xmit = plip_tx_packet;
+ dev->open = plip_open;
+ dev->stop = plip_close;
+ dev->get_stats = plip_get_stats;
+ dev->set_config = plip_config;
+ dev->do_ioctl = plip_ioctl;
+ dev->header_cache_update = NULL;
+ dev->tx_queue_len = 10;
+ dev->flags = IFF_POINTOPOINT|IFF_NOARP;
memset(dev->dev_addr, 0xfc, ETH_ALEN);
/* Set the private structure */
@@ -282,8 +335,12 @@
memset(dev->priv, 0, sizeof(struct net_local));
nl = (struct net_local *) dev->priv;
- nl->orig_rebuild_header = dev->rebuild_header;
- dev->rebuild_header = plip_rebuild_header;
+ nl->orig_hard_header = dev->hard_header;
+ dev->hard_header = plip_hard_header;
+
+ nl->orig_hard_header_cache = dev->hard_header_cache;
+ dev->hard_header_cache = plip_hard_header_cache;
+
nl->pardev = pardev;
nl->port_owner = 0;
@@ -295,13 +352,21 @@
/* Initialize task queue structures */
nl->immediate.next = NULL;
nl->immediate.sync = 0;
- nl->immediate.routine = (void *)(void *)plip_bh;
+ nl->immediate.routine = (void (*)(void *))plip_bh;
nl->immediate.data = dev;
nl->deferred.next = NULL;
nl->deferred.sync = 0;
- nl->deferred.routine = (void *)(void *)plip_kick_bh;
+ nl->deferred.routine = (void (*)(void *))plip_kick_bh;
nl->deferred.data = dev;
+
+ if (dev->irq == -1) {
+ nl->timer.next = NULL;
+ nl->timer.sync = 0;
+ nl->timer.routine = (void (*)(void *))plip_timer_bh;
+ nl->timer.data = dev;
+ }
+
spin_lock_init(&nl->lock);
return 0;
@@ -373,6 +438,22 @@
}
}
+static void
+plip_timer_bh(struct net_device *dev)
+{
+ struct net_local *nl = (struct net_local *)dev->priv;
+
+ if (!(atomic_read (&nl->kill_timer))) {
+ if (!dev->interrupt)
+ plip_interrupt (-1, dev, NULL);
+
+ queue_task (&nl->timer, &tq_timer);
+ }
+ else {
+ up (&nl->killed_timer_sem);
+ }
+}
+
static int
plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
struct plip_local *snd, struct plip_local *rcv,
@@ -401,7 +482,7 @@
/* Try again later */
return TIMEOUT;
}
- c0 = inb(PAR_STATUS(dev));
+ c0 = read_status(dev);
printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",
dev->name, snd->state, c0);
} else
@@ -420,7 +501,7 @@
/* Try again later */
return TIMEOUT;
}
- c0 = inb(PAR_STATUS(dev));
+ c0 = read_status(dev);
printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",
dev->name, rcv->state, c0);
}
@@ -441,10 +522,10 @@
DISABLE(dev->irq);
synchronize_irq();
}
- outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ disable_parport_interrupts (dev);
dev->tbusy = 1;
nl->connection = PLIP_CN_ERROR;
- outb(0x00, PAR_DATA(dev));
+ write_data (dev, 0x00);
return TIMEOUT;
}
@@ -459,7 +540,7 @@
/* PLIP_RECEIVE --- receive a byte(two nibbles)
Returns OK on success, TIMEOUT on timeout */
inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
+plip_receive(unsigned short nibble_timeout, struct net_device *dev,
enum plip_nibble_state *ns_p, unsigned char *data_p)
{
unsigned char c0, c1;
@@ -469,10 +550,10 @@
case PLIP_NB_BEGIN:
cx = nibble_timeout;
while (1) {
- c0 = inb(status_addr);
+ c0 = read_status(dev);
udelay(PLIP_DELAY_UNIT);
if ((c0 & 0x80) == 0) {
- c1 = inb(status_addr);
+ c1 = read_status(dev);
if (c0 == c1)
break;
}
@@ -480,17 +561,16 @@
return TIMEOUT;
}
*data_p = (c0 >> 3) & 0x0f;
- outb(0x10, --status_addr); /* send ACK */
- status_addr++;
+ write_data (dev, 0x10); /* send ACK */
*ns_p = PLIP_NB_1;
case PLIP_NB_1:
cx = nibble_timeout;
while (1) {
- c0 = inb(status_addr);
+ c0 = read_status(dev);
udelay(PLIP_DELAY_UNIT);
if (c0 & 0x80) {
- c1 = inb(status_addr);
+ c1 = read_status(dev);
if (c0 == c1)
break;
}
@@ -498,8 +578,7 @@
return TIMEOUT;
}
*data_p |= (c0 << 1) & 0xf0;
- outb(0x00, --status_addr); /* send ACK */
- status_addr++;
+ write_data (dev, 0x00); /* send ACK */
*ns_p = PLIP_NB_BEGIN;
case PLIP_NB_2:
break;
@@ -512,7 +591,6 @@
plip_receive_packet(struct net_device *dev, struct net_local *nl,
struct plip_local *snd, struct plip_local *rcv)
{
- unsigned short status_addr = PAR_STATUS(dev);
unsigned short nibble_timeout = nl->nibble;
unsigned char *lbuf;
@@ -520,9 +598,9 @@
case PLIP_PK_TRIGGER:
DISABLE(dev->irq);
/* Don't need to synchronize irq, as we can safely ignore it */
- outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ disable_parport_interrupts (dev);
dev->interrupt = 0;
- outb(0x01, PAR_DATA(dev)); /* send ACK */
+ write_data (dev, 0x01); /* send ACK */
if (net_debug > 2)
printk(KERN_DEBUG "%s: receive start\n", dev->name);
rcv->state = PLIP_PK_LENGTH_LSB;
@@ -530,26 +608,26 @@
case PLIP_PK_LENGTH_LSB:
if (snd->state != PLIP_PK_DONE) {
- if (plip_receive(nl->trigger, status_addr,
+ if (plip_receive(nl->trigger, dev,
&rcv->nibble, &rcv->length.b.lsb)) {
/* collision, here dev->tbusy == 1 */
rcv->state = PLIP_PK_DONE;
nl->is_deferred = 1;
nl->connection = PLIP_CN_SEND;
queue_task(&nl->deferred, &tq_timer);
- outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_parport_interrupts (dev);
ENABLE(dev->irq);
return OK;
}
} else {
- if (plip_receive(nibble_timeout, status_addr,
+ if (plip_receive(nibble_timeout, dev,
&rcv->nibble, &rcv->length.b.lsb))
return TIMEOUT;
}
rcv->state = PLIP_PK_LENGTH_MSB;
case PLIP_PK_LENGTH_MSB:
- if (plip_receive(nibble_timeout, status_addr,
+ if (plip_receive(nibble_timeout, dev,
&rcv->nibble, &rcv->length.b.msb))
return TIMEOUT;
if (rcv->length.h > dev->mtu + dev->hard_header_len
@@ -572,7 +650,7 @@
case PLIP_PK_DATA:
lbuf = rcv->skb->data;
do
- if (plip_receive(nibble_timeout, status_addr,
+ if (plip_receive(nibble_timeout, dev,
&rcv->nibble, &lbuf[rcv->byte]))
return TIMEOUT;
while (++rcv->byte < rcv->length.h);
@@ -582,7 +660,7 @@
rcv->state = PLIP_PK_CHECKSUM;
case PLIP_PK_CHECKSUM:
- if (plip_receive(nibble_timeout, status_addr,
+ if (plip_receive(nibble_timeout, dev,
&rcv->nibble, &rcv->data))
return TIMEOUT;
if (rcv->data != rcv->checksum) {
@@ -604,20 +682,20 @@
printk(KERN_DEBUG "%s: receive end\n", dev->name);
/* Close the connection. */
- outb (0x00, PAR_DATA(dev));
+ write_data (dev, 0x00);
spin_lock_irq(&nl->lock);
if (snd->state != PLIP_PK_DONE) {
nl->connection = PLIP_CN_SEND;
spin_unlock_irq(&nl->lock);
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_parport_interrupts (dev);
ENABLE(dev->irq);
return OK;
} else {
nl->connection = PLIP_CN_NONE;
spin_unlock_irq(&nl->lock);
- outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_parport_interrupts (dev);
ENABLE(dev->irq);
return OK;
}
@@ -628,7 +706,7 @@
/* PLIP_SEND --- send a byte (two nibbles)
Returns OK on success, TIMEOUT when timeout */
inline static int
-plip_send(unsigned short nibble_timeout, unsigned short data_addr,
+plip_send(unsigned short nibble_timeout, struct net_device *dev,
enum plip_nibble_state *ns_p, unsigned char data)
{
unsigned char c0;
@@ -636,37 +714,34 @@
switch (*ns_p) {
case PLIP_NB_BEGIN:
- outb((data & 0x0f), data_addr);
+ write_data (dev, data & 0x0f);
*ns_p = PLIP_NB_1;
case PLIP_NB_1:
- outb(0x10 | (data & 0x0f), data_addr);
+ write_data (dev, 0x10 | (data & 0x0f));
cx = nibble_timeout;
- data_addr++;
while (1) {
- c0 = inb(data_addr);
+ c0 = read_status(dev);
if ((c0 & 0x80) == 0)
break;
if (--cx == 0)
return TIMEOUT;
udelay(PLIP_DELAY_UNIT);
}
- outb(0x10 | (data >> 4), --data_addr);
+ write_data (dev, 0x10 | (data >> 4));
*ns_p = PLIP_NB_2;
case PLIP_NB_2:
- outb((data >> 4), data_addr);
- data_addr++;
+ write_data (dev, (data >> 4));
cx = nibble_timeout;
while (1) {
- c0 = inb(data_addr);
+ c0 = read_status(dev);
if (c0 & 0x80)
break;
if (--cx == 0)
return TIMEOUT;
udelay(PLIP_DELAY_UNIT);
}
- data_addr--;
*ns_p = PLIP_NB_BEGIN;
return OK;
}
@@ -678,7 +753,6 @@
plip_send_packet(struct net_device *dev, struct net_local *nl,
struct plip_local *snd, struct plip_local *rcv)
{
- unsigned short data_addr = PAR_DATA(dev);
unsigned short nibble_timeout = nl->nibble;
unsigned char *lbuf;
unsigned char c0;
@@ -693,11 +767,11 @@
switch (snd->state) {
case PLIP_PK_TRIGGER:
- if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80)
+ if ((read_status(dev) & 0xf8) != 0x80)
return HS_TIMEOUT;
/* Trigger remote rx interrupt. */
- outb(0x08, data_addr);
+ write_data (dev, 0x08);
cx = nl->trigger;
while (1) {
udelay(PLIP_DELAY_UNIT);
@@ -708,7 +782,7 @@
nl->enet_stats.collisions++;
return OK;
}
- c0 = inb(PAR_STATUS(dev));
+ c0 = read_status(dev);
if (c0 & 0x08) {
spin_unlock_irq(&nl->lock);
DISABLE(dev->irq);
@@ -724,7 +798,7 @@
nl->enet_stats.collisions++;
return OK;
}
- outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ disable_parport_interrupts (dev);
if (net_debug > 2)
printk(KERN_DEBUG "%s: send start\n", dev->name);
snd->state = PLIP_PK_LENGTH_LSB;
@@ -734,19 +808,19 @@
}
spin_unlock_irq(&nl->lock);
if (--cx == 0) {
- outb(0x00, data_addr);
+ write_data (dev, 0x00);
return HS_TIMEOUT;
}
}
case PLIP_PK_LENGTH_LSB:
- if (plip_send(nibble_timeout, data_addr,
+ if (plip_send(nibble_timeout, dev,
&snd->nibble, snd->length.b.lsb))
return TIMEOUT;
snd->state = PLIP_PK_LENGTH_MSB;
case PLIP_PK_LENGTH_MSB:
- if (plip_send(nibble_timeout, data_addr,
+ if (plip_send(nibble_timeout, dev,
&snd->nibble, snd->length.b.msb))
return TIMEOUT;
snd->state = PLIP_PK_DATA;
@@ -755,7 +829,7 @@
case PLIP_PK_DATA:
do
- if (plip_send(nibble_timeout, data_addr,
+ if (plip_send(nibble_timeout, dev,
&snd->nibble, lbuf[snd->byte]))
return TIMEOUT;
while (++snd->byte < snd->length.h);
@@ -765,7 +839,7 @@
snd->state = PLIP_PK_CHECKSUM;
case PLIP_PK_CHECKSUM:
- if (plip_send(nibble_timeout, data_addr,
+ if (plip_send(nibble_timeout, dev,
&snd->nibble, snd->checksum))
return TIMEOUT;
@@ -776,14 +850,14 @@
case PLIP_PK_DONE:
/* Close the connection */
- outb (0x00, data_addr);
+ write_data (dev, 0x00);
snd->skb = NULL;
if (net_debug > 2)
printk(KERN_DEBUG "%s: send end\n", dev->name);
nl->connection = PLIP_CN_CLOSING;
nl->is_deferred = 1;
queue_task(&nl->deferred, &tq_timer);
- outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_parport_interrupts (dev);
ENABLE(dev->irq);
return OK;
}
@@ -815,7 +889,7 @@
{
unsigned char status;
- status = inb(PAR_STATUS(dev));
+ status = read_status(dev);
if ((status & 0xf8) == 0x80) {
if (net_debug > 2)
printk(KERN_DEBUG "%s: reset interface.\n", dev->name);
@@ -823,7 +897,7 @@
nl->should_relinquish = 0;
dev->tbusy = 0;
dev->interrupt = 0;
- outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_parport_interrupts (dev);
ENABLE(dev->irq);
mark_bh(NET_BH);
} else {
@@ -854,9 +928,9 @@
if (dev->interrupt)
return;
- c0 = inb(PAR_STATUS(dev));
+ c0 = read_status(dev);
if ((c0 & 0xf8) != 0xc0) {
- if (net_debug > 1)
+ if ((dev->irq != -1) && (net_debug > 1))
printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name);
return;
}
@@ -893,22 +967,6 @@
}
}
-/* We don't need to send arp, for plip is point-to-point. */
-static int
-plip_rebuild_header(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct net_local *nl = (struct net_local *)dev->priv;
- struct ethhdr *eth = (struct ethhdr *)skb->data;
-
- if ((dev->flags & IFF_NOARP)==0)
- return nl->orig_rebuild_header(skb);
-
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
- return 0;
-}
-
static int
plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
{
@@ -955,6 +1013,51 @@
return 0;
}
+static void
+plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
+{
+ struct in_device *in_dev;
+
+ if ((in_dev=dev->ip_ptr) != NULL) {
+ /* Any address will do - we take the first */
+ struct in_ifaddr *ifa=in_dev->ifa_list;
+ if (ifa != NULL) {
+ memcpy(eth->h_source, dev->dev_addr, 6);
+ memset(eth->h_dest, 0xfc, 2);
+ memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
+ }
+ }
+}
+
+static int
+plip_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len)
+{
+ struct net_local *nl = (struct net_local *)dev->priv;
+ int ret;
+
+ if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
+ plip_rewrite_address (dev, (struct ethhdr *)skb->data);
+
+ return ret;
+}
+
+int plip_hard_header_cache(struct neighbour *neigh,
+ struct hh_cache *hh)
+{
+ struct net_local *nl = (struct net_local *)neigh->dev->priv;
+ int ret;
+
+ if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
+ {
+ struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2);
+ plip_rewrite_address (neigh->dev, eth);
+ }
+
+ return ret;
+}
+
/* Open/initialize the board. This is called (in the current kernel)
sometime after booting when the 'ifconfig' program is run.
@@ -976,10 +1079,15 @@
nl->should_relinquish = 0;
/* Clear the data port. */
- outb (0x00, PAR_DATA(dev));
+ write_data (dev, 0x00);
/* Enable rx interrupt. */
- outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_parport_interrupts (dev);
+ if (dev->irq == -1)
+ {
+ atomic_set (&nl->kill_timer, 0);
+ queue_task (&nl->timer, &tq_timer);
+ }
/* Initialize the state machine. */
nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
@@ -988,21 +1096,24 @@
nl->is_deferred = 0;
/* Fill in the MAC-level header.
- (ab)Use "dev->broadcast" to store point-to-point MAC address.
-
- PLIP doesn't have a real mac address, but we need to create one
- to be DOS compatible. */
- memset(dev->dev_addr, 0xfc, ETH_ALEN);
- memset(dev->broadcast, 0xfc, ETH_ALEN);
+ We used to abuse dev->broadcast to store the point-to-point
+ MAC address, but we no longer do it. Instead, we fetch the
+ interface address whenever it is needed, which is cheap enough
+ because we use the hh_cache. Actually, abusing dev->broadcast
+ didn't work, because when using plip_open the point-to-point
+ address isn't yet known.
+ PLIP doesn't have a real MAC address, but we need it to be
+ DOS compatible, and to properly support taps (otherwise,
+ when the device address isn't identical to the address of a
+ received frame, the kernel incorrectly drops it). */
if ((in_dev=dev->ip_ptr) != NULL) {
- /*
- * Any address will do - we take the first
- */
+ /* Any address will do - we take the first. We already
+ have the first two bytes filled with 0xfc, from
+ plip_init_dev(). */
struct in_ifaddr *ifa=in_dev->ifa_list;
if (ifa != NULL) {
memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
- memcpy(dev->broadcast+2, &ifa->ifa_address, 4);
}
}
@@ -1027,6 +1138,13 @@
DISABLE(dev->irq);
synchronize_irq();
+ if (dev->irq == -1)
+ {
+ init_MUTEX_LOCKED (&nl->killed_timer_sem);
+ atomic_set (&nl->kill_timer, 1);
+ down (&nl->killed_timer_sem);
+ }
+
#ifdef NOTDEF
outb(0x00, PAR_DATA(dev));
#endif
@@ -1095,7 +1213,7 @@
if (!parport_claim(nl->pardev)) {
nl->port_owner = 1;
/* Clear the data port. */
- outb (0x00, PAR_DATA(dev));
+ write_data (dev, 0x00);
}
return;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)