summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/3c501.c10
-rw-r--r--drivers/net/3c503.c23
-rw-r--r--drivers/net/3c505.c6
-rw-r--r--drivers/net/3c505.h4
-rw-r--r--drivers/net/3c509.c31
-rw-r--r--drivers/net/3c59x.c1136
-rw-r--r--drivers/net/7990.c649
-rw-r--r--drivers/net/7990.h256
-rw-r--r--drivers/net/82596.c1356
-rw-r--r--drivers/net/8390.c904
-rw-r--r--drivers/net/8390.h190
-rw-r--r--drivers/net/Config.in38
-rw-r--r--drivers/net/Makefile151
-rw-r--r--drivers/net/Space.c485
-rw-r--r--drivers/net/ac3200.c158
-rw-r--r--drivers/net/am79c961a.c173
-rw-r--r--drivers/net/apne.c633
-rw-r--r--drivers/net/apricot.c1031
-rw-r--r--drivers/net/arcnet.c17
-rw-r--r--drivers/net/atari_bionet.c71
-rw-r--r--drivers/net/bmac.c1451
-rw-r--r--drivers/net/bmac.h164
-rw-r--r--drivers/net/com90xx.c1791
-rw-r--r--drivers/net/cops.c360
-rw-r--r--drivers/net/cops_ffdrv.h2
-rw-r--r--drivers/net/cops_ltdrv.h2
-rw-r--r--drivers/net/daynaport.c603
-rw-r--r--drivers/net/de4x5.c469
-rw-r--r--drivers/net/de4x5.h2
-rw-r--r--drivers/net/defxx.c13
-rw-r--r--drivers/net/defxx.h3
-rw-r--r--drivers/net/e2100.c30
-rw-r--r--drivers/net/eepro.c3
-rw-r--r--drivers/net/eepro100.c31
-rw-r--r--drivers/net/eexpress.c6
-rw-r--r--drivers/net/epic100.c31
-rw-r--r--drivers/net/es3210.c18
-rw-r--r--drivers/net/ewrk3.c4
-rw-r--r--drivers/net/hamradio/Config.in11
-rw-r--r--drivers/net/hamradio/Makefile10
-rw-r--r--drivers/net/hamradio/baycom_epp.c1557
-rw-r--r--drivers/net/hamradio/baycom_par.c10
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c326
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c111
-rw-r--r--drivers/net/hamradio/bpqether.c1
-rw-r--r--drivers/net/hamradio/dmascc.c5
-rw-r--r--drivers/net/hamradio/hdlcdrv.c81
-rw-r--r--drivers/net/hamradio/mkiss.c164
-rw-r--r--drivers/net/hamradio/mkiss.h4
-rw-r--r--drivers/net/hamradio/soundmodem/Makefile2
-rw-r--r--drivers/net/hamradio/soundmodem/gentbl.c2
-rw-r--r--drivers/net/hamradio/soundmodem/sm.c107
-rw-r--r--drivers/net/hamradio/soundmodem/sm.h17
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2666.c356
-rw-r--r--drivers/net/hamradio/soundmodem/sm_psk4800.c418
-rw-r--r--drivers/net/hp-plus.c22
-rw-r--r--drivers/net/hp.c37
-rw-r--r--drivers/net/hp100.c4
-rw-r--r--drivers/net/hp100.h2
-rw-r--r--drivers/net/hplance.c247
-rw-r--r--drivers/net/hplance.h31
-rw-r--r--drivers/net/ibmtr.c158
-rw-r--r--drivers/net/ibmtr.h13
-rw-r--r--drivers/net/lance.c13
-rw-r--r--drivers/net/lne390.c438
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/mace.c10
-rw-r--r--drivers/net/myri_sbus.c18
-rw-r--r--drivers/net/myri_sbus.h2
-rw-r--r--drivers/net/ne.c48
-rw-r--r--drivers/net/ne2k-pci.c600
-rw-r--r--drivers/net/net_init.c96
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c2
-rw-r--r--drivers/net/pcnet32.c316
-rw-r--r--drivers/net/plip.c45
-rw-r--r--drivers/net/ppp.c4231
-rw-r--r--drivers/net/rtl8139.c1356
-rw-r--r--drivers/net/sdla.c11
-rw-r--r--drivers/net/sdla_fr.c6
-rw-r--r--drivers/net/sdla_ppp.c4
-rw-r--r--drivers/net/sdla_x25.c36
-rw-r--r--drivers/net/sdladrv.c2
-rw-r--r--drivers/net/seeq8005.c3
-rw-r--r--drivers/net/sgiseeq.c14
-rw-r--r--drivers/net/shaper.c16
-rw-r--r--drivers/net/sk_g16.c7
-rw-r--r--drivers/net/sktr.c2695
-rw-r--r--drivers/net/sktr.h1098
-rw-r--r--drivers/net/sktr_firmware.h3616
-rw-r--r--drivers/net/slip.c2
-rw-r--r--drivers/net/smc-mca.c20
-rw-r--r--drivers/net/smc-ultra.c20
-rw-r--r--drivers/net/smc-ultra32.c21
-rw-r--r--drivers/net/sunhme.c211
-rw-r--r--drivers/net/sunhme.h4
-rw-r--r--drivers/net/sunlance.c38
-rw-r--r--drivers/net/sunqe.c30
-rw-r--r--drivers/net/sunqe.h4
-rw-r--r--drivers/net/tlan.c1497
-rw-r--r--drivers/net/tlan.h264
-rw-r--r--drivers/net/tulip.c17
-rw-r--r--drivers/net/wavelan.c835
-rw-r--r--drivers/net/wavelan.h136
-rw-r--r--drivers/net/wavelan.p.h521
-rw-r--r--drivers/net/wd.c42
-rw-r--r--drivers/net/yellowfin.c1309
107 files changed, 27247 insertions, 8414 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index dd1b4a6ae..188de03d0 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -1,4 +1,4 @@
-/* 3c501.c: A 3Com 3c501 ethernet driver for linux. */
+/* 3c501.c: A 3Com 3c501 Ethernet driver for Linux. */
/*
Written 1992,1993,1994 Donald Becker
@@ -64,14 +64,14 @@
The driver is less efficient than it could be. It switches through
receive mode even if more transmits are queued. If this worries you buy
- a real ethernet card.
+ a real Ethernet card.
The combination of slow receive restart and no real multicast
filter makes the board unusable with a kernel compiled for IP
multicasting in a real multicast environment. That's down to the board,
but even with no multicast programs running a multicast IP kernel is
in group 224.0.0.1 and you will therefore be listening to all multicasts.
- One nv conference running over that ethernet and you can give up.
+ One nv conference running over that Ethernet and you can give up.
*/
@@ -564,7 +564,7 @@ static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* Timed out
*/
if (el_debug)
- printk("%s: Transmit failed 16 times, ethernet jammed?\n",dev->name);
+ printk("%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);
outb(AX_SYS, AX_CMD);
lp->stats.tx_aborted_errors++;
}
@@ -749,7 +749,7 @@ static int el1_close(struct device *dev)
int ioaddr = dev->base_addr;
if (el_debug > 2)
- printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr);
+ printk("%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr);
dev->tbusy = 1;
dev->start = 0;
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index a2010a526..75a2e37ad 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -160,7 +160,7 @@ el2_probe1(struct device *dev, int ioaddr))
/* Reset and/or avoid any lurking NE2000 */
if (inb(ioaddr + 0x408) == 0xff) {
- udelay(1000);
+ mdelay(1);
return ENODEV;
}
@@ -186,6 +186,9 @@ el2_probe1(struct device *dev, int ioaddr))
return ENODEV;
}
+ if (load_8390_module("3c503.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("3c503.c: Passed a NULL device.\n");
@@ -346,7 +349,7 @@ el2_open(struct device *dev)
outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR);
if (*irqp == autoirq_report(0) /* It's a good IRQ line! */
- && request_irq (dev->irq = *irqp, &ei_interrupt, 0, ei_status.name, dev) == 0)
+ && request_irq (dev->irq = *irqp, ei_interrupt, 0, ei_status.name, dev) == 0)
break;
}
} while (*++irqp);
@@ -355,7 +358,7 @@ el2_open(struct device *dev)
return -EAGAIN;
}
} else {
- if (request_irq(dev->irq, &ei_interrupt, 0, ei_status.name, dev)) {
+ if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev)) {
return -EAGAIN;
}
}
@@ -658,11 +661,15 @@ init_module(void)
}
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
+ lock_8390_module();
return 0;
}
@@ -674,13 +681,15 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
struct device *dev = &dev_el2[this_dev];
if (dev->priv != NULL) {
+ void *priv = dev->priv;
/* NB: el2_close() handles free_irq */
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
release_region(dev->base_addr, EL2_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index d28bb2c52..a1a822fa0 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1,9 +1,9 @@
/*
- * Linux ethernet device driver for the 3Com Etherlink Plus (3C505)
+ * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
* By Craig Southeren, Juha Laiho and Philip Blundell
*
* 3c505.c This module implements an interface to the 3Com
- * Etherlink Plus (3c505) ethernet card. Linux device
+ * Etherlink Plus (3c505) Ethernet card. Linux device
* driver interface reverse engineered from the Linux 3C509
* device drivers. Some 3C505 information gleaned from
* the Crynwr packet driver. Still this driver would not
@@ -1568,7 +1568,7 @@ __initfunc(int elplus_probe(struct device *dev))
outb_control(adapter->hcr_val & ~CMDE, dev);
/*
- * copy ethernet address into structure
+ * copy Ethernet address into structure
*/
for (i = 0; i < 6; i++)
dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
index bea9b5031..41993d4ec 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/3c505.h
@@ -65,7 +65,7 @@
#define DMA_BRST 0x01 /* DMA burst */
/*
- * maximum amount of data data allowed in a PCB
+ * maximum amount of data allowed in a PCB
*/
#define MAX_PCB_DATA 62
@@ -216,7 +216,7 @@ struct Memdump {
/*
Primary Command Block. The most important data structure. All communication
between the host and the adapter is done with these. (Except for the actual
-ethernet data, which has different packaging.)
+Ethernet data, which has different packaging.)
*/
typedef struct {
byte command;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index ae344c99d..ca8e80f8e 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -47,11 +47,9 @@ static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n";
#include <linux/module.h>
#include <linux/config.h> /* for CONFIG_MCA */
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/malloc.h>
@@ -136,7 +134,7 @@ static ushort read_eeprom(short ioaddr, int index);
static int el3_open(struct device *dev);
static int el3_start_xmit(struct sk_buff *skb, struct device *dev);
static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void update_stats(int addr, struct device *dev);
+static void update_stats(struct device *dev);
static struct enet_statistics *el3_get_stats(struct device *dev);
static int el3_rx(struct device *dev);
static int el3_close(struct device *dev);
@@ -180,6 +178,9 @@ int el3_probe(struct device *dev)
}
#ifdef CONFIG_MCA
+#warning "The MCA code in drivers/net/3c509.c does not compile"
+#warning "See http://glycerine.itsmm.uni.edu/mca/ for patches."
+#if 0
if (MCA_bus) {
mca_adaptor_select_mode(1);
for (i = 0; i < 8; i++)
@@ -197,6 +198,7 @@ int el3_probe(struct device *dev)
}
#endif
+#endif
/* Reset the ISA PnP mechanism on 3c509b. */
outb(0x02, 0x279); /* Select PnP config control register. */
@@ -210,7 +212,7 @@ int el3_probe(struct device *dev)
if (inb(id_port) & 0x01)
break;
}
- if (id_port >= 0x200) { /* GCC optimizes this test out. */
+ if (id_port >= 0x200) {
/* Rare -- do we really need a warning? */
printk(" WARNING: No I/O port available for 3c509 activation.\n");
return -ENODEV;
@@ -453,6 +455,8 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
dev->tbusy = 0;
}
+ lp->stats.tx_bytes += skb->len;
+
if (el3_debug > 4) {
printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
dev->name, skb->len, inw(ioaddr + EL3_STATUS));
@@ -533,10 +537,11 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->interrupt = 1;
ioaddr = dev->base_addr;
- status = inw(ioaddr + EL3_STATUS);
- if (el3_debug > 4)
+ if (el3_debug > 4) {
+ status = inw(ioaddr + EL3_STATUS);
printk("%s: interrupt, status %4.4x.\n", dev->name, status);
+ }
while ((status = inw(ioaddr + EL3_STATUS)) &
(IntLatch | RxComplete | StatsFull)) {
@@ -555,7 +560,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & (AdapterFailure | RxEarly | StatsFull)) {
/* Handle all uncommon interrupts. */
if (status & StatsFull) /* Empty statistics. */
- update_stats(ioaddr, dev);
+ update_stats(dev);
if (status & RxEarly) { /* Rx early is unused. */
el3_rx(dev);
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
@@ -602,7 +607,7 @@ el3_get_stats(struct device *dev)
save_flags(flags);
cli();
- update_stats(dev->base_addr, dev);
+ update_stats(dev);
restore_flags(flags);
return &lp->stats;
}
@@ -612,9 +617,10 @@ el3_get_stats(struct device *dev)
operation, and it's simpler for the rest of the driver to assume that
window 1 is always valid rather than use a special window-state variable.
*/
-static void update_stats(int ioaddr, struct device *dev)
+static void update_stats(struct device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
+ int ioaddr = dev->base_addr;
if (el3_debug > 5)
printk(" Updating the statistics.\n");
@@ -667,6 +673,7 @@ el3_rx(struct device *dev)
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
+ lp->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -760,7 +767,7 @@ el3_close(struct device *dev)
/* But we explicitly zero the IRQ line select anyway. */
outw(0x0f00, ioaddr + WN0_IRQ);
- update_stats(ioaddr, dev);
+ update_stats(dev);
MOD_DEC_USE_COUNT;
return 0;
}
@@ -771,6 +778,10 @@ static int debug = -1;
static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+MODULE_PARM(debug,"i");
+MODULE_PARM(irq,"1-8i");
+MODULE_PARM(xcvr,"1-8i");
+
int
init_module(void)
{
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 6bb3dfd54..889229892 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1,6 +1,6 @@
/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
/*
- Written 1996-1997 by Donald Becker.
+ Written 1996-1998 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -15,17 +15,28 @@
*/
static char *version =
-"3c59x.c:v0.47H 12/4/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1512 effectively disables this feature. */
-static const int rx_copybreak = 200;
+static const rx_copybreak = 200;
/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const int mtu = 1500;
+static const mtu = 1500;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
+/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
+#ifdef VORTEX_DEBUG
+static int vortex_debug = VORTEX_DEBUG;
+#else
+static int vortex_debug = 1;
+#endif
+
+/* Some values here only for performance evaluation and path-coverage
+ debugging. */
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
+
/* Enable the automatic media selection code -- usually set. */
#define AUTOMEDIA 1
@@ -44,6 +55,7 @@ static int max_interrupt_work = 20;
#define RX_RING_SIZE 32
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+#include <linux/config.h>
#ifdef MODULE
#ifdef MODVERSIONS
#include <linux/modversions.h>
@@ -65,6 +77,7 @@ static int max_interrupt_work = 20;
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/bios32.h>
#include <linux/timer.h>
#include <asm/irq.h> /* For NR_IRQS only. */
#include <asm/bitops.h>
@@ -82,7 +95,7 @@ static int max_interrupt_work = 20;
#if LINUX_VERSION_CODE < 0x10300
#define RUN_AT(x) (x) /* What to put in timer->expires. */
#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#if defined(__alpha__)
+#if defined(__alpha)
#error "The Alpha architecture is only support with kernel version 2.0."
#endif
#define virt_to_bus(addr) ((unsigned long)addr)
@@ -92,6 +105,11 @@ static int max_interrupt_work = 20;
#define RUN_AT(x) (jiffies + (x))
#define DEV_ALLOC_SKB(len) dev_alloc_skb(len)
#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
+#else /* Grrr, unneeded incompatible change. */
+#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+#endif
#ifdef SA_SHIRQ
#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
@@ -110,10 +128,10 @@ static int max_interrupt_work = 20;
#define udelay(microsec) do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
#endif
-#if LINUX_VERSION_CODE < 0x20115
+#if LINUX_VERSION_CODE < 0x20138
#define test_and_set_bit(val, addr) set_bit(val, addr)
-#include <linux/bios32.h>
-#elif defined(MODULE)
+#endif
+#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
@@ -126,13 +144,6 @@ MODULE_PARM(compaq_irq, "i");
MODULE_PARM(compaq_prod_id, "i");
#endif
-/* "Knobs" for adjusting internal parameters. */
-/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define VORTEX_DEBUG 1
-/* Some values here only for performance evaluation and path-coverage
- debugging. */
-static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
-
/* Operational parameter that usually are not changed. */
/* The Vortex size is twice that of the original EtherLinkIII series: the
@@ -147,21 +158,19 @@ struct netdev_entry tc59x_drv =
{"Vortex", vortex_pci_probe, VORTEX_TOTAL_SIZE, NULL};
#endif
-#ifdef VORTEX_DEBUG
-static int vortex_debug = VORTEX_DEBUG;
-#else
-static int vortex_debug = 1;
-#endif
-
-/* Set iff a MII transceiver on any interface requires mdio preamble. */
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+ This only set with the original DP83840 on older 3c905 boards, so the extra
+ code size of a per-interface flag is not worthwhile. */
static char mii_preamble_required = 0;
-/* Caution! These entries must be consistent, with the EISA ones last. */
+/* Caution! These entries must be consistent. */
static const int product_ids[] = {
- 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0x9055,
- 0, 0};
+ 0x5900, 0x5920, 0x5970, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001,
+ 0x9050, 0x9051, 0x9055, 0x5057, 0 };
static const char *product_names[] = {
"3c590 Vortex 10Mbps",
+ "3c592 EISA 10mbps Demon/Vortex",
+ "3c597 EISA Fast Demon/Vortex",
"3c595 Vortex 100baseTX",
"3c595 Vortex 100baseT4",
"3c595 Vortex 100base-MII",
@@ -170,11 +179,8 @@ static const char *product_names[] = {
"3c905 Boomerang 100baseTx",
"3c905 Boomerang 100baseT4",
"3c905B Cyclone 100baseTx",
- "3c592 EISA 10mbps Demon/Vortex",
- "3c597 EISA Fast Demon/Vortex",
+ "3c575", /* Cardbus Boomerang */
};
-#define DEMON10_INDEX 9
-#define DEMON100_INDEX 10
/*
Theory of Operation
@@ -288,7 +294,7 @@ enum RxFilter {
/* Bits in the general status register. */
enum vortex_status {
- IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+ IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
IntReq = 0x0040, StatsFull = 0x0080,
DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
@@ -328,7 +334,7 @@ union wn3_config {
struct w3_config_fields {
unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
int pad8:8;
- unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+ unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
int pad24:7;
} u;
};
@@ -358,13 +364,15 @@ enum MasterCtrl {
struct boom_rx_desc {
u32 next; /* Last entry points to 0. */
s32 status;
- u32 addr; /* Up to addr/len possible.. */
- s32 length; /* set high bit to indicate last pair. */
+ u32 addr; /* Up to 63 addr/len pairs possible. */
+ s32 length; /* Set LAST_FRAG to indicate last pair. */
};
/* Values for the Rx status entry. */
enum rx_desc_status {
RxDComplete=0x00008000, RxDError=0x4000,
/* See boomerang_rx() for actual error bits */
+ IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
+ IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
};
struct boom_tx_desc {
@@ -377,9 +385,13 @@ struct boom_tx_desc {
/* Values for the Tx status entry. */
enum tx_desc_status {
CRCDisable=0x2000, TxDComplete=0x8000,
+ AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */
};
+/* Chip features we care about in vp->capabilities, read from the EEPROM. */
+enum ChipCaps { CapBusMaster=0x20 };
+
struct vortex_private {
char devname[8]; /* "ethN" string, also for kernel debug. */
const char *product_name;
@@ -394,19 +406,28 @@ struct vortex_private {
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
struct enet_statistics stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
+
+ /* PCI configuration space information. */
+ u8 pci_bus, pci_dev_fn; /* PCI bus location, for power management. */
+ u16 pci_device_id;
+
+ /* The remainder are related to chip state, mostly media selection. */
+ int in_interrupt;
struct timer_list timer; /* Media selection timer. */
int options; /* User-settable misc. driver options. */
- int last_rx_packets; /* For media autoselection. */
- unsigned int available_media:8, /* From Wn3_Options */
+ unsigned int
media_override:3, /* Passed-in media type. */
- default_media:3, /* Read from the EEPROM. */
+ default_media:3, /* Read from the EEPROM/Wn3_Config. */
full_duplex:1, autoselect:1,
bus_master:1, /* Vortex can only do a fragment bus-m. */
full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
+ hw_csums:1, /* Has hardware checksums. */
tx_full:1;
- u16 capabilities; /* Adapter capabilities word. */
- u16 info1, info2; /* Software information information. */
- unsigned char phys[2]; /* MII device addresses. */
+ u16 status_enable;
+ u16 available_media; /* From Wn3_Options. */
+ u16 capabilities, info1, info2; /* Various, from EEPROM. */
+ u16 advertising; /* NWay media advertisement */
+ unsigned char phys[2]; /* MII device addresses. */
};
/* The action to take with a media selection timer tick.
@@ -414,15 +435,15 @@ struct vortex_private {
*/
enum xcvr_types {
XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
- XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+ XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
};
static struct media_table {
- char *name;
- unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
- mask:8, /* The transceiver-present bit in Wn3_Config.*/
- next:8; /* The media type to try next. */
- short wait; /* Time before we check media status. */
+ char *name;
+ unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
+ mask:8, /* The transceiver-present bit in Wn3_Config.*/
+ next:8; /* The media type to try next. */
+ int wait; /* Time before we check media status. */
} media_tbl[] = {
{ "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
{ "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
@@ -430,14 +451,16 @@ static struct media_table {
{ "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10},
{ "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
{ "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10},
- { "MII", 0, 0x40, XCVR_10baseT, 3*HZ },
+ { "MII", 0, 0x41, XCVR_10baseT, 3*HZ },
{ "undefined", 0, 0x01, XCVR_10baseT, 10000},
+ { "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ},
+ { "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ },
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
static int vortex_scan(struct device *dev);
static struct device *vortex_found_device(struct device *dev, int ioaddr,
- int irq, const char *product_name,
+ int irq, int device_id,
int options, int card_idx);
static int vortex_probe1(struct device *dev);
static int vortex_open(struct device *dev);
@@ -481,31 +504,94 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
/* Note: this is the only limit on the number of cards supported!! */
static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
-#ifdef MODULE
static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* A list of all installed Vortex devices, for removing the driver module. */
static struct device *root_vortex_dev = NULL;
-#endif
#ifdef MODULE
/* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr = 0, compaq_irq = 0;
+static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
static int debug = -1;
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *vortex_attach(dev_locator_t *loc)
+{
+ u16 dev_id;
+ u32 io;
+ u8 bus, devfn, irq;
+ struct device *dev;
+
+ if (loc->bus != LOC_PCI) return NULL;
+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+ printk(KERN_INFO "vortex_attach(bus %d, function %d)\n", bus, devfn);
+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+ pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+ pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+ io &= ~3;
+ dev = vortex_found_device(NULL, io, irq, dev_id, 0, -1);
+ if (dev) {
+ dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+ strcpy(node->dev_name, dev->name);
+ node->major = node->minor = 0;
+ node->next = NULL;
+ MOD_INC_USE_COUNT;
+ return node;
+ }
+ return NULL;
+}
+
+static void vortex_detach(dev_node_t *node)
+{
+ struct device **devp, **next;
+ printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
+ for (devp = &root_vortex_dev; *devp; devp = next) {
+ next = &((struct vortex_private *)(*devp)->priv)->next_module;
+ if (strcmp((*devp)->name, node->dev_name) == 0) break;
+ }
+ if (*devp) {
+ struct device *dev = *devp;
+ if (dev->flags & IFF_UP)
+ vortex_close(dev);
+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
+ unregister_netdev(dev);
+ kfree(dev);
+ *devp = *next;
+ kfree(node);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+struct driver_operations vortex_ops = {
+ "3c59x_cb", vortex_attach, NULL, NULL, vortex_detach
+};
+
+#endif /* Cardbus support */
+
+
int
init_module(void)
{
- int cards_found;
-
if (debug >= 0)
vortex_debug = debug;
if (vortex_debug)
printk(version);
root_vortex_dev = NULL;
- cards_found = vortex_scan(0);
- return cards_found ? 0 : -ENODEV;
+#ifdef CARDBUS
+ register_driver(&vortex_ops);
+ return 0;
+#else
+ {
+ int cards_found = vortex_scan(0);
+ if (cards_found == 0)
+ printk("No 3Com Vortex/Boomerang cards found.\n");
+ return cards_found ? 0 : -ENODEV;
+ }
+#endif
}
#else
@@ -525,28 +611,22 @@ int tc59x_probe(struct device *dev)
static int vortex_scan(struct device *dev)
{
int cards_found = 0;
- const char *product_name;
-#ifndef NO_PCI /* Allow an EISA-only driver. */
+ /* Allow an EISA-only driver. */
+#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
/* Ideally we would detect all cards in slot order. That would
be best done a central PCI probe dispatch, which wouldn't work
well with the current structure. So instead we detect 3Com cards
in slot order. */
- if (pci_present()) {
+ if (pcibios_present()) {
static int pci_index = 0;
unsigned char pci_bus, pci_device_fn;
for (;pci_index < 0xff; pci_index++) {
-#if LINUX_VERSION_CODE >= 0x20155
- unsigned int pci_irq_line;
- struct pci_dev *pdev;
-#else
- unsigned char pci_irq_line;
-#endif
- unsigned char pci_latency;
- unsigned short pci_command, new_command, vendor, device;
- unsigned int pci_ioaddr;
- int board_index = 0;
+ u8 pci_latency;
+ u16 pci_command, new_command, vendor, device;
+ int irq;
+ long ioaddr;
if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
pci_index, &pci_bus, &pci_device_fn)
@@ -556,42 +636,42 @@ static int vortex_scan(struct device *dev)
PCI_VENDOR_ID, &vendor);
pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_DEVICE_ID, &device);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ {
#if LINUX_VERSION_CODE >= 0x20155
- pdev = pci_find_slot(pci_bus, pci_device_fn);
- pci_irq_line = pdev->irq;
- pci_ioaddr = pdev->base_address[0];
+ struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+ ioaddr = pdev->base_address[0];
+ irq = pdev->irq;
#else
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ u32 pci_ioaddr;
+ u8 pci_irq_line;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ ioaddr = pci_ioaddr;
+ irq = pci_irq_line;
#endif
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
+ }
/* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
+ ioaddr &= ~3;
if (vendor != TCOM_VENDOR_ID)
continue;
- for (board_index = 0; product_ids[board_index]; board_index++) {
- if (device == product_ids[board_index])
- break;
- }
- if (product_ids[board_index])
- product_name = product_names[board_index];
- else if ((device & 0xfff0) == 0x9000)
- product_name = "3c900";
- else if ((device & 0xfff0) == 0x9050)
- product_name = "3c905";
- else {
- printk("Unknown 3Com PCI ethernet adapter type %4.4x detected:"
- " not configured.\n", device);
+ if (ioaddr == 0) {
+ printk(KERN_WARNING " A 3Com network adapter has been found, "
+ "however it has not been assigned an I/O address.\n"
+ " You may need to power-cycle the machine for this "
+ "device to work!\n");
continue;
}
- if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE))
+
+ if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
continue;
+ /* Activate the card. */
new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
if (pci_command != new_command) {
printk(KERN_INFO " The PCI BIOS has not enabled this"
@@ -601,21 +681,26 @@ static int vortex_scan(struct device *dev)
PCI_COMMAND, new_command);
}
- dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line,
- product_name, dev && dev->mem_start
+ dev = vortex_found_device(dev, ioaddr, irq,
+ device, dev && dev->mem_start
? dev->mem_start : options[cards_found],
cards_found);
if (dev) {
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
/* Get and check the latency values. On the 3c590 series
the latency timer must be set to the maximum value to avoid
data corruption that occurs when the timer expires during
a transfer -- a bug in the Vortex chip only. */
- unsigned char new_latency = (device&0xff00) == 0x5900 ? 248 : 32;
+ u8 new_latency = (device&0xff00) == 0x5900 ? 248 : 32;
+ vp->pci_bus = pci_bus;
+ vp->pci_dev_fn = pci_device_fn;
+ vp->pci_device_id = device;
+
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < new_latency) {
- printk("%s: Overriding PCI latency"
+ printk(KERN_INFO "%s: Overriding PCI latency"
" timer (CFLT) setting of %d, new value is %d.\n",
dev->name, pci_latency, new_latency);
pcibios_write_config_byte(pci_bus, pci_device_fn,
@@ -631,24 +716,19 @@ static int vortex_scan(struct device *dev)
/* Now check all slots of the EISA bus. */
if (EISA_bus) {
static int ioaddr = 0x1000;
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- int product_id;
- char *product_name;
+ for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
+ int device_id;
if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
continue;
/* Check the standard EISA ID register for an encoded '3Com'. */
if (inw(ioaddr + 0xC80) != 0x6d50)
continue;
/* Check for a product that we support, 3c59{2,7} any rev. */
- product_id = inw(ioaddr + 0xC82) & 0xF0FF;
- if (product_id == 0x7059) /* 597 */
- product_name = "3c597 EISA Fast Demon/Vortex";
- else if (product_id == 0x2059) /* 592 */
- product_name = "3c592 EISA 10mbps Demon/Vortex";
- else
+ device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+ if ((device_id & 0xFF00) != 0x5900)
continue;
vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
- product_name, dev && dev->mem_start
+ device_id, dev && dev->mem_start
? dev->mem_start : options[cards_found],
cards_found);
dev = 0;
@@ -659,7 +739,7 @@ static int vortex_scan(struct device *dev)
#ifdef MODULE
/* Special code to work-around the Compaq PCI BIOS32 problem. */
if (compaq_ioaddr) {
- vortex_found_device(dev, compaq_ioaddr, compaq_irq, "3Com Vortex",
+ vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_device_id,
dev && dev->mem_start ? dev->mem_start
: options[cards_found], cards_found);
cards_found++;
@@ -674,17 +754,40 @@ static int vortex_scan(struct device *dev)
static struct device *
vortex_found_device(struct device *dev, int ioaddr, int irq,
- const char *product_name, int options, int card_idx)
+ int device_id, int option, int card_idx)
{
struct vortex_private *vp;
+ const char *product_name;
+ int board_index = 0;
+
+ for (board_index = 0; product_ids[board_index]; board_index++) {
+ if (device_id == product_ids[board_index])
+ break;
+ }
+ /* Handle products we don't recognize, but might still work with. */
+ if (product_ids[board_index])
+ product_name = product_names[board_index];
+ else if ((device_id & 0xff00) == 0x5900)
+ product_name = "3c590 Vortex";
+ else if ((device_id & 0xfff0) == 0x9000)
+ product_name = "3c900";
+ else if ((device_id & 0xfff0) == 0x9050)
+ product_name = "3c905";
+ else {
+ printk(KERN_WARNING "Unknown 3Com PCI ethernet adapter type %4.4x detected:"
+ " not configured.\n", device_id);
+ return 0;
+ }
#ifdef MODULE
/* Allocate and fill new device structure. */
- int dev_size = sizeof(struct device) +
- sizeof(struct vortex_private) + 15; /* Pad for alignment */
+ {
+ int dev_size = sizeof(struct device) +
+ sizeof(struct vortex_private) + 15; /* Pad for alignment */
- dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
- memset(dev, 0, dev_size);
+ dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
+ memset(dev, 0, dev_size);
+ }
/* Align the Rx and Tx ring entries. */
dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
vp = (struct vortex_private *)dev->priv;
@@ -693,17 +796,17 @@ vortex_found_device(struct device *dev, int ioaddr, int irq,
dev->irq = irq;
dev->init = vortex_probe1;
vp->product_name = product_name;
- vp->options = options;
+ vp->options = option;
if (card_idx >= 0) {
if (full_duplex[card_idx] >= 0)
vp->full_duplex = full_duplex[card_idx];
} else
- vp->full_duplex = (options >= 0 && (options & 0x10) ? 1 : 0);
+ vp->full_duplex = (option > 0 && (option & 0x10) ? 1 : 0);
- if (options >= 0) {
- vp->media_override = ((options & 7) == XCVR_10baseTOnly) ?
- XCVR_10baseT : options & 7;
- vp->bus_master = (options & 16) ? 1 : 0;
+ if (option > 0) {
+ vp->media_override = ((option & 7) == XCVR_10baseTOnly) ?
+ XCVR_10baseT : option & 7;
+ vp->bus_master = (option & 16) ? 1 : 0;
} else {
vp->media_override = 7;
vp->bus_master = 0;
@@ -726,11 +829,11 @@ vortex_found_device(struct device *dev, int ioaddr, int irq,
vp = (struct vortex_private *)dev->priv;
vp->product_name = product_name;
- vp->options = options;
- if (options >= 0) {
- vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
- vp->full_duplex = (options & 8) ? 1 : 0;
- vp->bus_master = (options & 16) ? 1 : 0;
+ vp->options = option;
+ if (option >= 0) {
+ vp->media_override = ((option & 7) == 2) ? 0 : option & 7;
+ vp->full_duplex = (option & 8) ? 1 : 0;
+ vp->bus_master = (option & 16) ? 1 : 0;
} else {
vp->media_override = 7;
vp->full_duplex = 0;
@@ -746,63 +849,87 @@ static int vortex_probe1(struct device *dev)
{
int ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ u16 *ether_addr = (u16 *)dev->dev_addr;
unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
- printk("%s: 3Com %s at %#3x,", dev->name,
- vp->product_name, ioaddr);
+ printk(KERN_INFO "%s: 3Com %s at %#3x,",
+ dev->name, vp->product_name, ioaddr);
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
- for (i = 0; i < 0x18; i++) {
- u16 *phys_addr = (u16 *)dev->dev_addr;
+ for (i = 0; i < 0x40; i++) {
int timer;
+#ifdef CARDBUS
+ outw(0x230 + i, ioaddr + Wn0EepromCmd);
+#else
outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
+#endif
/* Pause for at least 162 us. for the read to take place. */
- for (timer = 4; timer >= 0; timer--) {
+ for (timer = 10; timer >= 0; timer--) {
udelay(162);
if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
break;
}
eeprom[i] = inw(ioaddr + Wn0EepromData);
- checksum ^= eeprom[i];
- if (i >= 10 && i < 13)
- phys_addr[i - 10] = htons(inw(ioaddr + Wn0EepromData));
}
+ for (i = 0; i < 0x18; i++)
+ checksum ^= eeprom[i];
checksum = (checksum ^ (checksum >> 8)) & 0xff;
+ if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */
+ while (i < 0x21)
+ checksum ^= eeprom[i++];
+ checksum = (checksum ^ (checksum >> 8)) & 0xff;
+ }
if (checksum != 0x00)
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
+
+ for (i = 0; i < 3; i++)
+ ether_addr[i] = htons(eeprom[i + 10]);
for (i = 0; i < 6; i++)
printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
printk(", IRQ %d\n", dev->irq);
/* Tell them about an invalid IRQ. */
if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
- printk(" *** Warning: this IRQ is unlikely to work! ***\n");
+ printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
+ dev->irq);
+
+ /* Extract our information from the EEPROM data. */
+ vp->info1 = eeprom[13];
+ vp->info2 = eeprom[15];
+ vp->capabilities = eeprom[16];
+
+ if (vp->info1 & 0x8000)
+ vp->full_duplex = 1;
{
char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
union wn3_config config;
EL3WINDOW(3);
vp->available_media = inw(ioaddr + Wn3_Options);
+ if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */
+ vp->available_media = 0x40;
config.i = inl(ioaddr + Wn3_Config);
if (vortex_debug > 1)
- printk(" Internal config register is %4.4x, transceivers %#x.\n",
- config.i, inw(ioaddr + Wn3_Options));
- printk(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+ printk(KERN_DEBUG " Internal config register is %4.4x, "
+ "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options));
+ printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
8 << config.u.ram_size,
config.u.ram_width ? "word" : "byte",
ram_split[config.u.ram_split],
config.u.autoselect ? "autoselect/" : "",
+ config.u.xcvr ? "NWay Autonegotiation" :
media_tbl[config.u.xcvr].name);
- dev->if_port = config.u.xcvr;
vp->default_media = config.u.xcvr;
vp->autoselect = config.u.autoselect;
}
+
if (vp->media_override != 7) {
- printk(" Media override to transceiver type %d (%s).\n",
+ printk(KERN_INFO " Media override to transceiver type %d (%s).\n",
vp->media_override, media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
- }
+ } else
+ dev->if_port = vp->default_media;
if (dev->if_port == XCVR_MII) {
int phy, phy_idx = 0;
@@ -810,31 +937,34 @@ static int vortex_probe1(struct device *dev)
for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
int mii_status;
mdio_sync(ioaddr, 32);
- mii_status = mdio_read(ioaddr, phy, 0);
- if (mii_status != 0xffff) {
+ mii_status = mdio_read(ioaddr, phy, 1);
+ if (mii_status && mii_status != 0xffff) {
vp->phys[phy_idx++] = phy;
- printk("%s: MII transceiver found at address %d.\n",
- dev->name, phy);
+ printk(KERN_INFO " MII transceiver found at address %d, status %4x.\n",
+ phy, mii_status);
mdio_sync(ioaddr, 32);
if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0)
mii_preamble_required = 1;
}
}
if (phy_idx == 0) {
- printk("%s: ***WARNING*** No MII transceivers found!\n",
- dev->name);
- vp->phys[0] = 0;
+ printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n");
+ vp->phys[0] = 24;
+ } else {
+ vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
+ if (vp->full_duplex) {
+ /* Only advertise the FD media types. */
+ vp->advertising &= 0x015F;
+ mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
+ }
}
}
- vp->info1 = eeprom[13];
- vp->info2 = eeprom[15];
- vp->capabilities = eeprom[16];
- if (vp->capabilities & 0x20) {
- vp->full_bus_master_tx = 1;
- printk(" Enabling bus-master transmits and %s receives.\n",
- (vp->info2 & 1) ? "early" : "whole-frame" );
- vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+ if (vp->capabilities & CapBusMaster) {
+ vp->full_bus_master_tx = 1;
+ printk(KERN_INFO" Enabling bus-master transmits and %s receives.\n",
+ (vp->info2 & 1) ? "early" : "whole-frame" );
+ vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
}
/* We do a request_region() to register /proc/ioports info. */
@@ -856,86 +986,6 @@ static int vortex_probe1(struct device *dev)
return 0;
}
-
-/* Read and write the MII registers using software-generated serial
- MDIO protocol. The maxium data clock rate is 2.5 Mhz. */
-#define mdio_delay() udelay(1)
-
-#define MDIO_SHIFT_CLK 0x01
-#define MDIO_DIR_WRITE 0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ 0x02
-#define MDIO_ENB_IN 0x00
-
-static void mdio_sync(int ioaddr, int bits)
-{
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
- /* Establish sync by sending at least 32 logic ones. */
- while (-- bits >= 0) {
- outw(MDIO_DATA_WRITE1, mdio_addr);
- mdio_delay();
- outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
-}
-static int mdio_read(int ioaddr, int phy_id, int location)
-{
- int i;
- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- unsigned int retval = 0;
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
- if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
-
- /* Shift the read command bits out. */
- for (i = 14; i >= 0; i--) {
- int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outw(dataval, mdio_addr);
- mdio_delay();
- outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- outw(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- return retval>>1 & 0xffff;
-}
-
-static void mdio_write(int ioaddr, int phy_id, int location, int value)
-{
- int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
- int i;
-
- if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outw(dataval, mdio_addr);
- mdio_delay();
- outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- /* Leave the interface idle. */
- for (i = 1; i >= 0; i--) {
- outw(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
-
- return;
-}
static int
@@ -952,7 +1002,7 @@ vortex_open(struct device *dev)
if (vp->media_override != 7) {
if (vortex_debug > 1)
- printk("%s: Media override to transceiver %d (%s).\n",
+ printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
dev->name, vp->media_override,
media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
@@ -963,7 +1013,7 @@ vortex_open(struct device *dev)
dev->if_port = media_tbl[dev->if_port].next;
if (vortex_debug > 1)
- printk("%s: Initial media type %s.\n",
+ printk(KERN_DEBUG "%s: Initial media type %s.\n",
dev->name, media_tbl[dev->if_port].name);
init_timer(&vp->timer);
@@ -979,8 +1029,6 @@ vortex_open(struct device *dev)
if (dev->if_port == XCVR_MII) {
int mii_reg1, mii_reg5;
- /* We cheat here: we know that we are using the 83840 transceiver
- which summarizes the FD status in an extended register. */
EL3WINDOW(4);
/* Read BMSR (reg1) only to clear old status. */
mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
@@ -991,7 +1039,7 @@ vortex_open(struct device *dev)
|| (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
vp->full_duplex = 1;
if (vortex_debug > 1)
- printk("%s: MII #%d status %4.4x, link partner capability %4.4x,"
+ printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
" setting %s-duplex.\n", dev->name, vp->phys[0],
mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
EL3WINDOW(3);
@@ -1002,18 +1050,18 @@ vortex_open(struct device *dev)
(dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
if (vortex_debug > 1) {
- printk("%s: vortex_open() InternalConfig %8.8x.\n",
+ printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
dev->name, config.i);
}
outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0 ; i--)
+ for (i = 2000; i >= 0 ; i--)
if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
outw(RxReset, ioaddr + EL3_CMD);
/* Wait a few ticks for the RxReset command to complete. */
- for (i = 20; i >= 0 ; i--)
+ for (i = 2000; i >= 0 ; i--)
if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
@@ -1021,8 +1069,7 @@ vortex_open(struct device *dev)
#ifdef SA_SHIRQ
/* Use the now-standard shared IRQ implementation. */
- if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
- vp->product_name, dev)) {
+ if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
return -EAGAIN;
}
#else
@@ -1037,7 +1084,7 @@ vortex_open(struct device *dev)
if (vortex_debug > 1) {
EL3WINDOW(4);
- printk("%s: vortex_open() irq %d media status %4.4x.\n",
+ printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
dev->name, dev->irq, inw(ioaddr + Wn4_Media));
}
@@ -1077,7 +1124,7 @@ vortex_open(struct device *dev)
outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
outl(0x0020, ioaddr + PktStatus);
if (vortex_debug > 2)
- printk("%s: Filling in the Rx ring.\n", dev->name);
+ printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name);
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
@@ -1111,6 +1158,7 @@ vortex_open(struct device *dev)
set_rx_mode(dev);
outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+ vp->in_interrupt = 0;
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
@@ -1118,16 +1166,16 @@ vortex_open(struct device *dev)
outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
/* Allow status bits to be seen. */
- outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull|TxComplete|
- (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
- (vp->full_bus_master_rx ? UpComplete : RxComplete) |
- (vp->bus_master ? DMADone : 0),
- ioaddr + EL3_CMD);
+ vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
+ (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+ (vp->full_bus_master_rx ? UpComplete : RxComplete) |
+ (vp->bus_master ? DMADone : 0);
+ outw(vp->status_enable, ioaddr + EL3_CMD);
/* Ack all pending events, and set active indicator mask. */
outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
ioaddr + EL3_CMD);
outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | AdapterFailure | TxComplete
+ | HostError | TxComplete
| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
ioaddr + EL3_CMD);
@@ -1146,7 +1194,7 @@ static void vortex_timer(unsigned long data)
int ok = 0;
if (vortex_debug > 1)
- printk("%s: Media selection timer tick happened, %s.\n",
+ printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
dev->name, media_tbl[dev->if_port].name);
save_flags(flags); cli(); {
@@ -1159,10 +1207,10 @@ static void vortex_timer(unsigned long data)
if (media_status & Media_LnkBeat) {
ok = 1;
if (vortex_debug > 1)
- printk("%s: Media %s has link beat, %x.\n",
+ printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
} else if (vortex_debug > 1)
- printk("%s: Media %s is has no link beat, %x.\n",
+ printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
break;
@@ -1171,7 +1219,7 @@ static void vortex_timer(unsigned long data)
int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
if (vortex_debug > 1)
- printk("%s: MII #%d status register is %4.4x, "
+ printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, "
"link partner capability %4.4x.\n",
dev->name, vp->phys[0], mii_reg1, mii_reg5);
if (mii_reg1 & 0x0004)
@@ -1180,7 +1228,7 @@ static void vortex_timer(unsigned long data)
}
default: /* Other media types handled by Tx timeouts. */
if (vortex_debug > 1)
- printk("%s: Media %s is has no indication, %x.\n",
+ printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
ok = 1;
}
@@ -1193,11 +1241,13 @@ static void vortex_timer(unsigned long data)
if (dev->if_port == XCVR_Default) { /* Go back to default. */
dev->if_port = vp->default_media;
if (vortex_debug > 1)
- printk("%s: Media selection failing, using default %s port.\n",
+ printk(KERN_DEBUG "%s: Media selection failing, using default "
+ "%s port.\n",
dev->name, media_tbl[dev->if_port].name);
} else {
if (vortex_debug > 1)
- printk("%s: Media selection failed, now trying %s port.\n",
+ printk(KERN_DEBUG "%s: Media selection failed, now trying "
+ "%s port.\n",
dev->name, media_tbl[dev->if_port].name);
vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
add_timer(&vp->timer);
@@ -1216,7 +1266,7 @@ static void vortex_timer(unsigned long data)
EL3WINDOW(old_window);
} restore_flags(flags);
if (vortex_debug > 1)
- printk("%s: Media selection timer finished, %s.\n",
+ printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
dev->name, media_tbl[dev->if_port].name);
#endif /* AUTOMEDIA*/
@@ -1227,84 +1277,59 @@ static void vortex_tx_timeout(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int ioaddr = dev->base_addr;
- int i;
+ int j;
- printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+ printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
dev->name, inb(ioaddr + TxStatus),
inw(ioaddr + EL3_STATUS));
/* Slight code bloat to be user friendly. */
if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
- printk("%s: Transmitter encountered 16 collisions --"
+ printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
" network cable problem?\n", dev->name);
if (inw(ioaddr + EL3_STATUS) & IntLatch) {
- printk("%s: Interrupt posted but not handled --"
+ printk(KERN_ERR "%s: Interrupt posted but not delivered --"
" IRQ blocked by another device?\n", dev->name);
/* Bad idea here.. but we might as well handle a few events. */
vortex_interrupt IRQ(dev->irq, dev, 0);
}
-#ifndef final_version
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (j = 200; j >= 0 ; j--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+
+#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300
if (vp->full_bus_master_tx) {
- printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
+ int i;
+ printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d "
+ "current %d.\n",
vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
- printk(" Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+ printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n",
+ inl(ioaddr + DownListPtr),
&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
for (i = 0; i < TX_RING_SIZE; i++) {
- printk(" %d: @%p length %8.8x status %8.8x\n", i,
+ printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i,
&vp->tx_ring[i],
vp->tx_ring[i].length,
vp->tx_ring[i].status);
}
}
-#ifdef notdef
- if (vp->full_bus_master_rx) {
- printk(" Switching to non-bus-master receives.\n");
- outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull |
- (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
- RxComplete | (vp->bus_master ? DMADone : 0),
- ioaddr + EL3_CMD);
- }
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-#endif
#endif
+ vp->stats.tx_errors++;
if (vp->full_bus_master_tx) {
- /* Change 6/25/97 Michael Sievers sieversm@mail.desy.de
- The card has been resetted, but the Tx Ring is still full.
- Since the card won't know where to resume, 'update' the
- Tx Ring. Probably, we'll lose 16 packets this way, these
- will be accounted for as 'dropped'. The code to update the
- Tx Ring is taken from the Interrupt handler. */
-
- unsigned int dirty_tx = vp->dirty_tx;
-
- if (vortex_debug > 0)
- printk("%s: Freeing Tx ring entries:", dev->name);
- while (vp->cur_tx - dirty_tx > 0) {
- int entry = dirty_tx % TX_RING_SIZE;
- if (inl(ioaddr + DownListPtr) ==
- virt_to_bus(&vp->tx_ring[entry]))
- break; /* It still hasn't been processed. */
- if (vp->tx_skbuff[entry]) {
- if (vortex_debug > 0)
- printk(" %d\n", entry);
- dev_kfree_skb(vp->tx_skbuff[entry]);
- vp->tx_skbuff[entry] = 0;
- vp->stats.tx_dropped++;
- }
if (vortex_debug > 0)
- printk(".\n");
- vp->stats.tx_errors++;
- dirty_tx++;
- }
- vp->dirty_tx = dirty_tx;
- vp->tx_full= 0;
- } else { /* not bus-master, no Tx ring to clear */
- vp->stats.tx_errors++;
- vp->stats.tx_dropped++;
- }
+ printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n",
+ dev->name);
+ if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0)
+ outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
+ ioaddr + DownListPtr);
+ if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
+ vp->tx_full = 0;
+ clear_bit(0, (void*)&dev->tbusy);
+ }
+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+ outw(DownUnstall, ioaddr + EL3_CMD);
+ } else
+ vp->stats.tx_dropped++;
/* Issue Tx Enable */
outw(TxEnable, ioaddr + EL3_CMD);
@@ -1312,20 +1337,99 @@ static void vortex_tx_timeout(struct device *dev)
/* Switch to register set 7 for normal use. */
EL3WINDOW(7);
-
- /* The TxFreeThreshold has to be set again after a reset! */
- if (vp->full_bus_master_tx) {
- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
- /* This is to be sure that all bus-master Tx features
- are correctly re-initialized after a reset, although
- the DownListPtr should already be 0 at this point. */
- outl(0, ioaddr + DownListPtr);
+}
+
+/*
+ * Handle uncommon interrupt sources. This is a seperate routine to minimize
+ * the cache impact.
+ */
+static void
+vortex_error(struct device *dev, int status)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int do_tx_reset = 0;
+ int i;
+
+ if (status & TxComplete) { /* Really "TxError" for us. */
+ unsigned char tx_status = inb(ioaddr + TxStatus);
+ /* Presumably a tx-timeout. We must merely re-enable. */
+ if (vortex_debug > 2
+ || (tx_status != 0x88 && vortex_debug > 0))
+ printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
+ dev->name, tx_status);
+ if (tx_status & 0x14) vp->stats.tx_fifo_errors++;
+ if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
+ outb(0, ioaddr + TxStatus);
+ if (tx_status & 0x30)
+ do_tx_reset = 1;
+ else /* Merely re-enable the transmitter. */
+ outw(TxEnable, ioaddr + EL3_CMD);
}
- /* finally, allow new Transmits */
- dev->tbusy = 0;
- /* End of Michael Sievers <sieversm@mail.desy.de> changes. */
+ if (status & RxEarly) { /* Rx early is unused. */
+ vortex_rx(dev);
+ outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+ }
+ if (status & StatsFull) { /* Empty statistics. */
+ static int DoneDidThat = 0;
+ if (vortex_debug > 4)
+ printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
+ update_stats(ioaddr, dev);
+ /* HACK: Disable statistics as an interrupt source. */
+ /* This occurs when we have the wrong media type! */
+ if (DoneDidThat == 0 &&
+ inw(ioaddr + EL3_STATUS) & StatsFull) {
+ printk(KERN_WARNING "%s: Updating statistics failed, disabling "
+ "stats as an interrupt source.\n", dev->name);
+ EL3WINDOW(5);
+ outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
+ EL3WINDOW(7);
+ DoneDidThat++;
+ }
+ }
+ if (status & IntReq) /* Restore all interrupt sources. */
+ outw(ioaddr + EL3_CMD, vp->status_enable);
+ if (status & HostError) {
+ u16 fifo_diag;
+ EL3WINDOW(4);
+ fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+ if (vortex_debug > 0)
+ printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+ dev->name, fifo_diag);
+ /* Adapter failure requires Tx/Rx reset and reinit. */
+ if (vp->full_bus_master_tx) {
+ outw(TotalReset | 0xff, ioaddr + EL3_CMD);
+ for (i = 2000; i >= 0 ; i--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ /* Re-enable the receiver. */
+ outw(RxEnable, ioaddr + EL3_CMD);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ } else if (fifo_diag & 0x0400)
+ do_tx_reset = 1;
+ if (fifo_diag & 0x3000) {
+ outw(RxReset, ioaddr + EL3_CMD);
+ for (i = 2000; i >= 0 ; i--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ /* Set the Rx filter to the current state. */
+ set_rx_mode(dev);
+ outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+ outw(AckIntr | HostError, ioaddr + EL3_CMD);
+ }
+ }
+ if (do_tx_reset) {
+ int j;
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (j = 200; j >= 0 ; j--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
+
}
+
static int
vortex_start_xmit(struct sk_buff *skb, struct device *dev)
{
@@ -1343,7 +1447,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
- outl((int)(skb->data), ioaddr + Wn7_MasterAddr);
+ outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
vp->tx_skb = skb;
outw(StartDMADown, ioaddr + EL3_CMD);
@@ -1351,9 +1455,9 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
} else {
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb);
+ DEV_FREE_SKB(skb);
if (inw(ioaddr + TxFree) > 1536) {
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
} else
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1361,9 +1465,9 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
#else
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb);
+ DEV_FREE_SKB(skb);
if (inw(ioaddr + TxFree) > 1536) {
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
} else
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1373,20 +1477,20 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
/* Clear the Tx status stack. */
{
- short tx_status;
+ int tx_status;
int i = 32;
while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
if (vortex_debug > 2)
- printk("%s: Tx error, status %2.2x.\n",
+ printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
dev->name, tx_status);
if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
- for (j = 20; j >= 0 ; j--)
+ for (j = 200; j >= 0 ; j--)
if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
@@ -1417,11 +1521,11 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
int i;
if (vortex_debug > 3)
- printk("%s: Trying to send a packet, Tx index %d.\n",
+ printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
dev->name, vp->cur_tx);
if (vp->tx_full) {
if (vortex_debug >0)
- printk("%s: Tx Ring full, refusing to send buffer.\n",
+ printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
dev->name);
return 1;
}
@@ -1436,7 +1540,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
cli();
outw(DownStall, ioaddr + EL3_CMD);
/* Wait for the stall to complete. */
- for (i = 60; i >= 0 ; i--)
+ for (i = 600; i >= 0 ; i--)
if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
break;
prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
@@ -1452,7 +1556,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
vp->tx_full = 1;
else { /* Clear previous interrupt enable. */
prev_entry->status &= ~TxIntrUploaded;
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
}
dev->trans_start = jiffies;
return 0;
@@ -1468,186 +1572,108 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
#else
struct device *dev = (struct device *)(irq2dev_map[irq]);
#endif
- struct vortex_private *lp;
+ struct vortex_private *vp;
int ioaddr, status;
int latency;
- int i = max_interrupt_work;
+ int work_done = max_interrupt_work;
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+ vp = (struct vortex_private *)dev->priv;
+ if (test_and_set_bit(0, (void*)&vp->in_interrupt)) {
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
return;
}
+ dev->interrupt = 1;
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
- lp = (struct vortex_private *)dev->priv;
status = inw(ioaddr + EL3_STATUS);
if (vortex_debug > 4)
- printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
- status, latency);
-#ifdef notdef
- /* This code guard against bogus hangs, but fails with shared IRQs. */
- if ((status & ~0xE000) == 0x0000) {
- static int donedidthis=0;
- /* Some interrupt controllers store a bogus interrupt from boot-time.
- Ignore a single early interrupt, but don't hang the machine for
- other interrupt problems. */
- if (donedidthis++ > 100) {
- printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
- dev->name, status, dev->start);
- FREE_IRQ(dev->irq, dev);
- }
- }
-#endif
-
+ printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+ dev->name, status, latency);
do {
if (vortex_debug > 5)
- printk("%s: In interrupt loop, status %4.4x.\n",
+ printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
dev->name, status);
if (status & RxComplete)
vortex_rx(dev);
+ if (status & UpComplete) {
+ outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+ boomerang_rx(dev);
+ }
if (status & TxAvailable) {
if (vortex_debug > 5)
- printk(" TX room bit was handled.\n");
+ printk(KERN_DEBUG " TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
mark_bh(NET_BH);
}
- if (status & TxComplete) { /* Really "TxError" for us. */
- unsigned char tx_status = inb(ioaddr + TxStatus);
- /* Presumably a tx-timeout. We must merely re-enable. */
- if (vortex_debug > 2
- || (tx_status != 0x88 && vortex_debug > 0))
- printk("%s: Transmit error, Tx status register %2.2x.\n",
- dev->name, tx_status);
- if (tx_status & 0x04) lp->stats.tx_fifo_errors++;
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
- outb(0, ioaddr + TxStatus);
- outw(TxEnable, ioaddr + EL3_CMD);
- }
+
if (status & DownComplete) {
- unsigned int dirty_tx = lp->dirty_tx;
+ unsigned int dirty_tx = vp->dirty_tx;
- while (lp->cur_tx - dirty_tx > 0) {
+ while (vp->cur_tx - dirty_tx > 0) {
int entry = dirty_tx % TX_RING_SIZE;
if (inl(ioaddr + DownListPtr) ==
- virt_to_bus(&lp->tx_ring[entry]))
+ virt_to_bus(&vp->tx_ring[entry]))
break; /* It still hasn't been processed. */
- if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry]);
- lp->tx_skbuff[entry] = 0;
+ if (vp->tx_skbuff[entry]) {
+ DEV_FREE_SKB(vp->tx_skbuff[entry]);
+ vp->tx_skbuff[entry] = 0;
}
- /* lp->stats.tx_packets++; Counted below. */
+ /* vp->stats.tx_packets++; Counted below. */
dirty_tx++;
}
- lp->dirty_tx = dirty_tx;
+ vp->dirty_tx = dirty_tx;
outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
- if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
- lp->tx_full= 0;
- dev->tbusy = 0;
+ if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+ vp->tx_full= 0;
+ clear_bit(0, (void*)&dev->tbusy);
mark_bh(NET_BH);
}
}
#ifdef VORTEX_BUS_MASTER
if (status & DMADone) {
outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- dev->tbusy = 0;
- dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */
+ clear_bit(0, (void*)&dev->tbusy);
+ DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
mark_bh(NET_BH);
}
#endif
- if (status & UpComplete) {
- boomerang_rx(dev);
- outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
- }
- if (status & (AdapterFailure | RxEarly | StatsFull)) {
- /* Handle all uncommon interrupts at once. */
- if (status & RxEarly) { /* Rx early is unused. */
- vortex_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & StatsFull) { /* Empty statistics. */
- static int DoneDidThat = 0;
- if (vortex_debug > 4)
- printk("%s: Updating stats.\n", dev->name);
- update_stats(ioaddr, dev);
- /* DEBUG HACK: Disable statistics as an interrupt source. */
- /* This occurs when we have the wrong media type! */
- if (DoneDidThat == 0 &&
- inw(ioaddr + EL3_STATUS) & StatsFull) {
- int win, reg;
- printk("%s: Updating stats failed, disabling stats as an"
- " interrupt source.\n", dev->name);
- for (win = 0; win < 8; win++) {
- EL3WINDOW(win);
- printk("\n Vortex window %d:", win);
- for (reg = 0; reg < 16; reg++)
- printk(" %2.2x", inb(ioaddr+reg));
- }
- EL3WINDOW(7);
- outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
- | UpComplete | DownComplete | TxComplete,
- ioaddr + EL3_CMD);
- DoneDidThat++;
- }
- }
- if (status & AdapterFailure) {
- u16 fifo_diag;
- EL3WINDOW(4);
- fifo_diag = inw(ioaddr + Wn4_FIFODiag);
- if (vortex_debug > 0)
- printk("%s: Host error, FIFO diagnostic register %4.4x.\n",
- dev->name, fifo_diag);
- /* Adapter failure requires Tx/Rx reset and reinit. */
- if (lp->full_bus_master_tx) {
- int j;
- outw(TotalReset | 0xff, ioaddr + EL3_CMD);
- for (j = 200; j >= 0 ; j--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- /* Re-enable the receiver. */
- outw(RxEnable, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
- } else if (fifo_diag & 0x0400) {
- int j;
- outw(TxReset, ioaddr + EL3_CMD);
- for (j = 20; j >= 0 ; j--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- outw(TxEnable, ioaddr + EL3_CMD);
- }
- if (fifo_diag & 0x2000) {
- outw(RxReset, ioaddr + EL3_CMD);
- /* Set the Rx filter to the current state. */
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
- }
+ /* Check for all uncommon interrupts at once. */
+ if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
+ vortex_error(dev, status);
+
+ if (--work_done < 0) {
+ if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
+ /* Just ack these and return. */
+ outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD);
+ } else {
+ printk(KERN_WARNING "%s: Too much work in interrupt, status "
+ "%4.4x. Temporarily disabling functions (%4.4x).\n",
+ dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
+ /* Disable all pending interrupts. */
+ outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
+ outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
+ /* Set a timer to reenable interrupts. */
+
+ break;
}
}
-
- if (--i < 0) {
- printk("%s: Too much work in interrupt, status %4.4x. "
- "Disabling functions (%4.4x).\n",
- dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
- /* Disable all pending interrupts. */
- outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
- outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
- break;
- }
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
if (vortex_debug > 4)
- printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
+ printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+ dev->name, status);
dev->interrupt = 0;
+ clear_bit(0, (void*)&vp->in_interrupt);
return;
}
@@ -1660,13 +1686,13 @@ vortex_rx(struct device *dev)
short rx_status;
if (vortex_debug > 5)
- printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+ printk(KERN_DEBUG" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
if (rx_status & 0x4000) { /* Error, update stats. */
unsigned char rx_error = inb(ioaddr + RxErrors);
if (vortex_debug > 2)
- printk(" Rx error: status %2.2x.\n", rx_error);
+ printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
vp->stats.rx_errors++;
if (rx_error & 0x01) vp->stats.rx_over_errors++;
if (rx_error & 0x02) vp->stats.rx_length_errors++;
@@ -1675,12 +1701,12 @@ vortex_rx(struct device *dev)
if (rx_error & 0x10) vp->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
- short pkt_len = rx_status & 0x1fff;
+ int pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
skb = DEV_ALLOC_SKB(pkt_len + 5);
if (vortex_debug > 4)
- printk("Receiving packet size %d status %4.4x.\n",
+ printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
if (skb != NULL) {
skb->dev = dev;
@@ -1706,8 +1732,8 @@ vortex_rx(struct device *dev)
break;
continue;
} else if (vortex_debug)
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, pkt_len);
+ printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
+ "size %d.\n", dev->name, pkt_len);
}
outw(RxDiscard, ioaddr + EL3_CMD);
vp->stats.rx_dropped++;
@@ -1730,13 +1756,15 @@ boomerang_rx(struct device *dev)
int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
if (vortex_debug > 5)
- printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
+ printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status "
+ "%4.4x.\n",
inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
- while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
+ while ((--rx_work_limit >= 0) &&
+ ((rx_status = vp->rx_ring[entry].status) & RxDComplete)) {
if (rx_status & RxDError) { /* Error, update stats. */
unsigned char rx_error = rx_status >> 16;
if (vortex_debug > 2)
- printk(" Rx error: status %2.2x.\n", rx_error);
+ printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
vp->stats.rx_errors++;
if (rx_error & 0x01) vp->stats.rx_over_errors++;
if (rx_error & 0x02) vp->stats.rx_length_errors++;
@@ -1745,11 +1773,11 @@ boomerang_rx(struct device *dev)
if (rx_error & 0x10) vp->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
- short pkt_len = rx_status & 0x1fff;
+ int pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
if (vortex_debug > 4)
- printk("Receiving packet size %d status %4.4x.\n",
+ printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
/* Check if the packet is long enough to just accept without
@@ -1772,18 +1800,34 @@ boomerang_rx(struct device *dev)
void *temp;
/* Pass up the skbuff already on the Rx ring. */
skb = vp->rx_skbuff[entry];
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: in boomerang_rx -- attempt to use NULL skb caught\n", dev->name);
+ break;
+ }
vp->rx_skbuff[entry] = NULL;
+#if LINUX_VERSION_CODE >= 0x10300
temp = skb_put(skb, pkt_len);
+#else
+ temp = skb->data;
+#endif
/* Remove this checking code for final release. */
if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
- printk("%s: Warning -- the skbuff addresses do not match"
- " in boomerang_rx: %p vs. %p / %p.\n", dev->name,
- bus_to_virt(vp->rx_ring[entry].addr),
- skb->head, temp);
+ printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
+ " in boomerang_rx: %p vs. %p.\n", dev->name,
+ bus_to_virt(vp->rx_ring[entry].addr), temp);
rx_nocopy++;
}
#if LINUX_VERSION_CODE > 0x10300
skb->protocol = eth_type_trans(skb, dev);
+ { /* Use hardware checksum info. */
+ int csum_bits = rx_status & 0xee000000;
+ if (csum_bits &&
+ (csum_bits == (IPChksumValid | TCPChksumValid) ||
+ csum_bits == (IPChksumValid | UDPChksumValid))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ rx_csumhits++;
+ }
+ }
#else
skb->len = pkt_len;
#endif
@@ -1792,8 +1836,6 @@ boomerang_rx(struct device *dev)
vp->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
- if (--rx_work_limit < 0)
- break;
}
/* Refill the Rx ring buffers. */
for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
@@ -1801,8 +1843,10 @@ boomerang_rx(struct device *dev)
entry = vp->dirty_rx % RX_RING_SIZE;
if (vp->rx_skbuff[entry] == NULL) {
skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
- if (skb == NULL)
+ if (skb == NULL) {
+ printk(KERN_DEBUG "%s: in boomerang_rx -- could not allocate skbuff\n", dev->name);
break; /* Bad news! */
+ }
skb->dev = dev; /* Mark as being used by this device. */
#if LINUX_VERSION_CODE > 0x10300
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
@@ -1813,7 +1857,14 @@ boomerang_rx(struct device *dev)
vp->rx_skbuff[entry] = skb;
}
vp->rx_ring[entry].status = 0; /* Clear complete bit. */
+ outw(UpUnstall, ioaddr + EL3_CMD);
}
+
+ if (vp->dirty_rx >= RX_RING_SIZE ) {
+ vp->cur_rx -= RX_RING_SIZE;
+ vp->dirty_rx -= RX_RING_SIZE;
+ }
+
return 0;
}
@@ -1828,16 +1879,16 @@ vortex_close(struct device *dev)
dev->tbusy = 1;
if (vortex_debug > 1) {
- printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+ printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
- printk("%s: vortex close stats: rx_nocopy %d rx_copy %d"
- " tx_queued %d.\n",
- dev->name, rx_nocopy, rx_copy, queued_packet);
+ printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
+ " tx_queued %d Rx pre-checksummed %d.\n",
+ dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
}
del_timer(&vp->timer);
- /* Turn off statistics ASAP. We update lp->stats below. */
+ /* Turn off statistics ASAP. We update vp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD);
/* Disable the receiver and transmitter. */
@@ -1865,7 +1916,7 @@ vortex_close(struct device *dev)
#if LINUX_VERSION_CODE < 0x20100
vp->rx_skbuff[i]->free = 1;
#endif
- dev_kfree_skb (vp->rx_skbuff[i]);
+ DEV_FREE_SKB(vp->rx_skbuff[i]);
vp->rx_skbuff[i] = 0;
}
}
@@ -1873,7 +1924,7 @@ vortex_close(struct device *dev)
outl(0, ioaddr + DownListPtr);
for (i = 0; i < TX_RING_SIZE; i++)
if (vp->tx_skbuff[i]) {
- dev_kfree_skb(vp->tx_skbuff[i]);
+ DEV_FREE_SKB(vp->tx_skbuff[i]);
vp->tx_skbuff[i] = 0;
}
}
@@ -1945,7 +1996,7 @@ static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
int phy = vp->phys[0] & 0x1f;
if (vortex_debug > 2)
- printk("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+ printk(KERN_DEBUG "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
dev->name, rq->ifr_ifrn.ifrn_name, cmd,
data[0], data[1], data[2], data[3]);
@@ -1957,7 +2008,7 @@ static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
+ if (!suser())
return -EPERM;
mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
return 0;
@@ -1975,11 +2026,11 @@ static void
set_rx_mode(struct device *dev)
{
int ioaddr = dev->base_addr;
- short new_mode;
+ int new_mode;
if (dev->flags & IFF_PROMISC) {
- if (vortex_debug > 3)
- printk("%s: Setting promiscuous mode.\n", dev->name);
+ if (vortex_debug > 0)
+ printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
} else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
@@ -1996,6 +2047,97 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
set_rx_mode(dev);
}
#endif
+
+
+/* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+ MDIO protocol. See the MII specifications or DP83840A data sheet
+ for details. */
+
+/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues. */
+#define mdio_delay() udelay(1)
+
+#define MDIO_SHIFT_CLK 0x01
+#define MDIO_DIR_WRITE 0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ 0x02
+#define MDIO_ENB_IN 0x00
+
+/* Generate the preamble required for initial synchronization and
+ a few older transceivers. */
+static void mdio_sync(int ioaddr, int bits)
+{
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+ /* Establish sync by sending at least 32 logic ones. */
+ while (-- bits >= 0) {
+ outw(MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+}
+
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ unsigned int retval = 0;
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+ if (mii_preamble_required)
+ mdio_sync(ioaddr, 32);
+
+ /* Shift the read command bits out. */
+ for (i = 14; i >= 0; i--) {
+ int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outw(dataval, mdio_addr);
+ mdio_delay();
+ outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outw(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return retval>>1 & 0xffff;
+}
+
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+ int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ int i;
+
+ if (mii_preamble_required)
+ mdio_sync(ioaddr, 32);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outw(dataval, mdio_addr);
+ mdio_delay();
+ outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Leave the interface idle. */
+ for (i = 1; i >= 0; i--) {
+ outw(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+
+ return;
+}
+
#ifdef MODULE
void
@@ -2003,6 +2145,10 @@ cleanup_module(void)
{
struct device *next_dev;
+#ifdef CARDBUS
+ unregister_driver(&vortex_ops);
+#endif
+
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
while (root_vortex_dev) {
next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
@@ -2018,7 +2164,9 @@ cleanup_module(void)
/*
* Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
+ * compile-command-alt1: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c59x_cb.o"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
new file mode 100644
index 000000000..1991659f0
--- /dev/null
+++ b/drivers/net/7990.c
@@ -0,0 +1,649 @@
+/*
+ * 7990.c -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ * NB: this was made easy by the fact that Jes Sorensen had cleaned up
+ * most of a2025 and sunlance with the aim of merging them, so the
+ * common code was pretty obvious.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h>
+#include <linux/errno.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "7990.h"
+
+/* Lossage Factor Nine, Mr Sulu. */
+#define WRITERAP(x) (lp->writerap(lp,x))
+#define WRITERDP(x) (lp->writerdp(lp,x))
+#define READRDP() (lp->readrdp(lp))
+/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh.
+ * If you want to switch them back then
+ * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll
+ */
+#define DECLARE_LL /* nothing to declare */
+
+/* debugging output macros, various flavours */
+/* #define TEST_HITS */
+#ifdef UNDEF
+#define PRINT_RINGS() \
+do { \
+ int t; \
+ for (t=0; t < RX_RING_SIZE; t++) { \
+ printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n",\
+ t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0,\
+ ib->brx_ring[t].length,\
+ ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits);\
+ }\
+ for (t=0; t < TX_RING_SIZE; t++) { \
+ printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n",\
+ t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0,\
+ ib->btx_ring[t].length,\
+ ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
+ }\
+} while (0)
+#else
+#define PRINT_RINGS()
+#endif
+
+/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
+static void load_csrs (struct lance_private *lp)
+{
+ volatile struct lance_init_block *aib = lp->lance_init_block;
+ int leptr;
+ DECLARE_LL;
+
+ leptr = LANCE_ADDR (aib);
+
+ WRITERAP(LE_CSR1); /* load address of init block */
+ WRITERDP(leptr & 0xFFFF);
+ WRITERAP(LE_CSR2);
+ WRITERDP(leptr >> 16);
+ WRITERAP(LE_CSR3);
+ WRITERDP(lp->busmaster_regval); /* set byteswap/ALEctrl/byte ctrl */
+
+ /* Point back to csr0 */
+ WRITERAP(LE_CSR0);
+}
+
+/* #define to 0 or 1 appropriately */
+#define DEBUG_IRING 0
+/* Set up the Lance Rx and Tx rings and the init block */
+/* Sets dev->tbusy */
+static void lance_init_ring (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
+ int leptr;
+ int i;
+
+ aib = lp->lance_init_block;
+
+ /* Lock out other processes while setting up hardware */
+ dev->tbusy = 1;
+ lp->rx_new = lp->tx_new = 0;
+ lp->rx_old = lp->tx_old = 0;
+
+ ib->mode = LE_MO_PROM; /* normal, enable Tx & Rx */
+
+ /* Copy the ethernet address to the lance init block
+ * Notice that we do a byteswap if we're big endian.
+ * [I think this is the right criterion; at least, sunlance,
+ * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
+ * However, the datasheet says that the BSWAP bit doesn't affect
+ * the init block, so surely it should be low byte first for
+ * everybody? Um.]
+ * We could define the ib->physaddr as three 16bit values and
+ * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
+ */
+#ifdef __BIG_ENDIAN
+ ib->phys_addr [0] = dev->dev_addr [1];
+ ib->phys_addr [1] = dev->dev_addr [0];
+ ib->phys_addr [2] = dev->dev_addr [3];
+ ib->phys_addr [3] = dev->dev_addr [2];
+ ib->phys_addr [4] = dev->dev_addr [5];
+ ib->phys_addr [5] = dev->dev_addr [4];
+#else
+ for (i=0; i<6; i++)
+ ib->phys_addr[i] = dev->dev_addr[i];
+#endif
+
+ if (DEBUG_IRING)
+ printk ("TX rings:\n");
+
+ /* Setup the Tx ring entries */
+ for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
+ leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
+ ib->btx_ring [i].tmd0 = leptr;
+ ib->btx_ring [i].tmd1_hadr = leptr >> 16;
+ ib->btx_ring [i].tmd1_bits = 0;
+ ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */
+ ib->btx_ring [i].misc = 0;
+ if (DEBUG_IRING)
+ printk ("%d: 0x%8.8x\n", i, leptr);
+ }
+
+ /* Setup the Rx ring entries */
+ if (DEBUG_IRING)
+ printk ("RX rings:\n");
+ for (i = 0; i < (1<<lp->lance_log_rx_bufs); i++) {
+ leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
+
+ ib->brx_ring [i].rmd0 = leptr;
+ ib->brx_ring [i].rmd1_hadr = leptr >> 16;
+ ib->brx_ring [i].rmd1_bits = LE_R1_OWN;
+ /* 0xf000 == bits that must be one (reserved, presumably) */
+ ib->brx_ring [i].length = -RX_BUFF_SIZE | 0xf000;
+ ib->brx_ring [i].mblength = 0;
+ if (DEBUG_IRING)
+ printk ("%d: 0x%8.8x\n", i, leptr);
+ }
+
+ /* Setup the initialization block */
+
+ /* Setup rx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->brx_ring);
+ ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
+ ib->rx_ptr = leptr;
+ if (DEBUG_IRING)
+ printk ("RX ptr: %8.8x\n", leptr);
+
+ /* Setup tx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->btx_ring);
+ ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
+ ib->tx_ptr = leptr;
+ if (DEBUG_IRING)
+ printk ("TX ptr: %8.8x\n", leptr);
+
+ /* Clear the multicast filter */
+ ib->filter [0] = 0;
+ ib->filter [1] = 0;
+ PRINT_RINGS();
+}
+
+/* LANCE must be STOPped before we do this, too... */
+static int init_restart_lance (struct lance_private *lp)
+{
+ int i;
+ DECLARE_LL;
+
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_INIT);
+
+ /* Need a hook here for sunlance ledma stuff */
+
+ /* Wait for the lance to complete initialization */
+ for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++)
+ barrier();
+ if ((i == 100) || (READRDP() & LE_C0_ERR)) {
+ printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP());
+ return -1;
+ }
+
+ /* Clear IDON by writing a "1", enable interrupts and start lance */
+ WRITERDP(LE_C0_IDON);
+ WRITERDP(LE_C0_INEA | LE_C0_STRT);
+
+ return 0;
+}
+
+static int lance_reset (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int status;
+ DECLARE_LL;
+
+ /* Stop the lance */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+
+ load_csrs (lp);
+ lance_init_ring (dev);
+ dev->trans_start = jiffies;
+ dev->interrupt = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ status = init_restart_lance (lp);
+#ifdef DEBUG_DRIVER
+ printk ("Lance restart=%d\n", status);
+#endif
+ return status;
+}
+
+static int lance_rx (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile struct lance_rx_desc *rd;
+ unsigned char bits;
+ int len = 0; /* XXX shut up gcc warnings */
+ struct sk_buff *skb = 0; /* XXX shut up gcc warnings */
+#ifdef TEST_HITS
+ int i;
+#endif
+ DECLARE_LL;
+
+#ifdef TEST_HITS
+ printk ("[");
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (i == lp->rx_new)
+ printk ("%s",
+ ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X");
+ else
+ printk ("%s",
+ ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1");
+ }
+ printk ("]");
+#endif
+
+ WRITERDP(LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */
+ for (rd = &ib->brx_ring [lp->rx_new]; /* For each Rx ring we own... */
+ !((bits = rd->rmd1_bits) & LE_R1_OWN);
+ rd = &ib->brx_ring [lp->rx_new]) {
+
+ /* We got an incomplete frame? */
+ if ((bits & LE_R1_POK) != LE_R1_POK) {
+ lp->stats.rx_over_errors++;
+ lp->stats.rx_errors++;
+ continue;
+ } else if (bits & LE_R1_ERR) {
+ /* Count only the end frame as a rx error,
+ * not the beginning
+ */
+ if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ } else {
+ len = (rd->mblength & 0xfff) - 4;
+ skb = dev_alloc_skb (len+2);
+
+ if (skb == 0) {
+ printk ("%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ rd->mblength = 0;
+ rd->rmd1_bits = LE_R1_OWN;
+ lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+ return 0;
+ }
+
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align */
+ skb_put (skb, len); /* make room */
+ eth_copy_and_sum(skb,
+ (unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
+ len, 0);
+ skb->protocol = eth_type_trans (skb, dev);
+ netif_rx (skb);
+ lp->stats.rx_packets++;
+ }
+
+ /* Return the packet to the pool */
+ rd->mblength = 0;
+ rd->rmd1_bits = LE_R1_OWN;
+ lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+ }
+ return 0;
+}
+
+static int lance_tx (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile struct lance_tx_desc *td;
+ int i, j;
+ int status;
+ DECLARE_LL;
+
+ /* csr0 is 2f3 */
+ WRITERDP(LE_C0_TINT | LE_C0_INEA);
+ /* csr0 is 73 */
+
+ j = lp->tx_old;
+ for (i = j; i != lp->tx_new; i = j) {
+ td = &ib->btx_ring [i];
+
+ /* If we hit a packet not owned by us, stop */
+ if (td->tmd1_bits & LE_T1_OWN)
+ break;
+
+ if (td->tmd1_bits & LE_T1_ERR) {
+ status = td->misc;
+
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+
+ if (status & LE_T3_CLOS) {
+ lp->stats.tx_carrier_errors++;
+ if (lp->auto_select) {
+ lp->tpe = 1 - lp->tpe;
+ printk("%s: Carrier Lost, trying %s\n",
+ dev->name, lp->tpe?"TPE":"AUI");
+ /* Stop the lance */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+ lance_init_ring (dev);
+ load_csrs (lp);
+ init_restart_lance (lp);
+ return 0;
+ }
+ }
+
+ /* buffer errors and underflows turn off the transmitter */
+ /* Restart the adapter */
+ if (status & (LE_T3_BUF|LE_T3_UFL)) {
+ lp->stats.tx_fifo_errors++;
+
+ printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+ dev->name);
+ /* Stop the lance */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+ lance_init_ring (dev);
+ load_csrs (lp);
+ init_restart_lance (lp);
+ return 0;
+ }
+ } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
+ /*
+ * So we don't count the packet more than once.
+ */
+ td->tmd1_bits &= ~(LE_T1_POK);
+
+ /* One collision before packet was sent. */
+ if (td->tmd1_bits & LE_T1_EONE)
+ lp->stats.collisions++;
+
+ /* More than one collision, be optimistic. */
+ if (td->tmd1_bits & LE_T1_EMORE)
+ lp->stats.collisions += 2;
+
+ lp->stats.tx_packets++;
+ }
+
+ j = (j + 1) & lp->tx_ring_mod_mask;
+ }
+ lp->tx_old = j;
+ WRITERDP(LE_C0_TINT | LE_C0_INEA);
+ return 0;
+}
+
+static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *)dev_id;
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int csr0;
+ DECLARE_LL;
+
+ WRITERAP(LE_CSR0); /* LANCE Controller Status */
+ csr0 = READRDP();
+
+ PRINT_RINGS();
+
+ if (!(csr0 & LE_C0_INTR)) /* Check if any interrupt has */
+ return; /* been generated by the Lance. */
+
+ if (dev->interrupt)
+ printk ("%s: again", dev->name);
+
+ dev->interrupt = 1;
+
+ /* Acknowledge all the interrupt sources ASAP */
+ WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
+
+ if ((csr0 & LE_C0_ERR)) {
+ /* Clear the error condition */
+ WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
+ }
+
+ if (csr0 & LE_C0_RINT)
+ lance_rx (dev);
+
+ if (csr0 & LE_C0_TINT)
+ lance_tx (dev);
+
+ /* Log misc errors. */
+ if (csr0 & LE_C0_BABL)
+ lp->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & LE_C0_MISS)
+ lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & LE_C0_MERR) {
+ printk("%s: Bus master arbitration failure, status %4.4x.\n",
+ dev->name, csr0);
+ /* Restart the chip. */
+ WRITERDP(LE_C0_STRT);
+ }
+
+ if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
+ dev->tbusy = 0;
+ mark_bh (NET_BH);
+ }
+
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+
+ dev->interrupt = 0;
+}
+
+int lance_open (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ DECLARE_LL;
+
+ /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
+ if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+ return -EAGAIN;
+
+ return lance_reset(dev);
+}
+
+int lance_close (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ DECLARE_LL;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ /* Stop the LANCE */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+
+ free_irq(lp->irq, dev);
+
+ return 0;
+}
+
+int lance_start_xmit (struct sk_buff *skb, struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ int entry, skblen, len;
+ int status = 0;
+ static int outs;
+ DECLARE_LL;
+
+ lance_reset(dev);
+
+ /* Transmitter timeout, serious problems */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+
+ if (tickssofar < 100) {
+ status = -1;
+ } else {
+ printk ("%s: transmit timed out, status %04x, resetting\n",
+ dev->name, READRDP());
+ lance_reset (dev);
+ }
+ return status;
+ }
+
+ /* Block a timer-based transmit from overlapping. */
+ if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
+ printk ("Transmitter access conflict.\n");
+ return -1;
+ }
+
+ skblen = skb->len;
+
+ if (!TX_BUFFS_AVAIL)
+ return -1;
+
+#ifdef DEBUG_DRIVER
+ /* dump the packet */
+ {
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ if ((i % 16) == 0)
+ printk ("\n");
+ printk ("%2.2x ", skb->data [i]);
+ }
+ }
+#endif
+ len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+ entry = lp->tx_new & lp->tx_ring_mod_mask;
+ ib->btx_ring [entry].length = (-len) | 0xf000;
+ ib->btx_ring [entry].misc = 0;
+
+ memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+
+ /* Now, give the packet to the lance */
+ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+ lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+
+ outs++;
+ /* Kick the lance: transmit now */
+ WRITERDP(LE_C0_INEA | LE_C0_TDMD);
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+
+ if (TX_BUFFS_AVAIL)
+ dev->tbusy = 0;
+
+ return status;
+}
+
+struct net_device_stats *lance_get_stats (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+
+ return &lp->stats;
+}
+
+/* taken from the depca driver via a2065.c */
+static void lance_load_multicast (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile u16 *mcast_table = (u16 *)&ib->filter;
+ struct dev_mc_list *dmi=dev->mc_list;
+ char *addrs;
+ int i, j, bit, byte;
+ u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+ /* set all multicast bits */
+ if (dev->flags & IFF_ALLMULTI){
+ ib->filter [0] = 0xffffffff;
+ ib->filter [1] = 0xffffffff;
+ return;
+ }
+ /* clear the multicast filter */
+ ib->filter [0] = 0;
+ ib->filter [1] = 0;
+
+ /* Add addresses */
+ for (i = 0; i < dev->mc_count; i++){
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ /* multicast address? */
+ if (!(*addrs & 1))
+ continue;
+
+ crc = 0xffffffff;
+ for (byte = 0; byte < 6; byte++)
+ for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
+ {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+
+ if (test)
+ {
+ crc = crc ^ poly;
+ }
+ }
+
+ crc = crc >> 26;
+ mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+ }
+ return;
+}
+
+
+void lance_set_multicast (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ DECLARE_LL;
+
+ while (dev->tbusy)
+ schedule();
+ set_bit (0, (void *) &dev->tbusy);
+
+ while (lp->tx_old != lp->tx_new)
+ schedule();
+
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+ lance_init_ring (dev);
+
+ if (dev->flags & IFF_PROMISC) {
+ ib->mode |= LE_MO_PROM;
+ } else {
+ ib->mode &= ~LE_MO_PROM;
+ lance_load_multicast (dev);
+ }
+ load_csrs (lp);
+ init_restart_lance (lp);
+ dev->tbusy = 0;
+}
+
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
new file mode 100644
index 000000000..4a8f07207
--- /dev/null
+++ b/drivers/net/7990.h
@@ -0,0 +1,256 @@
+/*
+ * 7990.h -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ */
+
+#ifndef _7990_H
+#define _7990_H
+
+/* The lance only has two register locations. We communicate mostly via memory. */
+struct lance_regs
+{
+ unsigned short rdp; /* Register Data Port */
+ unsigned short rap; /* Register Address Port */
+};
+
+/* Transmit/receive ring definitions.
+ * We allow the specific drivers to override these defaults if they want to.
+ * NB: according to lance.c, increasing the number of buffers is a waste
+ * of space and reduces the chance that an upper layer will be able to
+ * reorder queued Tx packets based on priority. [Clearly there is a minimum
+ * limit too: too small and we drop rx packets and can't tx at full speed.]
+ * 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5.
+ */
+
+/* Blast! This won't work. The problem is that we can't specify a default
+ * setting because that would cause the lance_init_block struct to be
+ * too long (and overflow the RAM on shared-memory cards like the HP LANCE.
+ */
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+#endif
+
+#define TX_RING_SIZE (1<<LANCE_LOG_TX_BUFFERS)
+#define RX_RING_SIZE (1<<LANCE_LOG_RX_BUFFERS)
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
+#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
+#define PKT_BUFF_SIZE (1544)
+#define RX_BUFF_SIZE PKT_BUFF_SIZE
+#define TX_BUFF_SIZE PKT_BUFF_SIZE
+
+/* Each receive buffer is described by a receive message descriptor (RMD) */
+struct lance_rx_desc {
+ volatile unsigned short rmd0; /* low address of packet */
+ volatile unsigned char rmd1_bits; /* descriptor bits */
+ volatile unsigned char rmd1_hadr; /* high address of packet */
+ volatile short length; /* This length is 2s complement (negative)!
+ * Buffer length
+ */
+ volatile unsigned short mblength; /* Actual number of bytes received */
+};
+
+/* Ditto for TMD: */
+struct lance_tx_desc {
+ volatile unsigned short tmd0; /* low address of packet */
+ volatile unsigned char tmd1_bits; /* descriptor bits */
+ volatile unsigned char tmd1_hadr; /* high address of packet */
+ volatile short length; /* Length is 2s complement (negative)! */
+ volatile unsigned short misc;
+};
+
+/* There are three memory structures accessed by the LANCE:
+ * the initialization block, the receive and transmit descriptor rings,
+ * and the data buffers themselves. In fact we might as well put the
+ * init block,the Tx and Rx rings and the buffers together in memory:
+ */
+struct lance_init_block {
+ volatile unsigned short mode; /* Pre-set mode (reg. 15) */
+ volatile unsigned char phys_addr[6]; /* Physical ethernet address */
+ volatile unsigned filter[2]; /* Multicast filter (64 bits) */
+
+ /* Receive and transmit ring base, along with extra bits. */
+ volatile unsigned short rx_ptr; /* receive descriptor addr */
+ volatile unsigned short rx_len; /* receive len and high addr */
+ volatile unsigned short tx_ptr; /* transmit descriptor addr */
+ volatile unsigned short tx_len; /* transmit len and high addr */
+
+ /* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
+ * This will be true if this whole struct is 8-byte aligned.
+ */
+ volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
+ volatile struct lance_rx_desc brx_ring[RX_RING_SIZE];
+
+ volatile char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+ volatile char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
+ /* we use this just to make the struct big enough that we can move its startaddr
+ * in order to force alignment to an eight byte boundary.
+ */
+};
+
+/* This is where we keep all the stuff the driver needs to know about.
+ * I'm definitely unhappy about the mechanism for allowing specific
+ * drivers to add things...
+ */
+struct lance_private
+{
+ char *name;
+ volatile struct lance_regs *ll;
+ volatile struct lance_init_block *init_block; /* CPU address of RAM */
+ volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
+
+ int rx_new, tx_new;
+ int rx_old, tx_old;
+
+ int lance_log_rx_bufs, lance_log_tx_bufs;
+ int rx_ring_mod_mask, tx_ring_mod_mask;
+
+ struct net_device_stats stats;
+ int tpe; /* TPE is selected */
+ int auto_select; /* cable-selection is by carrier */
+ unsigned short busmaster_regval;
+
+ unsigned int irq; /* IRQ to register */
+
+ /* This is because the HP LANCE is disgusting and you have to check
+ * a DIO-specific register every time you read/write the LANCE regs :-<
+ * [could we get away with making these some sort of macro?]
+ */
+ void (*writerap)(void *, unsigned short);
+ void (*writerdp)(void *, unsigned short);
+ unsigned short (*readrdp)(struct lance_private *);
+};
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+/*
+ * Am7990 Control and Status Registers
+ */
+#define LE_CSR0 0x0000 /* LANCE Controller Status */
+#define LE_CSR1 0x0001 /* IADR[15:0] (bit0==0 ie word aligned) */
+#define LE_CSR2 0x0002 /* IADR[23:16] (high bits reserved) */
+#define LE_CSR3 0x0003 /* Misc */
+
+/*
+ * Bit definitions for CSR0 (LANCE Controller Status)
+ */
+#define LE_C0_ERR 0x8000 /* Error = BABL | CERR | MISS | MERR */
+#define LE_C0_BABL 0x4000 /* Babble: Transmitted too many bits */
+#define LE_C0_CERR 0x2000 /* No Heartbeat (10BASE-T) */
+#define LE_C0_MISS 0x1000 /* Missed Frame (no rx buffer to put it in) */
+#define LE_C0_MERR 0x0800 /* Memory Error */
+#define LE_C0_RINT 0x0400 /* Receive Interrupt */
+#define LE_C0_TINT 0x0200 /* Transmit Interrupt */
+#define LE_C0_IDON 0x0100 /* Initialization Done */
+#define LE_C0_INTR 0x0080 /* Interrupt Flag
+ = BABL | MISS | MERR | RINT | TINT | IDON */
+#define LE_C0_INEA 0x0040 /* Interrupt Enable */
+#define LE_C0_RXON 0x0020 /* Receive On */
+#define LE_C0_TXON 0x0010 /* Transmit On */
+#define LE_C0_TDMD 0x0008 /* Transmit Demand */
+#define LE_C0_STOP 0x0004 /* Stop */
+#define LE_C0_STRT 0x0002 /* Start */
+#define LE_C0_INIT 0x0001 /* Initialize */
+
+
+/*
+ * Bit definitions for CSR3
+ */
+#define LE_C3_BSWP 0x0004 /* Byte Swap
+ (on for big endian byte order) */
+#define LE_C3_ACON 0x0002 /* ALE Control
+ (on for active low ALE) */
+#define LE_C3_BCON 0x0001 /* Byte Control */
+
+
+/*
+ * Mode Flags
+ */
+#define LE_MO_PROM 0x8000 /* Promiscuous Mode */
+/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990,
+ * but they are in NetBSD's am7990.h, presumably for backwards-compatible chips
+ */
+#define LE_MO_DRCVBC 0x4000 /* disable receive broadcast */
+#define LE_MO_DRCVPA 0x2000 /* disable physical address detection */
+#define LE_MO_DLNKTST 0x1000 /* disable link status */
+#define LE_MO_DAPC 0x0800 /* disable automatic polarity correction */
+#define LE_MO_MENDECL 0x0400 /* MENDEC loopback mode */
+#define LE_MO_LRTTSEL 0x0200 /* lower RX threshold / TX mode selection */
+#define LE_MO_PSEL1 0x0100 /* port selection bit1 */
+#define LE_MO_PSEL0 0x0080 /* port selection bit0 */
+/* and this one is from the C-LANCE data sheet... */
+#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
+ (C-LANCE, not original LANCE) */
+#define LE_MO_INTL 0x0040 /* Internal Loopback */
+#define LE_MO_DRTY 0x0020 /* Disable Retry */
+#define LE_MO_FCOLL 0x0010 /* Force Collision */
+#define LE_MO_DXMTFCS 0x0008 /* Disable Transmit CRC */
+#define LE_MO_LOOP 0x0004 /* Loopback Enable */
+#define LE_MO_DTX 0x0002 /* Disable Transmitter */
+#define LE_MO_DRX 0x0001 /* Disable Receiver */
+
+
+/*
+ * Receive Flags
+ */
+#define LE_R1_OWN 0x80 /* LANCE owns the descriptor */
+#define LE_R1_ERR 0x40 /* Error */
+#define LE_R1_FRA 0x20 /* Framing Error */
+#define LE_R1_OFL 0x10 /* Overflow Error */
+#define LE_R1_CRC 0x08 /* CRC Error */
+#define LE_R1_BUF 0x04 /* Buffer Error */
+#define LE_R1_SOP 0x02 /* Start of Packet */
+#define LE_R1_EOP 0x01 /* End of Packet */
+#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
+
+
+/*
+ * Transmit Flags
+ */
+#define LE_T1_OWN 0x80 /* LANCE owns the descriptor */
+#define LE_T1_ERR 0x40 /* Error */
+#define LE_T1_RES 0x20 /* Reserved, LANCE writes this with a zero */
+#define LE_T1_EMORE 0x10 /* More than one retry needed */
+#define LE_T1_EONE 0x08 /* One retry needed */
+#define LE_T1_EDEF 0x04 /* Deferred */
+#define LE_T1_SOP 0x02 /* Start of Packet */
+#define LE_T1_EOP 0x01 /* End of Packet */
+#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
+
+/*
+ * Error Flags
+ */
+#define LE_T3_BUF 0x8000 /* Buffer Error */
+#define LE_T3_UFL 0x4000 /* Underflow Error */
+#define LE_T3_LCOL 0x1000 /* Late Collision */
+#define LE_T3_CLOS 0x0800 /* Loss of Carrier */
+#define LE_T3_RTY 0x0400 /* Retry Error */
+#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry */
+
+/* Miscellaneous useful macros */
+
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+ lp->tx_old+lp->tx_ring_mod_mask-lp->tx_new:\
+ lp->tx_old - lp->tx_new-1)
+
+/* The LANCE only uses 24 bit addresses. This does the obvious thing. */
+#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
+
+/* Now the prototypes we export */
+extern int lance_open(struct device *dev);
+extern int lance_close (struct device *dev);
+extern int lance_start_xmit (struct sk_buff *skb, struct device *dev);
+extern struct net_device_stats *lance_get_stats (struct device *dev);
+extern void lance_set_multicast (struct device *dev);
+
+#endif /* ndef _7990_H */
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
new file mode 100644
index 000000000..43db9bc8d
--- /dev/null
+++ b/drivers/net/82596.c
@@ -0,0 +1,1356 @@
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+ Based on Apricot.c
+ Written 1994 by Mark Evans.
+ This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
+
+
+ Modified to support the 82596 ethernet chips on 680x0 VME boards.
+ by Richard Hirst <richard@sleepie.demon.co.uk>
+ Renamed to be 82596.c
+
+ *** Untested on Apricot hardware, and may require some hacking
+ *** to make it work. The old 82596.c reported hasn't worked
+ *** since 1.3.xx anyway. I have been unable to find any users
+ *** of Apricot hardware to test this on.
+
+ Most of my modifications relate to the braindead big-endian
+ implementation by Intel. When the i596 is operating in
+ 'big-endian' mode, it thinks a 32 bit value of 0x12345678
+ should be stored as 0x56781234. This is a real pain, when
+ you have linked lists which are shared by the 680x0 and the
+ i596.
+
+ Driver skeleton
+ Written 1993 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@super.org or
+ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+ */
+
+static const char *version = "82596.c:v1.0 15/07/98\n";
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h> /*?? */
+
+#ifdef CONFIG_MVME16x_NET
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef CONFIG_BVME6000_NET
+#include <asm/bvme6000hw.h>
+#endif
+
+/*
+ * Define various macros for Channel Attention, word swapping etc., dependant
+ * on architecture. MVME and BVME are 680x0 based, otherwise it is Intel.
+ */
+
+#ifdef __mc68000__
+#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define ISCP_BUSY 0x00010000
+#define MACH_IS_APRICOT 0
+#else
+#define WSWAPrfd(x) x
+#define WSWAPiscp(x) ((struct i596_iscp *)(x))
+#define WSWAPscb(x) ((struct i596_scb *)(x))
+#define WSWAPcmd(x) x
+#define WSWAPtbd(x) x
+#define WSWAPchar(x) x
+#define ISCP_BUSY 0x0001
+#define MACH_IS_APRICOT 1
+#endif
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET 0x00 /* reset 82596 */
+#define PORT_SELFTEST 0x01 /* selftest */
+#define PORT_ALTSCP 0x02 /* alternate SCB address */
+#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
+
+#ifndef HAVE_PORTRESERVE
+#define check_region(addr, size) 0
+#define request_region(addr, size,name) do ; while(0)
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif
+
+#define APRICOT_DEBUG 2
+
+#ifdef APRICOT_DEBUG
+int i596_debug = APRICOT_DEBUG;
+#else
+int i596_debug = 1;
+#endif
+
+#define I596_TOTAL_SIZE 17
+
+#define I596_NULL -1
+
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+#define CMD_FLEX 0x0008 /* Enable flexible memory model */
+
+enum commands {
+ CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+ CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C 0x8000 /* Set to 0 after execution */
+#define STAT_B 0x4000 /* Command being executed */
+#define STAT_OK 0x2000 /* Command executed ok */
+#define STAT_A 0x1000 /* Command aborted */
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define RX_ABORT 0x0040
+
+struct i596_reg {
+ unsigned short porthi;
+ unsigned short portlo;
+ unsigned long ca;
+};
+
+struct i596_cmd {
+ unsigned short status;
+ unsigned short command;
+ struct i596_cmd *next;
+};
+
+#define EOF 0x8000
+#define SIZE_MASK 0x3fff
+
+struct i596_tbd {
+ unsigned short size;
+ unsigned short pad;
+ struct i596_tbd *next;
+ char *data;
+};
+
+struct tx_cmd {
+ struct i596_cmd cmd;
+ struct i596_tbd *tbd;
+ unsigned short size;
+ unsigned short pad;
+ struct sk_buff *skb; /* So we can free it after tx */
+};
+
+struct i596_rfd {
+ unsigned short stat;
+ unsigned short cmd;
+ struct i596_rfd *next;
+ long rbd;
+ unsigned short count;
+ unsigned short size;
+ char data[1532];
+};
+
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+ unsigned short status;
+ unsigned short command;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ unsigned long crc_err;
+ unsigned long align_err;
+ unsigned long resource_err;
+ unsigned long over_err;
+ unsigned long rcvdt_err;
+ unsigned long short_err;
+ unsigned short t_on;
+ unsigned short t_off;
+};
+
+struct i596_iscp {
+ unsigned long stat;
+ struct i596_scb *scb;
+};
+
+struct i596_scp {
+ unsigned long sysbus;
+ unsigned long pad;
+ struct i596_iscp *iscp;
+};
+
+struct i596_private {
+ volatile struct i596_scp scp;
+ volatile struct i596_iscp iscp;
+ volatile struct i596_scb scb;
+ struct i596_cmd set_add;
+ char eth_addr[8];
+ struct i596_cmd set_conf;
+ char i596_config[16];
+ struct i596_cmd tdr;
+ unsigned long stat;
+ int last_restart __attribute__((aligned(4)));
+ struct i596_rfd *rx_tail;
+ struct i596_cmd *cmd_tail;
+ struct i596_cmd *cmd_head;
+ int cmd_backlog;
+ unsigned long last_cmd;
+ struct net_device_stats stats;
+};
+
+char init_setup[] =
+{
+ 0x8E, /* length, prefetch on */
+ 0xC8, /* fifo to 8, monitor off */
+#ifdef CONFIG_VME
+ 0xc0, /* don't save bad frames */
+#else
+ 0x80, /* don't save bad frames */
+#endif
+ 0x2E, /* No source address insertion, 8 byte preamble */
+ 0x00, /* priority and backoff defaults */
+ 0x60, /* interframe spacing */
+ 0x00, /* slot time LSB */
+ 0xf2, /* slot time and retries */
+ 0x00, /* promiscuous mode */
+ 0x00, /* collision detect */
+ 0x40, /* minimum frame length */
+ 0xff,
+ 0x00,
+ 0x7f /* *multi IA */ };
+
+static int i596_open(struct device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
+static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int i596_close(struct device *dev);
+static struct net_device_stats *i596_get_stats(struct device *dev);
+static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd);
+static void print_eth(char *);
+static void set_multicast_list(struct device *dev);
+
+static int ticks_limit = 25;
+static int max_cmd_backlog = 16;
+
+
+static inline void CA(struct device *dev)
+{
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ ((struct i596_reg *) dev->base_addr)->ca = 1;
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile u32 i = *(volatile u32 *) (dev->base_addr);
+ }
+#endif
+#ifdef CONFIG_APRICOT_i596
+ if (MACH_IS_APRICOT) {
+ outw(0, (short) (dev->base_addr) + 4);
+ }
+#endif
+}
+
+
+static inline void MPU_PORT(struct device *dev, int c, volatile void *x)
+{
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
+ p->porthi = ((c) | (u32) (x)) & 0xffff;
+ p->portlo = ((c) | (u32) (x)) >> 16;
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ u32 v = (u32) (c) | (u32) (x);
+ v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+ *(volatile u32 *) dev->base_addr = v;
+ udelay(1);
+ *(volatile u32 *) dev->base_addr = v;
+ }
+#endif
+}
+
+
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)
+static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = dev_id;
+ struct i596_cmd *cmd;
+
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ printk("i596_error: lp = 0x%08x\n", (u32) lp);
+ printk("scp at %08x, .sysbus = %08x, .iscp = %08x\n",
+ (u32) & lp->scp, (u32) lp->scp.sysbus, (u32) lp->scp.iscp);
+ printk("iscp at %08x, .stat = %08x, .scb = %08x\n",
+ (u32) & lp->iscp, (u32) lp->iscp.stat, (u32) lp->iscp.scb);
+ printk("scb at %08x, .status = %04x, .command = %04x\n",
+ (u32) & lp->scb, lp->scb.status, lp->scb.command);
+ printk(" .cmd = %08x, .rfd = %08x\n", (u32) lp->scb.cmd,
+ (u32) lp->scb.rfd);
+ cmd = WSWAPcmd(lp->scb.cmd);
+ while (cmd && (u32) cmd < 0x1000000) {
+ printk("cmd at %08x, .status = %04x, .command = %04x, .next = %08x\n",
+ (u32) cmd, cmd->status, cmd->command, (u32) cmd->next);
+ cmd = WSWAPcmd(cmd->next);
+ }
+ while (1);
+}
+#endif
+
+static inline int init_rx_bufs(struct device *dev, int num)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ int i;
+ struct i596_rfd *rfd;
+
+ lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+
+ if (i596_debug > 1)
+ printk("%s: init_rx_bufs %d.\n", dev->name, num);
+
+ for (i = 0; i < num; i++) {
+ if (!(rfd = (struct i596_rfd *) kmalloc(sizeof(struct i596_rfd), GFP_KERNEL)))
+ break;
+
+ rfd->stat = 0x0000;
+ rfd->rbd = I596_NULL;
+ rfd->count = 0;
+ rfd->size = 1532;
+ if (i == 0) {
+ rfd->cmd = CMD_EOL;
+ lp->rx_tail = rfd;
+ } else
+ rfd->cmd = 0x0000;
+
+ rfd->next = lp->scb.rfd;
+ lp->scb.rfd = WSWAPrfd(rfd);
+ }
+
+ if (i != 0)
+ lp->rx_tail->next = lp->scb.rfd;
+
+ return (i);
+}
+
+static inline void remove_rx_bufs(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ struct i596_rfd *rfd = WSWAPrfd(lp->scb.rfd);
+
+ lp->rx_tail->next = (struct i596_rfd *) I596_NULL;
+
+ do {
+ lp->scb.rfd = rfd->next;
+ kfree(rfd);
+ rfd = WSWAPrfd(lp->scb.rfd);
+ }
+ while (rfd != lp->rx_tail);
+}
+
+static inline void init_i596_mem(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+#if !defined(CONFIG_MVME16x_NET) && !defined(CONFIG_BVME6000_NET)
+ short ioaddr = dev->base_addr;
+#endif
+ int boguscnt = 100000;
+ unsigned long flags;
+
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ /* Disable all ints for now */
+ pcc2[0x28] = 1;
+ pcc2[0x2a] = 0x40;
+ pcc2[0x2b] = 0x40; /* Set snooping bits now! */
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ }
+#endif
+
+ MPU_PORT(dev, PORT_RESET, 0);
+
+ udelay(100); /* Wait 100us - seems to help */
+
+ /* change the scp address */
+
+ MPU_PORT(dev, PORT_ALTSCP, &lp->scp);
+
+#else
+
+ /* change the scp address */
+ outw(0, ioaddr);
+ outw(0, ioaddr);
+ outb(4, ioaddr + 0xf);
+ outw(((((int) &lp->scp) & 0xffff) | 2), ioaddr);
+ outw((((int) &lp->scp) >> 16) & 0xffff, ioaddr);
+#endif
+
+ lp->last_cmd = jiffies;
+
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x)
+ lp->scp.sysbus = 0x00000054;
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000)
+ lp->scp.sysbus = 0x0000004c;
+#endif
+#ifdef CONFIG_APRICOT_i596
+ if (MACH_IS_APRICOT)
+ lp->scp.sysbus = 0x00440000;
+#endif
+
+ lp->scp.iscp = WSWAPiscp(&(lp->iscp));
+ lp->iscp.scb = WSWAPscb(&(lp->scb));
+ lp->iscp.stat = ISCP_BUSY;
+ lp->cmd_backlog = 0;
+
+ lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+
+ if (i596_debug > 1)
+ printk("%s: starting i82596.\n", dev->name);
+
+#if !defined(CONFIG_MVME16x_NET) && !defined(CONFIG_BVME6000_NET)
+ (void) inb(ioaddr + 0x10);
+ outb(4, ioaddr + 0xf);
+#endif
+ CA(dev);
+
+ while (lp->iscp.stat)
+ if (--boguscnt == 0) {
+ printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",
+ dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
+ lp->scb.command = 0;
+
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ /* Enable ints, etc. now */
+ pcc2[0x2a] = 0x08;
+ pcc2[0x2a] = 0x55; /* Edge sensitive */
+ pcc2[0x2b] = 0x55;
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 3;
+ }
+#endif
+
+ memcpy(lp->i596_config, init_setup, 14);
+ lp->set_conf.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->set_conf);
+
+ memcpy(lp->eth_addr, dev->dev_addr, 6);
+ lp->set_add.command = CmdSASetup;
+ i596_add_cmd(dev, &lp->set_add);
+
+ lp->tdr.command = CmdTDR;
+ i596_add_cmd(dev, &lp->tdr);
+
+ boguscnt = 200000;
+
+ save_flags(flags);
+ cli();
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",
+ dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
+ lp->scb.command = RX_START;
+ CA(dev);
+
+ restore_flags(flags);
+
+ boguscnt = 2000;
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",
+ lp->scb.status, lp->scb.command);
+ break;
+ }
+ return;
+}
+
+static inline int i596_rx(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ struct i596_rfd *rfd;
+ int frames = 0;
+
+ if (i596_debug > 3)
+ printk("i596_rx()\n");
+
+ rfd = WSWAPrfd(lp->scb.rfd); /* Reference next frame descriptor to check */
+
+ while ((rfd->stat) & STAT_C) { /* Loop while we have complete frames */
+ if (i596_debug > 2)
+ print_eth(rfd->data);
+
+ if ((rfd->stat) & STAT_OK) {
+ /* a good frame */
+ int pkt_len = rfd->count & 0x3fff;
+ struct sk_buff *skb = dev_alloc_skb(pkt_len);
+
+ frames++;
+
+ if (skb == NULL) {
+ printk("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
+ lp->stats.rx_dropped++;
+ } else {
+ skb->dev = dev;
+ memcpy(skb_put(skb, pkt_len), rfd->data, pkt_len);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
+ }
+ } else {
+ lp->stats.rx_errors++;
+ if ((rfd->stat) & 0x0001)
+ lp->stats.collisions++;
+ if ((rfd->stat) & 0x0080)
+ lp->stats.rx_length_errors++;
+ if ((rfd->stat) & 0x0100)
+ lp->stats.rx_over_errors++;
+ if ((rfd->stat) & 0x0200)
+ lp->stats.rx_fifo_errors++;
+ if ((rfd->stat) & 0x0400)
+ lp->stats.rx_frame_errors++;
+ if ((rfd->stat) & 0x0800)
+ lp->stats.rx_crc_errors++;
+ if ((rfd->stat) & 0x1000)
+ lp->stats.rx_length_errors++;
+ }
+
+ /* Clear the buffer descriptor count and EOF + F flags */
+
+ rfd->stat = 0;
+ rfd->count = 0;
+ rfd->cmd = CMD_EOL;
+ lp->rx_tail->cmd = 0;
+ lp->rx_tail = rfd;
+ lp->scb.rfd = rfd->next;
+ rfd = WSWAPrfd(lp->scb.rfd); /* Next frame descriptor to check */
+ }
+
+ if (i596_debug > 3)
+ printk("frames %d\n", frames);
+
+ return 0;
+}
+
+static inline void i596_cleanup_cmd(struct i596_private *lp)
+{
+ struct i596_cmd *ptr;
+ int boguscnt = 1000;
+
+ if (i596_debug > 4)
+ printk("i596_cleanup_cmd\n");
+
+ while (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
+ ptr = lp->cmd_head;
+
+ lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+ lp->cmd_backlog--;
+
+ switch ((ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ dev_kfree_skb(skb);
+
+ lp->stats.tx_errors++;
+ lp->stats.tx_aborted_errors++;
+
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ kfree(tx_cmd);
+ break;
+ }
+ case CmdMulticastList:
+ {
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ kfree(ptr);
+ break;
+ }
+ default:
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ }
+ }
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",
+ lp->scb.status, lp->scb.command);
+ break;
+ }
+ lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+}
+
+static inline void i596_reset(struct device *dev, struct i596_private *lp, int ioaddr)
+{
+ int boguscnt = 1000;
+ unsigned long flags;
+
+ if (i596_debug > 1)
+ printk("i596_reset\n");
+
+ save_flags(flags);
+ cli();
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",
+ lp->scb.status, lp->scb.command);
+ break;
+ }
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ lp->scb.command = CUC_ABORT | RX_ABORT;
+ CA(dev);
+
+ /* wait for shutdown */
+ boguscnt = 4000;
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",
+ lp->scb.status, lp->scb.command);
+ break;
+ }
+ restore_flags(flags);
+
+ i596_cleanup_cmd(lp);
+ i596_rx(dev);
+
+ dev->start = 1;
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ init_i596_mem(dev);
+}
+
+static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+ int boguscnt = 1000;
+
+ if (i596_debug > 4)
+ printk("i596_add_cmd\n");
+
+ cmd->status = 0;
+ cmd->command |= (CMD_EOL | CMD_INTR);
+ cmd->next = (struct i596_cmd *) I596_NULL;
+ save_flags(flags);
+ cli();
+
+ /*
+ * RGH 300597: Looks to me like there could be a race condition
+ * here. Just because we havn't picked up all the command items
+ * yet, doesn't mean that the 82596 hasn't finished processing
+ * them. So, we may need to do a CUC_START anyway.
+ * Maybe not. If it interrupts saying the CU is idle when there
+ * is still something in the cmd queue, the int handler with restart
+ * the CU.
+ */
+
+ if (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
+ lp->cmd_tail->next = WSWAPcmd(cmd);
+ } else {
+ lp->cmd_head = cmd;
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",
+ lp->scb.status, lp->scb.command);
+ break;
+ }
+ lp->scb.cmd = WSWAPcmd(cmd);
+ lp->scb.command = CUC_START;
+ CA(dev);
+ }
+ lp->cmd_tail = cmd;
+ lp->cmd_backlog++;
+
+ lp->cmd_head = WSWAPcmd(lp->scb.cmd); /* Is this redundant? RGH 300597 */
+ restore_flags(flags);
+
+ if (lp->cmd_backlog > max_cmd_backlog) {
+ unsigned long tickssofar = jiffies - lp->last_cmd;
+
+ if (tickssofar < ticks_limit)
+ return;
+
+ printk("%s: command unit timed out, status resetting.\n", dev->name);
+
+ i596_reset(dev, lp, ioaddr);
+ }
+}
+
+static int i596_open(struct device *dev)
+{
+ int i;
+
+ if (i596_debug > 1)
+ printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
+
+ if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", dev))
+ return -EAGAIN;
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ if (request_irq(0x56, &i596_error, 0, "apricot_error", dev))
+ return -EAGAIN;
+ }
+#endif
+ if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+ printk("%s: only able to allocate %d receive buffers\n", dev->name, i);
+
+ if (i < 4) {
+ free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+ MOD_INC_USE_COUNT;
+
+ /* Initialize the 82596 memory */
+ init_i596_mem(dev);
+
+ return 0; /* Always succeed */
+}
+
+static int i596_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+ struct tx_cmd *tx_cmd;
+
+ if (i596_debug > 2)
+ printk("%s: 82596 start xmit\n", dev->name);
+
+ /* Transmitter timeout, serious problems. */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ printk("%s: transmit timed out, status resetting.\n",
+ dev->name);
+ lp->stats.tx_errors++;
+ /* Try to restart the adaptor */
+ if (lp->last_restart == lp->stats.tx_packets) {
+ if (i596_debug > 1)
+ printk("Resetting board.\n");
+
+ /* Shutdown and restart */
+ i596_reset(dev, lp, ioaddr);
+ } else {
+ /* Issue a channel attention signal */
+ if (i596_debug > 1)
+ printk("Kicking board.\n");
+ lp->scb.command = CUC_START | RX_START;
+ CA(dev);
+ lp->last_restart = lp->stats.tx_packets;
+ }
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ }
+ if (i596_debug > 3)
+ printk("%s: i596_start_xmit() called\n", dev->name);
+
+ /* 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 (test_and_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;
+ dev->trans_start = jiffies;
+
+ tx_cmd = (struct tx_cmd *) kmalloc((sizeof(struct tx_cmd) + sizeof(struct i596_tbd)), GFP_ATOMIC);
+ if (tx_cmd == NULL) {
+ printk("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
+ lp->stats.tx_dropped++;
+
+ dev_kfree_skb(skb);
+ } else {
+ struct i596_tbd *tbd = (struct i596_tbd *) (tx_cmd + 1);
+ tx_cmd->tbd = WSWAPtbd(tbd);
+ tbd->next = (struct i596_tbd *) I596_NULL;
+
+ tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+ tx_cmd->skb = skb;
+
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tbd->pad = 0;
+ tbd->size = EOF | length;
+
+ tbd->data = WSWAPchar(skb->data);
+
+ if (i596_debug > 3)
+ print_eth(skb->data);
+ i596_add_cmd(dev, (struct i596_cmd *) tx_cmd);
+
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += length;
+ }
+ }
+
+ dev->tbusy = 0;
+
+ return 0;
+}
+
+
+static void print_eth(char *add)
+{
+ int i;
+
+ printk("print_eth(%08x)\n", (unsigned int) add);
+ printk("Dest ");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i]);
+ printk("\n");
+
+ printk("Source");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i + 6]);
+ printk("\n");
+ printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+}
+
+__initfunc(int i82596_probe(struct device *dev))
+{
+ int i;
+ struct i596_private *lp;
+ char eth_addr[6];
+
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ static int probed = 0;
+
+ if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
+ printk("Ethernet probe disabled - chip not present\n");
+ return ENODEV;
+ }
+ if (probed)
+ return ENODEV;
+ probed++;
+ memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */
+ dev->base_addr = MVME_I596_BASE;
+ dev->irq = (unsigned) MVME16x_IRQ_I596;
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;
+ unsigned char msr = rtc[3];
+ int i;
+
+ rtc[3] |= 0x80;
+ for (i = 0; i < 6; i++)
+ eth_addr[i] = rtc[i * 4 + 7]; /* Stored in RTC RAM at offset 1 */
+ rtc[3] = msr;
+ dev->base_addr = BVME_I596_BASE;
+ dev->irq = (unsigned) BVME_IRQ_I596;
+ }
+#endif
+#ifdef CONFIG_APRICOT_INTEL
+ int checksum = 0;
+ int ioaddr = 0x300;
+
+ /* this is easy the ethernet interface can only be at 0x300 */
+ /* first check nothing is already registered here */
+
+ if (check_region(ioaddr, I596_TOTAL_SIZE))
+ return ENODEV;
+
+ for (i = 0; i < 8; i++) {
+ eth_addr[i] = inb(ioaddr + 8 + i);
+ checksum += eth_addr[i];
+ }
+
+ /* checksum is a multiple of 0x100, got this wrong first time
+ some machines have 0x100, some 0x200. The DOS driver doesn't
+ even bother with the checksum */
+
+ if (checksum % 0x100)
+ return ENODEV;
+
+ /* Some other boards trip the checksum.. but then appear as ether
+ address 0. Trap these - AC */
+
+ if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
+ return ENODEV;
+
+ request_region(ioaddr, I596_TOTAL_SIZE, "i596");
+
+ dev->base_addr = ioaddr;
+ dev->irq = 10;
+#endif
+ ether_setup(dev);
+ printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr);
+
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+
+ printk(" IRQ %d.\n", dev->irq);
+
+ if (i596_debug > 0)
+ printk(version);
+
+ /* The APRICOT-specific entries in the device structure. */
+ dev->open = &i596_open;
+ dev->stop = &i596_close;
+ dev->hard_start_xmit = &i596_start_xmit;
+ dev->get_stats = &i596_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+
+ dev->mem_start = (int) kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL);
+ /* align for scp */
+ dev->priv = (void *) ((dev->mem_start + 0xf) & 0xfffffff0);
+
+ lp = (struct i596_private *) dev->priv;
+ if (i596_debug)
+ printk("%s: lp at 0x%08lx, lp->scb at 0x%08lx\n"
+ ,dev->name, (unsigned long) lp, (unsigned long) &lp->scb);
+ memset((void *) lp, 0, sizeof(struct i596_private));
+ lp->scb.command = 0;
+ lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+ lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+
+ return 0;
+}
+
+static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = dev_id;
+ struct i596_private *lp;
+ short ioaddr;
+ int boguscnt = 2000;
+ unsigned short status, ack_cmd = 0;
+
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
+ i596_error(BVME_IRQ_I596, NULL, NULL);
+ return;
+ }
+ }
+#endif
+ if (dev == NULL) {
+ printk("i596_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ if (i596_debug > 3)
+ printk("%s: i596_interrupt(): irq %d\n", dev->name, irq);
+
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+ dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+
+ lp = (struct i596_private *) dev->priv;
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
+ status = lp->scb.status;
+
+ if (i596_debug > 4)
+ printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status);
+
+ ack_cmd = status & 0xf000;
+
+ if ((status & 0x8000) || (status & 0x2000)) {
+ struct i596_cmd *ptr;
+
+ if ((i596_debug > 4) && (status & 0x8000))
+ printk("%s: i596 interrupt completed command.\n", dev->name);
+ if ((i596_debug > 4) && (status & 0x2000))
+ printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
+
+ while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C)) {
+ ptr = lp->cmd_head;
+
+ if (i596_debug > 2)
+ printk("cmd_head->status = %04x, ->command = %04x\n",
+ lp->cmd_head->status, lp->cmd_head->command);
+ lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+ lp->cmd_backlog--;
+
+ switch ((ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ if ((ptr->status) & STAT_OK) {
+ if (i596_debug > 2)
+ print_eth(skb->data);
+ } else {
+ lp->stats.tx_errors++;
+ if ((ptr->status) & 0x0020)
+ lp->stats.collisions++;
+ if (!((ptr->status) & 0x0040))
+ lp->stats.tx_heartbeat_errors++;
+ if ((ptr->status) & 0x0400)
+ lp->stats.tx_carrier_errors++;
+ if ((ptr->status) & 0x0800)
+ lp->stats.collisions++;
+ if ((ptr->status) & 0x1000)
+ lp->stats.tx_aborted_errors++;
+ }
+
+ dev_kfree_skb(skb);
+
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ kfree(tx_cmd);
+ break;
+ }
+ case CmdMulticastList:
+ {
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ kfree(ptr);
+ break;
+ }
+ case CmdTDR:
+ {
+ unsigned long status = *((unsigned long *) (ptr + 1));
+
+ if (status & 0x8000) {
+ if (i596_debug > 3)
+ printk("%s: link ok.\n", dev->name);
+ } else {
+ if (status & 0x4000)
+ printk("%s: Transceiver problem.\n", dev->name);
+ if (status & 0x2000)
+ printk("%s: Termination problem.\n", dev->name);
+ if (status & 0x1000)
+ printk("%s: Short circuit.\n", dev->name);
+
+ if (i596_debug > 1)
+ printk("%s: Time %ld.\n", dev->name, status & 0x07ff);
+ }
+ break;
+ }
+ case CmdConfigure:
+ {
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ /* Zap command so set_multicast_list() knows it is free */
+ ptr->command = 0;
+ break;
+ }
+ default:
+ ptr->next = (struct i596_cmd *) I596_NULL;
+ }
+ lp->last_cmd = jiffies;
+ }
+
+ ptr = lp->cmd_head;
+ while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail)) {
+ ptr->command &= 0x1fff;
+ ptr = WSWAPcmd(ptr->next);
+ }
+
+ if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start))
+ ack_cmd |= CUC_START;
+ lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+ }
+ if ((status & 0x1000) || (status & 0x4000)) {
+ if ((i596_debug > 4) && (status & 0x4000))
+ printk("%s: i596 interrupt received a frame.\n", dev->name);
+ /* Only RX_START if stopped - RGH 07-07-96 */
+ if (status & 0x1000) {
+ if (dev->start)
+ ack_cmd |= RX_START;
+ if (i596_debug > 1)
+ printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0);
+ }
+ i596_rx(dev);
+ }
+ /* acknowledge the interrupt */
+
+/* COMMENTED OUT <<<<<
+ if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start))
+ ack_cmd |= CUC_START;
+ */
+ boguscnt = 1000;
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
+ lp->scb.command = ack_cmd;
+
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ /* Ack the interrupt */
+
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ pcc2[0x2a] |= 0x08;
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ *ethirq = 3;
+ }
+#endif
+#ifdef CONFIG_APRICOT_INTEL
+ (void) inb(ioaddr + 0x10);
+ outb(4, ioaddr + 0xf);
+#endif
+ CA(dev);
+
+ if (i596_debug > 4)
+ printk("%s: exiting interrupt.\n", dev->name);
+
+ dev->interrupt = 0;
+ return;
+}
+
+static int i596_close(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ int boguscnt = 2000;
+ unsigned long flags;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ if (i596_debug > 1)
+ printk("%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, lp->scb.status);
+
+ save_flags(flags);
+ cli();
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("%s: close1 timed timed out with status %4.4x, cmd %4.4x.\n",
+ dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
+ lp->scb.command = CUC_ABORT | RX_ABORT;
+ CA(dev);
+
+ boguscnt = 2000;
+
+ while (lp->scb.command)
+ if (--boguscnt == 0) {
+ printk("%s: close2 timed timed out with status %4.4x, cmd %4.4x.\n",
+ dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
+ restore_flags(flags);
+
+ i596_cleanup_cmd(lp);
+
+#ifdef CONFIG_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ /* Disable all ints */
+ pcc2[0x28] = 1;
+ pcc2[0x2a] = 0x40;
+ pcc2[0x2b] = 0x40; /* Set snooping bits now! */
+ }
+#endif
+#ifdef CONFIG_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ }
+#endif
+
+ free_irq(dev->irq, dev);
+ remove_rx_bufs(dev);
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static struct net_device_stats *
+ i596_get_stats(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+
+ return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ struct i596_cmd *cmd;
+ int config = 0;
+
+ if (i596_debug > 1)
+ printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF");
+
+ if ((dev->flags & IFF_PROMISC) && !(lp->i596_config[8] & 0x01)) {
+ lp->i596_config[8] |= 0x01;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_PROMISC) && (lp->i596_config[8] & 0x01)) {
+ lp->i596_config[8] &= ~0x01;
+ config = 1;
+ }
+ if ((dev->flags & IFF_ALLMULTI) && (lp->i596_config[11] & 0x20)) {
+ lp->i596_config[11] &= ~0x20;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_ALLMULTI) && !(lp->i596_config[11] & 0x20)) {
+ lp->i596_config[11] |= 0x20;
+ config = 1;
+ }
+ if (config) {
+ if (lp->set_conf.command)
+ printk("%s: config change request already queued\n",
+ dev->name);
+ else {
+ lp->set_conf.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->set_conf);
+ }
+ }
+ if (dev->mc_count > 0) {
+ struct dev_mc_list *dmi;
+ unsigned char *cp;
+ cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd) + 2 + dev->mc_count * 6, GFP_ATOMIC);
+ if (cmd == NULL) {
+ printk("%s: set_multicast Memory squeeze.\n", dev->name);
+ return;
+ }
+ cmd->command = CmdMulticastList;
+ *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
+ cp = ((unsigned char *) (cmd + 1)) + 2;
+ for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+ memcpy(cp, dmi->dmi_addr, 6);
+ if (i596_debug > 1)
+ printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(cp + 0), *(cp + 1), *(cp + 2), *(cp + 3), *(cp + 4), *(cp + 5));
+ cp += 6;
+ }
+ if (i596_debug > 2)
+ print_eth(((char *) (cmd + 1)) + 2);
+ i596_add_cmd(dev, cmd);
+ }
+}
+
+#ifdef HAVE_DEVLIST
+static unsigned int i596_portlist[] __initdata =
+{0x300, 0};
+struct netdev_entry i596_drv =
+{"apricot", i82596_probe, I596_TOTAL_SIZE, apricot_portlist};
+#endif
+
+#ifdef MODULE
+static char devicename[9] =
+{0,};
+static struct device dev_apricot =
+{
+ devicename, /* device name inserted by /linux/drivers/net/net_init.c */
+ 0, 0, 0, 0,
+ 0x300, 10,
+ 0, 0, 0, NULL, i82596_probe};
+
+static int io = 0x300;
+static int irq = 10;
+MODULE_PARM(irq, "i");
+
+int init_module(void)
+{
+ dev_apricot.base_addr = io;
+ dev_apricot.irq = irq;
+ if (register_netdev(&dev_apricot) != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_netdev(&dev_apricot);
+ kfree((void *) dev_apricot.mem_start);
+ dev_apricot.priv = NULL;
+
+ /* If we don't do this, we can't re-insmod it later. */
+ release_region(dev_apricot.base_addr, I596_TOTAL_SIZE);
+}
+
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c"
+ * End:
+ */
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 23bd0883f..e00094f45 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -33,6 +33,10 @@
Alexey Kuznetsov : use the 8390's six bit hash multicast filter.
Paul Gortmaker : tweak ANK's above multicast changes a bit.
Paul Gortmaker : update packet statistics for v2.1.x
+ Alan Cox : support arbitary stupid port mappings on the
+ 68K Macintosh. Support >16bit I/O spaces
+ Paul Gortmaker : add kmod support for auto-loading of the 8390
+ module by all drivers that require it.
Sources:
@@ -41,7 +45,7 @@
*/
static const char *version =
- "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+ "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
#include <linux/module.h>
#include <linux/kernel.h>
@@ -55,7 +59,7 @@ static const char *version =
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/delay.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
@@ -65,6 +69,7 @@ static const char *version =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#define NS8390_CORE
#include "8390.h"
/* These are the operational function interfaces to board-specific
@@ -91,9 +96,7 @@ static const char *version =
#define ei_get_8390_hdr (ei_local->get_8390_hdr)
/* use 0 for production, 1 for verification, >2 for debug */
-#ifdef EI_DEBUG
-int ei_debug = EI_DEBUG;
-#else
+#ifndef ei_debug
int ei_debug = 1;
#endif
@@ -115,50 +118,53 @@ static void set_multicast_list(struct device *dev);
*/
int ei_open(struct device *dev)
{
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
- /* This can't happen unless somebody forgot to call ethdev_init(). */
- if (ei_local == NULL) {
- printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
- return -ENXIO;
- }
+ /* This can't happen unless somebody forgot to call ethdev_init(). */
+ if (ei_local == NULL)
+ {
+ printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
+ return -ENXIO;
+ }
- NS8390_init(dev, 1);
- dev->start = 1;
- ei_local->irqlock = 0;
- return 0;
+ NS8390_init(dev, 1);
+ dev->start = 1;
+ ei_local->irqlock = 0;
+ return 0;
}
/* Opposite of above. Only used when "ifconfig <devname> down" is done. */
int ei_close(struct device *dev)
{
- NS8390_init(dev, 0);
- dev->start = 0;
- return 0;
+ NS8390_init(dev, 0);
+ dev->start = 0;
+ return 0;
}
static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
- int e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int length, send_length, output_page;
-
-/*
- * We normally shouldn't be called if dev->tbusy is set, but the
- * existing code does anyway. If it has been too long since the
- * last Tx, we assume the board has died and kick it.
- */
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int length, send_length, output_page;
+
+ /*
+ * We normally shouldn't be called if dev->tbusy is set, but the
+ * existing code does anyway. If it has been too long since the
+ * last Tx, we assume the board has died and kick it.
+ */
- if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
+ if (dev->tbusy)
+ { /* Do timeouts, just like the 8003 driver. */
int txsr = inb(e8390_base+EN0_TSR), isr;
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX))) {
+ if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX)))
return 1;
- }
+
ei_local->stat.tx_errors++;
isr = inb(e8390_base+EN0_ISR);
- if (dev->start == 0) {
- printk("%s: xmit on stopped card\n", dev->name);
+ if (dev->start == 0)
+ {
+ printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name);
return 1;
}
@@ -169,138 +175,153 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
*/
printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
- dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
- (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+ dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+ (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
- if (!isr && !ei_local->stat.tx_packets) {
- /* The 8390 probably hasn't gotten on the cable yet. */
- ei_local->interface_num ^= 1; /* Try a different xcvr. */
+ if (!isr && !ei_local->stat.tx_packets)
+ {
+ /* The 8390 probably hasn't gotten on the cable yet. */
+ ei_local->interface_num ^= 1; /* Try a different xcvr. */
}
/* Try to restart the card. Perhaps the user has fixed something. */
ei_reset_8390(dev);
NS8390_init(dev, 1);
dev->trans_start = jiffies;
- }
+ }
- length = skb->len;
-
- /* Mask interrupts from the ethercard. */
- outb_p(0x00, e8390_base + EN0_IMR);
- disable_irq(dev->irq);
- synchronize_irq();
- if (dev->interrupt) {
- printk("%s: Tx request while isr active.\n",dev->name);
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- enable_irq(dev->irq);
- ei_local->stat.tx_errors++;
- dev_kfree_skb(skb);
- return 0;
- }
- ei_local->irqlock = 1;
+ length = skb->len;
+
+ /* Mask interrupts from the ethercard. */
+ outb_p(0x00, e8390_base + EN0_IMR);
+ disable_irq(dev->irq);
+ synchronize_irq();
+ if (dev->interrupt)
+ {
+ printk(KERN_WARNING "%s: Tx request while isr active.\n",dev->name);
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ enable_irq(dev->irq);
+ ei_local->stat.tx_errors++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ ei_local->irqlock = 1;
- send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
+ send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
#ifdef EI_PINGPONG
- /*
- * We have two Tx slots available for use. Find the first free
- * slot, and then perform some sanity checks. With two Tx bufs,
- * you get very close to transmitting back-to-back packets. With
- * only one Tx buf, the transmitter sits idle while you reload the
- * card, leaving a substantial gap between each transmitted packet.
- */
-
- if (ei_local->tx1 == 0) {
- output_page = ei_local->tx_start_page;
- ei_local->tx1 = send_length;
- if (ei_debug && ei_local->tx2 > 0)
- printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
- } else if (ei_local->tx2 == 0) {
- output_page = ei_local->tx_start_page + TX_1X_PAGES;
- ei_local->tx2 = send_length;
- if (ei_debug && ei_local->tx1 > 0)
- printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
- } else { /* We should never get here. */
- if (ei_debug)
- printk("%s: No Tx buffers free! irq=%d tx1=%d tx2=%d last=%d\n",
- dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
- ei_local->irqlock = 0;
- dev->tbusy = 1;
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- enable_irq(dev->irq);
- ei_local->stat.tx_errors++;
- return 1;
- }
-
- /*
- * Okay, now upload the packet and trigger a send if the transmitter
- * isn't already sending. If it is busy, the interrupt handler will
- * trigger the send later, upon receiving a Tx done interrupt.
- */
-
- ei_block_output(dev, length, skb->data, output_page);
- if (! ei_local->txing) {
- ei_local->txing = 1;
- NS8390_trigger_send(dev, send_length, output_page);
- dev->trans_start = jiffies;
- if (output_page == ei_local->tx_start_page) {
- ei_local->tx1 = -1;
- ei_local->lasttx = -1;
- } else {
- ei_local->tx2 = -1;
- ei_local->lasttx = -2;
+ /*
+ * We have two Tx slots available for use. Find the first free
+ * slot, and then perform some sanity checks. With two Tx bufs,
+ * you get very close to transmitting back-to-back packets. With
+ * only one Tx buf, the transmitter sits idle while you reload the
+ * card, leaving a substantial gap between each transmitted packet.
+ */
+
+ if (ei_local->tx1 == 0)
+ {
+ output_page = ei_local->tx_start_page;
+ ei_local->tx1 = send_length;
+ if (ei_debug && ei_local->tx2 > 0)
+ printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+ }
+ else if (ei_local->tx2 == 0)
+ {
+ output_page = ei_local->tx_start_page + TX_1X_PAGES;
+ ei_local->tx2 = send_length;
+ if (ei_debug && ei_local->tx1 > 0)
+ printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+ }
+ else
+ { /* We should never get here. */
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: No Tx buffers free! irq=%ld tx1=%d tx2=%d last=%d\n",
+ dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+ ei_local->irqlock = 0;
+ dev->tbusy = 1;
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ enable_irq(dev->irq);
+ ei_local->stat.tx_errors++;
+ return 1;
+ }
+
+ /*
+ * Okay, now upload the packet and trigger a send if the transmitter
+ * isn't already sending. If it is busy, the interrupt handler will
+ * trigger the send later, upon receiving a Tx done interrupt.
+ */
+
+ ei_block_output(dev, length, skb->data, output_page);
+ if (! ei_local->txing)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, output_page);
+ dev->trans_start = jiffies;
+ if (output_page == ei_local->tx_start_page)
+ {
+ ei_local->tx1 = -1;
+ ei_local->lasttx = -1;
+ }
+ else
+ {
+ ei_local->tx2 = -1;
+ ei_local->lasttx = -2;
+ }
}
- } else
- ei_local->txqueue++;
+ else ei_local->txqueue++;
- dev->tbusy = (ei_local->tx1 && ei_local->tx2);
+ dev->tbusy = (ei_local->tx1 && ei_local->tx2);
#else /* EI_PINGPONG */
- /*
- * Only one Tx buffer in use. You need two Tx bufs to come close to
- * back-to-back transmits. Expect a 20 -> 25% performance hit on
- * reasonable hardware if you only use one Tx buffer.
- */
+ /*
+ * Only one Tx buffer in use. You need two Tx bufs to come close to
+ * back-to-back transmits. Expect a 20 -> 25% performance hit on
+ * reasonable hardware if you only use one Tx buffer.
+ */
- ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
- ei_local->txing = 1;
- NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
- dev->trans_start = jiffies;
- dev->tbusy = 1;
+ ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ dev->tbusy = 1;
#endif /* EI_PINGPONG */
- /* Turn 8390 interrupts back on. */
- ei_local->irqlock = 0;
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- enable_irq(dev->irq);
+ /* Turn 8390 interrupts back on. */
+ ei_local->irqlock = 0;
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ enable_irq(dev->irq);
- dev_kfree_skb (skb);
- ei_local->stat.tx_bytes += send_length;
+ dev_kfree_skb (skb);
+ ei_local->stat.tx_bytes += send_length;
- return 0;
+ return 0;
}
/* The typical workload of the driver:
Handle the ether interface interrupts. */
+
void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct device *dev = dev_id;
- int e8390_base;
- int interrupts, nr_serviced = 0;
- struct ei_device *ei_local;
+ int e8390_base;
+ int interrupts, nr_serviced = 0;
+ struct ei_device *ei_local;
- if (dev == NULL) {
+ if (dev == NULL)
+ {
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return;
- }
- e8390_base = dev->base_addr;
- ei_local = (struct ei_device *) dev->priv;
- if (dev->interrupt || ei_local->irqlock) {
+ }
+
+ e8390_base = dev->base_addr;
+ ei_local = (struct ei_device *) dev->priv;
+ if (dev->interrupt || ei_local->irqlock)
+ {
#if 1 /* This might just be an interrupt for a PCI device sharing this line */
/* The "irqlock" check is only for testing. */
printk(ei_local->irqlock
@@ -310,39 +331,41 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
inb_p(e8390_base + EN0_IMR));
#endif
return;
- }
+ }
- dev->interrupt = 1;
- sti();
+ dev->interrupt = 1;
- /* Change to page 0 and read the intr status reg. */
- outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
- if (ei_debug > 3)
+ /* Change to page 0 and read the intr status reg. */
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+ if (ei_debug > 3)
printk("%s: interrupt(isr=%#2.2x).\n", dev->name,
inb_p(e8390_base + EN0_ISR));
- /* !!Assumption!! -- we stay in page 0. Don't break this. */
- while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
- && ++nr_serviced < MAX_SERVICE) {
- if (dev->start == 0) {
- printk("%s: interrupt from stopped card\n", dev->name);
+ /* !!Assumption!! -- we stay in page 0. Don't break this. */
+ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
+ && ++nr_serviced < MAX_SERVICE)
+ {
+ if (dev->start == 0)
+ {
+ printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
interrupts = 0;
break;
}
- if (interrupts & ENISR_OVER) {
+ if (interrupts & ENISR_OVER)
ei_rx_overrun(dev);
- } else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
+ else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
+ {
/* Got a good (?) packet. */
ei_receive(dev);
}
/* Push the next to-transmit packet through. */
- if (interrupts & ENISR_TX) {
+ if (interrupts & ENISR_TX)
ei_tx_intr(dev);
- } else if (interrupts & ENISR_TX_ERR) {
+ else if (interrupts & ENISR_TX_ERR)
ei_tx_err(dev);
- }
- if (interrupts & ENISR_COUNTERS) {
+ if (interrupts & ENISR_COUNTERS)
+ {
ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
@@ -350,16 +373,19 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
/* Ignore any RDC interrupts that make it back to here. */
- if (interrupts & ENISR_RDC) {
+ if (interrupts & ENISR_RDC)
+ {
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
}
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
- }
+ }
- if (interrupts && ei_debug) {
+ if (interrupts && ei_debug)
+ {
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
- if (nr_serviced >= MAX_SERVICE) {
+ if (nr_serviced >= MAX_SERVICE)
+ {
printk("%s: Too much work at interrupt, status %#2.2x\n",
dev->name, interrupts);
outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
@@ -367,9 +393,9 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
}
- }
- dev->interrupt = 0;
- return;
+ }
+ dev->interrupt = 0;
+ return;
}
/*
@@ -383,128 +409,143 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
static void ei_tx_err(struct device *dev)
{
- int e8390_base = dev->base_addr;
- unsigned char txsr = inb_p(e8390_base+EN0_TSR);
- unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ unsigned char txsr = inb_p(e8390_base+EN0_TSR);
+ unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
#ifdef VERBOSE_ERROR_DUMP
- printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
- if (txsr & ENTSR_ABT)
+ printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+ if (txsr & ENTSR_ABT)
printk("excess-collisions ");
- if (txsr & ENTSR_ND)
+ if (txsr & ENTSR_ND)
printk("non-deferral ");
- if (txsr & ENTSR_CRS)
+ if (txsr & ENTSR_CRS)
printk("lost-carrier ");
- if (txsr & ENTSR_FU)
+ if (txsr & ENTSR_FU)
printk("FIFO-underrun ");
- if (txsr & ENTSR_CDH)
+ if (txsr & ENTSR_CDH)
printk("lost-heartbeat ");
- printk("\n");
+ printk("\n");
#endif
- outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+ outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
- if (tx_was_aborted)
+ if (tx_was_aborted)
ei_tx_intr(dev);
- else {
+ else
+ {
ei_local->stat.tx_errors++;
if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
- }
+ }
}
/* We have finished a transmit: check for errors and then trigger the next
packet to be sent. */
+
static void ei_tx_intr(struct device *dev)
{
- int e8390_base = dev->base_addr;
- int status = inb(e8390_base + EN0_TSR);
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int status = inb(e8390_base + EN0_TSR);
- outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+ outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
#ifdef EI_PINGPONG
- /*
- * There are two Tx buffers, see which one finished, and trigger
- * the send of another one if it exists.
- */
- ei_local->txqueue--;
- if (ei_local->tx1 < 0) {
- if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
- printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx1);
- ei_local->tx1 = 0;
- dev->tbusy = 0;
- if (ei_local->tx2 > 0) {
- ei_local->txing = 1;
- NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
- dev->trans_start = jiffies;
- ei_local->tx2 = -1,
- ei_local->lasttx = 2;
- } else
- ei_local->lasttx = 20, ei_local->txing = 0;
- } else if (ei_local->tx2 < 0) {
- if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
- printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx2);
- ei_local->tx2 = 0;
- dev->tbusy = 0;
- if (ei_local->tx1 > 0) {
- ei_local->txing = 1;
- NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
- dev->trans_start = jiffies;
- ei_local->tx1 = -1;
- ei_local->lasttx = 1;
- } else
- ei_local->lasttx = 10, ei_local->txing = 0;
- } else
- printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
- dev->name, ei_local->lasttx);
+ /*
+ * There are two Tx buffers, see which one finished, and trigger
+ * the send of another one if it exists.
+ */
+ ei_local->txqueue--;
+
+ if (ei_local->tx1 < 0)
+ {
+ if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+ printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx1);
+ ei_local->tx1 = 0;
+ dev->tbusy = 0;
+ if (ei_local->tx2 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+ dev->trans_start = jiffies;
+ ei_local->tx2 = -1,
+ ei_local->lasttx = 2;
+ }
+ else ei_local->lasttx = 20, ei_local->txing = 0;
+ }
+ else if (ei_local->tx2 < 0)
+ {
+ if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
+ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx2);
+ ei_local->tx2 = 0;
+ dev->tbusy = 0;
+ if (ei_local->tx1 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ ei_local->tx1 = -1;
+ ei_local->lasttx = 1;
+ }
+ else
+ ei_local->lasttx = 10, ei_local->txing = 0;
+ }
+ else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
+ dev->name, ei_local->lasttx);
#else /* EI_PINGPONG */
- /*
- * Single Tx buffer: mark it free so another packet can be loaded.
- */
- ei_local->txing = 0;
- dev->tbusy = 0;
+ /*
+ * Single Tx buffer: mark it free so another packet can be loaded.
+ */
+ ei_local->txing = 0;
+ dev->tbusy = 0;
#endif
- /* Minimize Tx latency: update the statistics after we restart TXing. */
- if (status & ENTSR_COL)
- ei_local->stat.collisions++;
- if (status & ENTSR_PTX)
- ei_local->stat.tx_packets++;
- else {
- ei_local->stat.tx_errors++;
- if (status & ENTSR_ABT) {
- ei_local->stat.tx_aborted_errors++;
- ei_local->stat.collisions += 16;
+ /* Minimize Tx latency: update the statistics after we restart TXing. */
+ if (status & ENTSR_COL)
+ ei_local->stat.collisions++;
+ if (status & ENTSR_PTX)
+ ei_local->stat.tx_packets++;
+ else
+ {
+ ei_local->stat.tx_errors++;
+ if (status & ENTSR_ABT)
+ {
+ ei_local->stat.tx_aborted_errors++;
+ ei_local->stat.collisions += 16;
+ }
+ if (status & ENTSR_CRS)
+ ei_local->stat.tx_carrier_errors++;
+ if (status & ENTSR_FU)
+ ei_local->stat.tx_fifo_errors++;
+ if (status & ENTSR_CDH)
+ ei_local->stat.tx_heartbeat_errors++;
+ if (status & ENTSR_OWC)
+ ei_local->stat.tx_window_errors++;
}
- if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
- if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++;
- if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
- if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
- }
-
- mark_bh (NET_BH);
+ mark_bh (NET_BH);
}
/* We have a good packet(s), get it/them out of the buffers. */
static void ei_receive(struct device *dev)
{
- int e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- unsigned char rxing_page, this_frame, next_frame;
- unsigned short current_offset;
- int rx_pkt_count = 0;
- struct e8390_pkt_hdr rx_frame;
- int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ unsigned char rxing_page, this_frame, next_frame;
+ unsigned short current_offset;
+ int rx_pkt_count = 0;
+ struct e8390_pkt_hdr rx_frame;
+ int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
- while (++rx_pkt_count < 10) {
+ while (++rx_pkt_count < 10)
+ {
int pkt_len, pkt_stat;
/* Get the rx page (incoming packet pointer). */
@@ -520,7 +561,7 @@ static void ei_receive(struct device *dev)
/* Someday we'll omit the previous, iff we never get this message.
(There is at least one clone claimed to have a problem.) */
if (ei_debug > 0 && this_frame != ei_local->current_page)
- printk("%s: mismatched read page pointers %2x vs %2x.\n",
+ printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
dev->name, this_frame, ei_local->current_page);
if (this_frame == rxing_page) /* Read all the frames? */
@@ -547,24 +588,30 @@ static void ei_receive(struct device *dev)
continue;
}
- if (pkt_len < 60 || pkt_len > 1518) {
+ if (pkt_len < 60 || pkt_len > 1518)
+ {
if (ei_debug)
- printk("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+ printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
dev->name, rx_frame.count, rx_frame.status,
rx_frame.next);
ei_local->stat.rx_errors++;
ei_local->stat.rx_length_errors++;
- } else if ((pkt_stat & 0x0F) == ENRSR_RXOK) {
+ }
+ else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
+ {
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL) {
+ if (skb == NULL)
+ {
if (ei_debug > 1)
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+ printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, pkt_len);
ei_local->stat.rx_dropped++;
break;
- } else {
+ }
+ else
+ {
skb_reserve(skb,2); /* IP headers on 16 byte boundaries */
skb->dev = dev;
skb_put(skb, pkt_len); /* Make room */
@@ -576,9 +623,11 @@ static void ei_receive(struct device *dev)
if (pkt_stat & ENRSR_PHY)
ei_local->stat.multicast++;
}
- } else {
+ }
+ else
+ {
if (ei_debug)
- printk("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+ printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
dev->name, rx_frame.status, rx_frame.next,
rx_frame.count);
ei_local->stat.rx_errors++;
@@ -596,12 +645,12 @@ static void ei_receive(struct device *dev)
}
ei_local->current_page = next_frame;
outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
- }
+ }
- /* We used to also ack ENISR_OVER here, but that would sometimes mask
- a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
- outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
- return;
+ /* We used to also ack ENISR_OVER here, but that would sometimes mask
+ a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
+ outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
+ return;
}
/*
@@ -611,93 +660,99 @@ static void ei_receive(struct device *dev)
* This includes causing "the NIC to defer indefinitely when it is stopped
* on a busy network." Ugh.
*/
+
static void ei_rx_overrun(struct device *dev)
{
- int e8390_base = dev->base_addr;
- unsigned char was_txing, must_resend = 0;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int e8390_base = dev->base_addr;
+ unsigned char was_txing, must_resend = 0;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
- /*
- * Record whether a Tx was in progress and then issue the
- * stop command.
- */
- was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+ /*
+ * Record whether a Tx was in progress and then issue the
+ * stop command.
+ */
+ was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
- if (ei_debug > 1)
- printk("%s: Receiver overrun.\n", dev->name);
- ei_local->stat.rx_over_errors++;
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+ ei_local->stat.rx_over_errors++;
- /*
- * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
- * Early datasheets said to poll the reset bit, but now they say that
- * it "is not a reliable indicator and subsequently should be ignored."
- * We wait at least 10ms.
- */
- udelay(10*1000);
-
- /*
- * Reset RBCR[01] back to zero as per magic incantation.
- */
- outb_p(0x00, e8390_base+EN0_RCNTLO);
- outb_p(0x00, e8390_base+EN0_RCNTHI);
-
- /*
- * See if any Tx was interrupted or not. According to NS, this
- * step is vital, and skipping it will cause no end of havoc.
- */
- if (was_txing) {
- unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
- if (!tx_completed) must_resend = 1;
- }
-
- /*
- * Have to enter loopback mode and then restart the NIC before
- * you are allowed to slurp packets up off the ring.
- */
- outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
-
- /*
- * Clear the Rx ring of all the debris, and ack the interrupt.
- */
- ei_receive(dev);
- outb_p(ENISR_OVER, e8390_base+EN0_ISR);
-
- /*
- * Leave loopback mode, and resend any packet that got stopped.
- */
- outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
- if (must_resend)
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
-
+ /*
+ * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+ * Early datasheets said to poll the reset bit, but now they say that
+ * it "is not a reliable indicator and subsequently should be ignored."
+ * We wait at least 10ms.
+ */
+
+ udelay(10*1000);
+
+ /*
+ * Reset RBCR[01] back to zero as per magic incantation.
+ */
+ outb_p(0x00, e8390_base+EN0_RCNTLO);
+ outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+ /*
+ * See if any Tx was interrupted or not. According to NS, this
+ * step is vital, and skipping it will cause no end of havoc.
+ */
+
+ if (was_txing)
+ {
+ unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+ if (!tx_completed)
+ must_resend = 1;
+ }
+
+ /*
+ * Have to enter loopback mode and then restart the NIC before
+ * you are allowed to slurp packets up off the ring.
+ */
+ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+ /*
+ * Clear the Rx ring of all the debris, and ack the interrupt.
+ */
+ ei_receive(dev);
+ outb_p(ENISR_OVER, e8390_base+EN0_ISR);
+
+ /*
+ * Leave loopback mode, and resend any packet that got stopped.
+ */
+ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+ if (must_resend)
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
}
static struct net_device_stats *get_stats(struct device *dev)
{
- short ioaddr = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int ioaddr = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
- /* If the card is stopped, just return the present stats. */
- if (dev->start == 0) return &ei_local->stat;
-
- /* Read the counter registers, assuming we are in page 0. */
- ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
- ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
- ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+ /* If the card is stopped, just return the present stats. */
+ if (dev->start == 0)
+ return &ei_local->stat;
+
+ /* Read the counter registers, assuming we are in page 0. */
+ ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
+ ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
+ ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
- return &ei_local->stat;
+ return &ei_local->stat;
}
/*
* Update the given Autodin II CRC value with another data byte.
*/
+
static inline u32 update_crc(u8 byte, u32 current_crc)
{
int bit;
u8 ah = 0;
-
- for (bit=0; bit<8; bit++) {
+ for (bit=0; bit<8; bit++)
+ {
u8 carry = (current_crc>>31);
current_crc <<= 1;
ah = ((ah<<1) | carry) ^ byte;
@@ -713,14 +768,17 @@ static inline u32 update_crc(u8 byte, u32 current_crc)
* Form the 64 bit 8390 multicast table from the linked list of addresses
* associated with this dev structure.
*/
+
static inline void make_mc_bits(u8 *bits, struct device *dev)
{
struct dev_mc_list *dmi;
- for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next)
+ {
int i;
u32 crc;
- if (dmi->dmi_addrlen != ETH_ALEN) {
+ if (dmi->dmi_addrlen != ETH_ALEN)
+ {
printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
continue;
}
@@ -741,17 +799,19 @@ static inline void make_mc_bits(u8 *bits, struct device *dev)
static void set_multicast_list(struct device *dev)
{
- short ioaddr = dev->base_addr;
+ int e8390_base = dev->base_addr;
int i;
unsigned long flags;
- struct ei_device *ei = (struct ei_device*)dev->priv;
+ struct ei_device *ei_local = (struct ei_device*)dev->priv;
- if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
- memset(ei->mcfilter, 0, 8);
+ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
+ {
+ memset(ei_local->mcfilter, 0, 8);
if (dev->mc_list)
- make_mc_bits(ei->mcfilter, dev);
- } else
- memset(ei->mcfilter, 0xFF, 8); /* mcast set to accept-all */
+ make_mc_bits(ei_local->mcfilter, dev);
+ }
+ else
+ memset(ei_local->mcfilter, 0xFF, 8); /* mcast set to accept-all */
/*
* DP8390 manuals don't specify any magic sequence for altering
@@ -759,32 +819,47 @@ static void set_multicast_list(struct device *dev)
* ensure multicast mode is off prior to loading up the new hash
* table. If this proves to be not enough, we can always resort
* to stopping the NIC, loading the table and then restarting.
+ *
+ * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
+ * Elite16) appear to be write-only. The NS 8390 data sheet lists
+ * them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
+ * Ultra32 EISA) appears to have this bug fixed.
*/
if (dev->start)
- outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR);
+ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
save_flags(flags);
cli();
- outb_p(E8390_NODMA + E8390_PAGE1, ioaddr + E8390_CMD);
- for(i = 0; i < 8; i++)
- outb_p(ei->mcfilter[i], ioaddr + EN1_MULT + i);
- outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
+ outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+ for(i = 0; i < 8; i++)
+ {
+ outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+#ifdef NOT_83C690
+ if(inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
+ printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
+#endif
+ }
+ outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
restore_flags(flags);
- if(dev->flags&IFF_PROMISC)
- outb_p(E8390_RXCONFIG | 0x18, ioaddr + EN0_RXCR);
+ if(dev->flags&IFF_PROMISC)
+ outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
- outb_p(E8390_RXCONFIG | 0x08, ioaddr + EN0_RXCR);
- else
- outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR);
+ outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+ else
+ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
}
-/* Initialize the rest of the 8390 device structure. */
-__initfunc(int ethdev_init(struct device *dev))
+/*
+ * Initialize the rest of the 8390 device structure. Do NOT __initfunc
+ * this, as it is used by 8390 based modular drivers too.
+ */
+int ethdev_init(struct device *dev)
{
- if (ei_debug > 1)
+ if (ei_debug > 1)
printk(version);
- if (dev->priv == NULL) {
+ if (dev->priv == NULL)
+ {
struct ei_device *ei_local;
dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
@@ -792,106 +867,119 @@ __initfunc(int ethdev_init(struct device *dev))
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct ei_device));
ei_local = (struct ei_device *)dev->priv;
- }
+ }
- dev->hard_start_xmit = &ei_start_xmit;
- dev->get_stats = get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->hard_start_xmit = &ei_start_xmit;
+ dev->get_stats = get_stats;
+ dev->set_multicast_list = &set_multicast_list;
- ether_setup(dev);
+ ether_setup(dev);
- return 0;
+ return 0;
}
+
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
+
void NS8390_init(struct device *dev, int startp)
{
- int e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int i;
- int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
- unsigned long flags;
-
- /* Follow National Semi's recommendations for initing the DP83902. */
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
- outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
- /* Clear the remote byte count registers. */
- outb_p(0x00, e8390_base + EN0_RCNTLO);
- outb_p(0x00, e8390_base + EN0_RCNTHI);
- /* Set to monitor and loopback mode -- this is vital!. */
- outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
- outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
- /* Set the transmit page and receive ring. */
- outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
- ei_local->tx1 = ei_local->tx2 = 0;
- outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
- outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
- ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
- outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
- /* Clear the pending interrupts and mask. */
- outb_p(0xFF, e8390_base + EN0_ISR);
- outb_p(0x00, e8390_base + EN0_IMR);
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int i;
+ int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
+ unsigned long flags;
- /* Copy the station address into the DS8390 registers. */
- save_flags(flags);
- cli();
- outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
- for(i = 0; i < 6; i++) {
- outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
- }
+ if(sizeof(struct e8390_pkt_hdr)!=4)
+ panic("8390.c: header struct mispacked\n");
+ /* Follow National Semi's recommendations for initing the DP83902. */
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+ outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
+ /* Clear the remote byte count registers. */
+ outb_p(0x00, e8390_base + EN0_RCNTLO);
+ outb_p(0x00, e8390_base + EN0_RCNTHI);
+ /* Set to monitor and loopback mode -- this is vital!. */
+ outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+ /* Set the transmit page and receive ring. */
+ outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+ outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
+ ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
+ outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+ /* Clear the pending interrupts and mask. */
+ outb_p(0xFF, e8390_base + EN0_ISR);
+ outb_p(0x00, e8390_base + EN0_IMR);
- outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
- restore_flags(flags);
- dev->tbusy = 0;
- dev->interrupt = 0;
- ei_local->tx1 = ei_local->tx2 = 0;
- ei_local->txing = 0;
- if (startp) {
+ /* Copy the station address into the DS8390 registers. */
+ save_flags(flags);
+ cli();
+ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+ for(i = 0; i < 6; i++)
+ {
+ outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+ if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+ printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+ }
+
+ outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+ restore_flags(flags);
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_local->txing = 0;
+
+ if (startp)
+ {
outb_p(0xff, e8390_base + EN0_ISR);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
- outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
+ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
set_multicast_list(dev); /* (re)load the mcast table */
- }
- return;
+ }
+ return;
}
/* Trigger a transmit start, assuming the length is valid. */
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page)
{
- int e8390_base = dev->base_addr;
+ int e8390_base = dev->base_addr;
- outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
- if (inb_p(e8390_base) & E8390_TRANS) {
- printk("%s: trigger_send() called with the transmitter busy.\n",
- dev->name);
+ if (inb_p(e8390_base) & E8390_TRANS)
+ {
+ printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+ dev->name);
return;
- }
- outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
- outb_p(length >> 8, e8390_base + EN0_TCNTHI);
- outb_p(start_page, e8390_base + EN0_TPSR);
- outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
- return;
+ }
+ outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+ outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+ outb_p(start_page, e8390_base + EN0_TPSR);
+ outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
}
#ifdef MODULE
+struct module *NS8390_module = NULL;
+
int init_module(void)
{
- return 0;
+ NS8390_module = &__this_module;
+ return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
+ NS8390_module = NULL;
}
+
#endif /* MODULE */
/*
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index 5032e9b40..4418fb28d 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -1,16 +1,22 @@
/* Generic NS8390 register definitions. */
/* This file is part of Donald Becker's 8390 drivers, and is distributed
- under the same license.
+ under the same license. Auto-loading of 8390.o added by Paul Gortmaker.
Some of these names and comments originated from the Crynwr
packet drivers, which are distributed under the GPL. */
#ifndef _8390_h
#define _8390_h
+#include <linux/config.h>
#include <linux/if_ether.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
+/* With kmod, drivers can now load the 8390 module themselves! */
+#if 0 /* def CONFIG_KMOD */
+#define LOAD_8390_BY_KMOD
+#endif
+
#define TX_2X_PAGES 12
#define TX_1X_PAGES 6
@@ -32,21 +38,117 @@ struct e8390_pkt_hdr {
unsigned short count; /* header + packet length in bytes */
};
-/* From 8390.c */
+#ifdef notdef
extern int ei_debug;
-extern struct sigaction ei_sigaction;
+#else
+#define ei_debug 1
+#endif
+
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c */
+extern void autoirq_setup(int waittime);
+extern unsigned long autoirq_report(int waittime);
+#endif
+
+#if defined(LOAD_8390_BY_KMOD) && defined(MODULE) && !defined(NS8390_CORE)
+
+/* Function pointers to be mapped onto the 8390 core support */
+static int (*S_ethdev_init)(struct device *dev);
+static void (*S_NS8390_init)(struct device *dev, int startp);
+static int (*S_ei_open)(struct device *dev);
+static int (*S_ei_close)(struct device *dev);
+static void (*S_ei_interrupt)(int irq, void *dev_id, struct pt_regs *regs);
+
+
+#define NS8390_KSYSMS_PRESENT ( \
+ get_module_symbol(NULL, "ethdev_init") != 0 && \
+ get_module_symbol(NULL, "NS8390_init") != 0 && \
+ get_module_symbol(NULL, "ei_open") != 0 && \
+ get_module_symbol(NULL, "ei_close") != 0 && \
+ get_module_symbol(NULL, "ei_interrupt") != 0)
+
+extern __inline__ int load_8390_module(const char *driver)
+{
+
+ if (! NS8390_KSYSMS_PRESENT) {
+ int (*request_mod)(const char *module_name);
+
+ if (get_module_symbol("", "request_module") == 0) {
+ printk("%s: module auto-load (kmod) support not present.\n", driver);
+ printk("%s: unable to auto-load required 8390 module.\n", driver);
+ printk("%s: try \"modprobe 8390\" as root 1st.\n", driver);
+ return -ENOSYS;
+ }
+
+ request_mod = (void*)get_module_symbol("", "request_module");
+ if (request_mod("8390")) {
+ printk("%s: request to load the 8390 module failed.\n", driver);
+ return -ENOSYS;
+ }
-extern int ethif_init(struct device *dev);
+ /* Check if module really loaded and is valid */
+ if (! NS8390_KSYSMS_PRESENT) {
+ printk("%s: 8390.o not found/invalid or failed to load.\n", driver);
+ return -ENOSYS;
+ }
+
+ printk(KERN_INFO "%s: auto-loaded 8390 module.\n", driver);
+ }
+
+ /* Map the functions into place */
+ S_ethdev_init = (void*)get_module_symbol(0, "ethdev_init");
+ S_NS8390_init = (void*)get_module_symbol(0, "NS8390_init");
+ S_ei_open = (void*)get_module_symbol(0, "ei_open");
+ S_ei_close = (void*)get_module_symbol(0, "ei_close");
+ S_ei_interrupt = (void*)get_module_symbol(0, "ei_interrupt");
+
+ return 0;
+}
+
+/*
+ * Since a kmod aware driver won't explicitly show a dependence on the
+ * exported 8390 functions (due to the mapping above), the 8390 module
+ * (if present, and not in-kernel) needs to be protected from garbage
+ * collection. NS8390_module is only defined for a modular 8390 core.
+ */
+
+extern __inline__ void lock_8390_module(void)
+{
+ struct module **mod = (struct module**)get_module_symbol(0, "NS8390_module");
+
+ if (mod != NULL && *mod != NULL)
+ __MOD_INC_USE_COUNT(*mod);
+}
+
+extern __inline__ void unlock_8390_module(void)
+{
+ struct module **mod = (struct module**)get_module_symbol(0, "NS8390_module");
+
+ if (mod != NULL && *mod != NULL)
+ __MOD_DEC_USE_COUNT(*mod);
+}
+
+/*
+ * These are last so they only have scope over the driver
+ * code (wd, ne, 3c503, etc.) and not over the above code.
+ */
+#define ethdev_init S_ethdev_init
+#define NS8390_init S_NS8390_init
+#define ei_open S_ei_open
+#define ei_close S_ei_close
+#define ei_interrupt S_ei_interrupt
+
+#else /* not a module or kmod support not wanted */
+
+#define load_8390_module(driver) 0
+#define lock_8390_module() do { } while (0)
+#define unlock_8390_module() do { } while (0)
extern int ethdev_init(struct device *dev);
extern void NS8390_init(struct device *dev, int startp);
extern int ei_open(struct device *dev);
extern int ei_close(struct device *dev);
extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c */
-extern void autoirq_setup(int waittime);
-extern unsigned long autoirq_report(int waittime);
#endif
/* Most of these entries should be in 'struct device' (or most of the
@@ -75,6 +177,7 @@ struct ei_device {
unsigned char saved_irq; /* Original dev->irq value. */
/* The new statistics table. */
struct net_device_stats stat;
+ unsigned char *reg_offset; /* Register mapping table */
};
/* The maximum number of 8390 interrupt service routines called per IRQ. */
@@ -104,34 +207,41 @@ struct ei_device {
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
-#define E8390_CMD 0x00 /* The command register (for all pages) */
+
+#ifndef CONFIG_MAC
+#define EI_SHIFT(x) (x)
+#else
+#define EI_SHIFT(x) (ei_local->reg_offset[x])
+#endif
+
+#define E8390_CMD EI_SHIFT(0x00) /* The command register (for all pages) */
/* Page 0 register offsets. */
-#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
-#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
-#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
-#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
-#define EN0_TSR 0x04 /* Transmit status reg RD */
-#define EN0_TPSR 0x04 /* Transmit starting page WR */
-#define EN0_NCR 0x05 /* Number of collision reg RD */
-#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
-#define EN0_FIFO 0x06 /* FIFO RD */
-#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
-#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
-#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
-#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
-#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
-#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
-#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
-#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
-#define EN0_RSR 0x0c /* rx status reg RD */
-#define EN0_RXCR 0x0c /* RX configuration reg WR */
-#define EN0_TXCR 0x0d /* TX configuration reg WR */
-#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
-#define EN0_DCFG 0x0e /* Data configuration reg WR */
-#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
-#define EN0_IMR 0x0f /* Interrupt mask reg WR */
-#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
+#define EN0_CLDALO EI_SHIFT(0x01) /* Low byte of current local dma addr RD */
+#define EN0_STARTPG EI_SHIFT(0x01) /* Starting page of ring bfr WR */
+#define EN0_CLDAHI EI_SHIFT(0x02) /* High byte of current local dma addr RD */
+#define EN0_STOPPG EI_SHIFT(0x02) /* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY EI_SHIFT(0x03) /* Boundary page of ring bfr RD WR */
+#define EN0_TSR EI_SHIFT(0x04) /* Transmit status reg RD */
+#define EN0_TPSR EI_SHIFT(0x04) /* Transmit starting page WR */
+#define EN0_NCR EI_SHIFT(0x05) /* Number of collision reg RD */
+#define EN0_TCNTLO EI_SHIFT(0x05) /* Low byte of tx byte count WR */
+#define EN0_FIFO EI_SHIFT(0x06) /* FIFO RD */
+#define EN0_TCNTHI EI_SHIFT(0x06) /* High byte of tx byte count WR */
+#define EN0_ISR EI_SHIFT(0x07) /* Interrupt status reg RD WR */
+#define EN0_CRDALO EI_SHIFT(0x08) /* low byte of current remote dma address RD */
+#define EN0_RSARLO EI_SHIFT(0x08) /* Remote start address reg 0 */
+#define EN0_CRDAHI EI_SHIFT(0x09) /* high byte, current remote dma address RD */
+#define EN0_RSARHI EI_SHIFT(0x09) /* Remote start address reg 1 */
+#define EN0_RCNTLO EI_SHIFT(0x0a) /* Remote byte count reg WR */
+#define EN0_RCNTHI EI_SHIFT(0x0b) /* Remote byte count reg WR */
+#define EN0_RSR EI_SHIFT(0x0c) /* rx status reg RD */
+#define EN0_RXCR EI_SHIFT(0x0c) /* RX configuration reg WR */
+#define EN0_TXCR EI_SHIFT(0x0d) /* TX configuration reg WR */
+#define EN0_COUNTER0 EI_SHIFT(0x0d) /* Rcv alignment error counter RD */
+#define EN0_DCFG EI_SHIFT(0x0e) /* Data configuration reg WR */
+#define EN0_COUNTER1 EI_SHIFT(0x0e) /* Rcv CRC error counter RD */
+#define EN0_IMR EI_SHIFT(0x0f) /* Interrupt mask reg WR */
+#define EN0_COUNTER2 EI_SHIFT(0x0f) /* Rcv missed frame error counter RD */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
@@ -148,9 +258,11 @@ struct ei_device {
#define ENDCFG_WTS 0x01 /* word transfer mode selection */
/* Page 1 register offsets. */
-#define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */
-#define EN1_CURPAG 0x07 /* Current memory page RD WR */
-#define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_PHYS EI_SHIFT(0x01) /* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i) EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07) /* Current memory page RD WR */
+#define EN1_MULT EI_SHIFT(0x08) /* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i) EI_SHIFT(8+i) /* Get and set multicast filter */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
@@ -158,7 +270,7 @@ struct ei_device {
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
-#define ENRSR_PHY 0x20 /* physical/multicase address */
+#define ENRSR_PHY 0x20 /* physical/multicast address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index dfe3ed200..b50c8d638 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -24,18 +24,31 @@ fi
#
bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
- if [ "$CONFIG_PMAC" = "y" ]; then
+ if [ "$CONFIG_ARM" = "y" ]; then
+ if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
+ tristate 'AM79C961A support' CONFIG_ARM_AM79C961A
+ else
+ source drivers/acorn/net/Config.in
+ fi
+ fi
+ if [ "$CONFIG_PPC" = "y" ]; then
bool 'MACE (Power Mac ethernet) support' CONFIG_MACE
+ bool 'BMAC (G3 ethernet) support' CONFIG_BMAC
+ fi
+ if [ "$CONFIG_ZORRO" = "y" ]; then
+ tristate 'Ariadne support' CONFIG_ARIADNE
+ tristate 'A2065 support' CONFIG_A2065
+ tristate 'Hydra support' CONFIG_HYDRA
fi
if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
- tristate 'MIPS JAZZ onboard SONIC ethernet support' CONFIG_MIPS_JAZZ_SONIC
+ tristate 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
fi
bool '3COM cards' CONFIG_NET_VENDOR_3COM
if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
tristate '3c501 support' CONFIG_EL1
tristate '3c503 support' CONFIG_EL2
+ tristate '3c505 support' CONFIG_ELPLUS
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate '3c505 support' CONFIG_ELPLUS
tristate '3c507 support' CONFIG_EL16
if [ "$CONFIG_MCA" = "y" ]; then
tristate '3c523 support' CONFIG_ELMC
@@ -63,6 +76,10 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate 'NI5210 support' CONFIG_NI52
tristate 'NI6510 support' CONFIG_NI65
fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
+ tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
+ fi
bool 'Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -90,22 +107,29 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
if [ "$CONFIG_NET_EISA" = "y" ]; then
- bool 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
+ tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
fi
- tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
+ tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT
tristate 'CS89x0 support' CONFIG_CS89x0
tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+ if [ "$CONFIG_COBALT_MICRO_SERVER" = "y" ]; then
+ tristate 'Cobalt DECchip Tulip (dc21x4x) onboard support' CONFIG_COBALT_TULIP
+ fi
tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
+ fi
+ tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
+ tristate 'TI ThunderLAN support' CONFIG_TLAN
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
- tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
fi
fi
@@ -173,6 +197,8 @@ fi
bool 'Token Ring driver support' CONFIG_TR
if [ "$CONFIG_TR" = "y" ]; then
tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
+# tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS
+ tristate 'SysKonnect adapter support' CONFIG_SKTR
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3bd7f7280..6209d1767 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -12,14 +12,18 @@ L_OBJS := auto_irq.o
M_OBJS :=
MOD_LIST_NAME := NET_MODULES
-# Need these to keep track of whether the 8390, PPP and SLHC modules should
-# really go in the kernel or a module.
+# Need these to keep track of whether the 7990 (LANCE), 8390, PPP and SLHC
+# modules should really go in the kernel or a module.
CONFIG_8390_BUILTIN :=
CONFIG_8390_MODULE :=
CONFIG_SLHC_BUILTIN :=
CONFIG_SLHC_MODULE :=
CONFIG_PPPDEF_BUILTIN :=
CONFIG_PPPDEF_MODULE :=
+CONFIG_7990_BUILTIN :=
+CONFIG_7990_MODULE :=
+CONFIG_82596_BUILTIN :=
+CONFIG_82596_MODULE :=
ifeq ($(CONFIG_ISDN),y)
ifeq ($(CONFIG_ISDN_PPP),y)
@@ -51,6 +55,22 @@ else
endif
endif
+ifeq ($(CONFIG_IBMLS),y)
+L_OBJS += lanstreamer.o
+else
+ ifeq ($(CONFIG_IBMLS),m)
+ M_OBJS += lanstreamer.o
+ endif
+endif
+
+ifeq ($(CONFIG_SKTR),y)
+L_OBJS += sktr.o
+else
+ ifeq ($(CONFIG_SKTR),m)
+ M_OBJS += sktr.o
+ endif
+endif
+
ifeq ($(CONFIG_ETHERTAP),y)
L_OBJS += ethertap.o
else
@@ -59,6 +79,22 @@ else
endif
endif
+ifeq ($(CONFIG_DAYNAPORT), y)
+L_OBJS += daynaport.o
+CONFIG_8390_BUILTIN = y
+endif
+
+ifeq ($(CONFIG_APNE),y)
+L_OBJS += apne.o
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_APNE),m)
+ M_OBJS += apne.o
+ CONFIG_8390_MODULE = y
+ endif
+endif
+
+
ifeq ($(CONFIG_SHAPER),y)
L_OBJS += shaper.o
else
@@ -71,7 +107,6 @@ ifeq ($(CONFIG_SK_G16),y)
L_OBJS += sk_g16.o
endif
-
ifeq ($(CONFIG_HP100),y)
L_OBJS += hp100.o
else
@@ -104,6 +139,13 @@ else
endif
endif
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ETHERH),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
ifeq ($(CONFIG_WD80x3),y)
L_OBJS += wd.o
@@ -125,6 +167,24 @@ else
endif
endif
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ETHERH),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
+
+ifeq ($(CONFIG_NE2K_PCI),y)
+L_OBJS += ne2k-pci.o
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_NE2K_PCI),m)
+ CONFIG_8390_MODULE = y
+ M_OBJS += ne2k-pci.o
+ endif
+endif
+
ifeq ($(CONFIG_NE2000),y)
L_OBJS += ne.o
CONFIG_8390_BUILTIN = y
@@ -205,6 +265,15 @@ else
endif
endif
+ifeq ($(CONFIG_LNE390),y)
+L_OBJS += lne390.o
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_LNE390),m)
+ CONFIG_8390_MODULE = y
+ M_OBJS += lne390.o
+ endif
+endif
ifeq ($(CONFIG_PLIP),y)
L_OBJS += plip.o
@@ -234,13 +303,11 @@ ifeq ($(CONFIG_SLIP),y)
L_OBJS += slip.o
ifeq ($(CONFIG_SLIP_COMPRESSED),y)
CONFIG_SLHC_BUILTIN = y
- CONFIG_PPPDEF_BUILTIN = y
endif
else
ifeq ($(CONFIG_SLIP),m)
ifeq ($(CONFIG_SLIP_COMPRESSED),y)
CONFIG_SLHC_MODULE = y
- CONFIG_PPPDEF_MODULE = y
endif
M_OBJS += slip.o
endif
@@ -297,6 +364,10 @@ endif
ifeq ($(CONFIG_PCNET32),y)
L_OBJS += pcnet32.o
+else
+ ifeq ($(CONFIG_PCNET32),m)
+ M_OBJS += pcnet32.o
+ endif
endif
ifeq ($(CONFIG_DEFXX),y)
@@ -419,6 +490,22 @@ else
endif
endif
+ifeq ($(CONFIG_RTL8139),y)
+L_OBJS += rtl8139.o
+else
+ ifeq ($(CONFIG_RTL8139),m)
+ M_OBJS += rtl8139.o
+ endif
+endif
+
+ifeq ($(CONFIG_YELLOWFIN),y)
+L_OBJS += yellowfin.o
+else
+ ifeq ($(CONFIG_YELLOWFIN),m)
+ M_OBJS += yellowfin.o
+ endif
+endif
+
ifeq ($(CONFIG_WAVELAN),y)
L_OBJS += wavelan.o
else
@@ -510,10 +597,26 @@ else
endif
ifeq ($(CONFIG_APRICOT),y)
-L_OBJS += apricot.o
+CONFIG_82596_BUILTIN = y
else
ifeq ($(CONFIG_APRICOT),m)
- M_OBJS += apricot.o
+ CONFIG_82596_MODULE = y
+ endif
+endif
+
+ifeq ($(CONFIG_MVME16x_NET),y)
+CONFIG_82596_BUILTIN = y
+else
+ ifeq ($(CONFIG_MVME16x_NET),m)
+ CONFIG_82596_MODULE = y
+ endif
+endif
+
+ifeq ($(CONFIG_BVME6000_NET),y)
+CONFIG_82596_BUILTIN = y
+else
+ ifeq ($(CONFIG_BVME6000_NET),m)
+ CONFIG_82596_MODULE = y
endif
endif
@@ -621,6 +724,34 @@ else
endif
endif
+ifeq ($(CONFIG_HPLANCE),y)
+L_OBJS += hplance.o
+CONFIG_7990_BUILTIN = y
+else
+ ifeq ($(CONFIG_HPLANCE),m)
+ CONFIG_7990_MODULE = y
+ M_OBJS += hplance.o
+ endif
+endif
+# If we need generic LANCE support, either in the kernel or as a module,
+# build it in the appropriate way.
+ifdef CONFIG_7990_BUILTIN
+L_OBJS += 7990.o
+else
+ ifdef CONFIG_7990_MODULE
+ M_OBJS += 7990.o
+ endif
+endif
+
+# If anything built-in uses the 82596, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+ifdef CONFIG_82596_BUILTIN
+L_OBJS += 82596.o
+else
+ ifdef CONFIG_82596_MODULE
+ M_OBJS += 82596.o
+ endif
+endif
ifeq ($(CONFIG_EQUALIZER),y)
L_OBJS += eql.o
@@ -746,8 +877,12 @@ ifeq ($(CONFIG_MACE),y)
L_OBJS += mace.o
endif
+ifeq ($(CONFIG_BMAC),y)
+L_OBJS += bmac.o
+endif
+
ifeq ($(CONFIG_VENDOR_SANGOMA),y)
- L_OBJS += sdladrv.o
+ LX_OBJS += sdladrv.o
L_OBJS += sdlamain.o
ifeq ($(CONFIG_WANPIPE_X25),y)
L_OBJS += sdla_x25.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index b01c6a8a8..2fdfc177e 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -5,22 +5,21 @@
*
* Holds initial configuration information for devices.
*
- * NOTE: This file is a nice idea, but its current format does not work
- * well for drivers that support multiple units, like the SLIP
- * driver. We should actually have only one pointer to a driver
- * here, with the driver knowing how many units it supports.
- * Currently, the SLIP driver abuses the "base_addr" integer
- * field of the 'device' structure to store the unit number...
- * -FvK
- *
* Version: @(#)Space.c 1.0.7 08/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald J. Becker, <becker@super.org>
*
+ * Changelog:
+ * Paul Gortmaker (06/98):
+ * - sort probes in a sane way, make sure all (safe) probes
+ * get run once & failed autoprobes don't autoprobe again.
+ *
* FIXME:
- * Sort the device chain fastest first.
+ * Phase out placeholder dev entries put in the linked list
+ * here in favour of drivers using init_etherdev(NULL, ...)
+ * combined with a single find_all_devs() function (for 2.3)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -47,6 +46,7 @@ extern int ultra32_probe(struct device *dev);
extern int ultramca_probe(struct device *dev);
extern int wd_probe(struct device *dev);
extern int el2_probe(struct device *dev);
+extern int ne2k_pci_probe(struct device *dev);
extern int ne_probe(struct device *dev);
extern int hp_probe(struct device *dev);
extern int hp_plus_probe(struct device *dev);
@@ -61,7 +61,7 @@ extern int at1700_probe(struct device *);
extern int fmv18x_probe(struct device *);
extern int eth16i_probe(struct device *);
extern int depca_probe(struct device *);
-extern int apricot_probe(struct device *);
+extern int i82596_probe(struct device *);
extern int ewrk3_probe(struct device *);
extern int de4x5_probe(struct device *);
extern int el1_probe(struct device *);
@@ -71,6 +71,7 @@ extern int elmc_probe(struct device *);
extern int elplus_probe(struct device *);
extern int ac3200_probe(struct device *);
extern int es_probe(struct device *);
+extern int lne390_probe(struct device *);
extern int e2100_probe(struct device *);
extern int ni5010_probe(struct device *);
extern int ni52_probe(struct device *);
@@ -90,11 +91,24 @@ extern int atarilance_probe(struct device *);
extern int a2065_probe(struct device *);
extern int ariadne_probe(struct device *);
extern int hydra_probe(struct device *);
+extern int apne_probe(struct device *);
+extern int bionet_probe(struct device *);
+extern int pamsnet_probe(struct device *);
extern int tlan_probe(struct device *);
extern int mace_probe(struct device *);
+extern int bmac_probe(struct device *);
extern int cs89x0_probe(struct device *dev);
extern int ethertap_probe(struct device *dev);
+extern int ether1_probe (struct device *dev);
+extern int ether3_probe (struct device *dev);
+extern int etherh_probe (struct device *dev);
+extern int am79c961_probe(struct device *dev);
extern int epic100_probe(struct device *dev);
+extern int rtl8139_probe(struct device *dev);
+extern int hplance_probe(struct device *dev);
+
+/* Gigabit Ethernet adapters */
+extern int yellowfin_probe(struct device *dev);
/* Detachable devices ("pocket adaptors") */
extern int atp_init(struct device *);
@@ -105,205 +119,369 @@ extern int de620_probe(struct device *);
extern int dfx_probe(struct device *dev);
extern int apfddi_init(struct device *dev);
+/* HIPPI boards */
+extern int cern_hippi_probe(struct device *);
-__initfunc(static int ethif_probe(struct device *dev))
+struct devprobe
{
- u_long base_addr = dev->base_addr;
+ int (*probe)(struct device *dev);
+ int status; /* non-zero if autoprobe has failed */
+};
- if ((base_addr == 0xffe0) || (base_addr == 1))
- return 1; /* ENXIO */
+/*
+ * probe_list walks a list of probe functions and calls each so long
+ * as a non-zero ioaddr is given, or as long as it hasn't already failed
+ * to find a card in the past (as recorded by "status") when asked to
+ * autoprobe (i.e. a probe that fails to find a card when autoprobing
+ * will not be asked to autoprobe again). It exits when a card is found.
+ */
+__initfunc(static int probe_list(struct device *dev, struct devprobe *plist))
+{
+ struct devprobe *p = plist;
+ unsigned long base_addr = dev->base_addr;
+
+ while (p->probe != NULL) {
+ if (base_addr && p->probe(dev) == 0) /* probe given addr */
+ return 0;
+ else if (p->status == 0) { /* has autoprobe failed yet? */
+ p->status = p->probe(dev); /* no, try autoprobe */
+ if (p->status == 0)
+ return 0;
+ }
+ p++;
+ }
+ return -ENODEV;
+}
- if (1
-#ifdef CONFIG_HAPPYMEAL
- /* Please keep this one first, we'd like the on-board ethernet
- * to be probed first before other PCI cards on Ultra/PCI. -DaveM
- */
- && happy_meal_probe(dev)
+/*
+ * If your probe touches ISA ports (<0x400) in addition to
+ * looking for PCI cards, then put it in the isa_probes
+ * list instead.
+ */
+struct devprobe pci_probes[] __initdata = {
+#ifdef CONFIG_COBALT_TULIP
+ {tulip_probe, 0},
#endif
#ifdef CONFIG_DGRS
- && dgrs_probe(dev)
+ {dgrs_probe, 0},
#endif
-#if defined(CONFIG_VORTEX)
- && tc59x_probe(dev)
+#ifdef CONFIG_VORTEX
+ {tc59x_probe, 0},
#endif
-#if defined(CONFIG_SEEQ8005)
- && seeq8005_probe(dev)
+#ifdef CONFIG_DEC_ELCP
+ {tulip_probe, 0},
#endif
-#if defined(CONFIG_DEC_ELCP)
- && tulip_probe(dev)
+#ifdef CONFIG_NE2K_PCI
+ {ne2k_pci_probe, 0},
#endif
-#if defined(CONFIG_HP100)
- && hp100_probe(dev)
+#ifdef CONFIG_PCNET32
+ {pcnet32_probe, 0},
#endif
-#if defined(CONFIG_ULTRA)
- && ultra_probe(dev)
-#endif
-#if defined(CONFIG_ULTRAMCA)
- && ultramca_probe(dev)
+#ifdef CONFIG_EEXPRESS_PRO100 /* Intel EtherExpress Pro/100 */
+ {eepro100_probe, 0},
#endif
-#if defined(CONFIG_ULTRA32)
- && ultra32_probe(dev)
+#ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */
+ {de4x5_probe, 0},
#endif
-#if defined(CONFIG_SMC9194)
- && smc_init(dev)
+#ifdef CONFIG_TLAN
+ {tlan_probe, 0},
#endif
-#if defined(CONFIG_WD80x3) || defined(WD80x3)
- && wd_probe(dev)
+#ifdef CONFIG_EPIC100
+ {epic100_probe, 0},
#endif
-#if defined(CONFIG_EL2) || defined(EL2) /* 3c503 */
- && el2_probe(dev)
+#ifdef CONFIG_RTL8139
+ {rtl8139_probe, 0},
#endif
-#if defined(CONFIG_HPLAN) || defined(HPLAN)
- && hp_probe(dev)
+#ifdef CONFIG_YELLOWFIN
+ {yellowfin_probe, 0},
#endif
-#if defined(CONFIG_HPLAN_PLUS)
- && hp_plus_probe(dev)
+ {NULL, 0},
+};
+
+/*
+ * This is a bit of an artificial separation as there are PCI drivers
+ * that also probe for EISA cards (in the PCI group) and there are ISA
+ * drivers that probe for EISA cards (in the ISA group). These are the
+ * EISA only driver probes.
+ */
+struct devprobe eisa_probes[] __initdata = {
+#ifdef CONFIG_ULTRA32
+ {ultra32_probe, 0},
#endif
-#ifdef CONFIG_AC3200 /* Ansel Communications EISA 3200. */
- && ac3200_probe(dev)
+#ifdef CONFIG_AC3200
+ {ac3200_probe, 0},
#endif
#ifdef CONFIG_ES3210
- && es_probe(dev)
+ {es_probe, 0},
+#endif
+#ifdef CONFIG_LNE390
+ {lne390_probe, 0},
+#endif
+ {NULL, 0},
+};
+
+struct devprobe sparc_probes[] __initdata = {
+#ifdef CONFIG_HAPPYMEAL
+ {happy_meal_probe, 0},
+#endif
+#ifdef CONFIG_SUNLANCE
+ {sparc_lance_probe, 0},
+#endif
+#ifdef CONFIG_SUNQE
+ {qec_probe, 0},
+#endif
+#ifdef CONFIG_MYRI_SBUS
+ {myri_sbus_probe, 0},
+#endif
+ {NULL, 0},
+};
+
+struct devprobe mca_probes[] __initdata = {
+#ifdef CONFIG_ULTRAMCA
+ {ultramca_probe, 0},
+#endif
+#ifdef CONFIG_ELMC /* 3c523 */
+ {elmc_probe, 0},
+#endif
+ {NULL, 0},
+};
+
+/*
+ * ISA probes that touch addresses < 0x400 (including those that also
+ * look for EISA/PCI cards in addition to ISA cards).
+ */
+struct devprobe isa_probes[] __initdata = {
+#ifdef CONFIG_EL3 /* ISA, EISA (MCA someday) 3c5x9 */
+ {el3_probe, 0},
+#endif
+#ifdef CONFIG_HP100 /* ISA, EISA & PCI */
+ {hp100_probe, 0},
+#endif
+#ifdef CONFIG_ULTRA
+ {ultra_probe, 0},
+#endif
+#ifdef CONFIG_WD80x3
+ {wd_probe, 0},
+#endif
+#ifdef CONFIG_EL2 /* 3c503 */
+ {el2_probe, 0},
+#endif
+#ifdef CONFIG_HPLAN
+ {hp_probe, 0},
+#endif
+#ifdef CONFIG_HPLAN_PLUS
+ {hp_plus_probe, 0},
#endif
#ifdef CONFIG_E2100 /* Cabletron E21xx series. */
- && e2100_probe(dev)
+ {e2100_probe, 0},
+#endif
+#ifdef CONFIG_NE2000 /* ISA (use ne2k-pci for PCI cards) */
+ {ne_probe, 0},
#endif
-#if defined(CONFIG_NE2000) || defined(NE2000)
- && ne_probe(dev)
+#ifdef CONFIG_SMC9194
+ {smc_init, 0},
+#endif
+#ifdef CONFIG_SEEQ8005
+ {seeq8005_probe, 0},
#endif
#ifdef CONFIG_AT1500
- && at1500_probe(dev)
+ {at1500_probe, 0},
#endif
#ifdef CONFIG_CS89x0
- && cs89x0_probe(dev)
+ {cs89x0_probe, 0},
#endif
-#ifdef CONFIG_PCNET32
- && pcnet32_probe(dev)
-#endif
#ifdef CONFIG_AT1700
- && at1700_probe(dev)
+ {at1700_probe, 0},
#endif
#ifdef CONFIG_FMV18X /* Fujitsu FMV-181/182 */
- && fmv18x_probe(dev)
+ {fmv18x_probe, 0},
#endif
#ifdef CONFIG_ETH16I
- && eth16i_probe(dev) /* ICL EtherTeam 16i/32 */
-#endif
-#ifdef CONFIG_EL3 /* 3c509 */
- && el3_probe(dev)
+ {eth16i_probe, 0}, /* ICL EtherTeam 16i/32 */
#endif
#ifdef CONFIG_ZNET /* Zenith Z-Note and some IBM Thinkpads. */
- && znet_probe(dev)
+ {znet_probe, 0},
#endif
#ifdef CONFIG_EEXPRESS /* Intel EtherExpress */
- && express_probe(dev)
+ {express_probe, 0},
#endif
#ifdef CONFIG_EEXPRESS_PRO /* Intel EtherExpress Pro/10 */
- && eepro_probe(dev)
-#endif
-#ifdef CONFIG_EEXPRESS_PRO100 /* Intel EtherExpress Pro/100 */
- && eepro100_probe(dev)
+ {eepro_probe, 0},
#endif
#ifdef CONFIG_DEPCA /* DEC DEPCA */
- && depca_probe(dev)
+ {depca_probe, 0},
#endif
#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */
- && ewrk3_probe(dev)
+ {ewrk3_probe, 0},
#endif
-#ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */
- && de4x5_probe(dev)
-#endif
-#ifdef CONFIG_APRICOT /* Apricot I82596 */
- && apricot_probe(dev)
+#if defined(CONFIG_APRICOT) || defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET) /* Intel I82596 */
+ {i82596_probe, 0},
#endif
#ifdef CONFIG_EL1 /* 3c501 */
- && el1_probe(dev)
+ {el1_probe, 0},
#endif
-#if defined(CONFIG_WAVELAN) /* WaveLAN */
- && wavelan_probe(dev)
-#endif /* defined(CONFIG_WAVELAN) */
-#ifdef CONFIG_EL16 /* 3c507 */
- && el16_probe(dev)
+#ifdef CONFIG_WAVELAN /* WaveLAN */
+ {wavelan_probe, 0},
#endif
-#ifdef CONFIG_ELMC /* 3c523 */
- && elmc_probe(dev)
+#ifdef CONFIG_EL16 /* 3c507 */
+ {el16_probe, 0},
#endif
#ifdef CONFIG_ELPLUS /* 3c505 */
- && elplus_probe(dev)
-#endif
-#ifdef CONFIG_DE600 /* D-Link DE-600 adapter */
- && de600_probe(dev)
+ {elplus_probe, 0},
#endif
-#ifdef CONFIG_DE620 /* D-Link DE-620 adapter */
- && de620_probe(dev)
-#endif
-#if defined(CONFIG_SK_G16)
- && SK_init(dev)
+#ifdef CONFIG_SK_G16
+ {SK_init, 0},
#endif
#ifdef CONFIG_NI5010
- && ni5010_probe(dev)
+ {ni5010_probe, 0},
#endif
#ifdef CONFIG_NI52
- && ni52_probe(dev)
+ {ni52_probe, 0},
#endif
#ifdef CONFIG_NI65
- && ni65_probe(dev)
+ {ni65_probe, 0},
+#endif
+ {NULL, 0},
+};
+
+struct devprobe parport_probes[] __initdata = {
+#ifdef CONFIG_DE600 /* D-Link DE-600 adapter */
+ {de600_probe, 0},
+#endif
+#ifdef CONFIG_DE620 /* D-Link DE-620 adapter */
+ {de620_probe, 0},
+#endif
+#ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */
+ {atp_init, 0},
#endif
+ {NULL, 0},
+};
+
+struct devprobe m68k_probes[] __initdata = {
#ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */
- && atarilance_probe(dev)
+ {atarilance_probe, 0},
#endif
#ifdef CONFIG_A2065 /* Commodore/Ameristar A2065 Ethernet Board */
- && a2065_probe(dev)
+ {a2065_probe, 0},
#endif
#ifdef CONFIG_ARIADNE /* Village Tronic Ariadne Ethernet Board */
- && ariadne_probe(dev)
+ {ariadne_probe, 0},
#endif
#ifdef CONFIG_HYDRA /* Hydra Systems Amiganet Ethernet board */
- && hydra_probe(dev)
+ {hydra_probe, 0},
#endif
-#ifdef CONFIG_SUNLANCE
- && sparc_lance_probe(dev)
+#ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */
+ {apne_probe, 0},
#endif
-#ifdef CONFIG_TLAN
- && tlan_probe(dev)
+#ifdef CONFIG_ATARI_BIONET /* Atari Bionet Ethernet board */
+ {bionet_probe, 0},
#endif
-#ifdef CONFIG_SUNQE
- && qec_probe(dev)
+#ifdef CONFIG_ATARI_PAMSNET /* Atari PAMsNet Ethernet board */
+ {pamsnet_probe, 0},
#endif
-#ifdef CONFIG_MYRI_SBUS
- && myri_sbus_probe(dev)
+#ifdef CONFIG_HPLANCE /* HP300 internal Ethernet */
+ {hplance_probe, 0},
#endif
+ {NULL, 0},
+};
+
+struct devprobe ppc_probes[] __initdata = {
#ifdef CONFIG_MACE
- && mace_probe(dev)
+ {mace_probe, 0},
#endif
+#ifdef CONFIG_BMAC
+ {bmac_probe, 0},
+#endif
+ {NULL, 0},
+};
+
+struct devprobe sgi_probes[] __initdata = {
#ifdef CONFIG_SGISEEQ
- && sgiseeq_probe(dev)
+ {sgiseeq_probe, 0},
#endif
+ {NULL, 0},
+};
+
+struct devprobe mips_probes[] __initdata = {
#ifdef CONFIG_MIPS_JAZZ_SONIC
- && sonic_probe(dev)
-#endif
-#ifdef CONFIG_ARCH_ACORN
- && acorn_ethif_probe(dev)
+ {sonic_probe, 0},
#endif
-#ifdef CONFIG_ARM_AM79C961A
- && am79c961_probe(dev)
+ {NULL, 0},
+};
+
+struct devprobe arm_probes[] __initdata = {
+#ifdef CONFIG_ARM_ETHERH
+ {etherh_probe , 0},
#endif
-#ifdef CONFIG_EPIC100
- && epic100_probe(dev)
+#ifdef CONFIG_ARM_ETHER3
+ {ether3_probe , 0},
#endif
- && 1 ) {
- return 1; /* -ENODEV or -EAGAIN would be more accurate. */
- }
- return 0;
-}
+#ifdef CONFIG_ARM_ETHER1
+ {ether1_probe , 0},
+#endif
+#ifdef CONFIG_ARM_AM79C961A
+ {am79c961_probe, 0},
+#endif
+ {NULL, 0},
+};
+
+/*
+ * Unified ethernet device probe, segmented per architecture and
+ * per bus interface.
+ */
+__initfunc(static int ethif_probe(struct device *dev))
+{
+ unsigned long base_addr = dev->base_addr;
+ /*
+ * Backwards compatibility - historically an I/O base of 1 was
+ * used to indicate not to probe for this ethN interface
+ */
+ if (base_addr == 1)
+ return 1; /* ENXIO */
+
+ /*
+ * The arch specific probes are 1st so that any on-board ethernet
+ * will be probed before other ISA/EISA/MCA/PCI bus cards.
+ */
+ if (probe_list(dev, arm_probes) == 0)
+ return 0;
+ if (probe_list(dev, m68k_probes) == 0)
+ return 0;
+ if (probe_list(dev, mips_probes) == 0)
+ return 0;
+ if (probe_list(dev, ppc_probes) == 0)
+ return 0;
+ if (probe_list(dev, sgi_probes) == 0)
+ return 0;
+ if (probe_list(dev, sparc_probes) == 0)
+ return 0;
+ if (probe_list(dev, pci_probes) == 0)
+ return 0;
+ if (probe_list(dev, eisa_probes) == 0)
+ return 0;
+ if (probe_list(dev, mca_probes) == 0)
+ return 0;
+ /*
+ * Backwards compatibility - an I/O of 0xffe0 was used to indicate
+ * that we shouldn't do a bunch of potentially risky ISA probes
+ * for ethN (N>1). Since the widespread use of modules, *nobody*
+ * compiles a kernel with all the ISA drivers built in anymore,
+ * and so we should delete this check in linux 2.3 - Paul G.
+ */
+ if (base_addr != 0xffe0 && probe_list(dev, isa_probes) == 0)
+ return 0;
+ if (probe_list(dev, parport_probes) == 0)
+ return 0;
+ return -ENODEV;
+}
#ifdef CONFIG_FDDI
__initfunc(static int fddiif_probe(struct device *dev))
{
unsigned long base_addr = dev->base_addr;
- if ((base_addr == 0xffe0) || (base_addr == 1))
+ if (base_addr == 1)
return 1; /* ENXIO */
if (1
@@ -320,6 +498,28 @@ __initfunc(static int fddiif_probe(struct device *dev))
}
#endif
+#ifdef CONFIG_HIPPI
+static int hippi_probe(struct device *dev)
+{
+ /*
+ * Damn this is ugly.
+ *
+ * Why the heck would we want to determine this from the base
+ * address? Stupid PC'ism .... grrrrr.
+ */
+ if (dev->base_addr == -1)
+ return 1;
+
+ if (1
+#ifdef CONFIG_CERN_HIPPI
+ && cern_hippi_probe(dev)
+#endif
+ && 1 ) {
+ return 1; /* -ENODEV or -EAGAIN would be more accurate. */
+ }
+ return 0;
+}
+#endif
#ifdef CONFIG_ETHERTAP
static struct device tap0_dev = { "tap0", 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, };
@@ -335,14 +535,6 @@ __initfunc(static int fddiif_probe(struct device *dev))
# define NEXT_DEV (&sdla0_dev)
#endif
-/* Run-time ATtachable (Pocket) devices have a different (not "eth#") name. */
-#ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */
-static struct device atp_dev = {
- "atp0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, atp_init, /* ... */ };
-# undef NEXT_DEV
-# define NEXT_DEV (&atp_dev)
-#endif
-
#if defined(CONFIG_LTPC)
extern int ltpc_probe(struct device *);
static struct device dev_ltpc = {
@@ -382,15 +574,11 @@ static struct device atp_dev = {
# define ETH0_IRQ 0
#endif
-#ifndef __sparc__
-#define ETH_NOPROBE_ADDR 0xffe0
-#else
-#define ETH_NOPROBE_ADDR 0
-#endif
-
/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
- which means "don't probe". These entries exist to only to provide empty
- slots which may be enabled at boot-time. */
+ which means "don't do ISA probes". Distributions don't ship kernels with
+ all ISA drivers compiled in anymore, so its probably no longer an issue. */
+
+#define ETH_NOPROBE_ADDR 0xffe0
static struct device eth7_dev = {
"eth7", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
@@ -494,6 +682,9 @@ trif_probe(struct device *dev)
#ifdef CONFIG_IBMTR
&& ibmtr_probe(dev)
#endif
+#ifdef CONFIG_SKTR
+ && sktr_probe(dev)
+#endif
&& 1 ) {
return 1; /* -ENODEV or -EAGAIN would be more accurate. */
}
@@ -541,6 +732,20 @@ static struct device tr0_dev = {
#define NEXT_DEV (&fddi0_dev)
#endif
+#ifdef CONFIG_HIPPI
+ static struct device hip3_dev =
+ {"hip3", 0, 0, 0, 0, -1, 0, 0, 0, 0, NEXT_DEV, hippi_probe};
+ static struct device hip2_dev =
+ {"hip2", 0, 0, 0, 0, -1, 0, 0, 0, 0, &hip3_dev, hippi_probe};
+ static struct device hip1_dev =
+ {"hip1", 0, 0, 0, 0, -1, 0, 0, 0, 0, &hip2_dev, hippi_probe};
+ static struct device hip0_dev =
+ {"hip0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip1_dev, hippi_probe};
+
+#undef NEXT_DEV
+#define NEXT_DEV (&hip0_dev)
+#endif
+
#ifdef CONFIG_APBIF
extern int bif_init(struct device *dev);
static struct device bif_dev = {
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 584446c61..0fa32d8ca 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -7,11 +7,16 @@
incorporated herein by reference.
The author may be reached as becker@cesdis.gsfc.nasa.gov, or
- C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+ C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
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.
+
+ Changelog:
+
+ Paul Gortmaker 05/98 : add support for shared mem above 1MB.
+
*/
static const char *version =
@@ -29,23 +34,24 @@ static const char *version =
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/irq.h>
#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_NIC_BASE 0x00
+#define AC_SA_PROM 0x16 /* The station address PROM. */
+#define AC_ADDR0 0x00 /* Prefix station address values. */
+#define AC_ADDR1 0x40
+#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. */
+#define AC_RESET 0x00
+#define AC_ENABLE 0x01
+#define AC_CONFIG 0xC90 /* The configuration port. */
-#define AC_IO_EXTENT 0x10 /* IS THIS REALLY TRUE ??? */
+#define AC_IO_EXTENT 0x20
/* Actually accessed is:
* AC_NIC_BASE (0-15)
* AC_SA_PROM (0-5)
@@ -98,7 +104,6 @@ __initfunc(int ac3200_probe(struct device *dev))
else if (ioaddr > 0) /* Don't probe at all. */
return ENXIO;
- /* If you have a pre 0.99pl15 machine you should delete this line. */
if ( ! EISA_bus)
return ENXIO;
@@ -116,32 +121,19 @@ __initfunc(static int ac_probe1(int ioaddr, struct device *dev))
{
int i;
-#ifndef final_version
- printk("AC3200 ethercard probe at %#3x:", ioaddr);
+ if (inb_p(ioaddr + AC_ID_PORT) == 0xff)
+ return -ENODEV;
+
+ if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID)
+ return -ENODEV;
- 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");
+ printk(KERN_DEBUG "AC3200 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
- 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_ID_PORT), AC_EISA_ID);
- return ENODEV;
- }
-
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
@@ -149,33 +141,43 @@ __initfunc(static int ac_probe1(int ioaddr, struct device *dev))
dev = init_etherdev(0, 0);
}
- for(i = 0; i < ETHER_ADDR_LEN; i++)
- dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
+ printk("AC3200 in EISA slot %d, node", ioaddr/0x1000);
+ for(i = 0; i < 6; i++)
+ printk(" %02x", 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));
+#if 0
+ /* Check the vendor ID/prefix. Redundant after checking the EISA ID */
+ 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 ) {
+ printk(", not found (invalid prefix).\n");
+ return ENODEV;
+ }
#endif
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk (", unable to allocate memory for dev->priv.\n");
+ return -ENOMEM;
+ }
+
/* Assign and allocate the interrupt now. */
- if (dev->irq == 0)
+ if (dev->irq == 0) {
dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
- else if (dev->irq == 2)
- dev->irq = 9;
+ printk(", using");
+ } else {
+ dev->irq = irq_cannonicalize(dev->irq);
+ printk(", assigning");
+ }
if (request_irq(dev->irq, ei_interrupt, 0, "ac3200", dev)) {
- printk (" unable to get IRQ %d.\n", dev->irq);
+ printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
+ kfree(dev->priv);
+ dev->priv = NULL;
return EAGAIN;
}
- /* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (ethdev_init(dev)) {
- printk (" unable to allocate memory for dev->priv.\n");
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
+ printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
request_region(ioaddr, AC_IO_EXTENT, "ac3200");
@@ -194,6 +196,39 @@ __initfunc(static int ac_probe1(int ioaddr, struct device *dev))
dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
+
+ printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
+ dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
+
+ /*
+ * BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
+ * the card mem within the region covered by `normal' RAM !!!
+ */
+ if (dev->mem_start > 1024*1024) { /* phys addr > 1MB */
+ if (dev->mem_start < (unsigned long)high_memory) {
+ printk(KERN_CRIT "ac3200.c: Card RAM overlaps with normal memory!!!\n");
+ printk(KERN_CRIT "ac3200.c: Use EISA SCU to set card memory below 1MB,\n");
+ printk(KERN_CRIT "ac3200.c: or to an address above %p.\n", high_memory);
+ printk(KERN_CRIT "ac3200.c: Driver NOT installed.\n");
+ free_irq(dev->irq, dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return EINVAL;
+ }
+ dev->mem_start = (unsigned long)ioremap(dev->mem_start, AC_STOP_PG*0x100);
+ if (dev->mem_start == 0) {
+ printk(KERN_ERR "ac3200.c: Unable to remap card memory above 1MB !!\n");
+ printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n");
+ printk(KERN_ERR "ac3200.c: Driver NOT installed.\n");
+ free_irq(dev->irq, dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return EAGAIN;
+ }
+ printk("ac3200.c: remapped %dkB card memory to virtual address %#lx\n",
+ AC_STOP_PG/4, dev->mem_start);
+ }
+
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;
@@ -204,10 +239,6 @@ __initfunc(static int ac_probe1(int ioaddr, struct device *dev))
ei_status.stop_page = AC_STOP_PG;
ei_status.word16 = 1;
- printk("\n%s: AC3200 at %#x, IRQ %d, %s port, shared memory %#lx-%#lx.\n",
- dev->name, ioaddr, dev->irq, port_name[dev->if_port],
- dev->mem_start, dev->mem_end-1);
-
if (ei_debug > 0)
printk(version);
@@ -349,12 +380,15 @@ init_module(void)
if (io[this_dev] == 0 && this_dev != 0) break;
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -366,14 +400,16 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
struct device *dev = &dev_ac32[this_dev];
if (dev->priv != NULL) {
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
/* Someday free_irq may be in ac_close_card() */
free_irq(dev->irq, dev);
release_region(dev->base_addr, AC_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
index a2e91505e..4e0f00318 100644
--- a/drivers/net/am79c961a.c
+++ b/drivers/net/am79c961a.c
@@ -1,11 +1,10 @@
/*
- * linux/drivers/net/am79c961.c
+ * linux/drivers/net/am79c961.c
*
- * Derived from various things including skeleton.c
+ * Derived from various things including skeleton.c
*
- * R.M.King 1995.
+ * R.M.King 1995.
*/
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -35,33 +34,42 @@
#include "am79c961a.h"
static unsigned int net_debug = NET_DEBUG;
-static void am79c961_setmulticastlist (struct device *dev);
+
+static void
+am79c961_setmulticastlist (struct device *dev);
static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
-static void write_rreg (unsigned long base, unsigned int reg, unsigned short val)
+#define FUNC_PROLOGUE \
+ struct dev_priv *priv = (struct dev_priv *)dev->priv
+
+/* --------------------------------------------------------------------------- */
+
+static void
+write_rreg (unsigned long base, unsigned int reg, unsigned short val)
{
- __asm__("
- strh %1, [%2] @ NET_RAP
- strh %0, [%2, #-4] @ NET_RDP
- " : : "r" (val), "r" (reg), "r" (0xf0000464));
+ __asm__("
+ strh %1, [%2] @ NET_RAP
+ strh %0, [%2, #-4] @ NET_RDP
+ " : : "r" (val), "r" (reg), "r" (0xf0000464));
}
static inline void
write_ireg (unsigned long base, unsigned int reg, unsigned short val)
{
- __asm__("
- strh %1, [%2] @ NET_RAP
- strh %0, [%2, #8] @ NET_RDP
- " : : "r" (val), "r" (reg), "r" (0xf0000464));
+ __asm__("
+ strh %1, [%2] @ NET_RAP
+ strh %0, [%2, #8] @ NET_RDP
+ " : : "r" (val), "r" (reg), "r" (0xf0000464));
}
#define am_writeword(dev,off,val)\
- __asm__("\
- strh %0, [%1]\
- " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+ __asm__("\
+ strh %0, [%1]\
+ " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
-static inline void am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
+static inline void
+am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
{
offset = 0xe0000000 + (offset << 1);
length = (length + 1) & ~1;
@@ -72,8 +80,7 @@ static inline void am_writebuffer(struct device *dev, unsigned int offset, unsig
buf += 2;
length -= 2;
}
- while (length > 8)
- {
+ while (length > 8) {
unsigned int tmp, tmp2;
__asm__ __volatile__("
ldmia %1!, {%2, %3}
@@ -107,7 +114,8 @@ read_rreg (unsigned int base_addr, unsigned int reg)
return v;
}
-static inline unsigned short am_readword (struct device *dev, unsigned long off)
+static inline unsigned short
+am_readword (struct device *dev, unsigned long off)
{
unsigned long address = 0xe0000000 + (off << 1);
unsigned short val;
@@ -118,7 +126,8 @@ static inline unsigned short am_readword (struct device *dev, unsigned long off)
return val;
}
-static inline void am_readbuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
+static inline void
+am_readbuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
{
offset = 0xe0000000 + (offset << 1);
length = (length + 1) & ~1;
@@ -158,12 +167,8 @@ static inline void am_readbuffer(struct device *dev, unsigned int offset, unsign
}
}
-/*
- * From here on is mostly non ARM specific. Watch the fact it knows
- * the chip can hit all memory (kmalloc).
- */
-
-static int am79c961_ramtest(struct device *dev, unsigned int val)
+static int
+am79c961_ramtest(struct device *dev, unsigned int val)
{
unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
int i, error = 0, errorcount = 0;
@@ -190,9 +195,10 @@ static int am79c961_ramtest(struct device *dev, unsigned int val)
return errorcount;
}
-static void am79c961_init_for_open(struct device *dev)
+static void
+am79c961_init_for_open(struct device *dev)
{
- struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
unsigned long hdr_addr, first_free_addr;
unsigned long flags;
unsigned char *p;
@@ -212,9 +218,8 @@ static void am79c961_init_for_open(struct device *dev)
priv->rxtail = 0;
priv->rxhdr = hdr_addr;
- for (i = 0; i < RX_BUFFERS; i++)
- {
- priv->rxbuffer[i] = first_free_addr;
+ for (i = 0; i < RX_BUFFERS; i++) {
+ priv->rxbuffer[i] = first_free_addr;
am_writeword (dev, hdr_addr, first_free_addr);
am_writeword (dev, hdr_addr + 2, RMD_OWN);
am_writeword (dev, hdr_addr + 4, (-1600));
@@ -225,9 +230,8 @@ static void am79c961_init_for_open(struct device *dev)
priv->txhead = 0;
priv->txtail = 0;
priv->txhdr = hdr_addr;
- for (i = 0; i < TX_BUFFERS; i++)
- {
- priv->txbuffer[i] = first_free_addr;
+ for (i = 0; i < TX_BUFFERS; i++) {
+ priv->txbuffer[i] = first_free_addr;
am_writeword (dev, hdr_addr, first_free_addr);
am_writeword (dev, hdr_addr + 2, 0);
am_writeword (dev, hdr_addr + 4, 0);
@@ -251,7 +255,7 @@ static void am79c961_init_for_open(struct device *dev)
write_rreg (dev->base_addr, BASERXH, 0);
write_rreg (dev->base_addr, BASETXL, priv->txhdr);
write_rreg (dev->base_addr, BASERXH, 0);
- write_rreg (dev->base_addr, POLLINT, 0);
+ write_rreg (dev->base_addr, POLLINT, 0);
write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
@@ -259,7 +263,8 @@ static void am79c961_init_for_open(struct device *dev)
write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
}
-static int am79c961_init(struct device *dev)
+static int
+am79c961_init(struct device *dev)
{
unsigned long flags;
@@ -280,15 +285,14 @@ static int am79c961_init(struct device *dev)
/*
* This is the real probe routine.
*/
-
-static int am79c961_probe1(struct device *dev)
+static int
+am79c961_probe1(struct device *dev)
{
static unsigned version_printed = 0;
struct dev_priv *priv;
int i;
- if (!dev->priv)
- {
+ if (!dev->priv) {
dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
if (!dev->priv)
return -ENOMEM;
@@ -300,21 +304,19 @@ static int am79c961_probe1(struct device *dev)
/*
* The PNP initialisation should have been done by the ether bootp loader.
*/
-
inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */
udelay (5);
if (inb (dev->base_addr >> 1) != 0x08 ||
- inb ((dev->base_addr >> 1) + 1) != 00 ||
- inb ((dev->base_addr >> 1) + 2) != 0x2b)
- {
+ inb ((dev->base_addr >> 1) + 1) != 00 ||
+ inb ((dev->base_addr >> 1) + 2) != 0x2b) {
kfree (dev->priv);
dev->priv = NULL;
return -ENODEV;
- }
+ }
- /*
+ /*
* Ok, we've found a valid hw ID
*/
@@ -325,14 +327,12 @@ static int am79c961_probe1(struct device *dev)
request_region (dev->base_addr, 0x18, "am79c961");
/* Retrive and print the ethernet address. */
- for (i = 0; i < 6; i++)
- {
- dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff;
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff;
printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
}
- if (am79c961_init(dev))
- {
+ if (am79c961_init(dev)) {
kfree (dev->priv);
dev->priv = NULL;
return -ENODEV;
@@ -346,10 +346,12 @@ static int am79c961_probe1(struct device *dev)
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
+
return 0;
}
-int am79c961_probe(struct device *dev)
+int
+am79c961_probe(struct device *dev)
{
static int initialised = 0;
@@ -371,10 +373,10 @@ int am79c961_probe(struct device *dev)
* registers that "should" only need to be set once at boot, so that
* there is non-reboot way to recover if something goes wrong.
*/
-
-static int am79c961_open(struct device *dev)
+static int
+am79c961_open(struct device *dev)
{
- struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
MOD_INC_USE_COUNT;
@@ -384,6 +386,7 @@ static int am79c961_open(struct device *dev)
return -EAGAIN;
am79c961_init_for_open(dev);
+
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
@@ -393,13 +396,14 @@ static int am79c961_open(struct device *dev)
/*
* The inverse routine to am79c961_open().
*/
-
-static int am79c961_close(struct device *dev)
+static int
+am79c961_close(struct device *dev)
{
dev->tbusy = 1;
dev->start = 0;
am79c961_init(dev);
+
free_irq (dev->irq, dev);
MOD_DEC_USE_COUNT;
@@ -410,10 +414,9 @@ static int am79c961_close(struct device *dev)
* Get the current statistics. This may be called with the card open or
* closed.
*/
-
static struct enet_statistics *am79c961_getstats (struct device *dev)
{
- struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
return &priv->stats;
}
@@ -423,7 +426,6 @@ static struct enet_statistics *am79c961_getstats (struct device *dev)
* We don't attempt any packet filtering. The card may have a SEEQ 8004
* in which does not have the other ethernet address registers present...
*/
-
static void am79c961_setmulticastlist (struct device *dev)
{
unsigned long flags;
@@ -441,18 +443,16 @@ static void am79c961_setmulticastlist (struct device *dev)
}
/*
- * Transmit a packet
+ * Transmit a packet
*/
-
-static int am79c961_sendpacket(struct sk_buff *skb, struct device *dev)
+static int
+am79c961_sendpacket(struct sk_buff *skb, struct device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
- if (!dev->tbusy)
- {
+ if (!dev->tbusy) {
again:
- if (!test_and_set_bit(0, (void*)&dev->tbusy))
- {
+ if (!test_and_set_bit(0, (void*)&dev->tbusy)) {
unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned int hdraddr, bufaddr;
unsigned long flags;
@@ -474,17 +474,12 @@ again:
if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
dev->tbusy = 0;
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
- }
- else
- {
+ } else
printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
return 1;
- }
- }
- else
- {
+ } else {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 5)
return 1;
@@ -496,7 +491,8 @@ again:
}
}
-static void am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void
+am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct dev_priv *priv = (struct dev_priv *)dev->priv;
@@ -508,6 +504,7 @@ static void am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
dev->interrupt = 1;
+
status = read_rreg (dev->base_addr, CSR0);
write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
@@ -529,14 +526,13 @@ static void am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
* If we have a good packet(s), get it/them out of the buffers.
*/
-
-static void am79c961_rx(struct device *dev, struct dev_priv *priv)
+static void
+am79c961_rx(struct device *dev, struct dev_priv *priv)
{
unsigned long hdraddr;
unsigned long pktaddr;
- do
- {
+ do {
unsigned long status;
struct sk_buff *skb;
int len;
@@ -552,18 +548,15 @@ static void am79c961_rx(struct device *dev, struct dev_priv *priv)
if (priv->rxtail >= RX_BUFFERS)
priv->rxtail = 0;
- if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP))
- {
+ if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
am_writeword (dev, hdraddr + 2, RMD_OWN);
priv->stats.rx_errors ++;
- if (status & RMD_ERR)
- {
+ if (status & RMD_ERR) {
if (status & RMD_FRAM)
priv->stats.rx_frame_errors ++;
if (status & RMD_CRC)
priv->stats.rx_crc_errors ++;
- }
- else if (status & RMD_STP)
+ } else if (status & RMD_STP)
priv->stats.rx_length_errors ++;
continue;
}
@@ -595,8 +588,8 @@ static void am79c961_rx(struct device *dev, struct dev_priv *priv)
/*
* Update stats for the transmitted packet
*/
-
-static void am79c961_tx(struct device *dev, struct dev_priv *priv)
+static void
+am79c961_tx(struct device *dev, struct dev_priv *priv)
{
do {
unsigned long hdraddr;
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
new file mode 100644
index 000000000..005cc3195
--- /dev/null
+++ b/drivers/net/apne.c
@@ -0,0 +1,633 @@
+/*
+ * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200
+ *
+ * (C) Copyright 1997 Alain Malek
+ * (Alain.Malek@cryogen.com)
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is based on
+ *
+ * ne.c: A general non-shared-memory NS8390 ethernet driver for linux
+ * Written 1992-94 by Donald Becker.
+ *
+ * 8390.c: A general NS8390 ethernet driver core for linux.
+ * Written 1992-94 by Donald Becker.
+ *
+ * cnetdevice: A Sana-II ethernet driver for AmigaOS
+ * Written by Bruce Abbott (bhabbott@inhb.co.nz)
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of the Linux
+ * distribution for more details.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/setup.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/amigayle.h>
+#include <asm/amipcmcia.h>
+
+#include "8390.h"
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE (dev->base_addr)
+#define NE_CMD 0x00
+#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
+#define NE_RESET 0x1f+GAYLE_ODD /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT 0x20
+
+#define NE_EN0_ISR 0x07+GAYLE_ODD
+#define NE_EN0_DCFG 0x0e
+
+#define NE_EN0_RSARLO 0x08
+#define NE_EN0_RSARHI 0x09+GAYLE_ODD
+#define NE_EN0_RCNTLO 0x0a
+#define NE_EN0_RXCR 0x0c
+#define NE_EN0_TXCR 0x0d+GAYLE_ODD
+#define NE_EN0_RCNTHI 0x0b+GAYLE_ODD
+#define NE_EN0_IMR 0x0f+GAYLE_ODD
+
+#define NE1SM_START_PG 0x20 /* First page of TX buffer */
+#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */
+#define NESM_START_PG 0x40 /* First page of TX buffer */
+#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+
+int apne_probe(struct device *dev);
+static int apne_probe1(struct device *dev, int ioaddr);
+
+static int apne_open(struct device *dev);
+static int apne_close(struct device *dev);
+
+static void apne_reset_8390(struct device *dev);
+static void apne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void apne_block_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void apne_block_output(struct device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+static void apne_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int init_pcmcia(void);
+
+/* IO base address used for nic */
+
+#define IOBASE 0x300
+
+/*
+ use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand
+ you can find the values to use by looking at the cnet.device
+ config file example (the default values are for the CNET40BC card)
+*/
+
+/*
+#define MANUAL_CONFIG 0x20
+#define MANUAL_OFFSET 0x3f8
+
+#define MANUAL_HWADDR0 0x00
+#define MANUAL_HWADDR1 0x12
+#define MANUAL_HWADDR2 0x34
+#define MANUAL_HWADDR3 0x56
+#define MANUAL_HWADDR4 0x78
+#define MANUAL_HWADDR5 0x9a
+*/
+
+#define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
+
+
+static const char *version =
+ "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
+
+
+__initfunc(int apne_probe(struct device *dev))
+{
+#ifndef MANUAL_CONFIG
+ char tuple[8];
+#endif
+
+ if ( !(AMIGAHW_PRESENT(PCMCIA)) )
+ return (ENODEV);
+
+ printk("Looking for PCMCIA ethernet card : ");
+
+ /* check if a card is inserted */
+ if (!(PCMCIA_INSERTED)) {
+ printk("NO PCMCIA card inserted\n");
+ return (ENODEV);
+ }
+
+ /* disable pcmcia irq for readtuple */
+ pcmcia_disable_irq();
+
+#ifndef MANUAL_CONFIG
+ if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||
+ (tuple[2] != CISTPL_FUNCID_NETWORK)) {
+ printk("not an ethernet card\n");
+ return (ENODEV);
+ }
+#endif
+
+ printk("ethernet PCMCIA card inserted\n");
+
+ if (init_pcmcia())
+ return apne_probe1(dev, IOBASE+GAYLE_IO);
+ else
+ return (ENODEV);
+
+}
+
+
+__initfunc(static int apne_probe1(struct device *dev, int ioaddr))
+{
+ int i;
+ unsigned char SA_prom[32];
+ int wordlength = 2;
+ const char *name = NULL;
+ int start_page, stop_page;
+#ifndef MANUAL_HWADDR0
+ int neX000, ctron;
+#endif
+ static unsigned version_printed = 0;
+ static int pcmcia_offsets[16]={
+ 0, 1+GAYLE_ODD, 2, 3+GAYLE_ODD,
+ 4, 5+GAYLE_ODD, 6, 7+GAYLE_ODD,
+ 8, 9+GAYLE_ODD, 0xa, 0xb+GAYLE_ODD,
+ 0xc, 0xd+GAYLE_ODD, 0xe, 0xf+GAYLE_ODD };
+
+ if (load_8390_module("apne.c"))
+ return -ENOSYS;
+
+ /* We should have a "dev" from Space.c or the static module table. */
+ if (dev == NULL) {
+ printk(KERN_ERR "apne.c: Passed a NULL device.\n");
+ dev = init_etherdev(0, 0);
+ }
+
+ if (ei_debug && version_printed++ == 0)
+ printk(version);
+
+ printk("PCMCIA NE*000 ethercard probe");
+
+ /* Reset card. Who knows what dain-bramaged state it was left in. */
+ { unsigned long reset_start_time = jiffies;
+
+ writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+ while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2*HZ/100) {
+ printk(" not found (no reset ack).\n");
+ return ENODEV;
+ }
+
+ writeb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */
+ }
+
+#ifndef MANUAL_HWADDR0
+
+ /* Read the 16 bytes of station address PROM.
+ We must first initialize registers, similar to NS8390_init(eifdev, 0).
+ We can't reliably read the SAPROM address without this.
+ (I learned the hard way!). */
+ {
+ struct {unsigned long value, offset; } program_seq[] = {
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
+ {0x48, NE_EN0_DCFG}, /* Set byte-wide (0x48) access. */
+ {0x00, NE_EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, NE_EN0_RCNTHI},
+ {0x00, NE_EN0_IMR}, /* Mask completion irq. */
+ {0xFF, NE_EN0_ISR},
+ {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */
+ {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode. */
+ {32, NE_EN0_RCNTLO},
+ {0x00, NE_EN0_RCNTHI},
+ {0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000. */
+ {0x00, NE_EN0_RSARHI},
+ {E8390_RREAD+E8390_START, NE_CMD},
+ };
+ for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+ writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
+ }
+
+ }
+ for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
+ SA_prom[i] = readb(ioaddr + NE_DATAPORT);
+ SA_prom[i+1] = readb(ioaddr + NE_DATAPORT);
+ if (SA_prom[i] != SA_prom[i+1])
+ wordlength = 1;
+ }
+
+ /* At this point, wordlength *only* tells us if the SA_prom is doubled
+ up or not because some broken PCI cards don't respect the byte-wide
+ request in program_seq above, and hence don't have doubled up values.
+ These broken cards would otherwise be detected as an ne1000. */
+
+ if (wordlength == 2)
+ for (i = 0; i < 16; i++)
+ SA_prom[i] = SA_prom[i+i];
+
+ if (wordlength == 2) {
+ /* We must set the 8390 for word mode. */
+ writeb(0x49, ioaddr + NE_EN0_DCFG);
+ start_page = NESM_START_PG;
+ stop_page = NESM_STOP_PG;
+ } else {
+ start_page = NE1SM_START_PG;
+ stop_page = NE1SM_STOP_PG;
+ }
+
+ neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
+ ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
+
+ /* Set up the rest of the parameters. */
+ if (neX000) {
+ name = (wordlength == 2) ? "NE2000" : "NE1000";
+ } else if (ctron) {
+ name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
+ start_page = 0x01;
+ stop_page = (wordlength == 2) ? 0x40 : 0x20;
+ } else {
+ printk(" not found.\n");
+ return ENXIO;
+
+ }
+
+#else
+ wordlength = 2;
+ /* We must set the 8390 for word mode. */
+ writeb(0x49, ioaddr + NE_EN0_DCFG);
+ start_page = NESM_START_PG;
+ stop_page = NESM_STOP_PG;
+
+ SA_prom[0] = MANUAL_HWADDR0;
+ SA_prom[1] = MANUAL_HWADDR1;
+ SA_prom[2] = MANUAL_HWADDR2;
+ SA_prom[3] = MANUAL_HWADDR3;
+ SA_prom[4] = MANUAL_HWADDR4;
+ SA_prom[5] = MANUAL_HWADDR5;
+ name = "NE2000";
+#endif
+
+ dev->base_addr = ioaddr;
+
+ /* Install the Interrupt handler */
+ if (request_irq(IRQ_AMIGA_PORTS, apne_interrupt, 0, "apne Ethernet", dev))
+ return -EAGAIN;
+
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk (" unable to get memory for dev->priv.\n");
+ return -ENOMEM;
+ }
+
+ for(i = 0; i < ETHER_ADDR_LEN; i++) {
+ printk(" %2.2x", SA_prom[i]);
+ dev->dev_addr[i] = SA_prom[i];
+ }
+
+ printk("\n%s: %s found.\n",
+ dev->name, name);
+
+ ei_status.name = name;
+ ei_status.tx_start_page = start_page;
+ ei_status.stop_page = stop_page;
+ ei_status.word16 = (wordlength == 2);
+
+ ei_status.rx_start_page = start_page + TX_PAGES;
+
+ ei_status.reset_8390 = &apne_reset_8390;
+ ei_status.block_input = &apne_block_input;
+ ei_status.block_output = &apne_block_output;
+ ei_status.get_8390_hdr = &apne_get_8390_hdr;
+ ei_status.reg_offset = pcmcia_offsets;
+ dev->open = &apne_open;
+ dev->stop = &apne_close;
+ NS8390_init(dev, 0);
+
+ pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */
+ pcmcia_enable_irq();
+
+ return 0;
+}
+
+static int
+apne_open(struct device *dev)
+{
+ ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+apne_close(struct device *dev)
+{
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+ ei_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* Hard reset the card. This used to pause for the same period that a
+ 8390 reset command required, but that shouldn't be necessary. */
+static void
+apne_reset_8390(struct device *dev)
+{
+ unsigned long reset_start_time = jiffies;
+
+ init_pcmcia();
+
+ if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies);
+
+ writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+ ei_status.txing = 0;
+ ei_status.dmaing = 0;
+
+ /* This check _should_not_ be necessary, omit eventually. */
+ while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2*HZ/100) {
+ printk("%s: ne_reset_8390() did not complete.\n", dev->name);
+ break;
+ }
+ writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+static void
+apne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+
+ int nic_base = dev->base_addr;
+ int cnt;
+ char *ptrc;
+ short *ptrs;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne_get_8390_hdr "
+ "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+ writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
+ writeb(0, nic_base + NE_EN0_RCNTHI);
+ writeb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */
+ writeb(ring_page, nic_base + NE_EN0_RSARHI);
+ writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.word16) {
+ ptrs = (short*)hdr;
+ for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
+ *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+ } else {
+ ptrc = (char*)hdr;
+ for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
+ *ptrc++ = readb(NE_BASE + NE_DATAPORT);
+ }
+
+ writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */
+
+ hdr->count = WORDSWAP(hdr->count);
+
+ ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver. If you
+ are porting to a new ethercard, look at the packet driver source for hints.
+ The NEx000 doesn't share the on-board packet memory -- you have to put
+ the packet out through the "remote DMA" dataport using writeb. */
+
+static void
+apne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+ int nic_base = dev->base_addr;
+ char *buf = skb->data;
+ char *ptrc;
+ short *ptrs;
+ int cnt;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne_block_input "
+ "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+ writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+ writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
+ writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
+ writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
+ writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+ if (ei_status.word16) {
+ ptrs = (short*)buf;
+ for (cnt = 0; cnt < (count>>1); cnt++)
+ *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+ if (count & 0x01) {
+ buf[count-1] = readb(NE_BASE + NE_DATAPORT);
+ }
+ } else {
+ ptrc = (char*)buf;
+ for (cnt = 0; cnt < count; cnt++)
+ *ptrc++ = readb(NE_BASE + NE_DATAPORT);
+ }
+
+ writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+static void
+apne_block_output(struct device *dev, int count,
+ const unsigned char *buf, const int start_page)
+{
+ int nic_base = NE_BASE;
+ unsigned long dma_start;
+ char *ptrc;
+ short *ptrs;
+ int cnt;
+
+ /* Round the count up for word writes. Do we need to do this?
+ What effect will an odd byte count have on the 8390?
+ I should check someday. */
+ if (ei_status.word16 && (count & 0x01))
+ count++;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne_block_output."
+ "[DMAstat:%d][irqlock:%d][intr:%d]\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ /* We should already be in page 0, but to be safe... */
+ writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+ writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+
+ /* Now the normal output. */
+ writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+ writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
+ writeb(0x00, nic_base + NE_EN0_RSARLO);
+ writeb(start_page, nic_base + NE_EN0_RSARHI);
+
+ writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+ if (ei_status.word16) {
+ ptrs = (short*)buf;
+ for (cnt = 0; cnt < count>>1; cnt++)
+ writew(*ptrs++, NE_BASE+NE_DATAPORT);
+ } else {
+ ptrc = (char*)buf;
+ for (cnt = 0; cnt < count; cnt++)
+ writeb(*ptrc++, NE_BASE + NE_DATAPORT);
+ }
+
+ dma_start = jiffies;
+
+ while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
+ if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
+ printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+ apne_reset_8390(dev);
+ NS8390_init(dev,1);
+ break;
+ }
+
+ writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+ return;
+}
+
+static void apne_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned char pcmcia_intreq;
+
+ if (!(gayle.inten & GAYLE_IRQ_IRQ))
+ return;
+
+ pcmcia_intreq = pcmcia_get_intreq();
+
+ if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {
+ pcmcia_ack_int(pcmcia_intreq);
+ return;
+ }
+ if (ei_debug > 3)
+ printk("pcmcia intreq = %x\n", pcmcia_intreq);
+ pcmcia_disable_irq(); /* to get rid of the sti() within ei_interrupt */
+ ei_interrupt(irq, dev_id, regs);
+ pcmcia_ack_int(pcmcia_get_intreq());
+ pcmcia_enable_irq();
+}
+
+#ifdef MODULE
+static char devicename[9] = {0, };
+
+static struct device apne_dev =
+{
+ devicename,
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, apne_probe,
+};
+
+int init_module(void)
+{
+ int err;
+ if ((err = register_netdev(&apne_dev))) {
+ if (err == -EIO)
+ printk("No PCMCIA NEx000 ethernet card found.\n");
+ return (err);
+ }
+ lock_8390_module();
+ return (0);
+}
+
+void cleanup_module(void)
+{
+ unregister_netdev(&apne_dev);
+
+ pcmcia_disable_irq();
+
+ free_irq(IRQ_AMIGA_PORTS, &apne_dev);
+
+ pcmcia_reset();
+
+ unlock_8390_module();
+}
+
+#endif
+
+static int init_pcmcia(void)
+{
+ u_char config;
+#ifndef MANUAL_CONFIG
+ u_char tuple[32];
+ int offset_len;
+#endif
+ u_long offset;
+
+ pcmcia_reset();
+ pcmcia_program_voltage(PCMCIA_0V);
+ pcmcia_access_speed(PCMCIA_SPEED_250NS);
+ pcmcia_write_enable();
+
+#ifdef MANUAL_CONFIG
+ config = MANUAL_CONFIG;
+#else
+ /* get and write config byte to enable IO port */
+
+ if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)
+ return 0;
+
+ config = tuple[2] & 0x3f;
+#endif
+#ifdef MANUAL_OFFSET
+ offset = MANUAL_OFFSET;
+#else
+ if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
+ return 0;
+
+ offset_len = (tuple[2] & 0x3) + 1;
+ offset = 0;
+ while(offset_len--) {
+ offset = (offset << 8) | tuple[4+offset_len];
+ }
+#endif
+
+ writeb(config, GAYLE_ATTRIBUTE+offset);
+
+ return 1;
+}
diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c
deleted file mode 100644
index 94188da73..000000000
--- a/drivers/net/apricot.c
+++ /dev/null
@@ -1,1031 +0,0 @@
-/* apricot.c: An Apricot 82596 ethernet driver for linux. */
-/*
- Apricot
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
- Driver skeleton
- Written 1993 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@super.org or
- C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-
-
-*/
-
-static const char *version = "apricot.c:v0.2 05/12/94\n";
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#ifndef HAVE_PORTRESERVE
-#define check_region(addr, size) 0
-#define request_region(addr, size,name) do ; while(0)
-#endif
-
-#ifndef HAVE_ALLOC_SKB
-#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(buff, size) kfree_s(buff,size)
-#endif
-
-#define APRICOT_DEBUG 1
-
-#ifdef APRICOT_DEBUG
-int i596_debug = APRICOT_DEBUG;
-#else
-int i596_debug = 1;
-#endif
-
-#define APRICOT_TOTAL_SIZE 17
-
-#define I596_NULL -1
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-#define STAT_C 0x8000 /* Set to 0 after execution */
-#define STAT_B 0x4000 /* Command being executed */
-#define STAT_OK 0x2000 /* Command executed ok */
-#define STAT_A 0x1000 /* Command aborted */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-struct i596_cmd {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *next;
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- struct i596_tbd *next;
- char *data;
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- struct i596_tbd *tbd;
- unsigned short size;
- unsigned short pad;
-};
-
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- struct i596_rfd *next;
- long rbd;
- unsigned short count;
- unsigned short size;
- char data[1532];
-};
-
-#define RX_RING_SIZE 8
-
-struct i596_scb {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *cmd;
- struct i596_rfd *rfd;
- unsigned long crc_err;
- unsigned long align_err;
- unsigned long resource_err;
- unsigned long over_err;
- unsigned long rcvdt_err;
- unsigned long short_err;
- unsigned short t_on;
- unsigned short t_off;
-};
-
-struct i596_iscp {
- unsigned long stat;
- struct i596_scb *scb;
-};
-
-struct i596_scp {
- unsigned long sysbus;
- unsigned long pad;
- struct i596_iscp *iscp;
-};
-
-struct i596_private {
- struct i596_scp scp;
- struct i596_iscp iscp;
- struct i596_scb scb;
- struct i596_cmd set_add;
- char eth_addr[8];
- struct i596_cmd set_conf;
- char i596_config[16];
- struct i596_cmd tdr;
- unsigned long stat;
- int last_restart;
- struct i596_rfd *rx_tail;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- unsigned long last_cmd;
- struct net_device_stats stats;
-};
-
-char init_setup[] = {
- 0x8E, /* length, prefetch on */
- 0xC8, /* fifo to 8, monitor off */
- 0x80, /* don't save bad frames */
- 0x2E, /* No source address insertion, 8 byte preamble */
- 0x00, /* priority and backoff defaults */
- 0x60, /* interframe spacing */
- 0x00, /* slot time LSB */
- 0xf2, /* slot time and retries */
- 0x00, /* promiscuous mode */
- 0x00, /* collision detect */
- 0x40, /* minimum frame length */
- 0xff,
- 0x00,
- 0x7f /* *multi IA */ };
-
-static int i596_open(struct device *dev);
-static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
-static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int i596_close(struct device *dev);
-static struct net_device_stats *i596_get_stats(struct device *dev);
-static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct device *dev);
-
-
-static inline int
-init_rx_bufs(struct device *dev, int num)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int i;
- struct i596_rfd *rfd;
-
- lp->scb.rfd = (struct i596_rfd *)I596_NULL;
-
- if (i596_debug > 1) printk ("%s: init_rx_bufs %d.\n", dev->name, num);
-
- for (i = 0; i < num; i++)
- {
- if (!(rfd = (struct i596_rfd *)kmalloc(sizeof(struct i596_rfd), GFP_KERNEL)))
- break;
-
- rfd->stat = 0x0000;
- rfd->rbd = I596_NULL;
- rfd->count = 0;
- rfd->size = 1532;
- if (i == 0)
- {
- rfd->cmd = CMD_EOL;
- lp->rx_tail = rfd;
- }
- else
- rfd->cmd = 0x0000;
-
- rfd->next = lp->scb.rfd;
- lp->scb.rfd = rfd;
- }
-
- if (i != 0)
- lp->rx_tail->next = lp->scb.rfd;
-
- return (i);
-}
-
-static inline void
-remove_rx_bufs(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- struct i596_rfd *rfd = lp->scb.rfd;
-
- lp->rx_tail->next = (struct i596_rfd *)I596_NULL;
-
- do
- {
- lp->scb.rfd = rfd->next;
- kfree(rfd);
- rfd = lp->scb.rfd;
- }
- while (rfd != lp->rx_tail);
-}
-
-static inline void
-init_i596_mem(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- short ioaddr = dev->base_addr;
- int boguscnt = 100;
-
- /* change the scp address */
- outw(0, ioaddr);
- outw(0, ioaddr);
- outb(4, ioaddr+0xf);
- outw(((((int)&lp->scp) & 0xffff) | 2), ioaddr);
- outw((((int)&lp->scp)>>16) & 0xffff, ioaddr);
-
- lp->last_cmd = jiffies;
-
- lp->scp.sysbus = 0x00440000;
- lp->scp.iscp = &(lp->iscp);
- lp->iscp.scb = &(lp->scb);
- lp->iscp.stat = 0x0001;
- lp->cmd_backlog = 0;
-
- lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
-
- if (i596_debug > 2) printk("%s: starting i82596.\n", dev->name);
-
- (void) inb (ioaddr+0x10);
- outb(4, ioaddr+0xf);
- outw(0, ioaddr+4);
-
- while (lp->iscp.stat)
- if (--boguscnt == 0)
- {
- printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.command = 0;
-
- memcpy (lp->i596_config, init_setup, 14);
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, &lp->set_conf);
-
- memcpy (lp->eth_addr, dev->dev_addr, 6);
- lp->set_add.command = CmdSASetup;
- i596_add_cmd(dev, &lp->set_add);
-
- lp->tdr.command = CmdTDR;
- i596_add_cmd(dev, &lp->tdr);
-
- boguscnt = 200;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.command = RX_START;
- outw(0, ioaddr+4);
-
- boguscnt = 200;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- return;
-}
-
-static inline int
-i596_rx(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int frames = 0;
-
- if (i596_debug > 3) printk ("i596_rx()\n");
-
- while ((lp->scb.rfd->stat) & STAT_C)
- {
- if (i596_debug >2) print_eth(lp->scb.rfd->data);
-
- if ((lp->scb.rfd->stat) & STAT_OK)
- {
- /* a good frame */
- int pkt_len = lp->scb.rfd->count & 0x3fff;
- struct sk_buff *skb = dev_alloc_skb(pkt_len);
-
- frames++;
-
- if (skb == NULL)
- {
- printk ("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
- break;
- }
-
- skb->dev = dev;
- memcpy(skb_put(skb,pkt_len), lp->scb.rfd->data, pkt_len);
-
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
-
- if (i596_debug > 4) print_eth(skb->data);
- }
- else
- {
- lp->stats.rx_errors++;
- if ((lp->scb.rfd->stat) & 0x0001) lp->stats.collisions++;
- if ((lp->scb.rfd->stat) & 0x0080) lp->stats.rx_length_errors++;
- if ((lp->scb.rfd->stat) & 0x0100) lp->stats.rx_over_errors++;
- if ((lp->scb.rfd->stat) & 0x0200) lp->stats.rx_fifo_errors++;
- if ((lp->scb.rfd->stat) & 0x0400) lp->stats.rx_frame_errors++;
- if ((lp->scb.rfd->stat) & 0x0800) lp->stats.rx_crc_errors++;
- if ((lp->scb.rfd->stat) & 0x1000) lp->stats.rx_length_errors++;
- }
-
- lp->scb.rfd->stat = 0;
- lp->rx_tail->cmd = 0;
- lp->rx_tail = lp->scb.rfd;
- lp->scb.rfd = lp->scb.rfd->next;
- lp->rx_tail->count = 0;
- lp->rx_tail->cmd = CMD_EOL;
-
- }
-
- if (i596_debug > 3) printk ("frames %d\n", frames);
-
- return 0;
-}
-
-static inline void
-i596_cleanup_cmd(struct i596_private *lp)
-{
- struct i596_cmd *ptr;
- int boguscnt = 100;
-
- if (i596_debug > 4) printk ("i596_cleanup_cmd\n");
-
- while (lp->cmd_head != (struct i596_cmd *) I596_NULL)
- {
- ptr = lp->cmd_head;
-
- lp->cmd_head = lp->cmd_head->next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7)
- {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1;
-
- dev_kfree_skb(skb);
-
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
-
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(tx_cmd);
- break;
- }
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(ptr);
- break;
- }
- default:
- ptr->next = (struct i596_cmd * ) I596_NULL;
- }
- }
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.cmd = lp->cmd_head;
-}
-
-static inline void
-i596_reset(struct device *dev, struct i596_private *lp, int ioaddr)
-{
- int boguscnt = 100;
-
- if (i596_debug > 4) printk ("i596_reset\n");
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- dev->start = 0;
- dev->tbusy = 1;
-
- lp->scb.command = CUC_ABORT|RX_ABORT;
- outw(0, ioaddr+4);
-
- /* wait for shutdown */
- boguscnt = 400;
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- i596_cleanup_cmd(lp);
- i596_rx(dev);
-
- dev->start = 1;
- dev->tbusy = 0;
- dev->interrupt = 0;
- init_i596_mem(dev);
-}
-
-static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int ioaddr = dev->base_addr;
- unsigned long flags;
- int boguscnt = 100;
-
- if (i596_debug > 4) printk ("i596_add_cmd\n");
-
- cmd->status = 0;
- cmd->command |= (CMD_EOL|CMD_INTR);
- cmd->next = (struct i596_cmd *) I596_NULL;
-
- save_flags(flags);
- cli();
- if (lp->cmd_head != (struct i596_cmd *) I596_NULL)
- lp->cmd_tail->next = cmd;
- else
- {
- lp->cmd_head = cmd;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.cmd = cmd;
- lp->scb.command = CUC_START;
- outw (0, ioaddr+4);
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- lp->cmd_head = lp->scb.cmd;
- restore_flags(flags);
-
- if (lp->cmd_backlog > 16)
- {
- int tickssofar = jiffies - lp->last_cmd;
-
- if (tickssofar < 25) return;
-
- printk("%s: command unit timed out, status resetting.\n", dev->name);
-
- i596_reset(dev, lp, ioaddr);
- }
-}
-
-static int
-i596_open(struct device *dev)
-{
- int i;
-
- if (i596_debug > 1)
- printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
-
- if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", dev))
- return -EAGAIN;
-
- i = init_rx_bufs(dev, RX_RING_SIZE);
-
- if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
- printk("%s: only able to allocate %d receive buffers\n", dev->name, i);
-
- if (i < 4)
- {
- free_irq(dev->irq, dev);
- return -EAGAIN;
- }
-
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
- MOD_INC_USE_COUNT;
-
- /* Initialize the 82596 memory */
- init_i596_mem(dev);
-
- return 0; /* Always succeed */
-}
-
-static int
-i596_start_xmit(struct sk_buff *skb, struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int ioaddr = dev->base_addr;
- struct tx_cmd *tx_cmd;
-
- if (i596_debug > 2) printk ("%s: Apricot start xmit\n", dev->name);
-
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, status resetting.\n",
- dev->name);
- lp->stats.tx_errors++;
- /* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
- if (i596_debug > 1) printk ("Resetting board.\n");
-
- /* Shutdown and restart */
- i596_reset(dev,lp, ioaddr);
- } else {
- /* Issue a channel attention signal */
- if (i596_debug > 1) printk ("Kicking board.\n");
-
- lp->scb.command = CUC_START|RX_START;
- outw(0, ioaddr+4);
-
- lp->last_restart = lp->stats.tx_packets;
- }
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- }
-
- if (i596_debug > 3) printk("%s: i596_start_xmit() called\n", dev->name);
-
- /* 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 (test_and_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;
- dev->trans_start = jiffies;
-
- tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
- if (tx_cmd == NULL)
- {
- printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.tx_dropped++;
-
- dev_kfree_skb(skb);
- }
- else
- {
- tx_cmd->tbd = (struct i596_tbd *) (tx_cmd + 1);
- tx_cmd->tbd->next = (struct i596_tbd *) I596_NULL;
-
- tx_cmd->cmd.command = CMD_FLEX|CmdTx;
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tx_cmd->tbd->pad = 0;
- tx_cmd->tbd->size = EOF | length;
-
- tx_cmd->tbd->data = skb->data;
-
- if (i596_debug > 3) print_eth(skb->data);
-
- i596_add_cmd(dev, (struct i596_cmd *)tx_cmd);
-
- lp->stats.tx_packets++;
- lp->stats.tx_bytes+=length;
- }
- }
-
- dev->tbusy = 0;
-
- return 0;
-}
-
-
-static void print_eth(char *add)
-{
- int i;
-
- printk ("Dest ");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char)add[i]);
- printk ("\n");
-
- printk ("Source");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char)add[i+6]);
- printk ("\n");
- printk ("type %2.2X%2.2X\n", (unsigned char)add[12], (unsigned char)add[13]);
-}
-
-__initfunc(int apricot_probe(struct device *dev))
-{
- int i;
- struct i596_private *lp;
- int checksum = 0;
- int ioaddr = 0x300;
- char eth_addr[6];
-
- /* this is easy the ethernet interface can only be at 0x300 */
- /* first check nothing is already registered here */
-
- if (check_region(ioaddr, APRICOT_TOTAL_SIZE))
- return ENODEV;
-
- for (i = 0; i < 8; i++)
- {
- eth_addr[i] = inb(ioaddr+8+i);
- checksum += eth_addr[i];
- }
-
- /* checksum is a multiple of 0x100, got this wrong first time
- some machines have 0x100, some 0x200. The DOS driver doesn't
- even bother with the checksum */
-
- if (checksum % 0x100) return ENODEV;
-
- /* Some other boards trip the checksum.. but then appear as ether
- address 0. Trap these - AC */
-
- if(memcmp(eth_addr,"\x00\x00\x49",3)!= 0)
- return ENODEV;
-
- request_region(ioaddr, APRICOT_TOTAL_SIZE, "apricot");
-
- dev->base_addr = ioaddr;
- ether_setup(dev);
- printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr);
-
- for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
-
- dev->base_addr = ioaddr;
- dev->irq = 10;
- printk(" IRQ %d.\n", dev->irq);
-
- if (i596_debug > 0) printk(version);
-
- /* The APRICOT-specific entries in the device structure. */
- dev->open = &i596_open;
- dev->stop = &i596_close;
- dev->hard_start_xmit = &i596_start_xmit;
- dev->get_stats = &i596_get_stats;
- dev->set_multicast_list = &set_multicast_list;
-
- dev->mem_start = (int)kmalloc(sizeof(struct i596_private)+ 0x0f, GFP_KERNEL);
- /* align for scp */
- dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0);
-
- lp = (struct i596_private *)dev->priv;
- memset((void *)lp, 0, sizeof(struct i596_private));
- lp->scb.command = 0;
- lp->scb.cmd = (struct i596_cmd *) I596_NULL;
- lp->scb.rfd = (struct i596_rfd *)I596_NULL;
-
- return 0;
-}
-
-static void
-i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct device *dev = dev_id;
- struct i596_private *lp;
- short ioaddr;
- int boguscnt = 200;
- unsigned short status, ack_cmd = 0;
-
- if (dev == NULL) {
- printk ("i596_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-
- if (i596_debug > 3) printk ("%s: i596_interrupt(): irq %d\n",dev->name, irq);
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = 1;
-
- ioaddr = dev->base_addr;
-
- lp = (struct i596_private *)dev->priv;
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
- status = lp->scb.status;
-
- if (i596_debug > 4)
- printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status);
-
- ack_cmd = status & 0xf000;
-
- if ((status & 0x8000) || (status & 0x2000))
- {
- struct i596_cmd *ptr;
-
- if ((i596_debug > 4) && (status & 0x8000))
- printk("%s: i596 interrupt completed command.\n", dev->name);
- if ((i596_debug > 4) && (status & 0x2000))
- printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
-
- while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C))
- {
- ptr = lp->cmd_head;
-
- lp->cmd_head = lp->cmd_head->next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7)
- {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1;
-
- dev_kfree_skb(skb);
-
- if ((ptr->status) & STAT_OK)
- {
- if (i596_debug >2) print_eth(skb->data);
- }
- else
- {
- lp->stats.tx_errors++;
- if ((ptr->status) & 0x0020) lp->stats.collisions++;
- if (!((ptr->status) & 0x0040)) lp->stats.tx_heartbeat_errors++;
- if ((ptr->status) & 0x0400) lp->stats.tx_carrier_errors++;
- if ((ptr->status) & 0x0800) lp->stats.collisions++;
- if ((ptr->status) & 0x1000) lp->stats.tx_aborted_errors++;
- }
-
-
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(tx_cmd);
- break;
- }
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(ptr);
- break;
- }
- case CmdTDR:
- {
- unsigned long status = *((unsigned long *) (ptr + 1));
-
- if (status & 0x8000)
- {
- if (i596_debug > 3)
- printk("%s: link ok.\n", dev->name);
- }
- else
- {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n", dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n", dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n", dev->name);
-
- printk("%s: Time %ld.\n", dev->name, status & 0x07ff);
- }
- }
- default:
- ptr->next = (struct i596_cmd * ) I596_NULL;
-
- lp->last_cmd = jiffies;
- }
- }
-
- ptr = lp->cmd_head;
- while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail))
- {
- ptr->command &= 0x1fff;
- ptr = ptr->next;
- }
-
- if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd |= CUC_START;
- lp->scb.cmd = lp->cmd_head;
- }
-
- if ((status & 0x1000) || (status & 0x4000))
- {
- if ((i596_debug > 4) && (status & 0x4000))
- printk("%s: i596 interrupt received a frame.\n", dev->name);
- if ((i596_debug > 4) && (status & 0x1000))
- printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x0070);
-
- i596_rx(dev);
-
- if (dev->start) ack_cmd |= RX_START;
- }
-
- /* acknowledge the interrupt */
-
-/*
- if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd | = CUC_START;
-*/
- boguscnt = 100;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
- lp->scb.command = ack_cmd;
-
- (void) inb (ioaddr+0x10);
- outb (4, ioaddr+0xf);
- outw (0, ioaddr+4);
-
- if (i596_debug > 4)
- printk("%s: exiting interrupt.\n", dev->name);
-
- dev->interrupt = 0;
- return;
-}
-
-static int
-i596_close(struct device *dev)
-{
- int ioaddr = dev->base_addr;
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int boguscnt = 200;
-
- dev->start = 0;
- dev->tbusy = 1;
-
- if (i596_debug > 1)
- printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status);
-
- lp->scb.command = CUC_ABORT|RX_ABORT;
- outw(0, ioaddr+4);
-
- i596_cleanup_cmd(lp);
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: close timed timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
-static struct net_device_stats *
-i596_get_stats(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
-
- return &lp->stats;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- struct i596_cmd *cmd;
-
- if (i596_debug > 1)
- printk ("%s: set multicast list %d\n", dev->name, dev->mc_count);
-
- if (dev->mc_count > 0)
- {
- struct dev_mc_list *dmi;
- char *cp;
- cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC);
- if (cmd == NULL)
- {
- printk ("%s: set_multicast Memory squeeze.\n", dev->name);
- return;
- }
- cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
- cp=((char *)(cmd + 1))+2;
- for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
- {
- memcpy(cp, dmi,6);
- cp+=6;
- }
- print_eth (((char *)(cmd + 1)) + 2);
- i596_add_cmd(dev, cmd);
- }
- else
- {
- if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL)
- return;
- if (dev->mc_count == 0 && !(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
- {
- if(dev->flags&IFF_ALLMULTI)
- dev->flags|=IFF_PROMISC;
- lp->i596_config[8] &= ~0x01;
- }
- else
- lp->i596_config[8] |= 0x01;
-
- i596_add_cmd(dev, &lp->set_conf);
- }
-}
-
-#ifdef HAVE_DEVLIST
-static unsigned int apricot_portlist[] __initdata = {0x300, 0};
-struct netdev_entry apricot_drv =
-{"apricot", apricot_probe, APRICOT_TOTAL_SIZE, apricot_portlist};
-#endif
-
-#ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_apricot = {
- devicename, /* device name inserted by /linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0x300, 10,
- 0, 0, 0, NULL, apricot_probe };
-
-static int io = 0x300;
-static int irq = 10;
-MODULE_PARM(irq, "i");
-
-int
-init_module(void)
-{
- dev_apricot.base_addr = io;
- dev_apricot.irq = irq;
- if (register_netdev(&dev_apricot) != 0)
- return -EIO;
- return 0;
-}
-
-void
-cleanup_module(void)
-{
- unregister_netdev(&dev_apricot);
- kfree((void*)dev_apricot.mem_start);
- dev_apricot.priv = NULL;
-
- /* If we don't do this, we can't re-insmod it later. */
- release_region(dev_apricot.base_addr, APRICOT_TOTAL_SIZE);
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c apricot.c"
- * End:
- */
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c
index 16795257e..5974f8a8a 100644
--- a/drivers/net/arcnet.c
+++ b/drivers/net/arcnet.c
@@ -18,6 +18,13 @@
**********************
+ v3.02 (98/06/07)
+ - Use register_netdevice() instead of register_netdev() to create
+ new devices for RFC1051 and Ethernet encapsulation in arcnet_open.
+ Likewise for unregistering them later. This avoids the deadlock
+ encountered because the original routines call rtnl_lock() when
+ it's already locked. [dw]
+
v3.01 (98/04/17)
- Interrupt handler now also checks dev->[se]dev are non-NULL
to avoid crashes in interrupts during card init. [dw]
@@ -174,7 +181,7 @@
*/
static const char *version =
- "arcnet.c: v3.01 98/04/24 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@bond.net> et al.\n";
#include <linux/module.h>
#include <linux/config.h>
@@ -462,7 +469,7 @@ arcnet_open(struct device *dev)
}
sprintf(lp->edev->name,"%se",dev->name);
lp->edev->init=arcnetE_init;
- register_netdev(lp->edev);
+ register_netdevice(lp->edev);
#endif
#ifdef CONFIG_ARCNET_1051
@@ -472,7 +479,7 @@ arcnet_open(struct device *dev)
lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL);
sprintf(lp->sdev->name,"%ss",dev->name);
lp->sdev->init=arcnetS_init;
- register_netdev(lp->sdev);
+ register_netdevice(lp->sdev);
#endif
/* Enable TX if we need to */
@@ -548,7 +555,7 @@ arcnet_close(struct device *dev)
#ifdef CONFIG_ARCNET_ETH
/* free the ethernet-encap protocol device */
lp->edev->priv=NULL;
- unregister_netdev(lp->edev);
+ unregister_netdevice(lp->edev);
kfree(lp->edev->name);
kfree(lp->edev);
lp->edev=NULL;
@@ -557,7 +564,7 @@ arcnet_close(struct device *dev)
#ifdef CONFIG_ARCNET_1051
/* free the RFC1051-encap protocol device */
lp->sdev->priv=NULL;
- unregister_netdev(lp->sdev);
+ unregister_netdevice(lp->sdev);
kfree(lp->sdev->name);
kfree(lp->sdev);
lp->sdev=NULL;
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index 23c8054e3..f17950109 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -7,6 +7,8 @@
*
* Little adaptions for integration into pl7 by Roman Hodek
*
+ * Some changes in bionet_poll_rx by Karl-Heinz Lohner
+ *
What is it ?
------------
This driver controls the BIONET-100 LAN-Adapter which connects
@@ -238,7 +240,7 @@ get_frame(unsigned long paddr, int odd) {
dma_wd.dma_mode_status = 0x9a;
dma_wd.dma_mode_status = 0x19a;
dma_wd.dma_mode_status = 0x9a;
- dma_wd.fdc_acces_seccount = 0x05; /* sector count */
+ dma_wd.fdc_acces_seccount = 0x04; /* sector count (was 5) */
dma_wd.dma_lo = (unsigned char)paddr;
paddr >>= 8;
dma_wd.dma_md = (unsigned char)paddr;
@@ -293,7 +295,7 @@ hardware_send_packet(unsigned long paddr, int cnt) {
paddr >>= 8;
dma_wd.dma_hi = (unsigned char)paddr;
- dma_wd.fdc_acces_seccount = 0xaa; /* sector count */
+ dma_wd.fdc_acces_seccount = 0x4; /* sector count */
restore_flags(flags);
c = sendcmd(0,0x100,NODE_ADR | C_WRITE); /* CMD: WRITE */
@@ -454,6 +456,28 @@ bionet_send_packet(struct sk_buff *skb, struct device *dev) {
buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
}
+ if (bionet_debug >1) {
+ u_char *data = nic_packet->buffer, *p;
+ int i;
+
+ printk( "%s: TX pkt type 0x%4x from ", dev->name,
+ ((u_short *)data)[6]);
+
+ for( p = &data[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ printk(" to ");
+
+ for( p = data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+ printk( "%s: ", dev->name );
+ printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x len %d\n",
+ data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+ data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+ data[28], data[29], data[30], data[31], data[32], data[33],
+ length );
+ }
dma_cache_maintenance(buf, length, 1);
stat = hardware_send_packet(buf, length);
@@ -499,7 +523,7 @@ bionet_poll_rx(struct device *dev) {
while(boguscount--) {
status = get_frame((unsigned long)phys_nic_packet, 0);
- if( status != 1 ) break;
+ if( status == 0 ) break;
/* Good packet... */
@@ -508,34 +532,63 @@ bionet_poll_rx(struct device *dev) {
pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
lp->poll_time = bionet_min_poll_time; /* fast poll */
- if( pkt_len >= 60 && pkt_len <= 1514 ) {
-
+ if( pkt_len >= 60 && pkt_len <= 1520 ) {
+ /* ^^^^ war 1514 KHL */
/* Malloc up new buffer.
*/
- struct sk_buff *skb = alloc_skb(pkt_len, GFP_ATOMIC);
+ struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n",
dev->name);
lp->stats.rx_dropped++;
break;
}
- skb->len = pkt_len;
+
skb->dev = dev;
+ skb_reserve( skb, 2 ); /* 16 Byte align */
+ skb_put( skb, pkt_len ); /* make room */
/* 'skb->data' points to the start of sk_buff data area.
*/
memcpy(skb->data, nic_packet->buffer, pkt_len);
+ skb->protocol = eth_type_trans( skb, dev );
netif_rx(skb);
lp->stats.rx_packets++;
lp->stats.rx_bytes+=pkt_len;
- }
- }
/* 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.
*/
+ if (bionet_debug >1) {
+ u_char *data = nic_packet->buffer, *p;
+ int i;
+
+ printk( "%s: RX pkt type 0x%4x from ", dev->name,
+ ((u_short *)data)[6]);
+
+
+ for( p = &data[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ printk(" to ");
+ for( p = data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+ printk( "%s: ", dev->name );
+ printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x len %d\n",
+ data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+ data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+ data[28], data[29], data[30], data[31], data[32], data[33],
+ pkt_len );
+ }
+ }
+ else {
+ printk(" Packet has wrong length: %04d bytes\n", pkt_len);
+ lp->stats.rx_errors++;
+ }
+ }
stdma_release();
ENABLE_IRQ();
return;
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
new file mode 100644
index 000000000..536df548b
--- /dev/null
+++ b/drivers/net/bmac.c
@@ -0,0 +1,1451 @@
+/*
+ * Network device driver for the BMAC ethernet controller on
+ * Apple Powermacs. Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include "bmac.h"
+
+#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
+#define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define ENET_CRCPOLY 0x04c11db7
+
+/* a bunch of constants for the "Heathrow" interrupt controller.
+ These really should be in an include file somewhere */
+#define IoBaseHeathrow ((unsigned *)0xf3000000)
+#define HeathrowFCR 0x0038 /* FCR offset from Heathrow Base Address */
+#define fcrEnetEnabledBits 0x60000000 /* mask to enable Enet Xcvr/Controller */
+#define fcrResetEnetCell 0x80000000 /* mask used to reset Enet cell */
+#define fcrClearResetEnetCell 0x7fffffff /* mask used to clear reset Enet cell */
+#define fcrDisableEnet 0x1fffffff /* mask to disable Enet Xcvr/Controller */
+
+#define N_RX_RING 64
+#define N_TX_RING 32
+#define MAX_TX_ACTIVE 1
+#define ETHERCRC 4
+#define ETHERMINPACKET 64
+#define ETHERMTU 1500
+#define RX_BUFLEN (ETHERMTU + 14 + ETHERCRC + 2)
+#define TX_TIMEOUT HZ /* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR 0x80
+
+#define XXDEBUG(args)
+
+struct bmac_data {
+/* volatile struct bmac *bmac; */
+ struct sk_buff_head *queue;
+ volatile struct dbdma_regs *tx_dma;
+ int tx_dma_intr;
+ volatile struct dbdma_regs *rx_dma;
+ int rx_dma_intr;
+ volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */
+ volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */
+ struct sk_buff *rx_bufs[N_RX_RING];
+ int rx_fill;
+ int rx_empty;
+ struct sk_buff *tx_bufs[N_TX_RING];
+ char *tx_double[N_TX_RING]; /* yuck--double buffering */
+ int tx_fill;
+ int tx_empty;
+ unsigned char tx_fullup;
+ struct net_device_stats stats;
+ struct timer_list tx_timeout;
+ int timeout_active;
+ int reset_and_enabled;
+ int rx_allocated;
+ int tx_allocated;
+ unsigned short hash_use_count[64];
+ unsigned short hash_table_mask[4];
+};
+
+typedef struct bmac_reg_entry {
+ char *name;
+ unsigned short reg_offset;
+} bmac_reg_entry_t;
+
+#define N_REG_ENTRIES 30
+
+bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
+ {"MEMADD", MEMADD},
+ {"MEMDATAHI", MEMDATAHI},
+ {"MEMDATALO", MEMDATALO},
+ {"TXPNTR", TXPNTR},
+ {"RXPNTR", RXPNTR},
+ {"IPG1", IPG1},
+ {"IPG2", IPG2},
+ {"ALIMIT", ALIMIT},
+ {"SLOT", SLOT},
+ {"PALEN", PALEN},
+ {"PAPAT", PAPAT},
+ {"TXSFD", TXSFD},
+ {"JAM", JAM},
+ {"TXMAX", TXMAX},
+ {"TXMIN", TXMIN},
+ {"PAREG", PAREG},
+ {"DCNT", DCNT},
+ {"NCCNT", NCCNT},
+ {"NTCNT", NTCNT},
+ {"EXCNT", EXCNT},
+ {"LTCNT", LTCNT},
+ {"TXSM", TXSM},
+ {"RXCFG", RXCFG},
+ {"RXMAX", RXMAX},
+ {"RXMIN", RXMIN},
+ {"FRCNT", FRCNT},
+ {"AECNT", AECNT},
+ {"FECNT", FECNT},
+ {"RXSM", RXSM},
+ {"RXCV", RXCV}
+};
+
+struct device *bmac_devs = NULL;
+
+#if 0
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN];
+#endif
+
+/*
+ * Number of bytes of private data per BMAC: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES (sizeof(struct bmac_data) \
+ + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+ + sizeof(struct sk_buff_head))
+
+static unsigned char bitrev(unsigned char b);
+static int bmac_open(struct device *dev);
+static int bmac_close(struct device *dev);
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *bmac_stats(struct device *dev);
+static void bmac_set_multicast(struct device *dev);
+static int bmac_reset_and_enable(struct device *dev, int enable);
+static void bmac_start_chip(struct device *dev);
+static int bmac_init_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static void bmac_reset_chip(struct device *dev);
+static int bmac_set_address(struct device *dev, void *addr);
+static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_set_timeout(struct device *dev);
+static void bmac_tx_timeout(unsigned long data);
+static void bmac_reset_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
+static int bmac_output(struct sk_buff *skb, struct device *dev);
+static void bmac_start(struct device *dev);
+
+#define DBDMA_SET(x) ( ((x) | (x) << 16) )
+#define DBDMA_CLEAR(x) ( (x) << 16)
+
+static __inline__ void
+dbdma_st32(volatile unsigned long *a, unsigned long x)
+{
+ __asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+ return;
+}
+
+static __inline__ unsigned long
+dbdma_ld32(volatile unsigned long *a)
+{
+ unsigned long swap;
+ __asm__ volatile ("lwbrx %0,0,%1" : "=r" (swap) : "r" (a));
+ return swap;
+}
+
+void
+dbdma_stop(volatile struct dbdma_regs *dmap)
+{
+ dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
+ eieio();
+
+ while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH))
+ eieio();
+}
+
+static void
+dbdma_continue(volatile struct dbdma_regs *dmap)
+{
+ dbdma_st32((volatile unsigned long *)&dmap->control,
+ DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
+ eieio();
+}
+
+static void
+dbdma_reset(volatile struct dbdma_regs *dmap)
+{
+ dbdma_st32((volatile unsigned long *)&dmap->control,
+ DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
+ eieio();
+ while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio();
+}
+
+static void
+dbdma_setcmd(volatile struct dbdma_cmd *cp,
+ unsigned short cmd, unsigned count, unsigned long addr,
+ unsigned long cmd_dep)
+{
+ out_le16(&cp->command, cmd);
+ out_le16(&cp->req_count, count);
+ out_le32(&cp->phy_addr, addr);
+ out_le32(&cp->cmd_dep, cmd_dep);
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->res_count, 0);
+}
+
+static __inline__
+void bmwrite(struct device *dev, unsigned long reg_offset, unsigned data )
+{
+ out_le16((void *)dev->base_addr + reg_offset, data);
+}
+
+
+static __inline__
+volatile unsigned short bmread(struct device *dev, unsigned long reg_offset )
+{
+ return in_le16((void *)dev->base_addr + reg_offset);
+}
+
+static void
+bmac_reset_chip(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ volatile unsigned *heathrowFCR;
+ unsigned int fcrValue;
+
+ dbdma_reset(rd);
+ dbdma_reset(td);
+
+ heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+
+ fcrValue = in_le32(heathrowFCR);
+
+ fcrValue &= fcrDisableEnet; /* clear out Xvr and Controller Bit */
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ fcrValue |= fcrResetEnetCell; /* set bit to reset them */
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ fcrValue &= fcrDisableEnet;
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ fcrValue |= fcrEnetEnabledBits;
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ out_le32(heathrowFCR, fcrValue);
+}
+
+static void
+bmac_init_registers(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile unsigned short regValue;
+ unsigned short *pWord16;
+ int i;
+
+/* XXDEBUG(("bmac: enter init_registers\n")); */
+
+ bmwrite(dev, TXRST, TxResetBit);
+
+ do {
+ regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
+ } while (regValue & TxResetBit);
+
+ bmwrite(dev, RXRST, RxResetValue);
+ bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);
+ bmwrite(dev, RSEED, (unsigned short)0x1968);
+
+ regValue = bmread(dev, XIFC);
+ regValue |= TxOutputEnable;
+ bmwrite(dev, XIFC, regValue);
+
+ bmread(dev, PAREG);
+
+ /* set collision counters to 0 */
+ bmwrite(dev, NCCNT, 0);
+ bmwrite(dev, NTCNT, 0);
+ bmwrite(dev, EXCNT, 0);
+ bmwrite(dev, LTCNT, 0);
+
+ /* set rx counters to 0 */
+ bmwrite(dev, FRCNT, 0);
+ bmwrite(dev, LECNT, 0);
+ bmwrite(dev, AECNT, 0);
+ bmwrite(dev, FECNT, 0);
+ bmwrite(dev, RXCV, 0);
+
+ /* set tx fifo information */
+ bmwrite(dev, TXTH, 4); /* 4 octets before tx starts */
+
+ bmwrite(dev, TXFIFOCSR, 0); /* first disable txFIFO */
+ bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
+
+ /* set rx fifo information */
+ bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
+ bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+
+ //bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */
+ bmread(dev, STATUS); /* read it just to clear it */
+
+ bmwrite(dev, INTDISABLE, EnableNormal);
+
+ /* zero out the chip Hash Filter registers */
+ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+ bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+ bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+ bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+ bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+
+ pWord16 = (unsigned short *)dev->dev_addr;
+ bmwrite(dev, MADD0, *pWord16++);
+ bmwrite(dev, MADD1, *pWord16++);
+ bmwrite(dev, MADD2, *pWord16);
+
+
+ bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
+
+ return;
+}
+
+#if 0
+static void
+bmac_disable_interrupts(struct device *dev)
+{
+ bmwrite(dev, INTDISABLE, DisableAll);
+}
+
+static void
+bmac_enable_interrupts(struct device *dev)
+{
+ bmwrite(dev, INTDISABLE, EnableNormal);
+}
+#endif
+
+
+static void
+bmac_start_chip(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ unsigned short oldConfig;
+
+ /* enable rx dma channel */
+ dbdma_continue(rd);
+
+ /* turn on rx plus any other bits already on (promiscuous possibly) */
+ oldConfig = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+
+ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+}
+
+static int
+bmac_init_chip(struct device *dev)
+{
+ bmac_init_registers(dev);
+ return 1;
+}
+
+static int bmac_set_address(struct device *dev, void *addr)
+{
+ unsigned char *p = addr;
+ unsigned short *pWord16;
+ unsigned long flags;
+ int i;
+
+ XXDEBUG(("bmac: enter set_address\n"));
+ save_flags(flags); cli();
+
+ for (i = 0; i < 6; ++i) {
+ dev->dev_addr[i] = p[i];
+ }
+ /* load up the hardware address */
+ pWord16 = (unsigned short *)dev->dev_addr;
+ bmwrite(dev, MADD0, *pWord16++);
+ bmwrite(dev, MADD1, *pWord16++);
+ bmwrite(dev, MADD2, *pWord16);
+
+ restore_flags(flags);
+ XXDEBUG(("bmac: exit set_address\n"));
+ return 0;
+}
+
+static inline void bmac_set_timeout(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (bp->timeout_active)
+ del_timer(&bp->tx_timeout);
+ bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+ bp->tx_timeout.function = bmac_tx_timeout;
+ bp->tx_timeout.data = (unsigned long) dev;
+ add_timer(&bp->tx_timeout);
+ bp->timeout_active = 1;
+ restore_flags(flags);
+}
+
+static void
+bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp,
+ char *doubleBuf)
+{
+ void *vaddr, *page_break;
+ unsigned long baddr;
+ unsigned long len;
+
+ len = skb->len;
+ vaddr = skb->data;
+ baddr = virt_to_bus(vaddr);
+ page_break = round_page(vaddr);
+ if (trunc_page(vaddr) != trunc_page(vaddr+len) &&
+ (unsigned long)round_page(baddr) != virt_to_bus(page_break)) {
+ baddr = virt_to_bus(doubleBuf);
+ XXDEBUG(("bmac: double buffering, double=%#08x, skb->data=%#08x, len=%d\n", doubleBuf, skb->data, len));
+ } else
+ flush_page_to_ram((unsigned long)vaddr);
+
+ dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
+}
+
+static void
+bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp)
+{
+ dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0);
+}
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static unsigned char
+bitrev(unsigned char b)
+{
+ int d = 0, i;
+
+ for (i = 0; i < 8; ++i, b >>= 1)
+ d = (d << 1) | (b & 1);
+ return d;
+}
+
+
+static int
+bmac_init_tx_ring(struct bmac_data *bp)
+{
+ int i;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ char *addr;
+
+ if (!bp->tx_allocated) {
+ /* zero out tx cmds, alloc space for double buffering */
+ addr = (char *)kmalloc(ETHERMTU * N_TX_RING, GFP_DMA);
+ for (i = 0; i < N_TX_RING; i++, addr += ETHERMTU) bp->tx_double[i] = addr;
+ bp->tx_allocated = 1;
+ }
+ memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
+
+ bp->tx_empty = 0;
+ bp->tx_fill = 0;
+ bp->tx_fullup = 0;
+
+ /* put a branch at the end of the tx command list */
+ dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
+ (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
+
+ /* reset tx dma */
+ dbdma_reset(td);
+ out_le32(&td->wait_sel, 0x00200020);
+ out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
+
+ return 1;
+
+}
+
+static int
+bmac_init_rx_ring(struct bmac_data *bp)
+{
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ int i;
+
+ /* initialize list of sk_buffs for receiving and set up recv dma */
+ if (!bp->rx_allocated) {
+ for (i = 0; i < N_RX_RING; i++) {
+ bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+ skb_reserve(bp->rx_bufs[i], 2);
+ }
+ bp->rx_allocated = 1;
+ }
+
+ memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd));
+ for (i = 0; i < N_RX_RING; i++)
+ bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+
+ bp->rx_empty = 0;
+ bp->rx_fill = i;
+
+ /* Put a branch back to the beginning of the receive command list */
+ dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
+ (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
+
+ /* start rx dma */
+ dbdma_reset(rd);
+ out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
+
+ return 1;
+}
+
+
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ int i;
+
+ /* see if there's a free slot in the tx ring */
+/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
+/* bp->tx_empty, bp->tx_fill)); */
+ i = bp->tx_fill + 1;
+ if (i >= N_TX_RING) i = 0;
+ if (i == bp->tx_empty) {
+ dev->tbusy = 1;
+ bp->tx_fullup = 1;
+ XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
+ return -1; /* can't take it at the moment */
+ }
+
+ dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
+
+ bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill], bp->tx_double[bp->tx_fill]);
+
+ bp->tx_bufs[bp->tx_fill] = skb;
+ bp->tx_fill = i;
+
+ dbdma_continue(td);
+
+ return 0;
+}
+
+static int rxintcount = 0;
+
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_cmd *cp;
+ int i, nb, stat;
+ struct sk_buff *skb;
+ unsigned int residual;
+ int last;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ if (++rxintcount < 10) {
+ XXDEBUG(("bmac_rxdma_intr\n"));
+ }
+
+ last = -1;
+ i = bp->rx_empty;
+
+ while (1) {
+ cp = &bp->rx_cmds[i];
+ stat = ld_le16(&cp->xfer_status);
+ residual = ld_le16(&cp->res_count);
+ if ((stat & ACTIVE) == 0) break;
+ nb = RX_BUFLEN - residual - 2;
+ if (nb < (ETHERMINPACKET - ETHERCRC)) {
+ skb = NULL;
+ bp->stats.rx_length_errors++;
+ bp->stats.rx_errors++;
+ } else skb = bp->rx_bufs[i];
+ if (skb != NULL) {
+ nb -= ETHERCRC;
+ skb_put(skb, nb);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+ skb_reserve(bp->rx_bufs[i], 2);
+ bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+ ++bp->stats.rx_packets;
+ } else {
+ ++bp->stats.rx_dropped;
+ }
+ st_le16(&cp->res_count, 0);
+ st_le16(&cp->xfer_status, 0);
+ last = i;
+ if (++i >= N_RX_RING) i = 0;
+ }
+
+ if (last != -1) {
+ bp->rx_fill = last;
+ bp->rx_empty = i;
+ }
+
+ restore_flags(flags);
+
+ dbdma_continue(rd);
+
+ if (rxintcount < 10) {
+ XXDEBUG(("bmac_rxdma_intr done\n"));
+ }
+}
+
+static int txintcount = 0;
+
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_cmd *cp;
+ int stat;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ if (txintcount++ < 10) {
+ XXDEBUG(("bmac_txdma_intr\n"));
+ }
+
+/* del_timer(&bp->tx_timeout); */
+/* bp->timeout_active = 0; */
+
+ while (1) {
+ cp = &bp->tx_cmds[bp->tx_empty];
+ stat = ld_le16(&cp->xfer_status);
+ if (txintcount < 10) {
+ XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
+ }
+ if (!(stat & ACTIVE)) break;
+
+ if (bp->tx_bufs[bp->tx_empty]) {
+ ++bp->stats.tx_packets;
+ dev_kfree_skb(bp->tx_bufs[bp->tx_empty]);
+ }
+ bp->tx_bufs[bp->tx_empty] = NULL;
+ bp->tx_fullup = 0;
+ dev->tbusy = 0;
+/* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */
+/* i, bp->tx_fill)); */
+ mark_bh(NET_BH);
+ if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0;
+ if (bp->tx_empty == bp->tx_fill) break;
+ }
+
+ restore_flags(flags);
+
+ if (txintcount < 10) {
+ XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
+ }
+
+ bmac_start(dev);
+}
+
+static struct net_device_stats *bmac_stats(struct device *dev)
+{
+ struct bmac_data *p = (struct bmac_data *) dev->priv;
+
+ return &p->stats;
+}
+
+#if 0
+/* Real fast bit-reversal algorithm, 6-bit values */
+static int reverse6[64] = {
+ 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
+ 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
+ 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
+ 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
+ 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
+ 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
+ 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
+ 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
+};
+
+static unsigned int
+crc416(unsigned int curval, unsigned short nxtval)
+{
+ register unsigned int counter, cur = curval, next = nxtval;
+ register int high_crc_set, low_data_set;
+
+ /* Swap bytes */
+ next = ((next & 0x00FF) << 8) | (next >> 8);
+
+ /* Compute bit-by-bit */
+ for (counter = 0; counter < 16; ++counter) {
+ /* is high CRC bit set? */
+ if ((cur & 0x80000000) == 0) high_crc_set = 0;
+ else high_crc_set = 1;
+
+ cur = cur << 1;
+
+ if ((next & 0x0001) == 0) low_data_set = 0;
+ else low_data_set = 1;
+
+ next = next >> 1;
+
+ /* do the XOR */
+ if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY;
+ }
+ return cur;
+}
+
+static unsigned int
+bmac_crc(unsigned short *address)
+{
+ unsigned int newcrc;
+
+ XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
+ newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */
+ newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */
+ newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */
+
+ return(newcrc);
+}
+
+/*
+ * Add requested mcast addr to BMac's hash table filter.
+ *
+ */
+
+static void
+bmac_addhash(struct bmac_data *bp, unsigned char *addr)
+{
+ unsigned int crc;
+ unsigned short mask;
+
+ if (!(*addr
+ crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */
+ if (bp->hash_use_count[crc]++) return; /* This bit is already set */
+ mask = crc % 16;
+ mask = (unsigned char)1 << mask;
+ bp->hash_use_count[crc/16] |= mask;
+ }
+
+ static void
+ bmac_removehash(struct bmac_data *bp, unsigned char *addr)
+ {
+ unsigned int crc;
+ unsigned char mask;
+
+ /* Now, delete the address from the filter copy, as indicated */
+ crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */
+ if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
+ if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
+ mask = crc % 16;
+ mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
+ bp->hash_table_mask[crc/16] &= mask;
+ }
+
+/*
+ * Sync the adapter with the software copy of the multicast mask
+ * (logical address filter).
+ */
+
+ static void
+ bmac_rx_off(struct device *dev)
+ {
+ unsigned short rx_cfg;
+
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg &= ~RxMACEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+ do {
+ rx_cfg = bmread(dev, RXCFG);
+ } while (rx_cfg & RxMACEnable);
+ }
+
+ unsigned short
+ bmac_rx_on(struct device *dev, int hash_enable, int promisc_enable)
+ {
+ unsigned short rx_cfg;
+
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg |= RxMACEnable;
+ if (hash_enable) rx_cfg |= RxHashFilterEnable;
+ else rx_cfg &= ~RxHashFilterEnable;
+ if (promisc_enable) rx_cfg |= RxPromiscEnable;
+ else rx_cfg &= ~RxPromiscEnable;
+ bmwrite(dev, RXRST, RxResetValue);
+ bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
+ bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+ bmwrite(dev, RXCFG, rx_cfg );
+ return rx_cfg;
+ }
+
+ static void
+ bmac_update_hash_table_mask(struct device *dev, struct bmac_data *bp)
+ {
+ bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+ bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+ bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+ bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+ }
+
+#if 0
+ static void
+ bmac_add_multi(struct device *dev,
+ struct bmac_data *bp, unsigned char *addr)
+ {
+/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
+ bmac_addhash(bp, addr);
+ bmac_rx_off(dev);
+ bmac_update_hash_table_mask(dev, bp);
+ bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
+ }
+
+ static void
+ bmac_remove_multi(struct device *dev,
+ struct bmac_data *bp, unsigned char *addr)
+ {
+ bmac_removehash(bp, addr);
+ bmac_rx_off(dev);
+ bmac_update_hash_table_mask(dev, bp);
+ bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+ }
+#endif
+
+/* 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.
+ */
+ static void bmac_set_multicast(struct device *dev)
+ {
+ struct dev_mc_list *dmi;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ int num_addrs = dev->mc_count;
+ unsigned short rx_cfg;
+ int i;
+
+ XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
+
+ if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
+ bmac_update_hash_table_mask(dev, bp);
+ rx_cfg = bmac_rx_on(dev, 1, 0);
+ XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
+ } else if if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg |= RxPromiscEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+ rx_cfg = bmac_rx_on(dev, 0, 1);
+ XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
+ } else {
+ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+ for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
+ if (num_addrs == 0) {
+ rx_cfg = bmac_rx_on(dev, 0, 0);
+ XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
+ } else {
+ for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next)
+ bmac_addhash(bp, dmi->dmi_addr);
+ bmac_update_hash_table_mask(dev, bp);
+ rx_cfg = bmac_rx_on(dev, 1, 0);
+ XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
+ }
+ }
+/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
+ }
+#endif
+
+/* The version of set_multicast below was lifted from sunhme.c */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+ static void bmac_set_multicast(struct device *dev)
+ {
+ struct dev_mc_list *dmi = dev->mc_list;
+ char *addrs;
+ int i, j, bit, byte;
+ unsigned short rx_cfg;
+ u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+ /* Let the transmits drain. */
+/* while(dev->tbusy) schedule(); */
+
+ /* Lock out others. */
+/* set_bit(0, (void *) &dev->tbusy); */
+
+ if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ bmwrite(dev, BHASH0, 0xffff);
+ bmwrite(dev, BHASH1, 0xffff);
+ bmwrite(dev, BHASH2, 0xffff);
+ bmwrite(dev, BHASH3, 0xffff);
+ } else if(dev->flags & IFF_PROMISC) {
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg |= RxPromiscEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+ } else {
+ u16 hash_table[4];
+
+ for(i = 0; i < 4; i++) hash_table[i] = 0;
+
+ for(i = 0; i < dev->mc_count; i++) {
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ if(!(*addrs & 1))
+ continue;
+
+ crc = 0xffffffffU;
+ for(byte = 0; byte < 6; byte++) {
+ for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+ if(test)
+ crc = crc ^ poly;
+ }
+ }
+ crc >>= 26;
+ hash_table[crc >> 4] |= 1 << (crc & 0xf);
+ }
+ bmwrite(dev, BHASH0, hash_table[0]);
+ bmwrite(dev, BHASH1, hash_table[1]);
+ bmwrite(dev, BHASH2, hash_table[2]);
+ bmwrite(dev, BHASH3, hash_table[3]);
+ }
+
+ /* Let us get going again. */
+/* dev->tbusy = 0; */
+ }
+
+
+ static int miscintcount = 0;
+
+ static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ struct device *dev = (struct device *) dev_id;
+ struct bmac_data *bp = (struct bmac_data *)dev->priv;
+ unsigned int status = bmread(dev, STATUS);
+ if (miscintcount++ < 10) {
+ XXDEBUG(("bmac_misc_intr\n"));
+ }
+/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
+/* bmac_txdma_intr_inner(irq, dev_id, regs); */
+/* if (status & FrameReceived) bp->stats.rx_dropped++; */
+ if (status & RxErrorMask) bp->stats.rx_errors++;
+ if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
+ if (status & RxLenCntExp) bp->stats.rx_length_errors++;
+ if (status & RxOverFlow) bp->stats.rx_over_errors++;
+ if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
+
+/* if (status & FrameSent) bp->stats.tx_dropped++; */
+ if (status & TxErrorMask) bp->stats.tx_errors++;
+ if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
+ if (status & TxNormalCollExp) bp->stats.collisions++;
+ }
+
+/*
+ * Procedure for reading EEPROM
+ */
+#define SROMAddressLength 5
+#define DataInOn 0x0008
+#define DataInOff 0x0000
+#define Clk 0x0002
+#define ChipSelect 0x0001
+#define SDIShiftCount 3
+#define SD0ShiftCount 2
+#define DelayValue 1000 /* number of microseconds */
+#define SROMStartOffset 10 /* this is in words */
+#define SROMReadCount 3 /* number of words to read from SROM */
+#define SROMAddressBits 6
+#define EnetAddressOffset 20
+
+ static unsigned char
+ bmac_clock_out_bit(struct device *dev)
+ {
+ unsigned short data;
+ unsigned short val;
+
+ bmwrite(dev, SROMCSR, ChipSelect | Clk);
+ udelay(DelayValue);
+
+ data = bmread(dev, SROMCSR);
+ udelay(DelayValue);
+ val = (data >> SD0ShiftCount) & 1;
+
+ bmwrite(dev, SROMCSR, ChipSelect);
+ udelay(DelayValue);
+
+ return val;
+ }
+
+ static void
+ bmac_clock_in_bit(struct device *dev, unsigned int val)
+ {
+ unsigned short data;
+
+ if (val != 0 && val != 1) return;
+
+ data = (val << SDIShiftCount);
+ bmwrite(dev, SROMCSR, data | ChipSelect );
+ udelay(DelayValue);
+
+ bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
+ udelay(DelayValue);
+
+ bmwrite(dev, SROMCSR, data | ChipSelect);
+ udelay(DelayValue);
+ }
+
+ static void
+ reset_and_select_srom(struct device *dev)
+ {
+ /* first reset */
+ bmwrite(dev, SROMCSR, 0);
+ udelay(DelayValue);
+
+ /* send it the read command (110) */
+ bmac_clock_in_bit(dev, 1);
+ bmac_clock_in_bit(dev, 1);
+ bmac_clock_in_bit(dev, 0);
+ }
+
+ static unsigned short
+ read_srom(struct device *dev, unsigned int addr, unsigned int addr_len)
+ {
+ unsigned short data, val;
+ int i;
+
+ /* send out the address we want to read from */
+ for (i = 0; i < addr_len; i++) {
+ val = addr >> (addr_len-i-1);
+ bmac_clock_in_bit(dev, val & 1);
+ }
+
+ /* Now read in the 16-bit data */
+ data = 0;
+ for (i = 0; i < 16; i++) {
+ val = bmac_clock_out_bit(dev);
+ data <<= 1;
+ data |= val;
+ }
+ bmwrite(dev, SROMCSR, 0);
+
+ return data;
+ }
+
+/*
+ * It looks like Cogent and SMC use different methods for calculating
+ * checksums. What a pain..
+ */
+
+ static int
+ bmac_verify_checksum(struct device *dev)
+ {
+ unsigned short data, storedCS;
+
+ reset_and_select_srom(dev);
+ data = read_srom(dev, 3, SROMAddressBits);
+ storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
+
+ return 0;
+ }
+
+
+ static void
+ bmac_get_station_address(struct device *dev, unsigned char *ea)
+ {
+ int i;
+ unsigned short data;
+
+ for (i = 0; i < 6; i++)
+ {
+ reset_and_select_srom(dev);
+ data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
+ ea[2*i] = bitrev(data & 0x0ff);
+ ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+ }
+ }
+
+ static int bmac_reset_and_enable(struct device *dev, int enable)
+ {
+ struct bmac_data *bp = dev->priv;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ bp->reset_and_enabled = 0;
+ bmac_reset_chip(dev);
+ if (enable) {
+ if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0;
+ if (!bmac_init_chip(dev)) return 0;
+ bmac_start_chip(dev);
+ bmwrite(dev, INTDISABLE, EnableNormal);
+ bp->reset_and_enabled = 1;
+/* { */
+/* unsigned char random_packet[100]; */
+/* unsigned int i; */
+/* struct sk_buff *skb = dev_alloc_skb(RX_BUFLEN+2); */
+/* unsigned char *data = skb_put(skb, sizeof(random_packet)); */
+/* XXDEBUG(("transmitting random packet\n")); */
+/* for (i = 0; i < sizeof(random_packet); i++) data[i] = i; */
+/* bmac_transmit_packet(skb, dev); */
+/* XXDEBUG(("done transmitting random packet\n")); */
+/* } */
+ }
+ restore_flags(flags);
+ return 1;
+ }
+
+ int
+ bmac_probe(struct device *dev)
+ {
+ int j, rev;
+ struct bmac_data *bp;
+ struct device_node *bmacs;
+ unsigned char *addr;
+
+ bmacs = find_devices("bmac");
+ if (bmacs == NULL) return ENODEV;
+
+ bmac_devs = dev; /* KLUDGE!! */
+
+ if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) {
+ printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n",
+ bmacs->full_name);
+ return EINVAL;
+ }
+
+ if (dev == NULL) {
+ dev = init_etherdev(NULL, PRIV_BYTES);
+ bmac_devs = dev; /*KLUDGE!!*/
+ } else {
+ /* XXX this doesn't look right (but it's never used :-) */
+ dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+ if (dev->priv == 0) return -ENOMEM;
+ }
+
+ dev->base_addr = bmacs->addrs[0].address;
+ dev->irq = bmacs->intrs[0].line;
+
+ bmwrite(dev, INTDISABLE, DisableAll);
+
+ if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) {
+ printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+ if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
+ dev)) {
+ printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line);
+ return -EAGAIN;
+ }
+ if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
+ dev)) {
+ printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line);
+ return -EAGAIN;
+ }
+
+ addr = get_property(bmacs, "mac-address", NULL);
+ if (addr == NULL) {
+ addr = get_property(bmacs, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n",
+ dev->base_addr);
+ return -EAGAIN;
+ }
+ }
+
+ printk(KERN_INFO "%s: BMAC at", dev->name);
+ rev = addr[0] == 0 && addr[1] == 0xA0;
+ for (j = 0; j < 6; ++j) {
+ dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+ }
+ XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+ printk("\n");
+
+ dev->open = bmac_open;
+ dev->stop = bmac_close;
+ dev->hard_start_xmit = bmac_output;
+ dev->get_stats = bmac_stats;
+ dev->set_multicast_list = bmac_set_multicast;
+ dev->set_mac_address = bmac_set_address;
+
+ bmac_get_station_address(dev, addr);
+ if (bmac_verify_checksum(dev) != 0) return EINVAL;
+
+ ether_setup(dev);
+
+ bp = (struct bmac_data *) dev->priv;
+ memset(bp, 0, sizeof(struct bmac_data));
+ bp->tx_dma = (volatile struct dbdma_regs *) bmacs->addrs[1].address;
+ bp->tx_dma_intr = bmacs->intrs[1].line;
+ bp->rx_dma = (volatile struct dbdma_regs *) bmacs->addrs[2].address;
+ bp->rx_dma_intr = bmacs->intrs[2].line;
+
+ bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
+ bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
+
+ bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
+ skb_queue_head_init(bp->queue);
+
+ memset(&bp->stats, 0, sizeof(bp->stats));
+ memset((char *) bp->tx_cmds, 0,
+ (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+/* init_timer(&bp->tx_timeout); */
+/* bp->timeout_active = 0; */
+
+ if (!bmac_reset_and_enable(dev, 0)) return EINVAL;
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&(struct proc_dir_entry) {
+ PROC_NET_BMAC, 4, "bmac",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ bmac_proc_info
+ });
+#endif
+
+ return 0;
+ }
+
+ static int bmac_open(struct device *dev)
+ {
+/* XXDEBUG(("bmac: enter open\n")); */
+ /* reset the chip */
+ bmac_reset_and_enable(dev, 1);
+
+ dev->flags |= IFF_UP | IFF_RUNNING;
+
+ return 0;
+ }
+
+ static int bmac_close(struct device *dev)
+ {
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ unsigned short config;
+ int i;
+
+ dev->flags &= ~(IFF_UP | IFF_RUNNING);
+
+ /* disable rx and tx */
+ config = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+
+ config = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+
+ bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+
+ /* disable rx and tx dma */
+ st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
+ st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
+
+ /* free some skb's */
+ XXDEBUG(("bmac: free rx bufs\n"));
+ for (i=0; i<N_RX_RING; i++) {
+ if (bp->rx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->rx_bufs[i]);
+ bp->rx_bufs[i] = NULL;
+ }
+ }
+ bp->rx_allocated = 0;
+ XXDEBUG(("bmac: free doubles\n"));/*MEMORY LEAK BELOW!!! FIX!!! */
+ if (bp->tx_double[0] != NULL) kfree(bp->tx_double[0]);
+ XXDEBUG(("bmac: free tx bufs\n"));
+ for (i = 0; i<N_TX_RING; i++) {
+ if (bp->tx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->tx_bufs[i]);
+ bp->tx_bufs[i] = NULL;
+ }
+ }
+ bp->tx_allocated = 0;
+ bp->reset_and_enabled = 0;
+ XXDEBUG(("bmac: all bufs freed\n"));
+
+ return 0;
+ }
+
+ static void
+ bmac_start(struct device *dev)
+ {
+ struct bmac_data *bp = dev->priv;
+ int i;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ while (1) {
+ i = bp->tx_fill + 1;
+ if (i >= N_TX_RING) i = 0;
+ if (i == bp->tx_empty) break;
+ skb = skb_dequeue(bp->queue);
+ if (skb == NULL) break;
+ bmac_transmit_packet(skb, dev);
+ }
+ restore_flags(flags);
+ }
+
+ static int
+ bmac_output(struct sk_buff *skb, struct device *dev)
+ {
+ struct bmac_data *bp = dev->priv;
+ skb_queue_tail(bp->queue, skb);
+ bmac_start(dev);
+ return 0;
+ }
+
+ static void bmac_tx_timeout(unsigned long data)
+ {
+ struct device *dev = (struct device *) data;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_cmd *cp;
+ unsigned long flags;
+ unsigned short config, oldConfig;
+ int i;
+
+ XXDEBUG(("bmac: tx_timeout called\n"));
+ save_flags(flags); cli();
+ bp->timeout_active = 0;
+
+ /* update various counters */
+/* bmac_handle_misc_intrs(bp, 0); */
+
+ cp = &bp->tx_cmds[bp->tx_empty];
+/* XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
+/* ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, */
+/* mb->pr, mb->xmtfs, mb->fifofc)); */
+
+ /* turn off both tx and rx and reset the chip */
+ config = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+ config = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+ out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+ printk(KERN_ERR "bmac: transmit timeout - resetting\n");
+ bmac_reset_chip(dev);
+
+ /* restart rx dma */
+ cp = bus_to_virt(ld_le32(&rd->cmdptr));
+ out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+ out_le16(&cp->xfer_status, 0);
+ out_le32(&rd->cmdptr, virt_to_bus(cp));
+ out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
+
+ /* fix up the transmit side */
+ XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
+ bp->tx_empty, bp->tx_fill, bp->tx_fullup));
+ i = bp->tx_empty;
+ ++bp->stats.tx_errors;
+ if (i != bp->tx_fill) {
+ dev_kfree_skb(bp->tx_bufs[i]);
+ bp->tx_bufs[i] = NULL;
+ if (++i >= N_TX_RING) i = 0;
+ bp->tx_empty = i;
+ }
+ bp->tx_fullup = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n"));
+ if (i != bp->tx_fill) {
+ cp = &bp->tx_cmds[i];
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->command, OUTPUT_LAST);
+ out_le32(&td->cmdptr, virt_to_bus(cp));
+ out_le32(&td->control, DBDMA_SET(RUN));
+/* bmac_set_timeout(dev); */
+ XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
+ }
+
+ /* turn it back on */
+ oldConfig = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
+ restore_flags(flags);
+ }
+
+#if 0
+ static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
+ {
+ int i,*ip;
+
+ for (i=0;i< count;i++)
+ {
+ ip = (int*)(cp+i);
+
+ printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
+ ld_le32(ip+0),
+ ld_le32(ip+1),
+ ld_le32(ip+2),
+ ld_le32(ip+3));
+ }
+
+ }
+#endif
+
+ static int
+ bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy)
+ {
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
+ int i;
+
+ if (bmac_devs == NULL) return (-ENOSYS);
+
+ len += sprintf(buffer, "BMAC counters & registers\n");
+
+ for (i = 0; i<N_REG_ENTRIES; i++) {
+ len += sprintf(buffer + len, "%s: %#08x\n",
+ reg_entries[i].name,
+ bmread(bmac_devs, reg_entries[i].reg_offset));
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset+length) break;
+ }
+
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+
+ if (len > length) len = length;
+
+ return len;
+ }
diff --git a/drivers/net/bmac.h b/drivers/net/bmac.h
new file mode 100644
index 000000000..df3b93d1a
--- /dev/null
+++ b/drivers/net/bmac.h
@@ -0,0 +1,164 @@
+/*
+ * mace.h - definitions for the registers in the "Big Mac"
+ * Ethernet controller found in PowerMac G3 models.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The "Big MAC" appears to have some parts in common with the Sun "Happy Meal"
+ * (HME) controller. See sunhme.h
+ */
+
+
+/* register offsets */
+
+/* global status and control */
+#define XIFC 0x000 /* low-level interface control */
+# define TxOutputEnable 0x0001 /* output driver enable */
+# define XIFLoopback 0x0002 /* Loopback-mode XIF enable */
+# define MIILoopback 0x0004 /* Loopback-mode MII enable */
+# define MIILoopbackBits 0x0006
+# define MIIBuffDisable 0x0008 /* MII receive buffer disable */
+# define SQETestEnable 0x0010 /* SQE test enable */
+# define SQETimeWindow 0x03e0 /* SQE time window */
+# define XIFLanceMode 0x0010 /* Lance mode enable */
+# define XIFLanceIPG0 0x03e0 /* Lance mode IPG0 */
+#define TXFIFOCSR 0x100 /* transmit FIFO control */
+# define TxFIFOEnable 0x0001
+#define TXTH 0x110 /* transmit threshold */
+# define TxThreshold 0x0004
+#define RXFIFOCSR 0x120 /* receive FIFO control */
+# define RxFIFOEnable 0x0001
+#define MEMADD 0x130 /* memory address, unknown function */
+#define MEMDATAHI 0x140 /* memory data high, presently unused in driver */
+#define MEMDATALO 0x150 /* memory data low, presently unused in driver */
+#define XCVRIF 0x160 /* transceiver interface control */
+# define COLActiveLow 0x0002
+# define SerialMode 0x0004
+# define ClkBit 0x0008
+# define LinkStatus 0x0100
+#define CHIPID 0x170 /* chip ID */
+#define MIFCSR 0x180 /* ??? */
+#define SROMCSR 0x190 /* SROM control */
+# define ChipSelect 0x0001
+# define Clk 0x0002
+#define TXPNTR 0x1a0 /* transmit pointer */
+#define RXPNTR 0x1b0 /* receive pointer */
+#define STATUS 0x200 /* status--reading this clears it */
+#define INTDISABLE 0x210 /* interrupt enable/disable control */
+/* bits below are the same in both STATUS and INTDISABLE registers */
+# define FrameReceived 0x00000001 /* Received a frame */
+# define RxFrameCntExp 0x00000002 /* Receive frame counter expired */
+# define RxAlignCntExp 0x00000004 /* Align-error counter expired */
+# define RxCRCCntExp 0x00000008 /* CRC-error counter expired */
+# define RxLenCntExp 0x00000010 /* Length-error counter expired */
+# define RxOverFlow 0x00000020 /* Receive FIFO overflow */
+# define RxCodeViolation 0x00000040 /* Code-violation counter expired */
+# define SQETestError 0x00000080 /* Test error in XIF for SQE */
+# define FrameSent 0x00000100 /* Transmitted a frame */
+# define TxUnderrun 0x00000200 /* Transmit FIFO underrun */
+# define TxMaxSizeError 0x00000400 /* Max-packet size error */
+# define TxNormalCollExp 0x00000800 /* Normal-collision counter expired */
+# define TxExcessCollExp 0x00001000 /* Excess-collision counter expired */
+# define TxLateCollExp 0x00002000 /* Late-collision counter expired */
+# define TxNetworkCollExp 0x00004000 /* First-collision counter expired */
+# define TxDeferTimerExp 0x00008000 /* Defer-timer expired */
+# define RxFIFOToHost 0x00010000 /* Data moved from FIFO to host */
+# define RxNoDescriptors 0x00020000 /* No more receive descriptors */
+# define RxDMAError 0x00040000 /* Error during receive DMA */
+# define RxDMALateErr 0x00080000 /* Receive DMA, data late */
+# define RxParityErr 0x00100000 /* Parity error during receive DMA */
+# define RxTagError 0x00200000 /* Tag error during receive DMA */
+# define TxEOPError 0x00400000 /* Tx descriptor did not have EOP set */
+# define MIFIntrEvent 0x00800000 /* MIF is signaling an interrupt */
+# define TxHostToFIFO 0x01000000 /* Data moved from host to FIFO */
+# define TxFIFOAllSent 0x02000000 /* Transmitted all packets in FIFO */
+# define TxDMAError 0x04000000 /* Error during transmit DMA */
+# define TxDMALateError 0x08000000 /* Late error during transmit DMA */
+# define TxParityError 0x10000000 /* Parity error during transmit DMA */
+# define TxTagError 0x20000000 /* Tag error during transmit DMA */
+# define PIOError 0x40000000 /* PIO access got an error */
+# define PIOParityError 0x80000000 /* PIO access got a parity error */
+# define DisableAll 0xffffffff
+# define EnableAll 0x00000000
+/* # define NormalIntEvents ~(FrameReceived | FrameSent | TxUnderrun) */
+# define EnableNormal ~(FrameReceived | FrameSent)
+# define EnableErrors (FrameReceived | FrameSent)
+# define RxErrorMask (RxFrameCntExp | RxAlignCntExp | RxCRCCntExp | \
+ RxLenCntExp | RxOverFlow | RxCodeViolation)
+# define TxErrorMask (TxUnderrun | TxMaxSizeError | TxExcessCollExp | \
+ TxLateCollExp | TxNetworkCollExp | TxDeferTimerExp)
+
+/* transmit control */
+#define TXRST 0x420 /* transmit reset */
+# define TxResetBit 0x0001
+#define TXCFG 0x430 /* transmit configuration control*/
+# define TxMACEnable 0x0001 /* output driver enable */
+# define TxSlowMode 0x0020 /* enable slow mode */
+# define TxIgnoreColl 0x0040 /* ignore transmit collisions */
+# define TxNoFCS 0x0080 /* do not emit FCS */
+# define TxNoBackoff 0x0100 /* no backoff in case of collisions */
+# define TxFullDuplex 0x0200 /* enable full-duplex */
+# define TxNeverGiveUp 0x0400 /* don't give up on transmits */
+#define IPG1 0x440 /* Inter-packet gap 1 */
+#define IPG2 0x450 /* Inter-packet gap 2 */
+#define ALIMIT 0x460 /* Transmit attempt limit */
+#define SLOT 0x470 /* Transmit slot time */
+#define PALEN 0x480 /* Size of transmit preamble */
+#define PAPAT 0x490 /* Pattern for transmit preamble */
+#define TXSFD 0x4a0 /* Transmit frame delimiter */
+#define JAM 0x4b0 /* Jam size */
+#define TXMAX 0x4c0 /* Transmit max pkt size */
+#define TXMIN 0x4d0 /* Transmit min pkt size */
+#define PAREG 0x4e0 /* Count of transmit peak attempts */
+#define DCNT 0x4f0 /* Transmit defer timer */
+#define NCCNT 0x500 /* Transmit normal-collision counter */
+#define NTCNT 0x510 /* Transmit first-collision counter */
+#define EXCNT 0x520 /* Transmit excess-collision counter */
+#define LTCNT 0x530 /* Transmit late-collision counter */
+#define RSEED 0x540 /* Transmit random number seed */
+#define TXSM 0x550 /* Transmit state machine */
+
+/* receive control */
+#define RXRST 0x620 /* receive reset */
+# define RxResetValue 0x0000
+#define RXCFG 0x630 /* receive configuration control */
+# define RxMACEnable 0x0001 /* receiver overall enable */
+# define RxCFGReserved 0x0004
+# define RxPadStripEnab 0x0020 /* enable pad byte stripping */
+# define RxPromiscEnable 0x0040 /* turn on promiscuous mode */
+# define RxNoErrCheck 0x0080 /* disable receive error checking */
+# define RxCRCNoStrip 0x0100 /* disable auto-CRC-stripping */
+# define RxRejectOwnPackets 0x0200 /* don't receive our own packets */
+# define RxGrpPromisck 0x0400 /* enable group promiscuous mode */
+# define RxHashFilterEnable 0x0800 /* enable hash filter */
+# define RxAddrFilterEnable 0x1000 /* enable address filter */
+#define RXMAX 0x640 /* Max receive packet size */
+#define RXMIN 0x650 /* Min receive packet size */
+#define MADD2 0x660 /* our enet address, high part */
+#define MADD1 0x670 /* our enet address, middle part */
+#define MADD0 0x680 /* our enet address, low part */
+#define FRCNT 0x690 /* receive frame counter */
+#define LECNT 0x6a0 /* Receive excess length error counter */
+#define AECNT 0x6b0 /* Receive misaligned error counter */
+#define FECNT 0x6c0 /* Receive CRC error counter */
+#define RXSM 0x6d0 /* Receive state machine */
+#define RXCV 0x6e0 /* Receive code violation */
+
+#define BHASH3 0x700 /* multicast hash register */
+#define BHASH2 0x710 /* multicast hash register */
+#define BHASH1 0x720 /* multicast hash register */
+#define BHASH0 0x730 /* multicast hash register */
+
+#define AFR2 0x740 /* address filtering setup? */
+#define AFR1 0x750 /* address filtering setup? */
+#define AFR0 0x760 /* address filtering setup? */
+#define AFCR 0x770 /* address filter compare register? */
+# define EnableAllCompares 0x0fff
+
+/* bits in XIFC */
diff --git a/drivers/net/com90xx.c b/drivers/net/com90xx.c
index 659eb7ad9..f605ce20b 100644
--- a/drivers/net/com90xx.c
+++ b/drivers/net/com90xx.c
@@ -1,28 +1,28 @@
-/* $Id: com90xx.c,v 1.6 1997/11/09 11:05:01 mj Exp $
+/* $Id: com90xx.c,v 1.9 1998/03/21 18:02:51 alan Exp $
- Derived from the original arcnet.c,
- Written 1994-1996 by Avery Pennarun,
- which was in turn derived from skeleton.c by Donald Becker.
+ Derived from the original arcnet.c,
+ Written 1994-1996 by Avery Pennarun,
+ which was in turn derived from skeleton.c by Donald Becker.
- Contact Avery at: apenwarr@bond.net or
- RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
+ Contact Avery at: apenwarr@bond.net or
+ RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
- **********************
+ **********************
- The original copyright of skeleton.c was as follows:
+ The original copyright of skeleton.c was as follows:
- skeleton.c Written 1993 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.
+ skeleton.c Written 1993 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.
- **********************
+ **********************
- For more details, see drivers/net/arcnet.c
+ For more details, see drivers/net/arcnet.c
- **********************
-*/
+ **********************
+ */
#include <linux/module.h>
@@ -94,34 +94,34 @@
#ifdef MODULE
static
#endif
- int arc90xx_probe(struct device *dev);
-static void arc90xx_rx(struct device *dev,int recbuf);
-static int arc90xx_found(struct device *dev,int ioaddr,int airq,u_long shmem,int more);
-static void arc90xx_inthandler (struct device *dev);
-static int arc90xx_reset (struct device *dev, int reset_delay);
-static void arc90xx_setmask (struct device *dev, u_char mask);
-static void arc90xx_command (struct device *dev, u_char command);
-static u_char arc90xx_status (struct device *dev);
-static void arc90xx_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
- char *data,int length,int daddr,int exceptA, int offset);
-static void arc90xx_openclose(int open);
+int arc90xx_probe(struct device *dev);
+static void arc90xx_rx(struct device *dev, int recbuf);
+static int arc90xx_found(struct device *dev, int ioaddr, int airq, u_long shmem, int more);
+static void arc90xx_inthandler(struct device *dev);
+static int arc90xx_reset(struct device *dev, int reset_delay);
+static void arc90xx_setmask(struct device *dev, u_char mask);
+static void arc90xx_command(struct device *dev, u_char command);
+static u_char arc90xx_status(struct device *dev);
+static void arc90xx_prepare_tx(struct device *dev, u_char * hdr, int hdrlen,
+ char *data, int length, int daddr, int exceptA, int offset);
+static void arc90xx_openclose(int open);
/* Module parameters */
#ifdef MODULE
-static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-static int irq=0; /* or use the insmod io= irq= shmem= options */
-static int shmem=0;
-static char *device; /* use eg. device="arc1" to change name */
+static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq = 0; /* or use the insmod io= irq= shmem= options */
+static int shmem = 0;
+static char *device; /* use eg. device="arc1" to change name */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(shmem, "i");
MODULE_PARM(device, "s");
#else
-__initfunc(void com90xx_setup (char *str, int *ints));
-char __initdata com90xx_explicit=0;
+__initfunc(void com90xx_setup(char *str, int *ints));
+char __initdata com90xx_explicit = 0;
extern struct device arcnet_devs[];
extern char arcnet_dev_names[][10];
@@ -139,12 +139,12 @@ extern int arcnet_num_devs;
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _RESET (ioaddr+8) /* software reset (on read) */
-#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
-#define _ADDR_HI (ioaddr+15) /* Control registers for said */
+#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
+#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
-#define _CONFIG (ioaddr+2) /* Configuration register */
+#define _CONFIG (ioaddr+2) /* Configuration register */
-#define RDDATAflag 0x00 /* Next access is a read/~write */
+#define RDDATAflag 0x00 /* Next access is a read/~write */
#define ARCSTATUS inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
@@ -153,7 +153,7 @@ extern int arcnet_num_devs;
#define ARCRESET inb(_RESET)
static const char *version =
- "com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+"com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
/****************************************************************************
@@ -166,7 +166,7 @@ static const char *version =
* If dev->base_addr == 0, probe all likely locations.
* If dev->base_addr == 1, always return failure.
* If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
+ * (detachable devices only).
*
* NOTE: the list of possible ports/shmems is static, so it is retained
* across calls to arcnet_probe. So, if more than one ARCnet probe is made,
@@ -175,811 +175,736 @@ static const char *version =
* FIXME: grab all devices in one shot and eliminate the big static array.
*/
-static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { 0 };
-static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { 0 };
+static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = {
+ 0
+};
+static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = {
+ 0
+};
__initfunc(int arc90xx_probe(struct device *dev))
{
- static int init_once = 0;
- static int numports=sizeof(ports)/sizeof(ports[0]),
- numshmems=sizeof(shmems)/sizeof(shmems[0]);
- int count,status,delayval,ioaddr,numprint,airq,retval=-ENODEV,
- openparen=0;
- unsigned long airqmask;
- int *port;
- u_long *shmem;
-
- if (!init_once)
- {
- for (count=0x200; count<=0x3f0; count+=16)
- ports[(count-0x200)/16] = count;
- for (count=0xA0000; count<=0xFF800; count+=2048)
- shmems[(count-0xA0000)/2048] = count;
- BUGLVL(D_NORMAL) printk(version);
- BUGMSG(D_DURING,"space used for probe buffers: %d+%d=%d bytes\n",
- sizeof(ports),sizeof(shmems),
- sizeof(ports)+sizeof(shmems));
- }
- init_once++;
-
- BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
- dev->base_addr,dev->irq,dev->mem_start);
-
- if (dev->base_addr > 0x1ff) /* Check a single specified port */
- {
- ports[0]=dev->base_addr;
- numports=1;
- }
- else if (dev->base_addr > 0) /* Don't probe at all. */
- return -ENXIO;
-
- if (dev->mem_start)
- {
- shmems[0]=dev->mem_start;
- numshmems=1;
- }
-
- /* Stage 1: abandon any reserved ports, or ones with status==0xFF
- * (empty), and reset any others by reading the reset port.
- */
- BUGMSG(D_INIT,"Stage 1: ");
- numprint=0;
- for (port = &ports[0]; port-ports<numports; port++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 1: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%Xh ",*port);
-
- ioaddr=*port;
-
- if (check_region(*port, ARCNET_TOTAL_SIZE))
- {
- BUGMSG2(D_INIT_REASONS,"(check_region)\n");
- BUGMSG(D_INIT_REASONS,"Stage 1: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
+ static int init_once = 0;
+ static int numports = sizeof(ports) / sizeof(ports[0]), numshmems = sizeof(shmems) / sizeof(shmems[0]);
+ int count, status, delayval, ioaddr, numprint, airq, retval = -ENODEV,
+ openparen = 0;
+ unsigned long airqmask;
+ int *port;
+ u_long *shmem;
+
+ if (!init_once) {
+ for (count = 0x200; count <= 0x3f0; count += 16)
+ ports[(count - 0x200) / 16] = count;
+ for (count = 0xA0000; count <= 0xFF800; count += 2048)
+ shmems[(count - 0xA0000) / 2048] = count;
+ BUGLVL(D_NORMAL) printk(version);
+ BUGMSG(D_DURING, "space used for probe buffers: %d+%d=%d bytes\n",
+ sizeof(ports), sizeof(shmems),
+ sizeof(ports) + sizeof(shmems));
}
+ init_once++;
- if (ARCSTATUS == 0xFF)
- {
- BUGMSG2(D_INIT_REASONS,"(empty)\n");
- BUGMSG(D_INIT_REASONS,"Stage 1: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
- }
+ BUGMSG(D_INIT, "given: base %lXh, IRQ %d, shmem %lXh\n",
+ dev->base_addr, dev->irq, dev->mem_start);
- ARCRESET; /* begin resetting card */
-
- BUGMSG2(D_INIT_REASONS,"\n");
- BUGMSG(D_INIT_REASONS,"Stage 1: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- }
- BUGMSG2(D_INIT,"\n");
-
- if (!numports)
- {
- BUGMSG(D_NORMAL,"Stage 1: No ARCnet cards found.\n");
- return -ENODEV;
- }
-
- /* Stage 2: we have now reset any possible ARCnet cards, so we can't
- * do anything until they finish. If D_INIT, print the list of
- * cards that are left.
- */
- BUGMSG(D_INIT,"Stage 2: ");
- numprint=0;
- for (port = &ports[0]; port-ports<numports; port++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 2: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%Xh ",*port);
- }
- BUGMSG2(D_INIT,"\n");
- JIFFER(RESETtime);
-
- /* Stage 3: abandon any shmem addresses that don't have the signature
- * 0xD1 byte in the right place, or are read-only.
- */
- BUGMSG(D_INIT,"Stage 3: ");
- numprint=0;
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- {
- u_long ptr;
-
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 3: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%lXh ",*shmem);
-
- ptr=(u_long)(*shmem);
-
- if (readb(ptr) != TESTvalue)
- {
- BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
- readb(ptr),TESTvalue);
- BUGMSG(D_INIT_REASONS,"Stage 3: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *shmem=shmems[numshmems-1];
- numshmems--;
- shmem--;
- continue;
- }
+ if (dev->base_addr > 0x1ff) { /* Check a single specified port */
+ ports[0] = dev->base_addr;
+ numports = 1;
+ } else if (dev->base_addr > 0) /* Don't probe at all. */
+ return -ENXIO;
- /* By writing 0x42 to the TESTvalue location, we also make
- * sure no "mirror" shmem areas show up - if they occur
- * in another pass through this loop, they will be discarded
- * because *cptr != TESTvalue.
- */
- writeb(0x42,ptr);
- if (readb(ptr) != 0x42)
- {
- BUGMSG2(D_INIT_REASONS,"(read only)\n");
- BUGMSG(D_INIT_REASONS,"Stage 3: ");
- *shmem=shmems[numshmems-1];
- numshmems--;
- shmem--;
- continue;
+ if (dev->mem_start) {
+ shmems[0] = dev->mem_start;
+ numshmems = 1;
}
+ /* Stage 1: abandon any reserved ports, or ones with status==0xFF
+ * (empty), and reset any others by reading the reset port.
+ */
+ BUGMSG(D_INIT, "Stage 1: ");
+ numprint = 0;
+ for (port = &ports[0]; port - ports < numports; port++) {
+ numprint++;
+ if (numprint > 8) {
+ BUGMSG2(D_INIT, "\n");
+ BUGMSG(D_INIT, "Stage 1: ");
+ numprint = 1;
+ }
+ BUGMSG2(D_INIT, "%Xh ", *port);
+
+ ioaddr = *port;
+
+ if (check_region(*port, ARCNET_TOTAL_SIZE)) {
+ BUGMSG2(D_INIT_REASONS, "(check_region)\n");
+ BUGMSG(D_INIT_REASONS, "Stage 1: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ *port = ports[numports - 1];
+ numports--;
+ port--;
+ continue;
+ }
+ if (ARCSTATUS == 0xFF) {
+ BUGMSG2(D_INIT_REASONS, "(empty)\n");
+ BUGMSG(D_INIT_REASONS, "Stage 1: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ *port = ports[numports - 1];
+ numports--;
+ port--;
+ continue;
+ }
+ ARCRESET; /* begin resetting card */
- BUGMSG2(D_INIT_REASONS,"\n");
- BUGMSG(D_INIT_REASONS,"Stage 3: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- }
- BUGMSG2(D_INIT,"\n");
-
- if (!numshmems)
- {
- BUGMSG(D_NORMAL,"Stage 3: No ARCnet cards found.\n");
- return -ENODEV;
- }
-
- /* Stage 4: something of a dummy, to report the shmems that are
- * still possible after stage 3.
- */
- BUGMSG(D_INIT,"Stage 4: ");
- numprint=0;
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 4: ");
- numprint=1;
+ BUGMSG2(D_INIT_REASONS, "\n");
+ BUGMSG(D_INIT_REASONS, "Stage 1: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
}
- BUGMSG2(D_INIT,"%lXh ",*shmem);
- }
- BUGMSG2(D_INIT,"\n");
-
- /* Stage 5: for any ports that have the correct status, can disable
- * the RESET flag, and (if no irq is given) generate an autoirq,
- * register an ARCnet device.
- *
- * Currently, we can only register one device per probe, so quit
- * after the first one is found.
- */
- BUGMSG(D_INIT,"Stage 5: ");
- numprint=0;
- for (port = &ports[0]; port-ports<numports; port++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 5: ");
- numprint=1;
+ BUGMSG2(D_INIT, "\n");
+
+ if (!numports) {
+ BUGMSG(D_NORMAL, "Stage 1: No ARCnet cards found.\n");
+ return -ENODEV;
}
- BUGMSG2(D_INIT,"%Xh ",*port);
-
- ioaddr=*port;
- status=ARCSTATUS;
-
- if ((status & 0x9D)
- != (NORXflag|RECONflag|TXFREEflag|RESETflag))
- {
- BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status);
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
+ /* Stage 2: we have now reset any possible ARCnet cards, so we can't
+ * do anything until they finish. If D_INIT, print the list of
+ * cards that are left.
+ */
+ BUGMSG(D_INIT, "Stage 2: ");
+ numprint = 0;
+ for (port = &ports[0]; port - ports < numports; port++) {
+ numprint++;
+ if (numprint > 8) {
+ BUGMSG2(D_INIT, "\n");
+ BUGMSG(D_INIT, "Stage 2: ");
+ numprint = 1;
+ }
+ BUGMSG2(D_INIT, "%Xh ", *port);
}
-
- ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
- status=ARCSTATUS;
- if (status & RESETflag)
- {
- BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n",
- status);
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
+ BUGMSG2(D_INIT, "\n");
+ JIFFER(RESETtime);
+
+ /* Stage 3: abandon any shmem addresses that don't have the signature
+ * 0xD1 byte in the right place, or are read-only.
+ */
+ BUGMSG(D_INIT, "Stage 3: ");
+ numprint = 0;
+ for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) {
+ u_long ptr;
+
+ numprint++;
+ if (numprint > 8) {
+ BUGMSG2(D_INIT, "\n");
+ BUGMSG(D_INIT, "Stage 3: ");
+ numprint = 1;
+ }
+ BUGMSG2(D_INIT, "%lXh ", *shmem);
+
+ ptr = (u_long) (*shmem);
+
+ if (readb(ptr) != TESTvalue) {
+ BUGMSG2(D_INIT_REASONS, "(mem=%02Xh, not %02Xh)\n",
+ readb(ptr), TESTvalue);
+ BUGMSG(D_INIT_REASONS, "Stage 3: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ *shmem = shmems[numshmems - 1];
+ numshmems--;
+ shmem--;
+ continue;
+ }
+ /* By writing 0x42 to the TESTvalue location, we also make
+ * sure no "mirror" shmem areas show up - if they occur
+ * in another pass through this loop, they will be discarded
+ * because *cptr != TESTvalue.
+ */
+ writeb(0x42, ptr);
+ if (readb(ptr) != 0x42) {
+ BUGMSG2(D_INIT_REASONS, "(read only)\n");
+ BUGMSG(D_INIT_REASONS, "Stage 3: ");
+ *shmem = shmems[numshmems - 1];
+ numshmems--;
+ shmem--;
+ continue;
+ }
+ BUGMSG2(D_INIT_REASONS, "\n");
+ BUGMSG(D_INIT_REASONS, "Stage 3: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
}
+ BUGMSG2(D_INIT, "\n");
- /* skip this completely if an IRQ was given, because maybe
- * we're on a machine that locks during autoirq!
- */
- if (!dev->irq)
- {
- /* if we do this, we're sure to get an IRQ since the
- * card has just reset and the NORXflag is on until
- * we tell it to start receiving.
- */
- airqmask = probe_irq_on();
- AINTMASK(NORXflag);
- udelay(1);
- AINTMASK(0);
- airq = probe_irq_off(airqmask);
-
- if (airq<=0)
- {
- BUGMSG2(D_INIT_REASONS,"(airq=%d)\n",airq);
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
- }
+ if (!numshmems) {
+ BUGMSG(D_NORMAL, "Stage 3: No ARCnet cards found.\n");
+ return -ENODEV;
}
- else
- {
- airq=dev->irq;
+ /* Stage 4: something of a dummy, to report the shmems that are
+ * still possible after stage 3.
+ */
+ BUGMSG(D_INIT, "Stage 4: ");
+ numprint = 0;
+ for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) {
+ numprint++;
+ if (numprint > 8) {
+ BUGMSG2(D_INIT, "\n");
+ BUGMSG(D_INIT, "Stage 4: ");
+ numprint = 1;
+ }
+ BUGMSG2(D_INIT, "%lXh ", *shmem);
}
+ BUGMSG2(D_INIT, "\n");
+
+ /* Stage 5: for any ports that have the correct status, can disable
+ * the RESET flag, and (if no irq is given) generate an autoirq,
+ * register an ARCnet device.
+ *
+ * Currently, we can only register one device per probe, so quit
+ * after the first one is found.
+ */
+ BUGMSG(D_INIT, "Stage 5: ");
+ numprint = 0;
+ for (port = &ports[0]; port - ports < numports; port++) {
+ numprint++;
+ if (numprint > 8) {
+ BUGMSG2(D_INIT, "\n");
+ BUGMSG(D_INIT, "Stage 5: ");
+ numprint = 1;
+ }
+ BUGMSG2(D_INIT, "%Xh ", *port);
+
+ ioaddr = *port;
+ status = ARCSTATUS;
+
+ if ((status & 0x9D)
+ != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
+ BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status);
+ BUGMSG(D_INIT_REASONS, "Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ *port = ports[numports - 1];
+ numports--;
+ port--;
+ continue;
+ }
+ ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
+ status = ARCSTATUS;
+ if (status & RESETflag) {
+ BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
+ status);
+ BUGMSG(D_INIT_REASONS, "Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ *port = ports[numports - 1];
+ numports--;
+ port--;
+ continue;
+ }
+ /* skip this completely if an IRQ was given, because maybe
+ * we're on a machine that locks during autoirq!
+ */
+ if (!dev->irq) {
+ /* if we do this, we're sure to get an IRQ since the
+ * card has just reset and the NORXflag is on until
+ * we tell it to start receiving.
+ */
+ airqmask = probe_irq_on();
+ AINTMASK(NORXflag);
+ udelay(1);
+ AINTMASK(0);
+ airq = probe_irq_off(airqmask);
+
+ if (airq <= 0) {
+ BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
+ BUGMSG(D_INIT_REASONS, "Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ *port = ports[numports - 1];
+ numports--;
+ port--;
+ continue;
+ }
+ } else {
+ airq = dev->irq;
+ }
- BUGMSG2(D_INIT,"(%d,", airq);
- openparen=1;
+ BUGMSG2(D_INIT, "(%d,", airq);
+ openparen = 1;
- /* Everything seems okay. But which shmem, if any, puts
- * back its signature byte when the card is reset?
- *
- * If there are multiple cards installed, there might be
- * multiple shmems still in the list.
- */
+ /* Everything seems okay. But which shmem, if any, puts
+ * back its signature byte when the card is reset?
+ *
+ * If there are multiple cards installed, there might be
+ * multiple shmems still in the list.
+ */
#ifdef FAST_PROBE
- if (numports>1 || numshmems>1)
- {
- ARCRESET;
- JIFFER(RESETtime);
- }
- else
- {
- /* just one shmem and port, assume they match */
- writeb(TESTvalue,shmems[0]);
- }
+ if (numports > 1 || numshmems > 1) {
+ ARCRESET;
+ JIFFER(RESETtime);
+ } else {
+ /* just one shmem and port, assume they match */
+ writeb(TESTvalue, shmems[0]);
+ }
#else
- ARCRESET;
- JIFFER(RESETtime);
+ ARCRESET;
+ JIFFER(RESETtime);
#endif
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- {
- u_long ptr;
- ptr=(u_long)(*shmem);
-
- if (readb(ptr) == TESTvalue) /* found one */
- {
- int probe_more;
- BUGMSG2(D_INIT,"%lXh)\n", *shmem);
- openparen=0;
-
- /* register the card */
- if (init_once == 1 && numshmems > 1)
- probe_more = numshmems - 1;
- else
- probe_more = 0;
- retval=arc90xx_found(dev,*port,airq,*shmem,probe_more);
- if (retval) openparen=0;
-
- /* remove shmem from the list */
- *shmem=shmems[numshmems-1];
- numshmems--;
-
- break;
- }
- else
- {
- BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
- }
- }
-
- if (openparen)
- {
- BUGMSG2(D_INIT,"no matching shmem)\n");
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- }
+ for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) {
+ u_long ptr;
+ ptr = (u_long) (*shmem);
+
+ if (readb(ptr) == TESTvalue) { /* found one */
+ int probe_more;
+ BUGMSG2(D_INIT, "%lXh)\n", *shmem);
+ openparen = 0;
+
+ /* register the card */
+ if (init_once == 1 && numshmems > 1)
+ probe_more = numshmems - 1;
+ else
+ probe_more = 0;
+ retval = arc90xx_found(dev, *port, airq, *shmem, probe_more);
+ if (retval)
+ openparen = 0;
+
+ /* remove shmem from the list */
+ *shmem = shmems[numshmems - 1];
+ numshmems--;
+
+ break;
+ } else {
+ BUGMSG2(D_INIT_REASONS, "%Xh-", readb(ptr));
+ }
+ }
- *port=ports[numports-1];
- numports--;
- port--;
+ if (openparen) {
+ BUGMSG2(D_INIT, "no matching shmem)\n");
+ BUGMSG(D_INIT_REASONS, "Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint = 0;
+ }
+ *port = ports[numports - 1];
+ numports--;
+ port--;
- if (!retval) break;
- }
- BUGMSG(D_INIT_REASONS,"\n");
+ if (!retval)
+ break;
+ }
+ BUGMSG(D_INIT_REASONS, "\n");
- /* Now put back TESTvalue on all leftover shmems.
- */
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- writeb(TESTvalue,*shmem);
+ /* Now put back TESTvalue on all leftover shmems.
+ */
+ for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++)
+ writeb(TESTvalue, *shmem);
- if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n");
- return retval;
+ if (retval)
+ BUGMSG(D_NORMAL, "Stage 5: No ARCnet cards found.\n");
+ return retval;
}
/* Set up the struct device associated with this card. Called after
* probing succeeds.
*/
-__initfunc(static int arc90xx_found(struct device *dev,int ioaddr,int airq, u_long shmem, int more))
+__initfunc(static int arc90xx_found(struct device *dev, int ioaddr, int airq, u_long shmem, int more))
{
- struct arcnet_local *lp;
- u_long first_mirror,last_mirror;
- int mirror_size;
-
- /* reserve the irq */
- if (request_irq(airq,&arcnet_interrupt,0,"arcnet (90xx)",dev))
- {
- BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
- return -ENODEV;
- }
- dev->irq=airq;
-
- /* reserve the I/O region - guaranteed to work by check_region */
- request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (90xx)");
- dev->base_addr=ioaddr;
-
- /* find the real shared memory start/end points, including mirrors */
+ struct arcnet_local *lp;
+ u_long first_mirror, last_mirror;
+ int mirror_size;
+
+ /* reserve the irq */
+ if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) {
+ BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq);
+ return -ENODEV;
+ }
+ dev->irq = airq;
+
+ /* reserve the I/O region - guaranteed to work by check_region */
+ request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)");
+ dev->base_addr = ioaddr;
+
+ /* find the real shared memory start/end points, including mirrors */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
- /* guess the actual size of one "memory mirror" - the number of
- * bytes between copies of the shared memory. On most cards, it's
- * 2k (or there are no mirrors at all) but on some, it's 4k.
- */
- mirror_size=MIRROR_SIZE;
- if (readb(shmem)==TESTvalue
- && readb(shmem-mirror_size)!=TESTvalue
- && readb(shmem-2*mirror_size)==TESTvalue)
- mirror_size*=2;
-
- first_mirror=last_mirror=shmem;
- while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
- first_mirror+=mirror_size;
-
- while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size;
- last_mirror-=mirror_size;
-
- dev->mem_start=first_mirror;
- dev->mem_end=last_mirror+MIRROR_SIZE-1;
- dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
- dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
-
- /* Initialize the rest of the device structure. */
-
- dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
- if (dev->priv == NULL)
- {
- free_irq(airq,dev);
- release_region(ioaddr,ARCNET_TOTAL_SIZE);
- return -ENOMEM;
- }
- memset(dev->priv,0,sizeof(struct arcnet_local));
- lp=(struct arcnet_local *)(dev->priv);
- lp->card_type = ARC_90xx;
- lp->card_type_str = "COM 90xx";
- lp->arcnet_reset=arc90xx_reset;
- lp->asetmask=arc90xx_setmask;
- lp->astatus=arc90xx_status;
- lp->acommand=arc90xx_command;
- lp->openclose_device=arc90xx_openclose;
- lp->prepare_tx=arc90xx_prepare_tx;
- lp->inthandler=arc90xx_inthandler;
-
- /* Fill in the fields of the device structure with generic
- * values.
- */
- arcnet_setup(dev);
-
- /* And now fill particular fields with arcnet values */
- dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
- dev->hard_header_len=sizeof(struct ClientData);
- lp->sequence=1;
- lp->recbuf=0;
-
- BUGMSG(D_DURING,"ClientData header size is %d.\n",
- sizeof(struct ClientData));
- BUGMSG(D_DURING,"HardHeader size is %d.\n",
- sizeof(struct archdr));
-
- /* get and check the station ID from offset 1 in shmem */
- lp->stationid = readb(first_mirror+1);
-
- if (lp->stationid==0)
- BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
- "for broadcasts!\n");
- else if (lp->stationid==255)
- BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
- "DOS networking programs!\n");
- dev->dev_addr[0]=lp->stationid;
-
- BUGMSG(D_NORMAL,"ARCnet COM90xx: station %02Xh found at %03lXh, IRQ %d, "
- "ShMem %lXh (%ld*%xh).\n",
- lp->stationid,
- dev->base_addr, dev->irq, dev->mem_start,
- (dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size);
-
- /* OK. We're finished. If there are probably other cards, add other
- * COM90xx drivers to the device chain, so they get probed later.
- */
+ /* guess the actual size of one "memory mirror" - the number of
+ * bytes between copies of the shared memory. On most cards, it's
+ * 2k (or there are no mirrors at all) but on some, it's 4k.
+ */
+ mirror_size = MIRROR_SIZE;
+ if (readb(shmem) == TESTvalue
+ && readb(shmem - mirror_size) != TESTvalue
+ && readb(shmem - 2 * mirror_size) == TESTvalue)
+ mirror_size *= 2;
+
+ first_mirror = last_mirror = shmem;
+ while (readb(first_mirror) == TESTvalue)
+ first_mirror -= mirror_size;
+ first_mirror += mirror_size;
+
+ while (readb(last_mirror) == TESTvalue)
+ last_mirror += mirror_size;
+ last_mirror -= mirror_size;
+
+ dev->mem_start = first_mirror;
+ dev->mem_end = last_mirror + MIRROR_SIZE - 1;
+ dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
+ dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
+
+ /* Initialize the rest of the device structure. */
+
+ dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
+ if (dev->priv == NULL) {
+ free_irq(airq, dev);
+ release_region(ioaddr, ARCNET_TOTAL_SIZE);
+ return -ENOMEM;
+ }
+ memset(dev->priv, 0, sizeof(struct arcnet_local));
+ lp = (struct arcnet_local *) (dev->priv);
+ lp->card_type = ARC_90xx;
+ lp->card_type_str = "COM 90xx";
+ lp->arcnet_reset = arc90xx_reset;
+ lp->asetmask = arc90xx_setmask;
+ lp->astatus = arc90xx_status;
+ lp->acommand = arc90xx_command;
+ lp->openclose_device = arc90xx_openclose;
+ lp->prepare_tx = arc90xx_prepare_tx;
+ lp->inthandler = arc90xx_inthandler;
+
+ /* Fill in the fields of the device structure with generic
+ * values.
+ */
+ arcnet_setup(dev);
+
+ /* And now fill particular fields with arcnet values */
+ dev->mtu = 1500; /* completely arbitrary - agrees with ether, though */
+ dev->hard_header_len = sizeof(struct ClientData);
+ lp->sequence = 1;
+ lp->recbuf = 0;
+
+ BUGMSG(D_DURING, "ClientData header size is %d.\n",
+ sizeof(struct ClientData));
+ BUGMSG(D_DURING, "HardHeader size is %d.\n",
+ sizeof(struct archdr));
+
+ /* get and check the station ID from offset 1 in shmem */
+ lp->stationid = readb(first_mirror + 1);
+
+ if (lp->stationid == 0)
+ BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved "
+ "for broadcasts!\n");
+ else if (lp->stationid == 255)
+ BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse "
+ "DOS networking programs!\n");
+ dev->dev_addr[0] = lp->stationid;
+
+ BUGMSG(D_NORMAL, "ARCnet COM90xx: station %02Xh found at %03lXh, IRQ %d, "
+ "ShMem %lXh (%ld*%xh).\n",
+ lp->stationid,
+ dev->base_addr, dev->irq, dev->mem_start,
+ (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size);
+
+ /* OK. We're finished. If there are probably other cards, add other
+ * COM90xx drivers to the device chain, so they get probed later.
+ */
#ifndef MODULE
- while (!com90xx_explicit && more--)
- {
- if (arcnet_num_devs < MAX_ARCNET_DEVS)
- {
- arcnet_devs[arcnet_num_devs].next=dev->next;
- dev->next=&arcnet_devs[arcnet_num_devs];
- dev=dev->next;
- dev->name=(char *)&arcnet_dev_names[arcnet_num_devs];
- arcnet_num_devs++;
- }
- else
- {
- BUGMSG(D_NORMAL, "Too many arcnet devices - no more will be probed for.\n");
- return 0;
+ while (!com90xx_explicit && more--) {
+ if (arcnet_num_devs < MAX_ARCNET_DEVS) {
+ arcnet_devs[arcnet_num_devs].next = dev->next;
+ dev->next = &arcnet_devs[arcnet_num_devs];
+ dev = dev->next;
+ dev->name = (char *) &arcnet_dev_names[arcnet_num_devs];
+ arcnet_num_devs++;
+ } else {
+ BUGMSG(D_NORMAL, "Too many arcnet devices - no more will be probed for.\n");
+ return 0;
+ }
+ arcnet_makename(dev->name);
+ dev->init = arc90xx_probe;
}
- arcnet_makename(dev->name);
- dev->init=arc90xx_probe;
- }
#endif
- return 0;
+ return 0;
}
/* Do a hardware reset on the card, and set up necessary registers.
- *
+
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
*
* However, it does make sure the card is in a defined state.
*/
-int arc90xx_reset(struct device *dev,int reset_delay)
+int arc90xx_reset(struct device *dev, int reset_delay)
{
- struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
- short ioaddr=dev->base_addr;
- int delayval,recbuf=lp->recbuf;
-
- if (reset_delay==3)
- {
- ARCRESET;
- return 0;
- }
-
- /* no IRQ's, please! */
- lp->intmask=0;
- SETMASK;
-
- BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
- dev->name,ARCSTATUS);
-
- if (reset_delay)
- {
- /* reset the card */
- ARCRESET;
- JIFFER(RESETtime);
- }
-
- ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
- ACOMMAND(CFLAGScmd|CONFIGclear);
-
- /* verify that the ARCnet signature byte is present */
- if (readb(dev->mem_start) != TESTvalue)
- {
- BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
- return 1;
- }
-
- /* clear out status variables */
- recbuf=lp->recbuf=0;
- lp->txbuf=2;
-
- /* enable extended (512-byte) packets */
- ACOMMAND(CONFIGcmd|EXTconf);
+ struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+ short ioaddr = dev->base_addr;
+ int delayval, recbuf = lp->recbuf;
+
+ if (reset_delay == 3) {
+ ARCRESET;
+ return 0;
+ }
+ /* no IRQ's, please! */
+ lp->intmask = 0;
+ SETMASK;
+
+ BUGMSG(D_INIT, "Resetting %s (status=%Xh)\n",
+ dev->name, ARCSTATUS);
+
+ if (reset_delay) {
+ /* reset the card */
+ ARCRESET;
+ JIFFER(RESETtime);
+ }
+ ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
+ ACOMMAND(CFLAGScmd | CONFIGclear);
+
+ /* verify that the ARCnet signature byte is present */
+ if (readb(dev->mem_start) != TESTvalue) {
+ BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
+ return 1;
+ }
+ /* clear out status variables */
+ recbuf = lp->recbuf = 0;
+ lp->txbuf = 2;
+
+ /* enable extended (512-byte) packets */
+ ACOMMAND(CONFIGcmd | EXTconf);
#ifndef SLOW_XMIT_COPY
- /* clean out all the memory to make debugging make more sense :) */
- BUGLVL(D_DURING)
- memset_io(dev->mem_start,0x42,2048);
+ /* clean out all the memory to make debugging make more sense :) */
+ BUGLVL(D_DURING)
+ memset_io(dev->mem_start, 0x42, 2048);
#endif
- /* and enable receive of our first packet to the first buffer */
- EnableReceiver();
+ /* and enable receive of our first packet to the first buffer */
+ EnableReceiver();
- /* re-enable interrupts */
- lp->intmask|=NORXflag;
+ /* re-enable interrupts */
+ lp->intmask |= NORXflag;
#ifdef DETECT_RECONFIGS
- lp->intmask|=RECONflag;
+ lp->intmask |= RECONflag;
#endif
- SETMASK;
+ SETMASK;
- /* done! return success. */
- return 0;
+ /* done! return success. */
+ return 0;
}
static void arc90xx_openclose(int open)
{
- if (open)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
+ if (open)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
}
static void arc90xx_setmask(struct device *dev, u_char mask)
{
- short ioaddr=dev->base_addr;
+ short ioaddr = dev->base_addr;
- AINTMASK(mask);
+ AINTMASK(mask);
}
static u_char arc90xx_status(struct device *dev)
{
- short ioaddr=dev->base_addr;
+ short ioaddr = dev->base_addr;
- return ARCSTATUS;
+ return ARCSTATUS;
}
static void arc90xx_command(struct device *dev, u_char cmd)
{
- short ioaddr=dev->base_addr;
+ short ioaddr = dev->base_addr;
- ACOMMAND(cmd);
+ ACOMMAND(cmd);
}
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
-static void
-arc90xx_inthandler(struct device *dev)
+static void arc90xx_inthandler(struct device *dev)
{
- struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
- int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
-
- AINTMASK(0);
-
- BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
- ARCSTATUS,lp->intmask);
-
- do
- {
- status = ARCSTATUS;
- didsomething=0;
-
- /* RESET flag was enabled - card is resetting and if RX
- * is disabled, it's NOT because we just got a packet.
- */
- if (status & RESETflag)
- {
- BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
- status);
- arc90xx_reset(dev,0);
-
- /* all other flag values are just garbage */
- break;
- }
+ struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+ int ioaddr = dev->base_addr, status, boguscount = 3, didsomething;
- /* RX is inhibited - we must have received something. */
- if (status & lp->intmask & NORXflag)
- {
- int recbuf=lp->recbuf=!lp->recbuf;
+ AINTMASK(0);
- BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
- status);
+ BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
+ ARCSTATUS, lp->intmask);
- /* enable receive of our next packet */
- EnableReceiver();
+ do {
+ status = ARCSTATUS;
+ didsomething = 0;
- /* Got a packet. */
- arc90xx_rx(dev,!recbuf);
+ /* RESET flag was enabled - card is resetting and if RX
+ * is disabled, it's NOT because we just got a packet.
+ */
+ if (status & RESETflag) {
+ BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n",
+ status);
+ arc90xx_reset(dev, 0);
- didsomething++;
- }
-
- /* it can only be an xmit-done irq if we're xmitting :) */
- /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
- if (status & lp->intmask & TXFREEflag)
- {
- struct Outgoing *out=&(lp->outgoing);
- int was_sending=lp->sending;
-
- lp->intmask &= ~TXFREEflag;
-
- lp->in_txhandler++;
- if (was_sending) lp->sending--;
-
- BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
- status,out->numsegs,out->segnum,out->skb);
-
- if (was_sending && !(status&TXACKflag))
- {
- if (lp->lasttrans_dest != 0)
- {
- BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
- status,lp->lasttrans_dest);
- lp->stats.tx_errors++;
- lp->stats.tx_carrier_errors++;
- }
- else
- {
- BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
- status,
- lp->lasttrans_dest);
+ /* all other flag values are just garbage */
+ break;
}
- }
-
- /* send packet if there is one */
- arcnet_go_tx(dev,0);
- didsomething++;
-
- if (lp->intx)
- {
- BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
- ARCSTATUS,lp->intx);
- lp->in_txhandler--;
- continue;
- }
-
- if (!lp->outgoing.skb)
- {
- BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
-
- /* inform upper layers */
- if (!lp->txready) arcnet_tx_done(dev, lp);
- lp->in_txhandler--;
- continue;
- }
-
- /* if more than one segment, and not all segments
- * are done, then continue xmit.
- */
- if (out->segnum<out->numsegs)
- arcnetA_continue_tx(dev);
- arcnet_go_tx(dev,0);
-
- /* if segnum==numsegs, the transmission is finished;
- * free the skb.
- */
- if (out->segnum>=out->numsegs)
- {
- /* transmit completed */
- out->segnum++;
- if (out->skb)
- {
- lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb);
- }
- out->skb=NULL;
+ /* RX is inhibited - we must have received something. */
+ if (status & lp->intmask & NORXflag) {
+ int recbuf = lp->recbuf = !lp->recbuf;
- /* inform upper layers */
- if (!lp->txready) arcnet_tx_done(dev, lp);
- }
- didsomething++;
+ BUGMSG(D_DURING, "receive irq (status=%Xh)\n",
+ status);
- lp->in_txhandler--;
- }
- else if (lp->txready && !lp->sending && !lp->intx)
- {
- BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
- status);
- arcnet_go_tx(dev,0);
- didsomething++;
- }
+ /* enable receive of our next packet */
+ EnableReceiver();
+
+ /* Got a packet. */
+ arc90xx_rx(dev, !recbuf);
+ didsomething++;
+ }
+ /* it can only be an xmit-done irq if we're xmitting :) */
+ /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending) */
+ if (status & lp->intmask & TXFREEflag) {
+ struct Outgoing *out = &(lp->outgoing);
+ int was_sending = lp->sending;
+
+ lp->intmask &= ~TXFREEflag;
+
+ lp->in_txhandler++;
+ if (was_sending)
+ lp->sending--;
+
+ BUGMSG(D_DURING, "TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
+ status, out->numsegs, out->segnum, out->skb);
+
+ if (was_sending && !(status & TXACKflag)) {
+ if (lp->lasttrans_dest != 0) {
+ BUGMSG(D_EXTRA, "transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
+ status, lp->lasttrans_dest);
+ lp->stats.tx_errors++;
+ lp->stats.tx_carrier_errors++;
+ } else {
+ BUGMSG(D_DURING, "broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
+ status,
+ lp->lasttrans_dest);
+ }
+ }
+ /* send packet if there is one */
+ arcnet_go_tx(dev, 0);
+ didsomething++;
+
+ if (lp->intx) {
+ BUGMSG(D_DURING, "TXDONE while intx! (status=%Xh, intx=%d)\n",
+ ARCSTATUS, lp->intx);
+ lp->in_txhandler--;
+ continue;
+ }
+ if (!lp->outgoing.skb) {
+ BUGMSG(D_DURING, "TX IRQ done: no split to continue.\n");
+
+ /* inform upper layers */
+ if (!lp->txready)
+ arcnet_tx_done(dev, lp);
+ lp->in_txhandler--;
+ continue;
+ }
+ /* if more than one segment, and not all segments
+ * are done, then continue xmit.
+ */
+ if (out->segnum < out->numsegs)
+ arcnetA_continue_tx(dev);
+ arcnet_go_tx(dev, 0);
+
+ /* if segnum==numsegs, the transmission is finished;
+ * free the skb.
+ */
+ if (out->segnum >= out->numsegs) {
+ /* transmit completed */
+ out->segnum++;
+ if (out->skb) {
+ lp->stats.tx_bytes += out->skb->len;
+ dev_kfree_skb(out->skb);
+ }
+ out->skb = NULL;
+
+ /* inform upper layers */
+ if (!lp->txready)
+ arcnet_tx_done(dev, lp);
+ }
+ didsomething++;
+
+ lp->in_txhandler--;
+ } else if (lp->txready && !lp->sending && !lp->intx) {
+ BUGMSG(D_NORMAL, "recovery from silent TX (status=%Xh)\n",
+ status);
+ arcnet_go_tx(dev, 0);
+ didsomething++;
+ }
#ifdef DETECT_RECONFIGS
- if (status & (lp->intmask) & RECONflag)
- {
- ACOMMAND(CFLAGScmd|CONFIGclear);
- lp->stats.tx_carrier_errors++;
+ if (status & (lp->intmask) & RECONflag) {
+ ACOMMAND(CFLAGScmd | CONFIGclear);
+ lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
- BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
- status);
-#endif /* SHOW_RECONFIGS */
+ BUGMSG(D_NORMAL, "Network reconfiguration detected (status=%Xh)\n",
+ status);
+#endif /* SHOW_RECONFIGS */
#ifdef RECON_THRESHOLD
- /* is the RECON info empty or old? */
- if (!lp->first_recon || !lp->last_recon ||
- jiffies-lp->last_recon > HZ*10)
- {
- if (lp->network_down)
- BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
- lp->first_recon=lp->last_recon=jiffies;
- lp->num_recons=lp->network_down=0;
-
- BUGMSG(D_DURING,"recon: clearing counters.\n");
- }
- else /* add to current RECON counter */
- {
- lp->last_recon=jiffies;
- lp->num_recons++;
-
- BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
- lp->num_recons,
- (lp->last_recon-lp->first_recon)/HZ,
- lp->network_down);
-
- /* if network is marked up;
- * and first_recon and last_recon are 60+ sec
- * apart;
- * and the average no. of recons counted is
- * > RECON_THRESHOLD/min;
- * then print a warning message.
- */
- if (!lp->network_down
- && (lp->last_recon-lp->first_recon)<=HZ*60
- && lp->num_recons >= RECON_THRESHOLD)
- {
- lp->network_down=1;
- BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
- }
- else if (!lp->network_down
- && lp->last_recon-lp->first_recon > HZ*60)
- {
- /* reset counters if we've gone for
- * over a minute.
- */
- lp->first_recon=lp->last_recon;
- lp->num_recons=1;
- }
- }
- }
- else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
- {
- if (lp->network_down)
- BUGMSG(D_NORMAL,"cabling restored?\n");
- lp->first_recon=lp->last_recon=0;
- lp->num_recons=lp->network_down=0;
-
- BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
+ /* is the RECON info empty or old? */
+ if (!lp->first_recon || !lp->last_recon ||
+ jiffies - lp->last_recon > HZ * 10) {
+ if (lp->network_down)
+ BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n");
+ lp->first_recon = lp->last_recon = jiffies;
+ lp->num_recons = lp->network_down = 0;
+
+ BUGMSG(D_DURING, "recon: clearing counters.\n");
+ } else { /* add to current RECON counter */
+ lp->last_recon = jiffies;
+ lp->num_recons++;
+
+ BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n",
+ lp->num_recons,
+ (lp->last_recon - lp->first_recon) / HZ,
+ lp->network_down);
+
+ /* if network is marked up;
+ * and first_recon and last_recon are 60+ sec
+ * apart;
+ * and the average no. of recons counted is
+ * > RECON_THRESHOLD/min;
+ * then print a warning message.
+ */
+ if (!lp->network_down
+ && (lp->last_recon - lp->first_recon) <= HZ * 60
+ && lp->num_recons >= RECON_THRESHOLD) {
+ lp->network_down = 1;
+ BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n");
+ } else if (!lp->network_down
+ && lp->last_recon - lp->first_recon > HZ * 60) {
+ /* reset counters if we've gone for
+ * over a minute.
+ */
+ lp->first_recon = lp->last_recon;
+ lp->num_recons = 1;
+ }
+ }
+ } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) {
+ if (lp->network_down)
+ BUGMSG(D_NORMAL, "cabling restored?\n");
+ lp->first_recon = lp->last_recon = 0;
+ lp->num_recons = lp->network_down = 0;
+
+ BUGMSG(D_DURING, "not recon: clearing counters anyway.\n");
#endif
- }
-#endif /* DETECT_RECONFIGS */
- } while (--boguscount && didsomething);
+ }
+#endif /* DETECT_RECONFIGS */
+ } while (--boguscount && didsomething);
- BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
- ARCSTATUS,boguscount);
- BUGMSG(D_DURING,"\n");
+ BUGMSG(D_DURING, "net_interrupt complete (status=%Xh, count=%d)\n",
+ ARCSTATUS, boguscount);
+ BUGMSG(D_DURING, "\n");
- SETMASK; /* put back interrupt mask */
+ SETMASK; /* put back interrupt mask */
}
@@ -987,57 +912,52 @@ arc90xx_inthandler(struct device *dev)
* arcnet_rx routing to deal with it.
*/
-static void
-arc90xx_rx(struct device *dev,int recbuf)
+static void arc90xx_rx(struct device *dev, int recbuf)
{
- struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
- int ioaddr=dev->base_addr;
- union ArcPacket *arcpacket=
- (union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512);
- u_char *arcsoft;
- short length,offset;
- u_char daddr,saddr;
-
- lp->stats.rx_packets++;
-
- saddr=arcpacket->hardheader.source;
-
- /* if source is 0, it's a "used" packet! */
- if (saddr==0)
- {
- BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
- ARCSTATUS);
- lp->stats.rx_errors++;
- return;
- }
- /* Set source address to zero to mark it as old */
-
- arcpacket->hardheader.source=0;
-
- daddr=arcpacket->hardheader.destination;
-
- if (arcpacket->hardheader.offset1) /* Normal Packet */
- {
- offset=arcpacket->hardheader.offset1;
- arcsoft=&arcpacket->raw[offset];
- length=256-offset;
- }
- else /* ExtendedPacket or ExceptionPacket */
- {
- offset=arcpacket->hardheader.offset2;
- arcsoft=&arcpacket->raw[offset];
-
- length=512-offset;
- }
-
- arcnet_rx(lp, arcsoft, length, saddr, daddr);
-
- BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
+ struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+ int ioaddr = dev->base_addr;
+ union ArcPacket *arcpacket =
+ (union ArcPacket *) phys_to_virt(dev->mem_start + recbuf * 512);
+ u_char *arcsoft;
+ short length, offset;
+ u_char daddr, saddr;
+
+ lp->stats.rx_packets++;
+
+ saddr = arcpacket->hardheader.source;
+
+ /* if source is 0, it's a "used" packet! */
+ if (saddr == 0) {
+ BUGMSG(D_NORMAL, "discarding old packet. (status=%Xh)\n",
+ ARCSTATUS);
+ lp->stats.rx_errors++;
+ return;
+ }
+ /* Set source address to zero to mark it as old */
+
+ arcpacket->hardheader.source = 0;
+
+ daddr = arcpacket->hardheader.destination;
+
+ if (arcpacket->hardheader.offset1) { /* Normal Packet */
+ offset = arcpacket->hardheader.offset1;
+ arcsoft = &arcpacket->raw[offset];
+ length = 256 - offset;
+ } else { /* ExtendedPacket or ExceptionPacket */
+ offset = arcpacket->hardheader.offset2;
+ arcsoft = &arcpacket->raw[offset];
+
+ length = 512 - offset;
+ }
+
+ arcnet_rx(lp, arcsoft, length, saddr, daddr);
+
+ BUGLVL(D_RX) arcnet_dump_packet(lp->adev, arcpacket->raw, length > 240, "rx");
#ifndef SLOW_XMIT_COPY
- /* clean out the page to make debugging make more sense :) */
- BUGLVL(D_DURING)
- memset((void *)arcpacket->raw,0x42,512);
+ /* clean out the page to make debugging make more sense :) */
+ BUGLVL(D_DURING)
+ memset((void *) arcpacket->raw, 0x42, 512);
#endif
}
@@ -1045,91 +965,84 @@ arc90xx_rx(struct device *dev,int recbuf)
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
-static void
-arc90xx_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
- char *data,int length,int daddr,int exceptA, int offset)
+static void arc90xx_prepare_tx(struct device *dev, u_char * hdr, int hdrlen,
+ char *data, int length, int daddr, int exceptA, int offset)
{
- struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
- union ArcPacket *arcpacket =
- (union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1));
+ struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+ union ArcPacket *arcpacket =
+ (union ArcPacket *) phys_to_virt(dev->mem_start + 512 * (lp->txbuf ^ 1));
#ifdef SLOW_XMIT_COPY
- char *iptr,*iend,*optr;
+ char *iptr, *iend, *optr;
#endif
- lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
+ lp->txbuf = lp->txbuf ^ 1; /* XOR with 1 to alternate between 2 and 3 */
- length+=hdrlen;
+ length += hdrlen;
- BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
- hdr,length,data);
+ BUGMSG(D_TX, "arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
+ hdr, length, data);
#ifndef SLOW_XMIT_COPY
- /* clean out the page to make debugging make more sense :) */
- BUGLVL(D_DURING)
- memset_io(dev->mem_start+lp->txbuf*512,0x42,512);
+ /* clean out the page to make debugging make more sense :) */
+ BUGLVL(D_DURING)
+ memset_io(dev->mem_start + lp->txbuf * 512, 0x42, 512);
#endif
- arcpacket->hardheader.destination=daddr;
-
- /* load packet into shared memory */
- if (length<=MTU) /* Normal (256-byte) Packet */
- arcpacket->hardheader.offset1=offset=offset?offset:256-length;
-
- else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
- {
- arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=offset?offset:512-length;
- }
- else if (exceptA) /* RFC1201 Exception Packet */
- {
- arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=512-length-4;
-
- /* exception-specific stuff - these four bytes
- * make the packet long enough to fit in a 512-byte
- * frame.
- */
-
- arcpacket->raw[offset+0]=hdr[0];
- arcpacket->raw[offset+1]=0xFF; /* FF flag */
- arcpacket->raw[offset+2]=0xFF; /* FF padding */
- arcpacket->raw[offset+3]=0xFF; /* FF padding */
- offset+=4;
- }
- else /* "other" Exception packet */
- {
- /* RFC1051 - set 4 trailing bytes to 0 */
- memset(&arcpacket->raw[508],0,4);
-
- /* now round up to MinTU */
- arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=512-MinTU;
- }
-
- /* copy the packet into ARCnet shmem
- * - the first bytes of ClientData header are skipped
- */
-
- memcpy((u_char*)arcpacket+offset, (u_char*)hdr,hdrlen);
+ arcpacket->hardheader.destination = daddr;
+
+ /* load packet into shared memory */
+ if (length <= MTU) /* Normal (256-byte) Packet */
+ arcpacket->hardheader.offset1 = offset = offset ? offset : 256 - length;
+
+ else if (length >= MinTU || offset) { /* Extended (512-byte) Packet */
+ arcpacket->hardheader.offset1 = 0;
+ arcpacket->hardheader.offset2 = offset = offset ? offset : 512 - length;
+ } else if (exceptA) { /* RFC1201 Exception Packet */
+ arcpacket->hardheader.offset1 = 0;
+ arcpacket->hardheader.offset2 = offset = 512 - length - 4;
+
+ /* exception-specific stuff - these four bytes
+ * make the packet long enough to fit in a 512-byte
+ * frame.
+ */
+
+ arcpacket->raw[offset + 0] = hdr[0];
+ arcpacket->raw[offset + 1] = 0xFF; /* FF flag */
+ arcpacket->raw[offset + 2] = 0xFF; /* FF padding */
+ arcpacket->raw[offset + 3] = 0xFF; /* FF padding */
+ offset += 4;
+ } else { /* "other" Exception packet */
+ /* RFC1051 - set 4 trailing bytes to 0 */
+ memset(&arcpacket->raw[508], 0, 4);
+
+ /* now round up to MinTU */
+ arcpacket->hardheader.offset1 = 0;
+ arcpacket->hardheader.offset2 = offset = 512 - MinTU;
+ }
+
+ /* copy the packet into ARCnet shmem
+ * - the first bytes of ClientData header are skipped
+ */
+
+ memcpy((u_char *) arcpacket + offset, (u_char *) hdr, hdrlen);
#ifdef SLOW_XMIT_COPY
- for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcpacket+offset+hdrlen;
- iptr<iend; iptr++,optr++)
- {
- *optr=*iptr;
- /*udelay(5);*/
- }
+ for (iptr = data, iend = iptr + length - hdrlen, optr = (char *) arcpacket + offset + hdrlen;
+ iptr < iend; iptr++, optr++) {
+ *optr = *iptr;
+ /*udelay(5); */
+ }
#else
- memcpy((u_char*)arcpacket+offset+hdrlen, data,length-hdrlen);
+ memcpy((u_char *) arcpacket + offset + hdrlen, data, length - hdrlen);
#endif
- BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
- daddr,length);
+ BUGMSG(D_DURING, "transmitting packet to station %02Xh (%d bytes)\n",
+ daddr, length);
- BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
+ BUGLVL(D_TX) arcnet_dump_packet(dev, arcpacket->raw, length > MTU, "tx");
- lp->lastload_dest=daddr;
- lp->txready=lp->txbuf; /* packet is ready for sending */
+ lp->lastload_dest = daddr;
+ lp->txready = lp->txbuf; /* packet is ready for sending */
}
@@ -1143,118 +1056,112 @@ arc90xx_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
#ifdef MODULE
static char devicename[9] = "";
-static struct device thiscard = {
- devicename, /* device name is inserted by linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0, 0, /* I/O address, IRQ */
- 0, 0, 0, NULL, arc90xx_probe
+static struct device thiscard =
+{
+ devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+ 0, 0, 0, 0,
+ 0, 0, /* I/O address, IRQ */
+ 0, 0, 0, NULL, arc90xx_probe
};
int init_module(void)
{
- struct device *dev=&thiscard;
- if (device)
- strcpy(dev->name,device);
- else arcnet_makename(dev->name);
-
- dev->base_addr=io;
-
- dev->irq=irq;
- if (dev->irq==2) dev->irq=9;
-
- if (shmem)
- {
- dev->mem_start=shmem;
- dev->mem_end=thiscard.mem_start+512*4-1;
- dev->rmem_start=thiscard.mem_start+512*0;
- dev->rmem_end=thiscard.mem_start+512*2-1;
- }
-
- if (register_netdev(dev) != 0)
- return -EIO;
- arcnet_use_count(1);
- return 0;
+ struct device *dev = &thiscard;
+ if (device)
+ strcpy(dev->name, device);
+ else
+ arcnet_makename(dev->name);
+
+ dev->base_addr = io;
+
+ dev->irq = irq;
+ if (dev->irq == 2)
+ dev->irq = 9;
+
+ if (shmem) {
+ dev->mem_start = shmem;
+ dev->mem_end = thiscard.mem_start + 512 * 4 - 1;
+ dev->rmem_start = thiscard.mem_start + 512 * 0;
+ dev->rmem_end = thiscard.mem_start + 512 * 2 - 1;
+ }
+ if (register_netdev(dev) != 0)
+ return -EIO;
+ arcnet_use_count(1);
+ return 0;
}
void cleanup_module(void)
{
- struct device *dev=&thiscard;
- int ioaddr=dev->mem_start;
+ struct device *dev = &thiscard;
+ int ioaddr = dev->mem_start;
- if (dev->start) (*dev->stop)(dev);
+ if (dev->start)
+ (*dev->stop) (dev);
- /* Flush TX and disable RX */
- if (ioaddr)
- {
- AINTMASK(0); /* disable IRQ's */
- ACOMMAND(NOTXcmd); /* stop transmit */
- ACOMMAND(NORXcmd); /* disable receive */
+ /* Flush TX and disable RX */
+ if (ioaddr) {
+ AINTMASK(0); /* disable IRQ's */
+ ACOMMAND(NOTXcmd); /* stop transmit */
+ ACOMMAND(NORXcmd); /* disable receive */
#if defined(IO_MAPPED_BUFFERS) && !defined(COM20020)
- /* Set the thing back to MMAP mode, in case the old
- driver is loaded later */
- outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG);
+ /* Set the thing back to MMAP mode, in case the old
+ driver is loaded later */
+ outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
#endif
- }
-
- if (dev->irq)
- {
- free_irq(dev->irq,dev);
- }
-
- if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
- arcnet_use_count(0);
+ }
+ if (dev->irq) {
+ free_irq(dev->irq, dev);
+ }
+ if (dev->base_addr)
+ release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+ unregister_netdev(dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ arcnet_use_count(0);
}
#else
-__initfunc(void com90xx_setup (char *str, int *ints))
+__initfunc(void com90xx_setup(char *str, int *ints))
{
- struct device *dev;
+ struct device *dev;
- if (arcnet_num_devs == MAX_ARCNET_DEVS)
- {
- printk("com90xx: Too many ARCnet devices registered (max %d).\n",
- MAX_ARCNET_DEVS);
- return;
- }
-
- if (!ints[0] && (!str || !*str))
- {
- printk("com90xx: Disabled.\n");
- com90xx_explicit++;
- return;
- }
-
- dev=&arcnet_devs[arcnet_num_devs];
+ if (arcnet_num_devs == MAX_ARCNET_DEVS) {
+ printk("com90xx: Too many ARCnet devices registered (max %d).\n",
+ MAX_ARCNET_DEVS);
+ return;
+ }
+ if (!ints[0] && (!str || !*str)) {
+ printk("com90xx: Disabled.\n");
+ com90xx_explicit++;
+ return;
+ }
+ dev = &arcnet_devs[arcnet_num_devs];
- dev->dev_addr[3]=3;
- dev->init=arc90xx_probe;
+ dev->dev_addr[3] = 3;
+ dev->init = arc90xx_probe;
- switch(ints[0])
- {
- case 4: /* ERROR */
- printk("com20020: Too many arguments.\n");
+ switch (ints[0]) {
+ case 4: /* ERROR */
+ printk("com20020: Too many arguments.\n");
- case 3: /* Mem address */
- dev->mem_start=ints[3];
+ case 3: /* Mem address */
+ dev->mem_start = ints[3];
- case 2: /* IRQ */
- dev->irq=ints[2];
+ case 2: /* IRQ */
+ dev->irq = ints[2];
- case 1: /* IO address */
- dev->base_addr=ints[1];
- }
+ case 1: /* IO address */
+ dev->base_addr = ints[1];
+ }
- dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
+ dev->name = (char *) &arcnet_dev_names[arcnet_num_devs];
- if (str)
- strncpy(dev->name, str, 9);
+ if (str)
+ strncpy(dev->name, str, 9);
- arcnet_num_devs++;
+ arcnet_num_devs++;
}
-#endif /* MODULE */
+#endif /* MODULE */
diff --git a/drivers/net/cops.c b/drivers/net/cops.c
index 1231d6b36..1c0635c62 100644
--- a/drivers/net/cops.c
+++ b/drivers/net/cops.c
@@ -24,10 +24,16 @@
* Hooks for cops_setup routine
* (not yet implemented).
* 19971101 Jay Schulist Fixes for multiple lt* devices.
+ * 19980607 Steven Hirsch Fixed the badly broken support
+ * for Tangent type cards. Only
+ * tested on Daystar LT200. Some
+ * cleanup of formatting and program
+ * logic. Added emacs 'local-vars'
+ * setup for Jay's brace style.
*/
static const char *version =
- "cops.c:v0.02 3/17/97 Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n";
+"cops.c:v0.04 6/7/98 Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n";
/*
* Sources:
* COPS Localtalk SDK. This provides almost all of the information
@@ -118,17 +124,27 @@ static int irq = 0; /* Default IRQ */
*
* This driver should support:
* TANGENT driver mode:
- * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200
+ * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
+ * COPS LT-1
* DAYNA driver mode:
* Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95,
* Farallon PhoneNET PC III, Farallon PhoneNET PC II
* Other cards possibly supported mode unkown though:
- * Dayna DL2000 (Full length)
+ * Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
*
* Cards NOT supported by this driver but supported by the ltpc.c
* driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
* Farallon PhoneNET PC
* Original Apple LocalTalk PC card
+ *
+ * N.B.
+ *
+ * The Daystar Digital LT200 boards do not support interrupt-driven
+ * IO. You must specify 'io=0xff' as a module parameter to invoke
+ * polled mode. I also believe that the port probing logic is quite
+ * dangerous at best and certainly hopeless for a polled card. Best to
+ * specify both. - Steve H.
+ *
*/
/*
@@ -149,7 +165,9 @@ static int cops_irqlist[] = {
5, 4, 3, 0
};
-/* use 0 for production, 1 for verification, 2 for debug, 3 for very verbose debug */
+static struct timer_list cops_timer;
+
+/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
#ifndef COPS_DEBUG
#define COPS_DEBUG 1
#endif
@@ -181,11 +199,13 @@ static void cops_load (struct device *dev);
static int cops_nodeid (struct device *dev, int nodeid);
static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void cops_poll (unsigned long ltdev);
static void cops_rx (struct device *dev);
static int cops_send_packet (struct sk_buff *skb, struct device *dev);
static void set_multicast_list (struct device *dev);
static int cops_hard_header (struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len);
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len);
static int cops_ioctl (struct device *dev, struct ifreq *rq, int cmd);
static int cops_close (struct device *dev);
@@ -193,11 +213,10 @@ static struct enet_statistics *cops_get_stats (struct device *dev);
/*
- * Check for a network adaptor of this type, and return '0' iff one exists.
+ * Check for a network adaptor of this type, and return '0' iff one exists.
* If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
+ * If dev->base_addr in [1..0x1ff], always return failure.
+ * otherwise go with what we pass in.
*/
__initfunc(int cops_probe(struct device *dev))
{
@@ -212,6 +231,11 @@ __initfunc(int cops_probe(struct device *dev))
else if(base_addr != 0) /* Don't probe at all. */
return -ENXIO;
+ /* FIXME Does this really work for cards which generate irq?
+ * It's definitely N.G. for polled Tangent. sh
+ * Dayna cards don't autoprobe well at all, but if your card is
+ * at IRQ 5 & IO 0x240 we find it every time. ;) JS
+ */
for(i=0; cops_portlist[i]; i++) {
int ioaddr = cops_portlist[i];
if(check_region(ioaddr, COPS_IO_EXTENT))
@@ -232,17 +256,12 @@ __initfunc(static int cops_probe1(struct device *dev, int ioaddr))
{
struct cops_local *lp;
static unsigned version_printed = 0;
- int irqaddr = 0;
- int irqval;
int board = board_type;
if(cops_debug && version_printed++ == 0)
printk("%s", version);
- /* Fill in the 'dev' fields. */
- dev->base_addr = ioaddr;
-
/*
* Since this board has jumpered interrupts, allocate the interrupt
* vector now. There is no point in waiting since no other device
@@ -250,37 +269,47 @@ __initfunc(static int cops_probe1(struct device *dev, int ioaddr))
* interrupts are typically not reported by the boards, and we must
* used AutoIRQ to find them.
*/
-
- if(dev->irq < 2 && irq)
- dev->irq = irq;
-
- if(dev->irq < 2)
+ switch (dev->irq)
{
- irqaddr = cops_irq(ioaddr, board); /* COPS AutoIRQ routine */
- if(irqaddr == 0)
- return -EAGAIN; /* No IRQ found on this port */
- else
- dev->irq = irqaddr;
- }
- else if(dev->irq == 2)
- /*
- * Fixup for users that don't know that IRQ 2 is really
+ case 0:
+ /* COPS AutoIRQ routine */
+ dev->irq = cops_irq(ioaddr, board);
+ if(!dev->irq)
+ return -EINVAL; /* No IRQ found on this port */
+ break;
+
+ case 1:
+ return -EINVAL;
+ break;
+
+ /* Fixup for users that don't know that IRQ 2 is really
* IRQ 9, or don't know which one to set.
*/
- dev->irq = 9;
+ case 2:
+ dev->irq = 9;
+ break;
- /* Snarf the interrupt now. */
- irqval = request_irq(dev->irq, &cops_interrupt, 0, cardname, dev);
+ /* Polled operation requested. Although irq of zero passed as
+ * a parameter tells the init routines to probe, we'll
+ * overload it to denote polled operation at runtime.
+ */
+ case 0xff:
+ dev->irq = 0;
+ break;
- /* If its in use set it to 0 and disallow open() calls.. users can still
- ifconfig the irq one day */
+ default:
+ break;
+ }
- if(irqval)
- dev->irq = 0;
+ /* Reserve any actual interrupt. */
+ if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev))
+ return -EINVAL;
- dev->hard_start_xmit = &cops_send_packet;
+ /* Grab the region so no one else tries to probe our ioports. */
+ request_region(ioaddr, COPS_IO_EXTENT, cardname);
+ dev->base_addr = ioaddr;
- /* Initialize the device structure. */
+ /* Initialize the private device structure. */
dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL);
if(dev->priv == NULL)
return -ENOMEM;
@@ -291,20 +320,10 @@ __initfunc(static int cops_probe1(struct device *dev, int ioaddr))
/* Copy local board variable to lp struct. */
lp->board = board;
- /* Tell the user where the card is and what mode were in. */
- if(board==DAYNA)
- printk("%s: %s found at %#3x, using IRQ %d, in Dayna mode.\n",
- dev->name, cardname, ioaddr, dev->irq);
- if(board==TANGENT)
- printk("%s: %s found at %#3x, using IRQ %d, in Tangent mode.\n",
- dev->name, cardname, ioaddr, dev->irq);
-
- /* Grab the region so no one else tries to probe our ioports. */
- request_region(ioaddr, COPS_IO_EXTENT, cardname);
-
/* Fill in the fields of the device structure with LocalTalk values. */
ltalk_setup(dev);
+ dev->hard_start_xmit = &cops_send_packet;
dev->hard_header = cops_hard_header;
dev->get_stats = cops_get_stats;
dev->open = cops_open;
@@ -313,13 +332,26 @@ __initfunc(static int cops_probe1(struct device *dev, int ioaddr))
dev->set_multicast_list = &set_multicast_list;
dev->mc_list = NULL;
+ /* Tell the user where the card is and what mode we're in. */
+ if(board==DAYNA)
+ printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n",
+ dev->name, cardname, ioaddr, dev->irq);
+ if(board==TANGENT) {
+ if(dev->irq)
+ printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n",
+ dev->name, cardname, ioaddr, dev->irq);
+ else
+ printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n",
+ dev->name, cardname, ioaddr);
+
+ }
return 0;
}
__initfunc(static int cops_irq (int ioaddr, int board))
{ /*
* This does not use the IRQ to determine where the IRQ is. We just
- * assume that when we get a correct status response that is the IRQ then.
+ * assume that when we get a correct status response that it's the IRQ.
* This really just verifies the IO port but since we only have access
* to such a small number of IRQs (5, 4, 3) this is not bad.
* This will probably not work for more than one card.
@@ -367,10 +399,27 @@ __initfunc(static int cops_irq (int ioaddr, int board))
*/
static int cops_open(struct device *dev)
{
+ struct cops_local *lp = (struct cops_local *)dev->priv;
+
if(dev->irq==0)
{
- printk(KERN_WARNING "%s: No irq line set.\n", dev->name);
- return -EAGAIN;
+ /*
+ * I don't know if the Dayna-style boards support polled
+ * operation. For now, only allow it for Tangent.
+ */
+ if(lp->board==TANGENT) /* Poll 20 times per second */
+ {
+ init_timer(&cops_timer);
+ cops_timer.function = cops_poll;
+ cops_timer.data = (unsigned long)dev;
+ cops_timer.expires = jiffies + 5;
+ add_timer(&cops_timer);
+ }
+ else
+ {
+ printk(KERN_WARNING "%s: No irq line set\n", dev->name);
+ return -EAGAIN;
+ }
}
cops_jumpstart(dev); /* Start the card up. */
@@ -397,7 +446,7 @@ static int cops_jumpstart(struct device *dev)
* Once the card has the firmware loaded and has acquired
* the nodeid, if it is reset it will lose it all.
*/
- cops_reset(dev,1); /* Need to reset card before load firmware. */
+ cops_reset(dev,1); /* Need to reset card before load firmware. */
cops_load(dev); /* Load the firmware. */
/*
@@ -412,14 +461,12 @@ static int cops_jumpstart(struct device *dev)
return 0;
}
-static int tangent_wait_reset(int ioaddr)
+static void tangent_wait_reset(int ioaddr)
{
- int timeout=0;
+ int timeout=0;
- while(timeout < 5000 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
- udelay(1000); /* Wait 1000 useconds */
-
- return 0;
+ while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+ mdelay(1); /* Wait 1 second */
}
/*
@@ -432,23 +479,11 @@ static void cops_reset(struct device *dev, int sleep)
if(lp->board==TANGENT)
{
- inb(ioaddr); /* Clear request latch. */
- outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */
+ inb(ioaddr); /* Clear request latch. */
+ outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */
outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */
- /* Can take 5 seconds max - youch! */
- if(sleep)
- {
- long snapt=jiffies;
- while(jiffies-snapt<5*HZ)
- {
- if(inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)
- break;
- schedule();
- }
- }
- else
- tangent_wait_reset(ioaddr);
+ tangent_wait_reset(ioaddr);
outb(0, ioaddr+TANG_CLEAR_INT);
}
if(lp->board==DAYNA)
@@ -543,12 +578,13 @@ static void cops_load (struct device *dev)
}
if(cops_debug > 1)
- printk(KERN_DEBUG "%s: Uploaded firmware - %d bytes of %d bytes.\n", dev->name, i, ltf->length);
+ printk("%s: Uploaded firmware - %d bytes of %d bytes.\n",
+ dev->name, i, ltf->length);
- if(lp->board==DAYNA)
- outb(1, ioaddr+DAYNA_INT_CARD); /* Tell Dayna to run the firmware code. */
- else
- inb(ioaddr); /* Tell Tang to run the firmware code. */
+ if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */
+ outb(1, ioaddr+DAYNA_INT_CARD);
+ else /* Tell Tang to run the firmware code. */
+ inb(ioaddr);
if(lp->board==TANGENT)
{
@@ -575,16 +611,16 @@ static int cops_nodeid (struct device *dev, int nodeid)
/* Empty any pending adapter responses. */
while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
{
- outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */
+ outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */
if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
- cops_rx(dev); /* Kick out any packet waiting. */
+ cops_rx(dev); /* Kick any packets waiting. */
schedule();
}
- outb(2, ioaddr); /* Output command packet length as 2. */
+ outb(2, ioaddr); /* Output command packet length as 2. */
outb(0, ioaddr);
- outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */
- outb(nodeid, ioaddr); /* Suggest node address. */
+ outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */
+ outb(nodeid, ioaddr); /* Suggest node address. */
}
if(lp->board == TANGENT)
@@ -592,19 +628,19 @@ static int cops_nodeid (struct device *dev, int nodeid)
/* Empty any pending adapter responses. */
while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
{
- outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */
- cops_rx(dev); /* Kick out any packet waiting. */
+ outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */
+ cops_rx(dev); /* Kick out packets waiting. */
schedule();
}
- /* Not sure what Tangent does if random nodeid we picked is already used. */
+ /* Not sure what Tangent does if nodeid picked is used. */
if(nodeid == 0) /* Seed. */
- nodeid = jiffies&0xFF; /* Get a random try .*/
- outb(2, ioaddr); /* Command length LSB. */
- outb(0, ioaddr); /* Command length MSB. */
- outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */
+ nodeid = jiffies&0xFF; /* Get a random try */
+ outb(2, ioaddr); /* Command length LSB */
+ outb(0, ioaddr); /* Command length MSB */
+ outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */
outb(nodeid, ioaddr); /* LAP address hint. */
- outb(0xFF, ioaddr); /* Interrupt level to use (NONE). */
+ outb(0xFF, ioaddr); /* Int. level to use */
}
lp->node_acquire=0; /* Set nodeid holder to 0. */
@@ -626,7 +662,8 @@ static int cops_nodeid (struct device *dev, int nodeid)
}
if(cops_debug > 1)
- printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", dev->name, lp->node_acquire);
+ printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n",
+ dev->name, lp->node_acquire);
lp->nodeid=1; /* Set got nodeid to 1. */
@@ -634,6 +671,37 @@ static int cops_nodeid (struct device *dev, int nodeid)
}
/*
+ * Poll the Tangent type cards to see if we have work.
+ */
+static void cops_poll(unsigned long ltdev)
+{
+ int ioaddr, status;
+ int boguscount = 0;
+
+ struct device *dev = (struct device *)ltdev;
+
+ del_timer(&cops_timer);
+
+ if(dev == NULL)
+ return; /* We've been downed */
+
+ ioaddr = dev->base_addr;
+ do {
+ status=inb(ioaddr+TANG_CARD_STATUS);
+ if(status & TANG_RX_READY)
+ cops_rx(dev);
+ if(status & TANG_TX_READY)
+ dev->tbusy = 0;
+ status = inb(ioaddr+TANG_CARD_STATUS);
+ } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+
+ cops_timer.expires = jiffies+5;
+ add_timer(&cops_timer);
+
+ return;
+}
+
+/*
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
@@ -646,7 +714,8 @@ static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if(dev == NULL)
{
- printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+ cardname, irq);
return;
}
dev->interrupt = 1;
@@ -654,29 +723,31 @@ static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ioaddr = dev->base_addr;
lp = (struct cops_local *)dev->priv;
- do
- {
- /* Clear any interrupt. */
- outb(0, ioaddr + COPS_CLEAR_INT);
-
- if(lp->board==DAYNA)
- {
- status=inb(ioaddr+DAYNA_CARD_STATUS);
- if((status&0x03)==DAYNA_RX_REQUEST)
- cops_rx(dev);
- }
- else
- {
- status=inb(ioaddr+TANG_CARD_STATUS);
- if(status&TANG_RX_READY)
- cops_rx(dev);
- }
+ if(lp->board==DAYNA)
+ {
+ do {
+ outb(0, ioaddr + COPS_CLEAR_INT);
+ status=inb(ioaddr+DAYNA_CARD_STATUS);
+ if((status&0x03)==DAYNA_RX_REQUEST)
+ cops_rx(dev);
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ } while(++boguscount < 20);
+ }
+ else
+ {
+ do {
+ status=inb(ioaddr+TANG_CARD_STATUS);
+ if(status & TANG_RX_READY)
+ cops_rx(dev);
+ if(status & TANG_TX_READY)
+ dev->tbusy = 0;
+ status=inb(ioaddr+TANG_CARD_STATUS);
+ } while((++boguscount < 20) &&
+ (status&(TANG_RX_READY|TANG_TX_READY)));
+ }
- dev->tbusy = 0;
- mark_bh(NET_BH);
- } while (++boguscount < 20 );
dev->interrupt = 0;
-
return;
}
@@ -715,7 +786,10 @@ static void cops_rx(struct device *dev)
}
/* Get response length. */
- pkt_len = inb(ioaddr) & 0xFF;
+ if(lp->board==DAYNA)
+ pkt_len = inb(ioaddr) & 0xFF;
+ else
+ pkt_len = inb(ioaddr) & 0x00FF;
pkt_len |= (inb(ioaddr) << 8);
/* Input IO code. */
rsp_type=inb(ioaddr);
@@ -724,7 +798,8 @@ static void cops_rx(struct device *dev)
skb = dev_alloc_skb(pkt_len);
if(skb == NULL)
{
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
lp->stats.rx_dropped++;
while(pkt_len--) /* Discard packet */
inb(ioaddr);
@@ -737,14 +812,15 @@ static void cops_rx(struct device *dev)
insb(ioaddr, skb->data, pkt_len); /* Eat the Data */
if(lp->board==DAYNA)
- outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card. */
+ outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */
sti(); /* Restore interrupts. */
/* Check for bad response length */
if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
{
- printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len);
+ printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n",
+ dev->name, pkt_len);
lp->stats.tx_errors++;
kfree_skb(skb);
return;
@@ -752,8 +828,8 @@ static void cops_rx(struct device *dev)
/* Set nodeid and then get out. */
if(rsp_type == LAP_INIT_RSP)
- {
- lp->node_acquire = skb->data[0]; /* Nodeid taken from received packet. */
+ { /* Nodeid taken from received packet. */
+ lp->node_acquire = skb->data[0];
kfree_skb(skb);
return;
}
@@ -769,7 +845,7 @@ static void cops_rx(struct device *dev)
skb->mac.raw = skb->data; /* Point to entire packet. */
skb_pull(skb,3);
- skb->h.raw = skb->data; /* Point to just the data (Skip header). */
+ skb->h.raw = skb->data; /* Point to data (Skip header). */
/* Update the counters. */
lp->stats.rx_packets++;
@@ -815,26 +891,22 @@ static int cops_send_packet(struct sk_buff *skb, struct device *dev)
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
if(test_and_set_bit(0, (void*) &dev->tbusy) != 0)
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+ printk(KERN_WARNING "%s: Transmitter access conflict.\n",
+ dev->name);
else
{
cli(); /* Disable interrupts. */
- if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */
+ if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */
while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
- if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
+ if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
/* Output IO length. */
+ outb(skb->len, ioaddr);
if(lp->board == DAYNA)
- {
- outb(skb->len, ioaddr);
outb(skb->len >> 8, ioaddr);
- }
else
- {
- outb(skb->len&0x0FF, ioaddr);
outb((skb->len >> 8)&0x0FF, ioaddr);
- }
/* Output IO code. */
outb(LAP_WRITE, ioaddr);
@@ -844,7 +916,7 @@ static int cops_send_packet(struct sk_buff *skb, struct device *dev)
outsb(ioaddr, skb->data, skb->len); /* Send out the data. */
- if(lp->board==DAYNA) /* The Dayna requires you kick the card. */
+ if(lp->board==DAYNA) /* Dayna requires you kick the card */
outb(1, ioaddr+DAYNA_INT_CARD);
sti(); /* Restore interrupts. */
@@ -868,7 +940,7 @@ static int cops_send_packet(struct sk_buff *skb, struct device *dev)
static void set_multicast_list(struct device *dev)
{
if(cops_debug >= 3)
- printk("%s: set_mulicast_list executed. NeatO.\n", dev->name);
+ printk("%s: set_multicast_list executed\n", dev->name);
}
/*
@@ -876,7 +948,8 @@ static void set_multicast_list(struct device *dev)
*/
static int cops_hard_header(struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len)
{
if(cops_debug >= 3)
printk("%s: cops_hard_header executed. Wow!\n", dev->name);
@@ -925,6 +998,13 @@ static int cops_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
static int cops_close(struct device *dev)
{
+ struct cops_local *lp = (struct cops_local *)dev->priv;
+
+ /* If we were running polled, yank the timer.
+ */
+ if(lp->board==TANGENT && dev->irq==0)
+ del_timer(&cops_timer);
+
dev->tbusy = 1;
dev->start = 0;
@@ -966,7 +1046,8 @@ int init_module(void)
int result, err;
if(io == 0)
- printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", cardname);
+ printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
+ cardname);
/* Copy the parameters from insmod into the device structure. */
cops0_dev.base_addr = io;
@@ -988,7 +1069,16 @@ void cleanup_module(void)
unregister_netdev(&cops0_dev);
if(cops0_dev.priv)
kfree_s(cops0_dev.priv, sizeof(struct cops_local));
- free_irq(cops0_dev.irq, &cops0_dev);
+ if(cops0_dev.irq)
+ free_irq(cops0_dev.irq, &cops0_dev);
release_region(cops0_dev.base_addr, COPS_IO_EXTENT);
}
#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
+ * c-basic-offset: 4
+ * c-file-offsets: ((substatement-open . 0))
+ * End:
+ */
diff --git a/drivers/net/cops_ffdrv.h b/drivers/net/cops_ffdrv.h
index d3e337afc..2560866dd 100644
--- a/drivers/net/cops_ffdrv.h
+++ b/drivers/net/cops_ffdrv.h
@@ -1,7 +1,7 @@
/*
* The firmware this driver downloads into the Localtalk card is a
- * seperate program and is not GPL'd source code, even though the Linux
+ * separate program and is not GPL'd source code, even though the Linux
* side driver and the routine that loads this data into the card are.
*
* It is taken from the COPS SDK and is under the following license
diff --git a/drivers/net/cops_ltdrv.h b/drivers/net/cops_ltdrv.h
index 33f3d9a06..5d38fb68c 100644
--- a/drivers/net/cops_ltdrv.h
+++ b/drivers/net/cops_ltdrv.h
@@ -1,6 +1,6 @@
/*
* The firmware this driver downloads into the Localtalk card is a
- * seperate program and is not GPL'd source code, even though the Linux
+ * separate program and is not GPL'd source code, even though the Linux
* side driver and the routine that loads this data into the card are.
*
* It is taken from the COPS SDK and is under the following license
diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c
new file mode 100644
index 000000000..0b550fd57
--- /dev/null
+++ b/drivers/net/daynaport.c
@@ -0,0 +1,603 @@
+/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/*
+ Derived from code:
+
+ Written 1993-94 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.
+
+ TODO:
+
+ The block output routines may be wrong for non Dayna
+ cards
+
+ Reading MAC addresses
+*/
+
+static const char *version =
+ "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+int ns8390_probe1(struct device *dev, int word16, char *name, int id, int prom);
+
+static int ns8390_open(struct device *dev);
+static void ns8390_no_reset(struct device *dev);
+static int ns8390_close_card(struct device *dev);
+
+static void interlan_reset(struct device *dev);
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void dayna_block_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void dayna_block_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page);
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void sane_block_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void sane_block_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page);
+
+
+#define WD_START_PG 0x00 /* First page of TX buffer */
+#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
+#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
+
+
+#define DAYNA_MAC_BASE 0xf0007
+#define DAYNA_8390_BASE 0x80000 /* 3 */
+#define DAYNA_8390_MEM 0x00000
+#define DAYNA_MEMSIZE 0x04000 /* First word of each long ! */
+
+#define APPLE_8390_BASE 0xE0000
+#define APPLE_8390_MEM 0xD0000
+#define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */
+
+#define KINETICS_8390_BASE 0x80003
+#define KINETICS_8390_MEM 0x00000
+#define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */
+
+static int test_8390(volatile char *ptr, int scale)
+{
+ int regd;
+ int v;
+
+ if(nubus_hwreg_present(&ptr[0x00])==0)
+ return -EIO;
+ if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+ return -EIO;
+ if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+ return -EIO;
+ ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
+ regd=ptr[0x0D<<scale];
+ ptr[0x0D<<scale]=0xFF;
+ ptr[0x00]=E8390_NODMA+E8390_PAGE0;
+ v=ptr[0x0D<<scale];
+ if(ptr[0x0D<<scale]!=0)
+ {
+ ptr[0x0D<<scale]=regd;
+ return -ENODEV;
+ }
+/* printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
+ return 0;
+}
+/*
+ * Identify the species of NS8390 card/driver we need
+ */
+
+#define NS8390_DAYNA 1
+#define NS8390_INTERLAN 2
+#define NS8390_KINETICS 3
+#define NS8390_APPLE 4
+#define NS8390_FARALLON 5
+#define NS8390_ASANTE 6
+
+int ns8390_ident(struct nubus_type *nb)
+{
+ /* It appears anything with a software type of 0 is an apple
+ compatible - even if the hardware matches others */
+
+ if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
+ return NS8390_APPLE;
+
+ /* Dayna ex Kinetics board */
+ if(nb->DrHW==0x0103)
+ return NS8390_DAYNA;
+
+ /* Asante board */
+ if(nb->DrHW==0x0104)
+ return NS8390_ASANTE;
+ if(nb->DrHW==0x0100)
+ return NS8390_INTERLAN;
+ if(nb->DrHW==0x0106)
+ return NS8390_KINETICS;
+ if(nb->DrSW==0x010C)
+ return NS8390_FARALLON;
+ return -1;
+}
+
+/*
+ * Probe for 8390 cards.
+ * The ns8390_probe1() routine initializes the card and fills the
+ * station address field. On entry base_addr is set, irq is set
+ * (These come from the nubus probe code). dev->mem_start points
+ * at the memory ring, dev->mem_end gives the end of it.
+ */
+
+int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+{
+ struct device *dev;
+ volatile unsigned short *i;
+ volatile unsigned char *p;
+ int plen;
+ int id;
+
+ if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
+ return -ENODEV;
+ /* Ok so it is an ethernet network device */
+ if((id=ns8390_ident(match))==-1)
+ {
+ printk("Ethernet but type unknown %d\n",match->DrHW);
+ return -ENODEV;
+ }
+ dev = init_etherdev(0, 0);
+ if(dev==NULL)
+ return -ENOMEM;
+
+ /*
+ * Dayna specific init
+ */
+ if(id==NS8390_DAYNA)
+ {
+ dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
+ dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+
+ printk("daynaport: testing board: ");
+
+ printk("memory - ");
+
+ i=(void *)dev->mem_start;
+ memset((void *)i,0xAA, DAYNA_MEMSIZE);
+ while(i<(volatile unsigned short *)dev->mem_end)
+ {
+ if(*i!=0xAAAA)
+ goto membad;
+ *i=0x5555;
+ if(*i!=0x5555)
+ goto membad;
+ i+=2; /* Skip a word */
+ }
+
+ printk("controller - ");
+
+ p=(void *)dev->base_addr;
+ plen=0;
+
+ while(plen<0x3FF00)
+ {
+ if(test_8390(p,0)==0)
+ break;
+ if(test_8390(p,1)==0)
+ break;
+ if(test_8390(p,2)==0)
+ break;
+ if(test_8390(p,3)==0)
+ break;
+ plen++;
+ p++;
+ }
+ if(plen==0x3FF00)
+ goto membad;
+ printk("OK\n");
+ dev->irq=slot;
+ if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
+ return 0;
+ }
+ /* Apple, Farallon, Asante */
+ if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+ {
+ dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+ dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+ dev->irq=slot;
+ printk("apple/clone: testing board: ");
+
+ printk("memory - ");
+
+ i=(void *)dev->mem_start;
+ memset((void *)i,0xAA, DAYNA_MEMSIZE);
+ while(i<(volatile unsigned short *)dev->mem_end)
+ {
+ if(*i!=0xAAAA)
+ goto membad;
+ *i=0x5555;
+ if(*i!=0x5555)
+ goto membad;
+ i+=2; /* Skip a word */
+ }
+ printk("OK\n");
+
+ if(id==NS8390_FARALLON)
+ {
+ if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+ return 0;
+ }
+ else
+ {
+ if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
+ return 0;
+ }
+ }
+ /* Interlan */
+ if(id==NS8390_INTERLAN)
+ {
+ /* As apple and asante */
+ dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+ dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+ dev->irq=slot;
+ if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+ return 0;
+ }
+ /* Kinetics */
+ if(id==NS8390_KINETICS)
+ {
+ dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+ dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
+ dev->irq=slot;
+ if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+ return 0;
+ }
+ kfree(dev);
+ return -ENODEV;
+membad:
+ printk("failed.\n");
+ kfree(dev);
+ return -ENODEV;
+}
+
+int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, int promoff)
+{
+ static unsigned version_printed = 0;
+
+ static int fwrd4_offsets[16]={
+ 0, 4, 8, 12,
+ 16, 20, 24, 28,
+ 32, 36, 40, 44,
+ 48, 52, 56, 60
+ };
+ static int back4_offsets[16]={
+ 60, 56, 52, 48,
+ 44, 40, 36, 32,
+ 28, 24, 20, 16,
+ 12, 8, 4, 0
+ };
+
+ unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+
+ if (ei_debug && version_printed++ == 0)
+ printk(version);
+
+ /* Snarf the interrupt now. There's no point in waiting since we cannot
+ share a slot! and the board will usually be enabled. */
+ if (nubus_request_irq(dev->irq, dev, ei_interrupt))
+ {
+ printk (" unable to get nubus IRQ %d.\n", dev->irq);
+ return EAGAIN;
+ }
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev))
+ {
+ printk (" unable to get memory for dev->priv.\n");
+ nubus_free_irq(dev->irq);
+ return -ENOMEM;
+ }
+
+ /* OK, we are certain this is going to work. Setup the device. */
+
+ ei_status.name = model_name;
+ ei_status.word16 = word16;
+ ei_status.tx_start_page = WD_START_PG;
+ ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+
+ dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+ dev->rmem_end = dev->mem_end;
+
+ if(promoff==-1) /* Use nubus resources ? */
+ {
+ if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+ {
+ printk("mac_ns8390: MAC address not in resources!\n");
+ return -ENODEV;
+ }
+ }
+ else /* Pull it off the card */
+ {
+ int i=0;
+ int x=1;
+ /* These should go in the end I hope */
+ if(type==NS8390_DAYNA)
+ x=2;
+ if(type==NS8390_INTERLAN)
+ x=4;
+ while(i<6)
+ {
+ dev->dev_addr[i]=*prom;
+ prom+=x;
+ if(i)
+ printk(":");
+ printk("%02X",dev->dev_addr[i++]);
+ }
+ }
+
+ printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
+ model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+
+ switch(type)
+ {
+ case NS8390_DAYNA: /* Dayna card */
+ /* 16 bit, 4 word offsets */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ ei_status.block_input = &dayna_block_input;
+ ei_status.block_output = &dayna_block_output;
+ ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+ ei_status.reg_offset = fwrd4_offsets;
+ break;
+ case NS8390_APPLE: /* Apple/Asante/Farallon */
+ case NS8390_FARALLON:
+ case NS8390_ASANTE:
+ /* 16 bit card, register map is reversed */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+ case NS8390_INTERLAN: /* Interlan */
+ /* 16 bit card, map is forward */
+ ei_status.reset_8390 = &interlan_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+ case NS8390_KINETICS: /* Kinetics */
+ /* 8bit card, map is forward */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+ default:
+ panic("Detected a card I can't drive - whoops\n");
+ }
+ dev->open = &ns8390_open;
+ dev->stop = &ns8390_close_card;
+
+ NS8390_init(dev, 0);
+
+ return 0;
+}
+
+static int ns8390_open(struct device *dev)
+{
+ ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void ns8390_no_reset(struct device *dev)
+{
+ if (ei_debug > 1)
+ printk("Need to reset the NS8390 t=%lu...", jiffies);
+ ei_status.txing = 0;
+ if (ei_debug > 1) printk("reset not supported\n");
+ return;
+}
+
+static int ns8390_close_card(struct device *dev)
+{
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+ ei_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+struct nubus_device_specifier nubus_8390={
+ ns8390_probe,
+ NULL
+};
+
+
+/*
+ * Interlan Specific Code Starts Here
+ */
+
+static void interlan_reset(struct device *dev)
+{
+ unsigned char *target=nubus_slot_addr(dev->irq);
+ if (ei_debug > 1)
+ printk("Need to reset the NS8390 t=%lu...", jiffies);
+ ei_status.txing = 0;
+ /* This write resets the card */
+ target[0xC0000]=0;
+ if (ei_debug > 1) printk("reset complete\n");
+ return;
+}
+
+/*
+ * Daynaport code (some is used by other drivers)
+ */
+
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+
+/* Block input and output are easy on shared memory ethercards, and trivial
+ on the Daynaport card where there is no choice of how to do it.
+ The only complications are that the ring buffer wraps.
+*/
+
+static void dayna_cpu_memcpy(struct device *dev, void *to, int from, int count)
+{
+ volatile unsigned short *ptr;
+ unsigned short *target=to;
+ from<<=1; /* word, skip overhead */
+ ptr=(unsigned short *)(dev->mem_start+from);
+ while(count>=2)
+ {
+ *target++=*ptr++; /* Copy and */
+ ptr++; /* Cruft and */
+ count-=2;
+ }
+ /*
+ * Trailing byte ?
+ */
+ if(count)
+ {
+ /* Big endian */
+ unsigned short v=*ptr;
+ *((char *)target)=v>>8;
+ }
+}
+
+static void cpu_dayna_memcpy(struct device *dev, int to, const void *from, int count)
+{
+ volatile unsigned short *ptr;
+ const unsigned short *src=from;
+ to<<=1; /* word, skip overhead */
+ ptr=(unsigned short *)(dev->mem_start+to);
+ while(count>=2)
+ {
+ *ptr++=*src++; /* Copy and */
+ ptr++; /* Cruft and */
+ count-=2;
+ }
+ /*
+ * Trailing byte ?
+ */
+ if(count)
+ {
+ /* Big endian */
+ unsigned short v=*src;
+ *((char *)ptr)=v>>8;
+ }
+}
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+ dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+ /* Register endianism - fix here rather than 8390.c */
+ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+ unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+ unsigned long xfer_start = xfer_base+dev->mem_start;
+
+ /*
+ * Note the offset maths is done in card memory space which
+ * is word per long onto our space.
+ */
+
+ if (xfer_start + count > dev->rmem_end)
+ {
+ /* We must wrap the input move. */
+ int semi_count = dev->rmem_end - xfer_start;
+ dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+ count -= semi_count;
+ dayna_cpu_memcpy(dev, skb->data + semi_count,
+ dev->rmem_start - dev->mem_start, count);
+ }
+ else
+ {
+ dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+ }
+}
+
+static void dayna_block_output(struct device *dev, int count, const unsigned char *buf,
+ int start_page)
+{
+ long shmem = (start_page - WD_START_PG)<<8;
+
+ cpu_dayna_memcpy(dev, shmem, buf, count);
+}
+
+/*
+ * Cards with full width memory
+ */
+
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+ memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+ /* Register endianism - fix here rather than 8390.c */
+ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+ unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+ unsigned long xfer_start = xfer_base+dev->mem_start;
+
+ if (xfer_start + count > dev->rmem_end)
+ {
+ /* We must wrap the input move. */
+ int semi_count = dev->rmem_end - xfer_start;
+ memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
+ count -= semi_count;
+ memcpy(skb->data + semi_count,
+ (char *)dev->rmem_start, count);
+ }
+ else
+ {
+ memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
+ }
+}
+
+static void sane_block_output(struct device *dev, int count, const unsigned char *buf,
+ int start_page)
+{
+ long shmem = (start_page - WD_START_PG)<<8;
+
+ memcpy((char *)dev->mem_start+shmem, buf, count);
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
+ * version-control: t
+ * tab-width: 4
+ * kept-new-versions: 5
+ * End:
+ */
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index 06f527d70..deb25d949 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -213,14 +213,17 @@
insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
- For a compiled in driver, somewhere in this file, place e.g.
+ For a compiled in driver, at or above line 548, place e.g.
#define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
- Yes, I know full duplex isn't permissible on BNC or AUI; they're just
- examples. By default, full duplex is turned off and AUTO is the default
- autosense setting. In reality, I expect only the full duplex option to
+ Yes, I know full duplex isn't permissible on BNC or AUI; they're just
+ examples. By default, full duplex is turned off and AUTO is the default
+ autosense setting. In reality, I expect only the full duplex option to
be used. Note the use of single quotes in the two examples above and the
- lack of commas to separate items.
+ lack of commas to separate items. ALSO, you must get the requested media
+ correct in relation to what the adapter SROM says it has. There's no way
+ to determine this in advance other than by trial and error and common
+ sense, e.g. call a BNC connectored port 'BNC', not '10Mb'.
TO DO:
------
@@ -374,11 +377,33 @@
0.535 21-Feb-98 Fix Ethernet Address PROM reset bug for DC21040.
0.536 21-Mar-98 Change pci_probe() to use the pci_dev structure.
**Incompatible with 2.0.x from here.**
+ 0.540 5-Jul-98 Atomicize assertion of dev->interrupt for SMP
+ from <lma@varesearch.com>
+ Add TP, AUI and BNC cases to 21140m_autoconf() for
+ case where a 21140 under SROM control uses, e.g. AUI
+ from problem report by <delchini@lpnp09.in2p3.fr>
+ Add MII parallel detection to 2114x_autoconf() for
+ case where no autonegotiation partner exists from
+ problem report by <mlapsley@ndirect.co.uk>.
+ Add ability to force connection type directly even
+ when using SROM control from problem report by
+ <earl@exis.net>.
+ Updated the PCI interface to conform with the latest
+ version. I hope nothing is broken...
+ Add TX done interrupt modification from suggestion
+ by <Austin.Donnelly@cl.cam.ac.uk>.
+ Fix is_anc_capable() bug reported by
+ <Austin.Donnelly@cl.cam.ac.uk>.
+ Fix type[13]_infoblock() bug: during MII search, PHY
+ lp->rst not run because lp->ibn not initialised -
+ from report & fix by <paubert@iram.es>.
+ Fix probe bug with EISA & PCI cards present from
+ report by <eirik@netcom.com>.
=========================================================================
*/
-static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.540 1998/7/5 davies@maniac.ultranet.com\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -933,7 +958,7 @@ static int test_bad_enet(struct device *dev, int status);
static void eisa_probe(struct device *dev, u_long iobase);
#endif
static void pci_probe(struct device *dev, u_long iobase);
-static void srom_search(int index);
+static void srom_search(struct pci_dev *pdev);
static char *build_setup_frame(struct device *dev, int mode);
static void disable_ast(struct device *dev);
static void enable_ast(struct device *dev, u32 time_out);
@@ -980,12 +1005,12 @@ static int loading_module = 0;
static char name[DE4X5_NAME_LENGTH + 1];
#if !defined(__sparc_v9__) && !defined(__powerpc__)
static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
+static int lastEISA = 0;
+#else
+static int lastEISA = MAX_EISA_SLOTS; /* Only PCI probes */
#endif
static int num_de4x5s = 0;
static int cfrv = 0, useSROM = 0;
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
-static int lastEISA = 0;
-#endif
static int lastPCI = -1;
static struct device *lastModule = NULL;
@@ -1036,9 +1061,9 @@ static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = {
#define PHY_HARD_RESET {\
outl(GEP_HRST, DE4X5_GEP); /* Hard RESET the PHY dev. */\
- udelay(1000); /* Assert for 1ms */\
+ mdelay(1); /* Assert for 1ms */\
outl(0x00, DE4X5_GEP);\
- udelay(2000); /* Wait for 2ms */\
+ mdelay(2); /* Wait for 2ms */\
}
@@ -1054,7 +1079,9 @@ de4x5_probe(struct device *dev))
#if !defined(__sparc_v9__) && !defined(__powerpc__)
eisa_probe(dev, iobase);
#endif
- pci_probe(dev, iobase);
+ if (lastEISA == MAX_EISA_SLOTS) {
+ pci_probe(dev, iobase);
+ }
return (dev->priv ? 0 : -ENODEV);
}
@@ -1151,21 +1178,15 @@ de4x5_hw_init(struct device *dev, u_long iobase))
/*
** Choose correct autosensing in case someone messed up
*/
- if ((lp->params.autosense & AUTO) || lp->useSROM) {
- lp->autosense = AUTO;
- } else {
- if (lp->chipset != DC21140) {
- if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
- lp->params.autosense = TP;
- }
- if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
- lp->params.autosense = BNC;
- }
- lp->autosense = lp->params.autosense & 0x001f;
- } else {
- lp->autosense = lp->params.autosense & 0x00c0;
- }
- }
+ lp->autosense = lp->params.autosense;
+ if (lp->chipset != DC21140) {
+ if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
+ lp->params.autosense = TP;
+ }
+ if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
+ lp->params.autosense = BNC;
+ }
+ }
lp->fdx = lp->params.fdx;
sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
@@ -1308,8 +1329,9 @@ de4x5_open(struct device *dev)
lp->state = OPEN;
de4x5_dbg_open(dev);
+
if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
- lp->adapter_name, dev)) {
+ lp->adapter_name, dev)) {
printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
lp->adapter_name, dev)) {
@@ -1430,7 +1452,7 @@ de4x5_sw_reset(struct device *dev)
/* Poll for setup frame completion (adapter interrupts are disabled now) */
sti(); /* Ensure timer interrupts */
for (j=0, i=0;(i<500) && (j==0);i++) { /* Upto 500ms delay */
- udelay(1000);
+ mdelay(1);
if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
}
outl(omr, DE4X5_OMR); /* Stop everything! */
@@ -1448,7 +1470,7 @@ de4x5_sw_reset(struct device *dev)
}
/*
-** Writes a socket buffer address to the next available transmit descriptor
+** Writes a socket buffer address to the next available transmit descriptor.
*/
static int
de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
@@ -1542,12 +1564,11 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp = (struct de4x5_private *)dev->priv;
iobase = dev->base_addr;
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ if (test_and_set_bit(MASK_INTERRUPTS, (void*) &dev->interrupt))
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
DISABLE_IRQs; /* Ensure non re-entrancy */
synchronize_irq();
- dev->interrupt = MASK_INTERRUPTS;
for (limit=0; limit<8; limit++) {
sts = inl(DE4X5_STS); /* Read IRQ status */
@@ -1868,16 +1889,27 @@ de4x5_local_stats(struct device *dev, char *buf, int pkt_len)
return;
}
+/*
+** Removes the TD_IC flag from previous descriptor to improve TX performance.
+** If the flag is changed on a descriptor that is being read by the hardware,
+** I assume PCI transaction ordering will mean you are either successful or
+** just miss asserting the change to the hardware. Anyway you're messing with
+** a descriptor you don't own, but this shouldn't kill the chip provided
+** the descriptor register is read only to the hardware.
+*/
static void
load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+ int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1);
+
lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf));
lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
lp->tx_skb[lp->tx_new] = skb;
+ lp->tx_ring[entry].des1 &= cpu_to_le32(~TD_IC);
barrier();
+
lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
barrier();
@@ -2044,7 +2076,7 @@ eisa_probe(struct device *dev, u_long ioaddr))
return;
}
-#endif /* !(__sparc_v9__) */
+#endif /* !(__sparc_v9__) && !(__powerpc__) */
/*
** PCI bus I/O device probe
@@ -2057,22 +2089,25 @@ eisa_probe(struct device *dev, u_long ioaddr))
** bit. Here, check for I/O accesses and then set BM. If you put the card in
** a non BM slot, you're on your own (and complain to the PC vendor that your
** PC doesn't conform to the PCI standard)!
+**
+** This function is only compatible with the *latest* 2.1.x kernels. For 2.0.x
+** kernels use the V0.535[n] drivers.
*/
-#define PCI_DEVICE (dev_num << 3)
#define PCI_LAST_DEV 32
__initfunc(static void
pci_probe(struct device *dev, u_long ioaddr))
{
- u_char pb, pbus, dev_num, dnum, dev_fn, timer;
- u_short dev_id, vendor, index, status;
+ u_char pb, pbus, dev_num, dnum, timer;
+ u_short vendor, index, status;
u_int irq = 0, device, class = DE4X5_CLASS_CODE;
u_long iobase = 0; /* Clear upper 32 bits in Alphas */
struct bus_type *lp = &bus;
+ struct pci_dev *pdev = NULL;
if (lastPCI == NO_MORE_PCI) return;
- if (!pci_present()) {
+ if (!pcibios_present()) {
lastPCI = NO_MORE_PCI;
return; /* No PCI bus in this machine! */
}
@@ -2088,100 +2123,81 @@ pci_probe(struct device *dev, u_long ioaddr))
dnum = 0;
}
- for (index=lastPCI+1;
- (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
- index++) {
- dev_num = PCI_SLOT(dev_fn);
- if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85)
- struct pci_dev *pdev = pci_find_slot(pb, dev_fn);
-#else
- u_char tirq;
- u_int tmp;
-#endif
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
- continue;
- }
-
- /* Search for an SROM on this bus */
- if (lp->bus_num != pb) {
- lp->bus_num = pb;
- srom_search(index);
- }
+ for (index=lastPCI+1; (pdev=pci_find_class(class, pdev))!=NULL; index++) {
+ dev_num = PCI_SLOT(pdev->devfn);
+ pb = pdev->bus->number;
+ if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue;
- /* Get the chip configuration revision register */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
- /* Set the device number information */
- lp->device = dev_num;
+ /* Search for an SROM on this bus */
+ if (lp->bus_num != pb) {
lp->bus_num = pb;
-
- /* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
- lp->chipset = device;
+ srom_search(pdev);
+ }
- /* Get the board I/O address and IRQ */
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,85)
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
- iobase = tmp;
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
- irq = tirq;
-#else
- iobase = pdev->base_address[0];
- irq = pdev->irq;
-#endif
- iobase &= CBIO_MASK;
+ /* Get the chip configuration revision register */
+ pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv);
+
+ /* Set the device number information */
+ lp->device = dev_num;
+ lp->bus_num = pb;
+
+ /* Set the chipset information */
+ if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ lp->chipset = device;
- if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+ /* Get the board I/O address (64 bits on sparc64) */
+ iobase = pdev->base_address[0] & CBIO_MASK;
- /* Check if I/O accesses and Bus Mastering are enabled */
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ /* Fetch the IRQ to be used */
+ irq = pdev->irq;
+ if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+
+ /* Check if I/O accesses and Bus Mastering are enabled */
+ pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
#ifdef __powerpc__
- if (!(status & PCI_COMMAND_IO)) {
- status |= PCI_COMMAND_IO;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
+ if (!(status & PCI_COMMAND_IO)) {
+ status |= PCI_COMMAND_IO;
+ pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
+ }
#endif /* __powerpc__ */
- if (!(status & PCI_COMMAND_IO)) continue;
+ if (!(status & PCI_COMMAND_IO)) continue;
- if (!(status & PCI_COMMAND_MASTER)) {
- status |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
- if (!(status & PCI_COMMAND_MASTER)) continue;
+ if (!(status & PCI_COMMAND_MASTER)) {
+ status |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
+ }
+ if (!(status & PCI_COMMAND_MASTER)) continue;
- /* Check the latency timer for values >= 0x60 */
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
- if (timer < 0x60) {
- pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
- }
+ /* Check the latency timer for values >= 0x60 */
+ pcibios_read_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, &timer);
+ if (timer < 0x60) {
+ pcibios_write_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, 0x60);
+ }
- DevicePresent(DE4X5_APROM);
- if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
- dev->irq = irq;
- if ((status = de4x5_hw_init(dev, iobase)) == 0) {
- num_de4x5s++;
- if (loading_module) {
- link_modules(lastModule, dev);
- lastPCI = index;
- }
- return;
+ DevicePresent(DE4X5_APROM);
+ if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+ dev->irq = irq;
+ if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+ num_de4x5s++;
+ if (loading_module) {
+ link_modules(lastModule, dev);
+ lastPCI = index;
}
- } else if (ioaddr != 0) {
- printk("%s: region already allocated at 0x%04lx.\n", dev->name,
- iobase);
+ return;
}
+ } else if (ioaddr != 0) {
+ printk("%s: region already allocated at 0x%04lx.\n", dev->name,
+ iobase);
}
}
- if (loading_module) lastPCI = NO_MORE_PCI;
+ lastPCI = NO_MORE_PCI;
return;
}
@@ -2193,44 +2209,27 @@ pci_probe(struct device *dev, u_long ioaddr))
** For single port cards this is a time waster...
*/
__initfunc(static void
-srom_search(int index))
+srom_search(struct pci_dev *pdev))
{
- u_char pb, dev_fn;
- u_short dev_id, dev_num, vendor, status;
+ u_char pb;
+ u_short vendor, status;
u_int irq = 0, device, class = DE4X5_CLASS_CODE;
u_long iobase = 0; /* Clear upper 32 bits in Alphas */
int i, j;
struct bus_type *lp = &bus;
-#ifndef __sparc_v9__
- u_char tirq;
- u_int tmp;
-#endif
- for (;
- (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
- index++) {
-#ifdef __sparc_v9__
- struct pci_dev *pdev;
- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break;
- }
-#endif
- if (lp->bus_num != pb) return;
- dev_num = PCI_SLOT(dev_fn);
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
- continue;
- }
+ while ((pdev = pci_find_class(class, pdev))!= NULL) {
+ if (lp->bus_num != pdev->bus->number) return;
+ pb = pdev->bus->number;
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
/* Get the chip configuration revision register */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+ pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv);
/* Set the device number information */
- lp->device = dev_num;
+ lp->device = PCI_SLOT(pdev->devfn);
lp->bus_num = pb;
/* Set the chipset information */
@@ -2238,25 +2237,14 @@ srom_search(int index))
lp->chipset = device;
/* Get the board I/O address (64 bits on sparc64) */
-#ifndef __sparc_v9__
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
- iobase = tmp;
-#else
- iobase = pdev->base_address[0];
-#endif
- iobase &= CBIO_MASK;
+ iobase = pdev->base_address[0] & CBIO_MASK;
/* Fetch the IRQ to be used */
-#ifndef __sparc_v9__
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
- irq = tirq;
-#else
irq = pdev->irq;
-#endif
if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
/* Check if I/O accesses are enabled */
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
if (!(status & PCI_COMMAND_IO)) continue;
/* Search for a valid SROM attached to this DECchip */
@@ -2709,9 +2697,9 @@ dc21140m_autoconf(struct device *dev)
int ana, anlpa, cap, cr, slnk, sr;
int next_tick = DE4X5_AUTOSENSE_MS;
u_long imr, omr, iobase = dev->base_addr;
-
+
switch(lp->media) {
- case INIT:
+ case INIT:
if (lp->timeout < 0) {
DISABLE_IRQs;
lp->tx_enable = FALSE;
@@ -2757,9 +2745,9 @@ dc21140m_autoconf(struct device *dev)
}
break;
- case ANS:
+ case ANS:
switch (lp->local_state) {
- case 0:
+ case 0:
if (lp->timeout < 0) {
mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
}
@@ -2777,7 +2765,7 @@ dc21140m_autoconf(struct device *dev)
}
break;
- case 1:
+ case 1:
if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
next_tick = sr & ~TIMER_CB;
} else {
@@ -2805,7 +2793,7 @@ dc21140m_autoconf(struct device *dev)
}
break;
- case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
+ case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
if (lp->timeout < 0) {
lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
(~gep_rd(dev) & GEP_LNP));
@@ -2825,7 +2813,7 @@ dc21140m_autoconf(struct device *dev)
}
break;
- case _100Mb: /* Set 100Mb/s */
+ case _100Mb: /* Set 100Mb/s */
next_tick = 3000;
if (!lp->tx_enable) {
SET_100Mb;
@@ -2840,8 +2828,10 @@ dc21140m_autoconf(struct device *dev)
}
}
break;
-
- case _10Mb: /* Set 10Mb/s */
+
+ case BNC:
+ case AUI:
+ case _10Mb: /* Set 10Mb/s */
next_tick = 3000;
if (!lp->tx_enable) {
SET_10Mb;
@@ -2857,7 +2847,7 @@ dc21140m_autoconf(struct device *dev)
}
break;
- case NC:
+ case NC:
if (lp->media != lp->c_media) {
de4x5_dbg_media(dev);
lp->c_media = lp->media;
@@ -2893,33 +2883,54 @@ dc2114x_autoconf(struct device *dev)
int next_tick = DE4X5_AUTOSENSE_MS;
switch (lp->media) {
- case INIT:
+ case INIT:
if (lp->timeout < 0) {
DISABLE_IRQs;
lp->tx_enable = FALSE;
lp->linkOK = 0;
lp->timeout = -1;
- de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ if (lp->params.autosense & ~AUTO) {
+ srom_map_media(dev); /* Fixed media requested */
+ if (lp->media != lp->params.autosense) {
+ lp->tcount++;
+ lp->media = INIT;
+ return next_tick;
+ }
+ lp->media = INIT;
+ }
}
if ((next_tick = de4x5_reset_phy(dev)) < 0) {
next_tick &= ~TIMER_CB;
} else {
- lp->media = SPD_DET;
- if ((lp->infoblock_media == ANS) &&
+ if (lp->autosense == _100Mb) {
+ lp->media = _100Mb;
+ } else if (lp->autosense == _10Mb) {
+ lp->media = _10Mb;
+ } else if (lp->autosense == TP) {
+ lp->media = TP;
+ } else if (lp->autosense == BNC) {
+ lp->media = BNC;
+ } else if (lp->autosense == AUI) {
+ lp->media = AUI;
+ } else {
+ lp->media = SPD_DET;
+ if ((lp->infoblock_media == ANS) &&
((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
lp->media = ANS;
+ }
}
lp->local_state = 0;
next_tick = dc2114x_autoconf(dev);
}
break;
- case ANS:
+ case ANS:
switch (lp->local_state) {
- case 0:
+ case 0:
if (lp->timeout < 0) {
mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
}
@@ -2937,7 +2948,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
- case 1:
+ case 1:
if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
next_tick = sr & ~TIMER_CB;
} else {
@@ -2959,15 +2970,15 @@ dc2114x_autoconf(struct device *dev)
}
} /* Auto Negotiation failed to finish */
next_tick = dc2114x_autoconf(dev);
- } /* Auto Negotiation failed to start */
+ } /* Auto Negotiation failed to start */
break;
}
break;
-
- case AUI:
+
+ case AUI:
if (!lp->tx_enable) {
if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
+ omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
outl(omr & ~OMR_FDX, DE4X5_OMR);
}
irqs = 0;
@@ -2990,13 +3001,13 @@ dc2114x_autoconf(struct device *dev)
}
break;
- case AUI_SUSPECT:
+ case AUI_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
break;
- case BNC:
+ case BNC:
switch (lp->local_state) {
- case 0:
+ case 0:
if (lp->timeout < 0) {
omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */
outl(omr & ~OMR_FDX, DE4X5_OMR);
@@ -3012,7 +3023,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
- case 1:
+ case 1:
if (!lp->tx_enable) {
if ((sts = ping_media(dev, 3000)) < 0) {
next_tick = sts & ~TIMER_CB;
@@ -3033,11 +3044,11 @@ dc2114x_autoconf(struct device *dev)
}
break;
- case BNC_SUSPECT:
+ case BNC_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
break;
- case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
+ case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
if (srom_map_media(dev) < 0) {
lp->tcount++;
lp->media = INIT;
@@ -3053,9 +3064,17 @@ dc2114x_autoconf(struct device *dev)
lp->media = SPD_DET;
return PDET_LINK_WAIT;
}
- }
- if (((lp->media == _100Mb) && is_100_up(dev)) ||
+ }
+ if (lp->media == ANS) { /* Do MII parallel detection */
+ if (is_spd_100(dev)) {
+ lp->media = _100Mb;
+ } else {
+ lp->media = _10Mb;
+ }
+ next_tick = dc2114x_autoconf(dev);
+ } else if (((lp->media == _100Mb) && is_100_up(dev)) ||
((lp->media == _10Mb) && is_10_up(dev)) ||
+ (lp->media == TP) ||
(lp->media == BNC) || (lp->media == AUI)) {
next_tick = dc2114x_autoconf(dev);
} else {
@@ -3064,7 +3083,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
- case _10Mb:
+ case _10Mb:
next_tick = 3000;
if (!lp->tx_enable) {
SET_10Mb;
@@ -3080,7 +3099,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
- case _100Mb:
+ case _100Mb:
next_tick = 3000;
if (!lp->tx_enable) {
SET_100Mb;
@@ -3096,7 +3115,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
- default:
+ default:
lp->tcount++;
printk("Huh?: media:%02x\n", lp->media);
lp->media = INIT;
@@ -3466,7 +3485,7 @@ is_anc_capable(struct device *dev)
if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
} else if ((lp->chipset & ~0x00ff) == DC2114x) {
- return (inl(DE4X5_SISR) & SISR_LPN) >> 11;
+ return (inl(DE4X5_SISR) & SISR_LPN) >> 12;
} else {
return 0;
}
@@ -3879,7 +3898,7 @@ de4x5_ms_delay(u32 msec)
static int
EISA_signature(char *name, s32 eisa_id)
{
- c_char *signatures[] = DE4X5_SIGNATURE;
+ static c_char *signatures[] = DE4X5_SIGNATURE;
char ManCode[DE4X5_STRLEN];
union {
s32 ID;
@@ -3914,7 +3933,7 @@ EISA_signature(char *name, s32 eisa_id)
static int
PCI_signature(char *name, struct bus_type *lp)
{
- c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
+ static c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
if (lp->chipset == DC21040) {
@@ -4415,7 +4434,7 @@ srom_exec(struct device *dev, u_char *p)
while (count--) {
gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
*p++ : TWIDDLE(w++)), dev);
- udelay(2000); /* 2ms per action */
+ mdelay(2); /* 2ms per action */
}
if (lp->chipset != DC21140) {
@@ -4645,6 +4664,7 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
p += 2;
if (lp->state == INITIALISED) {
+ lp->ibn = 1;
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
@@ -4724,6 +4744,7 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
p += 2;
if (lp->state == INITIALISED) {
+ lp->ibn = 3;
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
@@ -5471,24 +5492,24 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
} tmp;
switch(ioc->cmd) {
- case DE4X5_GET_HWADDR: /* Get the hardware address */
+ case DE4X5_GET_HWADDR: /* Get the hardware address */
ioc->len = ETH_ALEN;
status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
if (status)
- break;
+ break;
for (i=0; i<ETH_ALEN; i++) {
tmp.addr[i] = dev->dev_addr[i];
}
copy_to_user(ioc->data, tmp.addr, ioc->len);
break;
- case DE4X5_SET_HWADDR: /* Set the hardware address */
+ case DE4X5_SET_HWADDR: /* Set the hardware address */
status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
if (status)
- break;
+ break;
status = -EPERM;
if (!capable(CAP_NET_ADMIN))
- break;
+ break;
status = 0;
copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
for (i=0; i<ETH_ALEN; i++) {
@@ -5498,13 +5519,13 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
/* Set up the descriptor and give ownership to the card */
while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
- SETUP_FRAME_LEN, NULL);
+ SETUP_FRAME_LEN, NULL);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
dev->tbusy = 0; /* Unlock the TX ring */
break;
- case DE4X5_SET_PROM: /* Set Promiscuous Mode */
+ case DE4X5_SET_PROM: /* Set Promiscuous Mode */
if (capable(CAP_NET_ADMIN)) {
omr = inl(DE4X5_OMR);
omr |= OMR_PR;
@@ -5515,7 +5536,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
- case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */
+ case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */
if (capable(CAP_NET_ADMIN)) {
omr = inl(DE4X5_OMR);
omr &= ~OMR_PR;
@@ -5526,11 +5547,11 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
- case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
+ case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
printk("%s: Boo!\n", dev->name);
break;
- case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
+ case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
if (capable(CAP_NET_ADMIN)) {
omr = inl(DE4X5_OMR);
omr |= OMR_PM;
@@ -5540,18 +5561,18 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
- case DE4X5_GET_STATS: /* Get the driver statistics */
+ case DE4X5_GET_STATS: /* Get the driver statistics */
ioc->len = sizeof(lp->pktStats);
status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
if (status)
- break;
+ break;
cli();
copy_to_user(ioc->data, &lp->pktStats, ioc->len);
sti();
break;
- case DE4X5_CLR_STATS: /* Zero out the driver statistics */
+ case DE4X5_CLR_STATS: /* Zero out the driver statistics */
if (capable(CAP_NET_ADMIN)) {
cli();
memset(&lp->pktStats, 0, sizeof(lp->pktStats));
@@ -5561,14 +5582,14 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
- case DE4X5_GET_OMR: /* Get the OMR Register contents */
+ case DE4X5_GET_OMR: /* Get the OMR Register contents */
tmp.addr[0] = inl(DE4X5_OMR);
if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
copy_to_user(ioc->data, tmp.addr, 1);
}
break;
- case DE4X5_SET_OMR: /* Set the OMR Register contents */
+ case DE4X5_SET_OMR: /* Set the OMR Register contents */
if (capable(CAP_NET_ADMIN)) {
if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
copy_from_user(tmp.addr, ioc->data, 1);
@@ -5579,7 +5600,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
- case DE4X5_GET_REG: /* Get the DE4X5 Registers */
+ case DE4X5_GET_REG: /* Get the DE4X5 Registers */
j = 0;
tmp.lval[0] = inl(DE4X5_STS); j+=4;
tmp.lval[1] = inl(DE4X5_BMR); j+=4;
@@ -5687,7 +5708,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
*/
- default:
+ default:
status = -EOPNOTSUPP;
}
@@ -5766,30 +5787,32 @@ unlink_modules(struct device *p)
static int
count_adapters(void)
{
- int i, j;
+ int i, j=0;
char name[DE4X5_STRLEN];
- u_char pb, dev_fn, dev_num;
- u_short dev_id, vendor;
+ u_char pb, dev_fn;
+ u_short vendor;
u_int class = DE4X5_CLASS_CODE;
u_int device;
+ struct pci_dev *pdev;
+
#if !defined(__sparc_v9__) && !defined(__powerpc__)
u_long iobase = 0x1000;
- for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+ for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
if (EISA_signature(name, EISA_ID)) j++;
}
#endif
- if (!pci_present()) return j;
+ if (!pcibios_present()) return j;
for (i=0;
(pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
i++) {
- dev_num = PCI_SLOT(dev_fn);
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
+ }
+
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
}
diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h
index c0c58ccf4..24ab33873 100644
--- a/drivers/net/de4x5.h
+++ b/drivers/net/de4x5.h
@@ -811,7 +811,7 @@
** Media / mode state machine definitions
** User selectable:
*/
-#define TP 0x0001 /* 10Base-T */
+#define TP 0x0040 /* 10Base-T (now equiv to _10Mb) */
#define TP_NW 0x0002 /* 10Base-T with Nway */
#define BNC 0x0004 /* Thinwire */
#define AUI 0x0008 /* Thickwire */
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 2faccc6fd..abca38d83 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -2013,6 +2013,8 @@ struct net_device_stats *dfx_ctl_get_stats(
bp->stats.rx_packets = bp->rcv_total_frames;
bp->stats.tx_packets = bp->xmt_total_frames;
+ bp->stats.rx_bytes = bp->rcv_total_bytes;
+ bp->stats.tx_bytes = bp->xmt_total_bytes;
bp->stats.rx_errors = (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors);
bp->stats.tx_errors = bp->xmt_length_errors;
bp->stats.rx_dropped = bp->rcv_discards;
@@ -3099,6 +3101,8 @@ void dfx_rcv_queue_process(
bp->rcv_total_frames++;
if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
bp->rcv_multicast_frames++;
+
+ bp->rcv_total_bytes += skb->len;
}
}
}
@@ -3375,13 +3379,14 @@ void dfx_xmt_done(
p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]);
- /* Return skb to operating system */
-
- dev_kfree_skb(p_xmt_drv_descr->p_skb);
-
/* Increment transmit counters */
bp->xmt_total_frames++;
+ bp->xmt_total_bytes += p_xmt_drv_descr->p_skb->len;
+
+ /* Return skb to operating system */
+
+ dev_kfree_skb(p_xmt_drv_descr->p_skb);
/*
* Move to start of next packet by updating completion index
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index 5707ad877..a1b4b579a 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -1771,9 +1771,12 @@ typedef struct DFX_board_tag
u32 rcv_length_errors;
u32 rcv_total_frames;
u32 rcv_multicast_frames;
+ u32 rcv_total_bytes;
+
u32 xmt_discards;
u32 xmt_length_errors;
u32 xmt_total_frames;
+ u32 xmt_total_bytes;
} DFX_board_t;
#endif /* #ifndef _DEFXX_H_ */
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index e4f0393d0..d95d34a4a 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -163,6 +163,9 @@ __initfunc(int e21_probe1(struct device *dev, int ioaddr))
inb(ioaddr + E21_MEDIA); /* Point to media selection. */
outb(0, ioaddr + E21_ASIC); /* and disable the secondary interface. */
+ if (load_8390_module("e2100.c"))
+ return -ENOSYS;
+
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -176,6 +179,12 @@ __initfunc(int e21_probe1(struct device *dev, int ioaddr))
for (i = 0; i < 6; i++)
printk(" %02X", station_addr[i]);
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk (" unable to get memory for dev->priv.\n");
+ return -ENOMEM;
+ }
+
if (dev->irq < 2) {
int irqlist[] = {15,11,10,12,5,9,3,4}, i;
for (i = 0; i < 8; i++)
@@ -190,12 +199,6 @@ __initfunc(int e21_probe1(struct device *dev, int ioaddr))
} else if (dev->irq == 2) /* Fixup luser bogosity: IRQ2 is really IRQ9 */
dev->irq = 9;
- /* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (ethdev_init(dev)) {
- printk (" unable to get memory for dev->priv.\n");
- return -ENOMEM;
- }
-
/* Grab the region so we can find a different board if IRQ select fails. */
request_region(ioaddr, E21_IO_EXTENT, "e2100");
@@ -423,12 +426,15 @@ init_module(void)
}
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -440,13 +446,15 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
struct device *dev = &dev_e21[this_dev];
if (dev->priv != NULL) {
+ void *priv = dev->priv;
/* NB: e21_close() handles free_irq */
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
release_region(dev->base_addr, E21_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 54a7ac5ef..b26a1bfc0 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1106,6 +1106,8 @@ hardware_send_packet(struct device *dev, void *buf, short length)
dev->tbusy = 0;
}
+ lp->stats.tx_bytes += length;
+
if (net_debug > 5)
printk("eepro: exiting hardware_send_packet routine.\n");
return;
@@ -1164,6 +1166,7 @@ eepro_rx(struct device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += rcv_size;
}
else { /* Not sure will ever reach here,
I set the 595 to discard bad received frames */
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index cc23deba7..37d4df7f9 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1,4 +1,4 @@
-/* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */
+/* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */
/*
NOTICE: this version tested with kernels 1.3.72 and later only!
Written 1996-1997 by Donald Becker.
@@ -33,7 +33,23 @@ static int rxdmacount = 0;
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
+/*
+ * NOTE! The value of 2000 means that this optimization never gets
+ * used. Rationale: it seems to be broken when in low-memory situations,
+ * apparently when alloc_skb() can return NULL the clever list of
+ * copy-buffers can get buggered.
+ *
+ * My personal suspicion is that the allocation failure will cause
+ * us to not remove the skb from the list of available buffers, but
+ * we'd already have done a "skb_push()" with the data we got, so
+ * the buffer stays on the list but the available memory in it
+ * shrinks until we panic.
+ *
+ * Donald, when you fix this you can shrink this value again.
+ *
+ * Linus
+ */
+static int rx_copybreak = 2000;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 200;
@@ -143,7 +159,7 @@ int speedo_debug = 3;
I. Board Compatibility
This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's
-single-chip fast ethernet controller for PCI, as used on the Intel
+single-chip fast Ethernet controller for PCI, as used on the Intel
EtherExpress Pro 100 adapter.
II. Board-specific settings
@@ -197,7 +213,7 @@ An additional complexity of these non-transmit commands are that they may be
added asynchronous to the normal transmit queue, so we disable interrupts
whenever the Tx descriptor ring is manipulated.
-A notable aspect of the these special configure commands is that they do
+A notable aspect of these special configure commands is that they do
work with the normal Tx ring entry scavenge method. The Tx ring scavenge
is done at interrupt time using the 'dirty_tx' index, and checking for the
command-complete bit. While the setup frames may have the NoOp command on the
@@ -475,6 +491,7 @@ int eepro100_init(struct device *dev)
if (pci_present()) {
static int pci_index = 0;
+
for (; pci_index < 8; pci_index++) {
unsigned char pci_bus, pci_device_fn, pci_latency;
#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
@@ -491,9 +508,9 @@ int eepro100_init(struct device *dev)
unsigned short pci_command;
if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82557,
- pci_index, &pci_bus,
- &pci_device_fn))
+ PCI_DEVICE_ID_INTEL_82557,
+ pci_index, &pci_bus,
+ &pci_device_fn))
break;
#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
pdev = pci_find_slot(pci_bus, pci_device_fn);
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index d1886f7c3..38c2b80b8 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -65,7 +65,7 @@
* Note by Zoltan Szilagyi 10-12-96:
*
* I've succeeded in eliminating the "CU wedged" messages, and hence the
- * lockups, which were only occuring with cards running in 8-bit mode ("force
+ * lockups, which were only occurring with cards running in 8-bit mode ("force
* 8-bit operation" in Intel's SoftSet utility). This version of the driver
* sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
* CU before submitting a packet for transmission, and then restarts it as soon
@@ -743,7 +743,7 @@ static void eexp_hw_set_interface(struct device *dev)
break;
}
outb(oldval, dev->base_addr+0x300e);
- udelay(20000);
+ mdelay(20);
}
/*
@@ -1357,7 +1357,7 @@ static void eexp_hw_init586(struct device *dev)
eexp_hw_rxinit(dev);
outb(0,ioaddr+EEPROM_Ctrl);
- udelay(5000);
+ mdelay(5);
scb_command(dev, 0xf000);
outb(0,ioaddr+SIGNAL_CA);
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index b6fc14f55..dc52fd84e 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -69,7 +69,6 @@ static int max_interrupt_work = 10;
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
@@ -124,6 +123,7 @@ char kernel_version[] = UTS_RELEASE;
#if (LINUX_VERSION_CODE < 0x20123)
#define test_and_set_bit(val, addr) set_bit(val, addr)
+#include <linux/bios32.h>
#else
#ifdef MODULE
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
@@ -258,7 +258,7 @@ static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
#endif
static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq,
- int chip_id, int options, int card_idx);
+ int chip_id, int options, int card_idx);
static int epic_open(struct device *dev);
static int read_eeprom(int ioaddr, int location);
static int mii_read(int ioaddr, int phy_id, int location);
@@ -293,11 +293,17 @@ int epic100_probe(struct device *dev)
well with the current structure. So instead we detect just the
Epic cards in slot order. */
- if (pcibios_present()) {
+ if (pci_present()) {
unsigned char pci_bus, pci_device_fn;
for (;pci_index < 0xff; pci_index++) {
- unsigned char pci_irq_line, pci_latency;
+#if LINUX_VERSION_CODE >= 0x20155
+ unsigned int pci_irq_line;
+ struct pci_dev *pdev;
+#else
+ unsigned char pci_irq_line;
+#endif
+ unsigned char pci_latency;
unsigned short pci_command, vendor, device;
unsigned int pci_ioaddr, chip_idx = 0;
@@ -317,10 +323,16 @@ int epic100_probe(struct device *dev)
pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_DEVICE_ID, &device);
+#if LINUX_VERSION_CODE >= 0x20155
+ pdev = pci_find_slot(pci_bus, pci_device_fn);
+ pci_irq_line = pdev->irq;
+ pci_ioaddr = pdev->base_address[0];
+#else
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_INTERRUPT_LINE, &pci_irq_line);
pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &pci_ioaddr);
+#endif
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
@@ -731,6 +743,17 @@ epic_start_xmit(struct sk_buff *skb, struct device *dev)
int entry;
u32 flag;
+#ifndef final_version
+ if (skb == NULL || skb->len <= 0) {
+ printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
+ dev->name);
+#if 0
+ dev_tint(dev);
+#endif
+ return 0;
+ }
+#endif
+
/* 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 (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index b4e3d1d79..6aeb146db 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -181,6 +181,9 @@ __initfunc(int es_probe1(struct device *dev, int ioaddr))
return ENODEV;
}
+ if (load_8390_module("es3210.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("es3210.c: Passed a NULL device.\n");
@@ -413,12 +416,15 @@ init_module(void)
if (io[this_dev] == 0 && this_dev != 0) break;
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -430,12 +436,14 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
struct device *dev = &dev_es3210[this_dev];
if (dev->priv != NULL) {
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
free_irq(dev->irq, dev);
release_region(dev->base_addr, ES_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 315cc27da..5618f1fcd 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -340,7 +340,7 @@ static int num_ewrk3s = 0, num_eth = 0;
*/
#define INIT_EWRK3 {\
outb(EEPROM_INIT, EWRK3_IOPR);\
- udelay(1000);\
+ mdelay(1);\
}
@@ -1139,7 +1139,7 @@ static int ewrk3_close(struct device *dev)
/*
** Clean out the TX and RX queues here (note that one entry
- ** may get added to either the TXD or RX queues if the the TX or RX
+ ** may get added to either the TXD or RX queues if the TX or RX
** just starts processing a packet before the STOP_EWRK3 command
** is received. This will be flushed in the ewrk3_open() call).
*/
diff --git a/drivers/net/hamradio/Config.in b/drivers/net/hamradio/Config.in
index 29e182fe9..2aaa087a1 100644
--- a/drivers/net/hamradio/Config.in
+++ b/drivers/net/hamradio/Config.in
@@ -11,17 +11,20 @@ if [ "$CONFIG_SCC" != "n" ]; then
bool ' support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO
fi
-dep_tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX $CONFIG_AX25
-dep_tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX $CONFIG_AX25
-dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_AX25
+tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX
+tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX
+tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR
+tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP
-dep_tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM $CONFIG_AX25
+tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM
if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
bool ' soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
bool ' soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
bool ' soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200
bool ' soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7
bool ' soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
+ bool ' soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
bool ' soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
+ bool ' soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
fi
diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile
index 07e2aade5..aeb14f32c 100644
--- a/drivers/net/hamradio/Makefile
+++ b/drivers/net/hamradio/Makefile
@@ -107,6 +107,16 @@ else
endif
endif
+ifeq ($(CONFIG_BAYCOM_EPP),y)
+L_OBJS += baycom_epp.o
+CONFIG_HDLCDRV_BUILTIN = y
+else
+ ifeq ($(CONFIG_BAYCOM_EPP),m)
+ CONFIG_HDLCDRV_MODULE = y
+ M_OBJS += baycom_epp.o
+ endif
+endif
+
ifeq ($(CONFIG_SOUNDMODEM),y)
ALL_SUB_DIRS += soundmodem
SUB_DIRS += soundmodem
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
new file mode 100644
index 000000000..2a2f4e909
--- /dev/null
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -0,0 +1,1557 @@
+/*****************************************************************************/
+
+/*
+ * baycom_epp.c -- baycom epp radio modem driver.
+ *
+ * Copyright (C) 1998
+ * Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ *
+ * History:
+ * 0.1 xx.xx.98 Initial version by Matthias Welwarsky (dg2fef)
+ * 0.2 21.04.98 Massive rework by Thomas Sailer
+ * Integrated FPGA EPP modem configuration routines
+ * 0.3 11.05.98 Took FPGA config out and moved it into a separate program
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/socket.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/parport.h>
+#include <linux/bitops.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+//#include <net/ax25dev.h>
+#include <linux/kmod.h>
+#include <linux/hdlcdrv.h>
+#include <linux/baycom.h>
+#include <linux/soundmodem.h>
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+/* prototypes for ax25_encapsulate and ax25_rebuild_header */
+#include <net/ax25.h>
+#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * currently this module is supposed to support both module styles, i.e.
+ * the old one present up to about 2.1.9, and the new one functioning
+ * starting with 2.1.21. The reason is I have a kit allowing to compile
+ * this module also under 2.0.x which was requested by several people.
+ * This will go in 2.2
+ */
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x20100
+#include <asm/uaccess.h>
+#else
+#include <asm/segment.h>
+#include <linux/mm.h>
+
+#undef put_user
+#undef get_user
+
+#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
+#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
+
+extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+{
+ int i = verify_area(VERIFY_READ, from, n);
+ if (i)
+ return i;
+ memcpy_fromfs(to, from, n);
+ return 0;
+}
+
+extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+{
+ int i = verify_area(VERIFY_WRITE, to, n);
+ if (i)
+ return i;
+ memcpy_tofs(to, from, n);
+ return 0;
+}
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+/* --------------------------------------------------------------------- */
+
+#define BAYCOM_DEBUG
+#define BAYCOM_MAGIC 19730510
+
+/* --------------------------------------------------------------------- */
+
+static const char paranoia_str[] = KERN_ERR
+"baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n";
+
+#define baycom_paranoia_check(dev,routine,retval) \
+({ \
+ if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->magic != BAYCOM_MAGIC) { \
+ printk(paranoia_str, routine); \
+ return retval; \
+ } \
+})
+
+#define baycom_paranoia_check_void(dev,routine) \
+({ \
+ if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->magic != BAYCOM_MAGIC) { \
+ printk(paranoia_str, routine); \
+ return; \
+ } \
+})
+
+/* --------------------------------------------------------------------- */
+
+static const char bc_drvname[] = "baycom_epp";
+static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_epp: version 0.3 compiled " __TIME__ " " __DATE__ "\n";
+
+/* --------------------------------------------------------------------- */
+
+#define NR_PORTS 4
+
+static struct device baycom_device[NR_PORTS];
+
+static struct {
+ const char *mode;
+ int iobase;
+} baycom_ports[NR_PORTS] = { { NULL, 0 }, };
+
+/* --------------------------------------------------------------------- */
+
+/* EPP status register */
+#define EPP_DCDBIT 0x80
+#define EPP_PTTBIT 0x08
+#define EPP_NREF 0x01
+#define EPP_NRAEF 0x02
+#define EPP_NRHF 0x04
+#define EPP_NTHF 0x20
+#define EPP_NTAEF 0x10
+#define EPP_NTEF EPP_PTTBIT
+
+/* EPP control register */
+#define EPP_TX_FIFO_ENABLE 0x10
+#define EPP_RX_FIFO_ENABLE 0x08
+#define EPP_MODEM_ENABLE 0x20
+#define EPP_LEDS 0xC0
+#define EPP_IRQ_ENABLE 0x10
+
+/* LPT registers */
+#define LPTREG_ECONTROL 0x402
+#define LPTREG_CONFIGB 0x401
+#define LPTREG_CONFIGA 0x400
+#define LPTREG_EPPDATA 0x004
+#define LPTREG_EPPADDR 0x003
+#define LPTREG_CONTROL 0x002
+#define LPTREG_STATUS 0x001
+#define LPTREG_DATA 0x000
+
+/* LPT control register */
+#define LPTCTRL_PROGRAM 0x04 /* 0 to reprogram */
+#define LPTCTRL_WRITE 0x01
+#define LPTCTRL_ADDRSTB 0x08
+#define LPTCTRL_DATASTB 0x02
+#define LPTCTRL_INTEN 0x10
+
+/* LPT status register */
+#define LPTSTAT_SHIFT_NINTR 6
+#define LPTSTAT_WAIT 0x80
+#define LPTSTAT_NINTR (1<<LPTSTAT_SHIFT_NINTR)
+#define LPTSTAT_PE 0x20
+#define LPTSTAT_DONE 0x10
+#define LPTSTAT_NERROR 0x08
+#define LPTSTAT_EPPTIMEOUT 0x01
+
+/* LPT data register */
+#define LPTDATA_SHIFT_TDI 0
+#define LPTDATA_SHIFT_TMS 2
+#define LPTDATA_TDI (1<<LPTDATA_SHIFT_TDI)
+#define LPTDATA_TCK 0x02
+#define LPTDATA_TMS (1<<LPTDATA_SHIFT_TMS)
+#define LPTDATA_INITBIAS 0x80
+
+
+/* EPP modem config/status bits */
+#define EPP_DCDBIT 0x80
+#define EPP_PTTBIT 0x08
+#define EPP_RXEBIT 0x01
+#define EPP_RXAEBIT 0x02
+#define EPP_RXHFULL 0x04
+
+#define EPP_NTHF 0x20
+#define EPP_NTAEF 0x10
+#define EPP_NTEF EPP_PTTBIT
+
+#define EPP_TX_FIFO_ENABLE 0x10
+#define EPP_RX_FIFO_ENABLE 0x08
+#define EPP_MODEM_ENABLE 0x20
+#define EPP_LEDS 0xC0
+#define EPP_IRQ_ENABLE 0x10
+
+/* Xilinx 4k JTAG instructions */
+#define XC4K_IRLENGTH 3
+#define XC4K_EXTEST 0
+#define XC4K_PRELOAD 1
+#define XC4K_CONFIGURE 5
+#define XC4K_BYPASS 7
+
+#define EPP_CONVENTIONAL 0
+#define EPP_FPGA 1
+#define EPP_FPGAEXTSTATUS 2
+
+#define TXBUFFER_SIZE ((HDLCDRV_MAXFLEN*6/5)+8)
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Information that need to be kept for each board.
+ */
+
+struct baycom_state {
+ int magic;
+
+ struct pardevice *pdev;
+ unsigned int bh_running;
+ struct tq_struct run_bh;
+ unsigned int modem;
+ unsigned int bitrate;
+ unsigned char stat;
+
+ char ifname[HDLCDRV_IFNAMELEN];
+
+ struct {
+ unsigned int intclk;
+ unsigned int divider;
+ unsigned int extmodem;
+ unsigned int loopback;
+ } cfg;
+
+ struct hdlcdrv_channel_params ch_params;
+
+ struct {
+ unsigned int bitbuf, bitstream, numbits, state;
+ unsigned char *bufptr;
+ int bufcnt;
+ unsigned char buf[TXBUFFER_SIZE];
+ } hdlcrx;
+
+ struct {
+ int calibrate;
+ int slotcnt;
+ int flags;
+ enum { tx_idle = 0, tx_keyup, tx_data, tx_tail } state;
+ unsigned char *bufptr;
+ int bufcnt;
+ unsigned char buf[TXBUFFER_SIZE];
+ } hdlctx;
+
+ struct net_device_stats stats;
+ unsigned int ptt_keyed;
+ struct sk_buff_head send_queue; /* Packets awaiting transmission */
+
+
+#ifdef BAYCOM_DEBUG
+ struct debug_vals {
+ unsigned long last_jiffies;
+ unsigned cur_intcnt;
+ unsigned last_intcnt;
+ int cur_pllcorr;
+ int last_pllcorr;
+ unsigned int mod_cycles;
+ unsigned int demod_cycles;
+ } debug_vals;
+#endif /* BAYCOM_DEBUG */
+};
+
+/* --------------------------------------------------------------------- */
+
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+
+/* --------------------------------------------------------------------- */
+
+#define KISS_VERBOSE
+
+/* --------------------------------------------------------------------- */
+
+#define PARAM_TXDELAY 1
+#define PARAM_PERSIST 2
+#define PARAM_SLOTTIME 3
+#define PARAM_TXTAIL 4
+#define PARAM_FULLDUP 5
+#define PARAM_HARDWARE 6
+#define PARAM_RETURN 255
+
+/* --------------------------------------------------------------------- */
+/*
+ * the CRC routines are stolen from WAMPES
+ * by Dieter Deyke
+ */
+
+static const unsigned short crc_ccitt_table[] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*---------------------------------------------------------------------------*/
+
+#if 0
+extern inline void append_crc_ccitt(unsigned char *buffer, int len)
+{
+ unsigned int crc = 0xffff;
+
+ for (;len>0;len--)
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff];
+ crc ^= 0xffff;
+ *buffer++ = crc;
+ *buffer++ = crc >> 8;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+extern inline int check_crc_ccitt(const unsigned char *buf, int cnt)
+{
+ unsigned int crc = 0xffff;
+
+ for (; cnt > 0; cnt--)
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
+ return (crc & 0xffff) == 0xf0b8;
+}
+
+/*---------------------------------------------------------------------------*/
+
+extern inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
+{
+ unsigned int crc = 0xffff;
+
+ for (; cnt > 0; cnt--)
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
+ crc ^= 0xffff;
+ return (crc & 0xffff);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800)
+
+/* --------------------------------------------------------------------- */
+
+static void inline baycom_int_freq(struct baycom_state *bc)
+{
+#ifdef BAYCOM_DEBUG
+ unsigned long cur_jiffies = jiffies;
+ /*
+ * measure the interrupt frequency
+ */
+ bc->debug_vals.cur_intcnt++;
+ if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+ bc->debug_vals.last_jiffies = cur_jiffies;
+ bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
+ bc->debug_vals.cur_intcnt = 0;
+ bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
+ bc->debug_vals.cur_pllcorr = 0;
+ }
+#endif /* BAYCOM_DEBUG */
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * eppconfig_path should be setable via /proc/sys.
+ */
+
+char eppconfig_path[256] = "/sbin/eppfpga";
+
+static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
+
+static int errno;
+
+static int exec_eppfpga(void *b)
+{
+ struct baycom_state *bc = (struct baycom_state *)b;
+ char modearg[256];
+ char portarg[16];
+ char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, NULL};
+ int i;
+
+ /* set up arguments */
+ sprintf(modearg, "%sclk,%smodem,divider=%d%s,extstat",
+ bc->cfg.intclk ? "int" : "ext",
+ bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider,
+ bc->cfg.loopback ? ",loopback" : "");
+ sprintf(portarg, "%ld", bc->pdev->port->base);
+ printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
+
+ for (i = 0; i < current->files->max_fds; i++ )
+ if (current->files->fd[i])
+ close(i);
+ set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */
+ current->uid = current->euid = current->fsuid = 0;
+ if (execve(eppconfig_path, argv, envp) < 0) {
+ printk(KERN_ERR "%s: failed to exec %s -s -p %s -m %s, errno = %d\n",
+ bc_drvname, eppconfig_path, portarg, modearg, errno);
+ return -errno;
+ }
+ return 0;
+}
+
+
+/* eppconfig: called during ifconfig up to configure the modem */
+
+static int eppconfig(struct baycom_state *bc)
+{
+ int i, pid, r;
+ mm_segment_t fs;
+
+ pid = kernel_thread(exec_eppfpga, bc, CLONE_FS);
+ if (pid < 0) {
+ printk(KERN_ERR "%s: fork failed, errno %d\n", bc_drvname, -pid);
+ return pid;
+ }
+ fs = get_fs();
+ set_fs(KERNEL_DS); /* Allow i to be in kernel space. */
+ r = waitpid(pid, &i, __WCLONE);
+ set_fs(fs);
+ if (r != pid) {
+ printk(KERN_ERR "%s: waitpid(%d) failed, returning %d\n",
+ bc_drvname, pid, r);
+ return -1;
+ }
+ printk(KERN_DEBUG "%s: eppfpga returned %d\n", bc_drvname, i);
+ return i;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void inline do_kiss_params(struct baycom_state *bc,
+ unsigned char *data, unsigned long len)
+{
+
+#ifdef KISS_VERBOSE
+#define PKP(a,b) printk(KERN_INFO "%s: channel params: " a "\n", bc->ifname, b)
+#else /* KISS_VERBOSE */
+#define PKP(a,b)
+#endif /* KISS_VERBOSE */
+
+ if (len < 2)
+ return;
+ switch(data[0]) {
+ case PARAM_TXDELAY:
+ bc->ch_params.tx_delay = data[1];
+ PKP("TX delay = %ums", 10 * bc->ch_params.tx_delay);
+ break;
+ case PARAM_PERSIST:
+ bc->ch_params.ppersist = data[1];
+ PKP("p persistence = %u", bc->ch_params.ppersist);
+ break;
+ case PARAM_SLOTTIME:
+ bc->ch_params.slottime = data[1];
+ PKP("slot time = %ums", bc->ch_params.slottime);
+ break;
+ case PARAM_TXTAIL:
+ bc->ch_params.tx_tail = data[1];
+ PKP("TX tail = %ums", bc->ch_params.tx_tail);
+ break;
+ case PARAM_FULLDUP:
+ bc->ch_params.fulldup = !!data[1];
+ PKP("%s duplex", bc->ch_params.fulldup ? "full" : "half");
+ break;
+ default:
+ break;
+ }
+#undef PKP
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * high performance HDLC encoder
+ * yes, it's ugly, but generates pretty good code
+ */
+
+#define ENCODEITERA(j) \
+({ \
+ if (!(notbitstream & (0x1f0 << j))) \
+ goto stuff##j; \
+ encodeend##j: \
+})
+
+#define ENCODEITERB(j) \
+({ \
+ stuff##j: \
+ bitstream &= ~(0x100 << j); \
+ bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | \
+ ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); \
+ numbit++; \
+ notbitstream = ~bitstream; \
+ goto encodeend##j; \
+})
+
+
+static void encode_hdlc(struct baycom_state *bc)
+{
+ struct sk_buff *skb;
+ unsigned char *wp, *bp;
+ int pkt_len;
+ unsigned bitstream, notbitstream, bitbuf, numbit, crc;
+ unsigned char crcarr[2];
+
+ if (bc->hdlctx.bufcnt > 0)
+ return;
+ while ((skb = skb_dequeue(&bc->send_queue))) {
+ if (skb->data[0] != 0) {
+ do_kiss_params(bc, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ continue;
+ }
+ pkt_len = skb->len-1; /* strip KISS byte */
+ if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) {
+ dev_kfree_skb(skb);
+ continue;
+ }
+ wp = bc->hdlctx.buf;
+ bp = skb->data+1;
+ crc = calc_crc_ccitt(bp, pkt_len);
+ crcarr[0] = crc;
+ crcarr[1] = crc >> 8;
+ *wp++ = 0x7e;
+ bitstream = bitbuf = numbit = 0;
+ while (pkt_len > -2) {
+ bitstream >>= 8;
+ bitstream |= ((unsigned int)*bp) << 8;
+ bitbuf |= ((unsigned int)*bp) << numbit;
+ notbitstream = ~bitstream;
+ bp++;
+ pkt_len--;
+ if (!pkt_len)
+ bp = crcarr;
+ ENCODEITERA(0);
+ ENCODEITERA(1);
+ ENCODEITERA(2);
+ ENCODEITERA(3);
+ ENCODEITERA(4);
+ ENCODEITERA(5);
+ ENCODEITERA(6);
+ ENCODEITERA(7);
+ goto enditer;
+ ENCODEITERB(0);
+ ENCODEITERB(1);
+ ENCODEITERB(2);
+ ENCODEITERB(3);
+ ENCODEITERB(4);
+ ENCODEITERB(5);
+ ENCODEITERB(6);
+ ENCODEITERB(7);
+ enditer:
+ numbit += 8;
+ while (numbit >= 8) {
+ *wp++ = bitbuf;
+ bitbuf >>= 8;
+ numbit -= 8;
+ }
+ }
+ bitbuf |= 0x7e7e << numbit;
+ numbit += 16;
+ while (numbit >= 8) {
+ *wp++ = bitbuf;
+ bitbuf >>= 8;
+ numbit -= 8;
+ }
+ bc->hdlctx.bufptr = bc->hdlctx.buf;
+ bc->hdlctx.bufcnt = wp - bc->hdlctx.buf;
+ dev_kfree_skb(skb);
+ bc->stats.tx_packets++;
+ return;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned short random_seed;
+
+static inline unsigned short random_num(void)
+{
+ random_seed = 28629 * random_seed + 157;
+ return random_seed;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void transmit(struct baycom_state *bc, int cnt, unsigned char stat)
+{
+ struct parport *pp = bc->pdev->port;
+ int i;
+
+ if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT))
+ bc->hdlctx.state = tx_idle;
+ if (bc->hdlctx.state == tx_idle && bc->hdlctx.calibrate <= 0) {
+ if (bc->hdlctx.bufcnt <= 0)
+ encode_hdlc(bc);
+ if (bc->hdlctx.bufcnt <= 0)
+ return;
+ if (!bc->ch_params.fulldup) {
+ if (!(stat & EPP_DCDBIT)) {
+ bc->hdlctx.slotcnt = bc->ch_params.slottime;
+ return;
+ }
+ if ((--bc->hdlctx.slotcnt) > 0)
+ return;
+ bc->hdlctx.slotcnt = bc->ch_params.slottime;
+ if ((random_num() % 256) > bc->ch_params.ppersist)
+ return;
+ }
+ }
+ if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) {
+ bc->hdlctx.state = tx_keyup;
+ bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_delay);
+ bc->ptt_keyed++;
+ }
+ while (cnt > 0) {
+ switch (bc->hdlctx.state) {
+ case tx_keyup:
+ i = min(cnt, bc->hdlctx.flags);
+ cnt -= i;
+ bc->hdlctx.flags -= i;
+ if (bc->hdlctx.flags <= 0)
+ bc->hdlctx.state = tx_data;
+ for (; i > 0; i--)
+ parport_epp_write_data(pp, 0x7e);
+ break;
+
+ case tx_data:
+ if (bc->hdlctx.bufcnt <= 0) {
+ encode_hdlc(bc);
+ if (bc->hdlctx.bufcnt <= 0) {
+ bc->hdlctx.state = tx_tail;
+ bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_tail);
+ break;
+ }
+ }
+ i = min(cnt, bc->hdlctx.bufcnt);
+ bc->hdlctx.bufcnt -= i;
+ cnt -= i;
+ for (; i > 0; i--)
+ parport_epp_write_data(pp, *(bc->hdlctx.bufptr)++);
+ break;
+
+ case tx_tail:
+ encode_hdlc(bc);
+ if (bc->hdlctx.bufcnt > 0) {
+ bc->hdlctx.state = tx_data;
+ break;
+ }
+ i = min(cnt, bc->hdlctx.flags);
+ if (i) {
+ cnt -= i;
+ bc->hdlctx.flags -= i;
+ for (; i > 0; i--)
+ parport_epp_write_data(pp, 0x7e);
+ break;
+ }
+
+ default: /* fall through */
+ if (bc->hdlctx.calibrate <= 0)
+ return;
+ i = min(cnt, bc->hdlctx.calibrate);
+ cnt -= i;
+ bc->hdlctx.calibrate -= i;
+ for (; i > 0; i--)
+ parport_epp_write_data(pp, 0);
+ break;
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void do_rxpacket(struct device *dev)
+{
+ struct baycom_state *bc = (struct baycom_state *)dev->priv;
+ struct sk_buff *skb;
+ unsigned char *cp;
+ unsigned pktlen;
+
+ if (bc->hdlcrx.bufcnt < 4)
+ return;
+ if (!check_crc_ccitt(bc->hdlcrx.buf, bc->hdlcrx.bufcnt))
+ return;
+ pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */
+ if (!(skb = dev_alloc_skb(pktlen))) {
+ printk("%s: memory squeeze, dropping packet\n", bc->ifname);
+ bc->stats.rx_dropped++;
+ return;
+ }
+ skb->dev = dev;
+ cp = skb_put(skb, pktlen);
+ *cp++ = 0; /* KISS kludge */
+ memcpy(cp, bc->hdlcrx.buf, pktlen - 1);
+ skb->protocol = htons(ETH_P_AX25);
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+ bc->stats.rx_packets++;
+}
+
+#define DECODEITERA(j) \
+({ \
+ if (!(notbitstream & (0x0fc << j))) /* flag or abort */ \
+ goto flgabrt##j; \
+ if ((bitstream & (0x1f8 << j)) == (0xf8 << j)) /* stuffed bit */ \
+ goto stuff##j; \
+ enditer##j: \
+})
+
+#define DECODEITERB(j) \
+({ \
+ flgabrt##j: \
+ if (!(notbitstream & (0x1fc << j))) { /* abort received */ \
+ state = 0; \
+ goto enditer##j; \
+ } \
+ if ((bitstream & (0x1fe << j)) != (0x0fc << j)) /* flag received */ \
+ goto enditer##j; \
+ if (state) \
+ do_rxpacket(dev); \
+ bc->hdlcrx.bufcnt = 0; \
+ bc->hdlcrx.bufptr = bc->hdlcrx.buf; \
+ state = 1; \
+ numbits = 7-j; \
+ goto enditer##j; \
+ stuff##j: \
+ numbits--; \
+ bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1); \
+ goto enditer##j; \
+})
+
+static void receive(struct device *dev, int cnt)
+{
+ struct baycom_state *bc = (struct baycom_state *)dev->priv;
+ struct parport *pp = bc->pdev->port;
+ unsigned int bitbuf, notbitstream, bitstream, numbits, state;
+ unsigned char ch;
+
+ numbits = bc->hdlcrx.numbits;
+ state = bc->hdlcrx.state;
+ bitstream = bc->hdlcrx.bitstream;
+ bitbuf = bc->hdlcrx.bitbuf;
+ for (; cnt > 0; cnt--) {
+ ch = parport_epp_read_data(pp);
+ bitstream >>= 8;
+ bitstream |= ch << 8;
+ bitbuf >>= 8;
+ bitbuf |= ch << 8;
+ numbits += 8;
+ notbitstream = ~bitstream;
+ DECODEITERA(0);
+ DECODEITERA(1);
+ DECODEITERA(2);
+ DECODEITERA(3);
+ DECODEITERA(4);
+ DECODEITERA(5);
+ DECODEITERA(6);
+ DECODEITERA(7);
+ goto enddec;
+ DECODEITERB(0);
+ DECODEITERB(1);
+ DECODEITERB(2);
+ DECODEITERB(3);
+ DECODEITERB(4);
+ DECODEITERB(5);
+ DECODEITERB(6);
+ DECODEITERB(7);
+ enddec:
+ while (state && numbits >= 8) {
+ if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
+ state = 0;
+ } else {
+ *(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits);
+ bc->hdlcrx.bufcnt++;
+ numbits -= 8;
+ }
+ }
+ }
+ bc->hdlcrx.numbits = numbits;
+ bc->hdlcrx.state = state;
+ bc->hdlcrx.bitstream = bitstream;
+ bc->hdlcrx.bitbuf = bitbuf;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef __i386__
+#define GETTICK(x) \
+({ \
+ if (current_cpu_data.x86_capability & X86_FEATURE_TSC) \
+ __asm__ __volatile__("rdtsc" : "=a" (x) : : "dx");\
+})
+#else /* __i386__ */
+#define GETTICK(x)
+#endif /* __i386__ */
+
+static void epp_bh(struct device *dev)
+{
+ struct baycom_state *bc;
+ struct parport *pp;
+ unsigned char stat;
+ unsigned int time1 = 0, time2 = 0, time3 = 0;
+ int cnt, cnt2;
+
+ baycom_paranoia_check_void(dev, "epp_bh");
+ bc = (struct baycom_state *)dev->priv;
+ if (!bc->bh_running)
+ return;
+ baycom_int_freq(bc);
+ pp = bc->pdev->port;
+ /* update status */
+ bc->stat = stat = parport_epp_read_addr(pp);
+ bc->debug_vals.last_pllcorr = stat;
+ GETTICK(time1);
+ if (bc->modem == EPP_FPGAEXTSTATUS) {
+ /* get input count */
+ parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1);
+ cnt = parport_epp_read_addr(pp);
+ cnt |= parport_epp_read_addr(pp) << 8;
+ cnt &= 0x7fff;
+ /* get output count */
+ parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2);
+ cnt2 = parport_epp_read_addr(pp);
+ cnt2 |= parport_epp_read_addr(pp) << 8;
+ cnt2 = 16384 - (cnt2 & 0x7fff);
+ /* return to normal */
+ parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE);
+ transmit(bc, cnt2, stat);
+ GETTICK(time2);
+ receive(dev, cnt);
+ bc->stat = stat = parport_epp_read_addr(pp);
+ } else {
+ /* try to tx */
+ switch (stat & (EPP_NTAEF|EPP_NTHF)) {
+ case EPP_NTHF:
+ cnt = 2048 - 256;
+ break;
+
+ case EPP_NTAEF:
+ cnt = 2048 - 1793;
+ break;
+
+ case 0:
+ cnt = 0;
+ break;
+
+ default:
+ cnt = 2048 - 1025;
+ break;
+ }
+ transmit(bc, cnt, stat);
+ GETTICK(time2);
+ /* do receiver */
+ while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) {
+ switch (stat & (EPP_NRAEF|EPP_NRHF)) {
+ case EPP_NRAEF:
+ cnt = 1025;
+ break;
+
+ case 0:
+ cnt = 1793;
+ break;
+
+ default:
+ cnt = 256;
+ break;
+ }
+ receive(dev, cnt);
+ stat = parport_epp_read_addr(pp);
+ if (parport_epp_check_timeout(pp))
+ goto epptimeout;
+ }
+ cnt = 0;
+ if (bc->bitrate < 50000)
+ cnt = 256;
+ else if (bc->bitrate < 100000)
+ cnt = 128;
+ while (cnt > 0 && stat & EPP_NREF) {
+ receive(dev, 1);
+ cnt--;
+ stat = parport_epp_read_addr(pp);
+ }
+ }
+ GETTICK(time3);
+#ifdef BAYCOM_DEBUG
+ bc->debug_vals.mod_cycles = time2 - time1;
+ bc->debug_vals.demod_cycles = time3 - time2;
+#endif /* BAYCOM_DEBUG */
+ if (parport_epp_check_timeout(pp))
+ goto epptimeout;
+ queue_task(&bc->run_bh, &tq_timer);
+ return;
+ epptimeout:
+ printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname);
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * ===================== network driver interface =========================
+ */
+
+static int baycom_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct baycom_state *bc;
+
+ baycom_paranoia_check(dev, "baycom_send_packet", 0);
+ bc = (struct baycom_state *)dev->priv;
+ skb_queue_tail(&bc->send_queue, skb);
+ dev->trans_start = jiffies;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_set_mac_address(struct device *dev, void *addr)
+{
+ struct sockaddr *sa = (struct sockaddr *)addr;
+
+ /* addr is an AX.25 shifted ASCII mac address */
+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct net_device_stats *baycom_get_stats(struct device *dev)
+{
+ struct baycom_state *bc;
+
+ baycom_paranoia_check(dev, "baycom_get_stats", NULL);
+ bc = (struct baycom_state *)dev->priv;
+ /*
+ * Get the current statistics. This may be called with the
+ * card open or closed.
+ */
+ return &bc->stats;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int epp_preempt(void *handle)
+{
+ /* we cannot relinquish the port in the middle of an operation */
+ return 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void epp_wakeup(void *handle)
+{
+ struct device *dev = (struct device *)handle;
+ struct baycom_state *bc;
+
+ baycom_paranoia_check_void(dev, "epp_wakeup");
+ bc = (struct baycom_state *)dev->priv;
+ printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name);
+ if (!parport_claim(bc->pdev))
+ printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name);
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+static int epp_open(struct device *dev)
+{
+ struct baycom_state *bc;
+ struct parport *pp;
+ const struct tq_struct run_bh = {
+ 0, 0, (void *)(void *)epp_bh, dev
+ };
+ unsigned int i, j;
+ unsigned char stat;
+ unsigned long tstart;
+
+ baycom_paranoia_check(dev, "epp_open", -ENXIO);
+ bc = (struct baycom_state *)dev->priv;
+ if (dev->start)
+ return 0;
+ pp = parport_enumerate();
+ while (pp && pp->base != dev->base_addr)
+ pp = pp->next;
+ if (!pp) {
+ printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr);
+ return -ENXIO;
+ }
+#if 0
+ if (pp->irq < 0) {
+ printk(KERN_ERR "%s: parport at 0x%lx has no irq\n", bc_drvname, pp->base);
+ return -ENXIO;
+ }
+#endif
+ memset(&bc->modem, 0, sizeof(bc->modem));
+ if (!(bc->pdev = parport_register_device(pp, dev->name, epp_preempt, epp_wakeup,
+ epp_interrupt, PARPORT_DEV_LURK, dev))) {
+ printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base);
+ return -ENXIO;
+ }
+ if (parport_claim(bc->pdev)) {
+ printk(KERN_ERR "%s: parport at 0x%lx busy\n", bc_drvname, pp->base);
+ parport_unregister_device(bc->pdev);
+ return -EBUSY;
+ }
+ if (!(pp->modes & (PARPORT_MODE_PCECPEPP|PARPORT_MODE_PCEPP))) {
+ printk(KERN_ERR "%s: parport at 0x%lx does not support any EPP mode\n",
+ bc_drvname, pp->base);
+ parport_unregister_device(bc->pdev);
+ return -EIO;
+ }
+ dev->irq = /*pp->irq*/ 0;
+ bc->run_bh = run_bh;
+ bc->bh_running = 1;
+ if (pp->modes & PARPORT_MODE_PCECPEPP) {
+ printk(KERN_INFO "%s: trying to enable EPP mode\n", bc_drvname);
+ parport_frob_econtrol(pp, 0xe0, 0x80);
+ }
+ /* bc->pdev->port->ops->change_mode(bc->pdev->port, PARPORT_MODE_PCEPP); not yet implemented */
+ bc->modem = EPP_CONVENTIONAL;
+ if (eppconfig(bc))
+ printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname);
+ else
+ bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS;
+ parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */
+ /* reset the modem */
+ parport_epp_write_addr(pp, 0);
+ parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE);
+ /* autoprobe baud rate */
+ tstart = jiffies;
+ i = 0;
+ while ((signed)(jiffies-tstart-HZ/3) < 0) {
+ stat = parport_epp_read_addr(pp);
+ if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) {
+ schedule();
+ continue;
+ }
+ for (j = 0; j < 256; j++)
+ parport_epp_read_data(pp);
+ i += 256;
+ }
+ for (j = 0; j < 256; j++) {
+ stat = parport_epp_read_addr(pp);
+ if (!(stat & EPP_NREF))
+ break;
+ parport_epp_read_data(pp);
+ i++;
+ }
+ tstart = jiffies - tstart;
+ bc->bitrate = i * (8 * HZ) / tstart;
+ j = 1;
+ i = bc->bitrate >> 3;
+ while (j < 7 && i > 150) {
+ j++;
+ i >>= 1;
+ }
+ printk(KERN_INFO "%s: autoprobed bitrate: %d int divider: %d int rate: %d\n",
+ bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2));
+ parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/);
+ /*
+ * initialise hdlc variables
+ */
+ bc->hdlcrx.state = 0;
+ bc->hdlcrx.numbits = 0;
+ bc->hdlctx.state = tx_idle;
+ bc->hdlctx.bufcnt = 0;
+ bc->hdlctx.slotcnt = bc->ch_params.slottime;
+ bc->hdlctx.calibrate = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ /* start the bottom half stuff */
+ queue_task(&bc->run_bh, &tq_timer);
+ MOD_INC_USE_COUNT;
+ return 0;
+
+#if 0
+ errreturn:
+ parport_release(bc->pdev);
+ parport_unregister_device(bc->pdev);
+ return -EIO;
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+static int epp_close(struct device *dev)
+{
+ struct baycom_state *bc;
+ struct parport *pp;
+ struct sk_buff *skb;
+
+ baycom_paranoia_check(dev, "epp_close", -EINVAL);
+ if (!dev->start)
+ return 0;
+ bc = (struct baycom_state *)dev->priv;
+ pp = bc->pdev->port;
+ bc->bh_running = 0;
+ dev->start = 0;
+ dev->tbusy = 1;
+ run_task_queue(&tq_timer); /* dequeue bottom half */
+ bc->stat = EPP_DCDBIT;
+ parport_epp_write_addr(pp, 0);
+ parport_write_control(pp, 0); /* reset the adapter */
+ parport_release(bc->pdev);
+ parport_unregister_device(bc->pdev);
+ /* Free any buffers left in the hardware transmit queue */
+ while ((skb = skb_dequeue(&bc->send_queue)))
+ dev_kfree_skb(skb);
+ printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n",
+ bc_drvname, dev->base_addr, dev->irq);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_setmode(struct baycom_state *bc, const char *modestr)
+{
+ const char *cp;
+
+ if (strstr(modestr,"intclk"))
+ bc->cfg.intclk = 1;
+ if (strstr(modestr,"extclk"))
+ bc->cfg.intclk = 0;
+ if (strstr(modestr,"intmodem"))
+ bc->cfg.extmodem = 0;
+ if (strstr(modestr,"extmodem"))
+ bc->cfg.extmodem = 1;
+ if (strstr(modestr,"noloopback"))
+ bc->cfg.loopback = 0;
+ if (strstr(modestr,"loopback"))
+ bc->cfg.loopback = 1;
+ if ((cp = strstr(modestr,"divider="))) {
+ bc->cfg.divider = simple_strtoul(cp+8, NULL, 0);
+ if (bc->cfg.divider < 1)
+ bc->cfg.divider = 1;
+ if (bc->cfg.divider > 1023)
+ bc->cfg.divider = 1023;
+ }
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct baycom_state *bc;
+ struct baycom_ioctl bi;
+ struct hdlcdrv_ioctl hi;
+ struct sm_ioctl si;
+
+ baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL);
+ bc = (struct baycom_state *)dev->priv;
+ if (cmd != SIOCDEVPRIVATE)
+ return -ENOIOCTLCMD;
+ if (get_user(cmd, (int *)ifr->ifr_data))
+ return -EFAULT;
+#ifdef BAYCOM_DEBUG
+ if (cmd == BAYCOMCTL_GETDEBUG) {
+ bi.data.dbg.debug1 = bc->ptt_keyed;
+ bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
+ bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
+ bc->debug_vals.last_intcnt = 0;
+ if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SMCTL_GETDEBUG) {
+ si.data.dbg.int_rate = bc->debug_vals.last_intcnt;
+ si.data.dbg.mod_cycles = bc->debug_vals.mod_cycles;
+ si.data.dbg.demod_cycles = bc->debug_vals.demod_cycles;
+ si.data.dbg.dma_residue = 0;
+ bc->debug_vals.mod_cycles = bc->debug_vals.demod_cycles = 0;
+ bc->debug_vals.last_intcnt = 0;
+ if (copy_to_user(ifr->ifr_data, &si, sizeof(si)))
+ return -EFAULT;
+ return 0;
+ }
+#endif /* BAYCOM_DEBUG */
+
+ if (copy_from_user(&hi, ifr->ifr_data, sizeof(hi)))
+ return -EFAULT;
+ switch (hi.cmd) {
+ default:
+ return -ENOIOCTLCMD;
+
+ case HDLCDRVCTL_GETCHANNELPAR:
+ hi.data.cp.tx_delay = bc->ch_params.tx_delay;
+ hi.data.cp.tx_tail = bc->ch_params.tx_tail;
+ hi.data.cp.slottime = bc->ch_params.slottime;
+ hi.data.cp.ppersist = bc->ch_params.ppersist;
+ hi.data.cp.fulldup = bc->ch_params.fulldup;
+ break;
+
+ case HDLCDRVCTL_SETCHANNELPAR:
+ if (!suser())
+ return -EACCES;
+ bc->ch_params.tx_delay = hi.data.cp.tx_delay;
+ bc->ch_params.tx_tail = hi.data.cp.tx_tail;
+ bc->ch_params.slottime = hi.data.cp.slottime;
+ bc->ch_params.ppersist = hi.data.cp.ppersist;
+ bc->ch_params.fulldup = hi.data.cp.fulldup;
+ bc->hdlctx.slotcnt = 1;
+ return 0;
+
+ case HDLCDRVCTL_GETMODEMPAR:
+ hi.data.mp.iobase = dev->base_addr;
+ hi.data.mp.irq = dev->irq;
+ hi.data.mp.dma = dev->dma;
+ hi.data.mp.dma2 = 0;
+ hi.data.mp.seriobase = 0;
+ hi.data.mp.pariobase = 0;
+ hi.data.mp.midiiobase = 0;
+ break;
+
+ case HDLCDRVCTL_SETMODEMPAR:
+ if ((!suser()) || dev->start)
+ return -EACCES;
+ dev->base_addr = hi.data.mp.iobase;
+ dev->irq = /*hi.data.mp.irq*/0;
+ dev->dma = /*hi.data.mp.dma*/0;
+ return 0;
+
+ case HDLCDRVCTL_GETSTAT:
+ hi.data.cs.ptt = !!(bc->stat & EPP_PTTBIT);
+ hi.data.cs.dcd = !(bc->stat & EPP_DCDBIT);
+ hi.data.cs.ptt_keyed = bc->ptt_keyed;
+ hi.data.cs.tx_packets = bc->stats.tx_packets;
+ hi.data.cs.tx_errors = bc->stats.tx_errors;
+ hi.data.cs.rx_packets = bc->stats.rx_packets;
+ hi.data.cs.rx_errors = bc->stats.rx_errors;
+ break;
+
+ case HDLCDRVCTL_OLDGETSTAT:
+ hi.data.ocs.ptt = !!(bc->stat & EPP_PTTBIT);
+ hi.data.ocs.dcd = !(bc->stat & EPP_DCDBIT);
+ hi.data.ocs.ptt_keyed = bc->ptt_keyed;
+ break;
+
+ case HDLCDRVCTL_CALIBRATE:
+ bc->hdlctx.calibrate = hi.data.calibrate * bc->bitrate / 8;
+ return 0;
+
+ case HDLCDRVCTL_DRIVERNAME:
+ strncpy(hi.data.drivername, "baycom_epp", sizeof(hi.data.drivername));
+ break;
+
+ case HDLCDRVCTL_GETMODE:
+ sprintf(hi.data.modename, "%sclk,%smodem,divider=%d%s",
+ bc->cfg.intclk ? "int" : "ext",
+ bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider,
+ bc->cfg.loopback ? ",loopback" : "");
+ break;
+
+ case HDLCDRVCTL_SETMODE:
+ if (!suser() || dev->start)
+ return -EACCES;
+ hi.data.modename[sizeof(hi.data.modename)-1] = '\0';
+ return baycom_setmode(bc, hi.data.modename);
+
+ case HDLCDRVCTL_MODELIST:
+ strncpy(hi.data.modename, "intclk,extclk,intmodem,extmodem,divider=x",
+ sizeof(hi.data.modename));
+ break;
+
+ case HDLCDRVCTL_MODEMPARMASK:
+ return HDLCDRV_PARMASK_IOBASE;
+
+ }
+ if (copy_to_user(ifr->ifr_data, &hi, sizeof(hi)))
+ return -EFAULT;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Check for a network adaptor of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, allocate space for the device and return success
+ * (detachable devices only).
+ */
+static int baycom_probe(struct device *dev)
+{
+ static char ax25_bcast[AX25_ADDR_LEN] = {
+ 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1
+ };
+ static char ax25_nocall[AX25_ADDR_LEN] = {
+ 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1
+ };
+ const struct hdlcdrv_channel_params dflt_ch_params = {
+ 20, 2, 10, 40, 0
+ };
+ struct baycom_state *bc;
+
+ if (!dev)
+ return -ENXIO;
+ baycom_paranoia_check(dev, "baycom_probe", -ENXIO);
+ /*
+ * not a real probe! only initialize data structures
+ */
+ bc = (struct baycom_state *)dev->priv;
+ /*
+ * initialize the baycom_state struct
+ */
+ bc->ch_params = dflt_ch_params;
+ bc->ptt_keyed = 0;
+
+ /*
+ * initialize the device struct
+ */
+ dev->open = epp_open;
+ dev->stop = epp_close;
+ dev->do_ioctl = baycom_ioctl;
+ dev->hard_start_xmit = baycom_send_packet;
+ dev->get_stats = baycom_get_stats;
+
+ /* Fill in the fields of the device structure */
+ dev_init_buffers(dev);
+
+ skb_queue_head_init(&bc->send_queue);
+
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ dev->hard_header = ax25_encapsulate;
+ dev->rebuild_header = ax25_rebuild_header;
+#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
+ dev->hard_header = NULL;
+ dev->rebuild_header = NULL;
+#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
+ dev->set_mac_address = baycom_set_mac_address;
+
+ dev->type = ARPHRD_AX25; /* AF_AX25 device */
+ dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
+ dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
+ dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
+ memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+
+ /* New style flags */
+ dev->flags = 0;
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+__initfunc(int baycom_epp_init(void))
+{
+ struct device *dev;
+ int i, found = 0;
+ char set_hw = 1;
+ struct baycom_state *bc;
+
+ printk(bc_drvinfo);
+ /*
+ * register net devices
+ */
+ for (i = 0; i < NR_PORTS; i++) {
+ dev = baycom_device+i;
+ if (!baycom_ports[i].mode)
+ set_hw = 0;
+ if (!set_hw)
+ baycom_ports[i].iobase = 0;
+ memset(dev, 0, sizeof(struct device));
+ if (!(bc = dev->priv = kmalloc(sizeof(struct baycom_state), GFP_KERNEL)))
+ return -ENOMEM;
+ /*
+ * initialize part of the baycom_state struct
+ */
+ memset(bc, 0, sizeof(struct baycom_state));
+ bc->magic = BAYCOM_MAGIC;
+ sprintf(bc->ifname, "bce%d", i);
+ /*
+ * initialize part of the device struct
+ */
+ dev->name = bc->ifname;
+ dev->if_port = 0;
+ dev->init = baycom_probe;
+ dev->start = 0;
+ dev->tbusy = 1;
+ dev->base_addr = baycom_ports[i].iobase;
+ dev->irq = 0;
+ dev->dma = 0;
+ if (register_netdev(dev)) {
+ printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, bc->ifname);
+ kfree(dev->priv);
+ return -ENXIO;
+ }
+ if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
+ set_hw = 0;
+ found++;
+ }
+ if (!found)
+ return -ENXIO;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+/*
+ * command line settable parameters
+ */
+static const char *mode[NR_PORTS] = { "epp", };
+static int iobase[NR_PORTS] = { 0x378, };
+
+#if LINUX_VERSION_CODE >= 0x20115
+
+MODULE_PARM(mode, "s");
+MODULE_PARM_DESC(mode, "baycom operating mode; epp");
+MODULE_PARM(iobase, "i");
+MODULE_PARM_DESC(iobase, "baycom io base address");
+
+MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
+MODULE_DESCRIPTION("Baycom epp amateur radio modem driver");
+
+#endif
+
+__initfunc(int init_module(void))
+{
+ int i;
+
+ for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {
+ baycom_ports[i].mode = mode[i];
+ baycom_ports[i].iobase = iobase[i];
+ }
+ if (i < NR_PORTS-1)
+ baycom_ports[i+1].mode = NULL;
+ return baycom_epp_init();
+}
+
+/* --------------------------------------------------------------------- */
+
+void cleanup_module(void)
+{
+ struct device *dev;
+ struct baycom_state *bc;
+ int i;
+
+ for(i = 0; i < NR_PORTS; i++) {
+ dev = baycom_device+i;
+ bc = (struct baycom_state *)dev->priv;
+ if (bc) {
+ if (bc->magic == BAYCOM_MAGIC) {
+ unregister_netdev(dev);
+ kfree(dev->priv);
+ } else
+ printk(paranoia_str, "cleanup_module");
+ }
+ }
+}
+
+#else /* MODULE */
+/* --------------------------------------------------------------------- */
+/*
+ * format: baycom=io,mode
+ * mode: epp
+ */
+
+__initfunc(void baycom_epp_setup(char *str, int *ints))
+{
+ int i;
+
+ for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
+ if ((i >= NR_PORTS) || (ints[0] < 1)) {
+ printk(KERN_INFO "%s: too many or invalid interface "
+ "specifications\n", bc_drvname);
+ return;
+ }
+ baycom_ports[i].mode = str;
+ baycom_ports[i].irq = ints[1];
+ if (i < NR_PORTS-1)
+ baycom_ports[i+1].mode = NULL;
+}
+
+#endif /* MODULE */
+/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 25fcd137e..e79a00ef6 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -329,9 +329,7 @@ static __inline__ void par96_rx(struct device *dev, struct baycom_state *bc)
static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct parport *pp = (struct parport *)dev_id;
- struct pardevice *pd = pp->cad;
- struct device *dev = (struct device *)pd->private;
+ struct device *dev = (struct device *)dev_id;
struct baycom_state *bc = (struct baycom_state *)dev->priv;
if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
@@ -347,13 +345,14 @@ static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
par96_rx(dev, bc);
if (--bc->modem.arb_divider <= 0) {
bc->modem.arb_divider = 6;
- sti();
+ __sti();
hdlcdrv_arbitrate(dev, &bc->hdrv);
}
}
- sti();
+ __sti();
hdlcdrv_transmitter(dev, &bc->hdrv);
hdlcdrv_receiver(dev, &bc->hdrv);
+ __cli();
}
/* --------------------------------------------------------------------- */
@@ -409,6 +408,7 @@ static int par96_open(struct device *dev)
}
dev->irq = pp->irq;
/* bc->pdev->port->ops->change_mode(bc->pdev->port, PARPORT_MODE_PCSPP); not yet implemented */
+ bc->hdrv.par.bitrate = 9600;
/* switch off PTT */
outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev));
/*bc->pdev->port->ops->enable_irq(bc->pdev->port); not yet implemented */
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index b70e4efde..cf6d0dfeb 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -3,7 +3,7 @@
/*
* baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem driver.
*
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1997-1998 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,6 +34,14 @@
* port, the kernel driver for serial ports cannot be used, and this
* driver only supports standard serial hardware (8250, 16450, 16550A)
*
+ * This modem usually draws its supply current out of the otherwise unused
+ * TXD pin of the serial port. Thus a contignuous stream of 0x00-bytes
+ * is transmitted to achieve a positive supply voltage.
+ *
+ * hsk: This is a 4800 baud FSK modem, designed for TNC use. It works fine
+ * in 'baycom-mode' :-) In contrast to the TCM3105 modem, power is
+ * externally supplied. So there's no need to provide the 0x00-byte-stream
+ * when receiving or idle, which drastically reduces interrupt load.
*
* Command line options (insmod command line)
*
@@ -49,6 +57,9 @@
* 0.3 26.04.97 init code/data tagged
* 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints)
* 0.5 11.11.97 ser12/par96 split into separate files
+ * 0.6 24.01.98 Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
+ * reduced interrupt load in transmit case
+ * reworked receiver
*/
/*****************************************************************************/
@@ -62,8 +73,10 @@
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -73,56 +86,6 @@
/* --------------------------------------------------------------------- */
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_READ, from, n);
- if (i)
- return i;
- memcpy_fromfs(to, from, n);
- return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_WRITE, to, n);
- if (i)
- return i;
- memcpy_tofs(to, from, n);
- return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
#define BAYCOM_DEBUG
/*
@@ -133,8 +96,8 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n)
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_ser_fdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_fdx: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1997-1998 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_ser_fdx: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -172,22 +135,18 @@ static struct {
struct baycom_state {
struct hdlcdrv_state hdrv;
- unsigned int baud, baud_us8, baud_arbdiv;
+ unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout;
unsigned int options;
struct modem_state {
- short arb_divider;
unsigned char flags;
+ unsigned char ptt;
unsigned int shreg;
struct modem_state_ser12 {
unsigned char tx_bit;
- int dcd_sum0, dcd_sum1, dcd_sum2;
- unsigned char last_sample;
unsigned char last_rxbit;
- unsigned int dcd_shreg;
- unsigned int dcd_time;
- unsigned int bit_pll;
- unsigned long last_jiffies;
+ int dcd_sum0, dcd_sum1, dcd_sum2;
+ int dcd_time;
unsigned int pll_time;
unsigned int txshreg;
} ser12;
@@ -236,12 +195,36 @@ static void inline baycom_int_freq(struct baycom_state *bc)
/* --------------------------------------------------------------------- */
-extern inline unsigned int hweight16(unsigned short w)
+static inline void ser12_set_divisor(struct device *dev,
+ unsigned int divisor)
+{
+ outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */
+ outb(divisor, DLL(dev->base_addr));
+ outb(divisor >> 8, DLM(dev->base_addr));
+ outb(0x01, LCR(dev->base_addr)); /* word length = 6 */
+ /*
+ * make sure the next interrupt is generated;
+ * 0 must be used to power the modem; the modem draws its
+ * power from the TxD line
+ */
+ outb(0x00, THR(dev->base_addr));
+ /*
+ * it is important not to set the divider while transmitting;
+ * this reportedly makes some UARTs generating interrupts
+ * in the hundredthousands per second region
+ * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
+ */
+}
+
+/* --------------------------------------------------------------------- */
+
+#if 0
+extern inline unsigned int hweight16(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned char w)
+extern inline unsigned int hweight8(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight16(unsigned short w)
+extern inline unsigned int hweight16(unsigned int w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -249,85 +232,67 @@ extern inline unsigned int hweight16(unsigned short w)
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
-extern inline unsigned int hweight8(unsigned char w)
+extern inline unsigned int hweight8(unsigned int w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
return (res & 0x0F) + ((res >> 4) & 0x0F);
}
+#endif
/* --------------------------------------------------------------------- */
-static __inline__ void ser12_rxsample(struct device *dev, struct baycom_state *bc, unsigned char news)
+static __inline__ void ser12_rx(struct device *dev, struct baycom_state *bc, struct timeval *tv, unsigned char curs)
{
- bc->modem.ser12.dcd_shreg <<= 1;
- bc->modem.ser12.bit_pll += 0x2000;
- if (bc->modem.ser12.last_sample != news) {
- bc->modem.ser12.last_sample = news;
- bc->modem.ser12.dcd_shreg |= 1;
- if (bc->modem.ser12.bit_pll < 0x9000)
- bc->modem.ser12.bit_pll += 0x1000;
- else
- bc->modem.ser12.bit_pll -= 0x1000;
- bc->modem.ser12.dcd_sum0 += 4 * hweight8(bc->modem.ser12.dcd_shreg & 0x38)
- - hweight16(bc->modem.ser12.dcd_shreg & 0x7c0);
+ int timediff;
+ int bdus8 = bc->baud_us >> 3;
+ int bdus4 = bc->baud_us >> 2;
+ int bdus2 = bc->baud_us >> 1;
+
+ timediff = 1000000 + tv->tv_usec - bc->modem.ser12.pll_time;
+ while (timediff >= 500000)
+ timediff -= 1000000;
+ while (timediff >= bdus2) {
+ timediff -= bc->baud_us;
+ bc->modem.ser12.pll_time += bc->baud_us;
+ bc->modem.ser12.dcd_time--;
+ /* first check if there is room to add a bit */
+ if (bc->modem.shreg & 1) {
+ hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff);
+ bc->modem.shreg = 0x10000;
+ }
+ /* add a one bit */
+ bc->modem.shreg >>= 1;
}
- hdlcdrv_channelbit(&bc->hdrv, !!bc->modem.ser12.last_sample);
- if ((--bc->modem.ser12.dcd_time) <= 0) {
- hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
- bc->modem.ser12.dcd_sum1 +
- bc->modem.ser12.dcd_sum2) < 0);
+ if (bc->modem.ser12.dcd_time <= 0) {
+ if (bc->options & BAYCOM_OPTIONS_SOFTDCD)
+ hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
+ bc->modem.ser12.dcd_sum1 +
+ bc->modem.ser12.dcd_sum2) < 0);
bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
bc->modem.ser12.dcd_sum0 = 2; /* slight bias */
- bc->modem.ser12.dcd_time = 120;
+ bc->modem.ser12.dcd_time += 120;
}
- if (bc->modem.ser12.bit_pll >= 0x10000) {
- bc->modem.ser12.bit_pll &= 0xffff;
- bc->modem.shreg >>= 1;
- if (bc->modem.ser12.last_rxbit == bc->modem.ser12.last_sample)
- bc->modem.shreg |= 0x10000;
- bc->modem.ser12.last_rxbit = bc->modem.ser12.last_sample;
- if (bc->modem.shreg & 1) {
- hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1);
- bc->modem.shreg = 0x10000;
- }
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static __inline__ void ser12_rx(struct device *dev, struct baycom_state *bc, unsigned char curs)
-{
- unsigned long curjiff;
- struct timeval tv;
- unsigned int timediff;
-
- /*
- * get current time
- */
- curjiff = jiffies;
- do_gettimeofday(&tv);
- if ((signed)(curjiff - bc->modem.ser12.last_jiffies) >= HZ/4) {
- /* long inactivity; clear HDLC and DCD */
- bc->modem.ser12.dcd_sum1 = 0;
- bc->modem.ser12.dcd_sum2 = 0;
- bc->modem.ser12.dcd_sum0 = 2;
- bc->modem.ser12.dcd_time = 120;
- hdlcdrv_setdcd(&bc->hdrv, 0);
- hdlcdrv_putbits(&bc->hdrv, 0xffff);
- bc->modem.ser12.last_jiffies = curjiff;
- bc->modem.ser12.pll_time = tv.tv_usec;
+ if (bc->modem.ser12.last_rxbit != curs) {
+ bc->modem.ser12.last_rxbit = curs;
+ bc->modem.shreg |= 0x10000;
+ /* adjust the PLL */
+ if (timediff > 0)
+ bc->modem.ser12.pll_time += bdus8;
+ else
+ bc->modem.ser12.pll_time += 1000000 - bdus8;
+ /* update DCD */
+ if (abs(timediff) > bdus4)
+ bc->modem.ser12.dcd_sum0 += 4;
+ else
+ bc->modem.ser12.dcd_sum0--;
+#ifdef BAYCOM_DEBUG
+ bc->debug_vals.cur_pllcorr = timediff;
+#endif /* BAYCOM_DEBUG */
}
- bc->modem.ser12.last_jiffies = curjiff;
- timediff = tv.tv_usec + 1000000 - bc->modem.ser12.pll_time;
- timediff %= 1000000;
- timediff /= bc->baud_us8;
- bc->modem.ser12.pll_time = (bc->modem.ser12.pll_time + timediff * (bc->baud_us8)) % 1000000;
- for (; timediff > 1; timediff--)
- ser12_rxsample(dev, bc, bc->modem.ser12.last_sample);
- if (timediff >= 1)
- ser12_rxsample(dev, bc, curs);
+ while (bc->modem.ser12.pll_time >= 1000000)
+ bc->modem.ser12.pll_time -= 1000000;
}
/* --------------------------------------------------------------------- */
@@ -336,25 +301,30 @@ static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct baycom_state *bc = (struct baycom_state *)dev->priv;
- unsigned char iir, msr = 0;
+ struct timeval tv;
+ unsigned char iir, msr;
unsigned int txcount = 0;
- unsigned int rxcount = 0;
- if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
+ if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC)
return;
-
- for (;;) {
- iir = inb(IIR(dev->base_addr));
- if (iir & 1)
- break;
+ /* fast way out for shared irq */
+ if ((iir = inb(IIR(dev->base_addr))) & 1)
+ return;
+ /* get current time */
+ do_gettimeofday(&tv);
+ msr = inb(MSR(dev->base_addr));
+ /* delta DCD */
+ if ((msr & 8) && !(bc->options & BAYCOM_OPTIONS_SOFTDCD))
+ hdlcdrv_setdcd(&bc->hdrv, !(msr & 0x80));
+ do {
switch (iir & 6) {
case 6:
inb(LSR(dev->base_addr));
- continue;
+ break;
case 4:
inb(RBR(dev->base_addr));
- continue;
+ break;
case 2:
/*
@@ -363,45 +333,53 @@ static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* power from the TxD line
*/
outb(0x00, THR(dev->base_addr));
- bc->modem.arb_divider--;
baycom_int_freq(bc);
- if (hdlcdrv_ptt(&bc->hdrv)) {
- /*
- * first output the last bit (!) then call HDLC transmitter,
- * since this may take quite long
- */
+ txcount++;
+ /*
+ * first output the last bit (!) then call HDLC transmitter,
+ * since this may take quite long
+ */
+ if (bc->modem.ptt)
outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
- txcount++;
- } else
+ else
outb(0x0d, MCR(dev->base_addr)); /* transmitter off */
- continue;
+ break;
default:
msr = inb(MSR(dev->base_addr));
- if (msr & 1) /* delta CTS interrupt */
- rxcount++;
- continue;
+ /* delta DCD */
+ if ((msr & 8) && !(bc->options & BAYCOM_OPTIONS_SOFTDCD))
+ hdlcdrv_setdcd(&bc->hdrv, !(msr & 0x80));
+ break;
}
- }
- if (rxcount)
- ser12_rx(dev, bc, msr & 0x10);
- if (txcount) {
-#ifdef BAYCOM_DEBUG
- if (bc->debug_vals.cur_pllcorr < txcount)
- bc->debug_vals.cur_pllcorr = txcount;
-#endif /* BAYCOM_DEBUG */
- if (bc->modem.ser12.txshreg <= 1)
+ iir = inb(IIR(dev->base_addr));
+ } while (!(iir & 1));
+ ser12_rx(dev, bc, &tv, msr & 0x10); /* CTS */
+ if (bc->modem.ptt && txcount) {
+ if (bc->modem.ser12.txshreg <= 1) {
bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
+ if (!hdlcdrv_ptt(&bc->hdrv)) {
+ ser12_set_divisor(dev, 115200/100/8);
+ bc->modem.ptt = 0;
+ goto end_transmit;
+ }
+ }
bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1));
bc->modem.ser12.txshreg >>= 1;
}
- sti();
- if (bc->modem.arb_divider <= 0) {
- bc->modem.arb_divider = bc->baud_arbdiv;
+ end_transmit:
+ __sti();
+ if (!bc->modem.ptt && txcount) {
hdlcdrv_arbitrate(dev, &bc->hdrv);
+ if (hdlcdrv_ptt(&bc->hdrv)) {
+ ser12_set_divisor(dev, bc->baud_uartdiv);
+ bc->modem.ser12.txshreg = 1;
+ bc->modem.ptt = 1;
+ }
}
hdlcdrv_transmitter(dev, &bc->hdrv);
hdlcdrv_receiver(dev, &bc->hdrv);
+ __cli();
}
/* --------------------------------------------------------------------- */
@@ -461,26 +439,25 @@ static int ser12_open(struct device *dev)
return -EACCES;
memset(&bc->modem, 0, sizeof(bc->modem));
bc->hdrv.par.bitrate = bc->baud;
- bc->baud_us8 = 125000/bc->baud;
- bc->baud_arbdiv = bc->baud/100;
+ bc->baud_us = 1000000/bc->baud;
+ bc->baud_uartdiv = (115200/8)/bc->baud;
if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown)
return -EIO;
outb(0, FCR(dev->base_addr)); /* disable FIFOs */
outb(0x0d, MCR(dev->base_addr));
- outb(0x0d, MCR(dev->base_addr));
outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT,
+ if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,
"baycom_ser_fdx", dev))
return -EBUSY;
request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx");
/*
- * set the SIO to 6 Bits/character and 19600 baud, so that
- * we get exactly (hopefully) one interrupt per radio symbol
+ * set the SIO to 6 Bits/character; during receive,
+ * the baud rate is set to produce 100 ints/sec
+ * to feed the channel arbitration process,
+ * during transmit to baud ints/sec to run
+ * the transmitter
*/
- outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */
- outb(115200/8/bc->baud, DLL(dev->base_addr));
- outb(0, DLM(dev->base_addr));
- outb(0x01, LCR(dev->base_addr)); /* word length = 6 */
+ ser12_set_divisor(dev, 115200/100/8);
/*
* enable transmitter empty interrupt and modem status interrupt
*/
@@ -491,6 +468,7 @@ static int ser12_open(struct device *dev)
* power from the TxD line
*/
outb(0x00, THR(dev->base_addr));
+ hdlcdrv_setdcd(&bc->hdrv, 0);
printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u options "
"0x%x baud %u uart %s\n", bc_drvname, dev->base_addr, dev->irq,
bc->options, bc->baud, uart_str[u]);
@@ -732,7 +710,7 @@ void cleanup_module(void)
#else /* MODULE */
/* --------------------------------------------------------------------- */
/*
- * format: baycom_ser_=io,irq,mode
+ * format: baycom_ser_fdx=io,irq,mode
* mode: [*]
* * indicates sofware DCD
*/
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index f1024658d..f472c8b9e 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -48,6 +48,7 @@
* 0.3 26.04.97 init code/data tagged
* 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints)
* 0.5 11.11.97 ser12/par96 split into separate files
+ * 0.6 14.04.98 cleanups
*/
/*****************************************************************************/
@@ -61,6 +62,8 @@
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -72,56 +75,6 @@
/* --------------------------------------------------------------------- */
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_READ, from, n);
- if (i)
- return i;
- memcpy_fromfs(to, from, n);
- return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_WRITE, to, n);
- if (i)
- return i;
- memcpy_tofs(to, from, n);
- return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
#define BAYCOM_DEBUG
/*
@@ -132,8 +85,8 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n)
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_ser_hdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_hdx: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1997-1998 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_ser_hdx: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -439,27 +392,52 @@ static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct baycom_state *bc = (struct baycom_state *)dev->priv;
+ unsigned char iir;
if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
return;
-
+ /* fast way out */
+ if ((iir = inb(IIR(dev->base_addr))) & 1)
+ return;
baycom_int_freq(bc);
- /*
- * check if transmitter active
- */
- if (hdlcdrv_ptt(&bc->hdrv))
- ser12_tx(dev, bc);
- else {
- ser12_rx(dev, bc);
- if (--bc->modem.arb_divider <= 0) {
- bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
- sti();
- hdlcdrv_arbitrate(dev, &bc->hdrv);
+ do {
+ switch (iir & 6) {
+ case 6:
+ inb(LSR(dev->base_addr));
+ break;
+
+ case 4:
+ inb(RBR(dev->base_addr));
+ break;
+
+ case 2:
+ /*
+ * check if transmitter active
+ */
+ if (hdlcdrv_ptt(&bc->hdrv))
+ ser12_tx(dev, bc);
+ else {
+ ser12_rx(dev, bc);
+ bc->modem.arb_divider--;
+ }
+ outb(0x00, THR(dev->base_addr));
+ break;
+
+ default:
+ inb(MSR(dev->base_addr));
+ break;
}
+ iir = inb(IIR(dev->base_addr));
+ } while (!(iir & 1));
+ if (bc->modem.arb_divider <= 0) {
+ bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
+ __sti();
+ hdlcdrv_arbitrate(dev, &bc->hdrv);
}
- sti();
+ __sti();
hdlcdrv_transmitter(dev, &bc->hdrv);
hdlcdrv_receiver(dev, &bc->hdrv);
+ __cli();
}
/* --------------------------------------------------------------------- */
@@ -521,9 +499,8 @@ static int ser12_open(struct device *dev)
return -EIO;
outb(0, FCR(dev->base_addr)); /* disable FIFOs */
outb(0x0d, MCR(dev->base_addr));
- outb(0x0d, MCR(dev->base_addr));
outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT,
+ if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,
"baycom_ser12", dev))
return -EBUSY;
request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12");
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index fcc9ed7cc..6116f3642 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -318,6 +318,7 @@ static int bpq_xmit(struct sk_buff *skb, struct device *dev)
}
skb->dev = dev;
+ skb->nh.raw = skb->data;
dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
bpq->stats.tx_packets++;
bpq->stats.tx_bytes+=skb->len;
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index c07f90249..bf453dc53 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1,5 +1,5 @@
/*
- * $Id: dmascc.c,v 1.2.1.3 1997/12/19 13:40:15 oe1kib Exp $
+ * $Id: dmascc.c,v 1.2.1.4 1998/06/10 02:24:11 kudielka Exp $
*
* Driver for high-speed SCC boards (those with DMA support)
* Copyright (C) 1997 Klaus Kudielka
@@ -381,7 +381,7 @@ __initfunc(int dmascc_init(void))
/* Check valid I/O address regions */
for (i = 0; i < hw[h].num_devs; i++)
- if (base[i])
+ if (base[i]) {
if (check_region(base[i], hw[h].io_size))
base[i] = 0;
else {
@@ -389,6 +389,7 @@ __initfunc(int dmascc_init(void))
t0[i] = base[i] + hw[h].tmr_offset + TMR_CNT0;
t1[i] = base[i] + hw[h].tmr_offset + TMR_CNT1;
}
+ }
/* Start timers */
for (i = 0; i < hw[h].num_devs; i++)
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index f4fb73844..1b2ee9eac 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -3,7 +3,7 @@
/*
* hdlcdrv.c -- HDLC packet radio network driver.
*
- * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-1998 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
* 0.4 16.04.97 init code/data tagged
* 0.5 30.07.97 made HDLC buffers bigger (solves a problem with the
* soundmodem driver)
+ * 0.6 05.04.98 add spinlocks
*/
/*****************************************************************************/
@@ -47,7 +48,9 @@
#include <linux/if.h>
#include <linux/malloc.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <asm/bitops.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
@@ -67,78 +70,6 @@
/* --------------------------------------------------------------------- */
/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_READ, from, n);
- if (i)
- return i;
- memcpy_fromfs(to, from, n);
- return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_WRITE, to, n);
- if (i)
- return i;
- memcpy_tofs(to, from, n);
- return 0;
-}
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#if LINUX_VERSION_CODE < 0x20115
-extern __inline__ void dev_init_buffers(struct device *dev)
-{
- int i;
- for(i=0;i<DEV_NUMBUFFS;i++)
- {
- skb_queue_head_init(&dev->buffs[i]);
- }
-}
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#if LINUX_VERSION_CODE < 0x20125
-#define test_and_set_bit set_bit
-#define test_and_clear_bit clear_bit
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
* The name of the card. Is used for messages and in the requests for
* io regions, irqs and dma channels
*/
@@ -844,10 +775,12 @@ static int hdlcdrv_probe(struct device *dev)
s->ch_params = dflt_ch_params;
s->ptt_keyed = 0;
+ spin_lock_init(&s->hdlcrx.hbuf.lock);
s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0;
s->hdlcrx.in_hdlc_rx = 0;
s->hdlcrx.rx_state = 0;
+ spin_lock_init(&s->hdlctx.hbuf.lock);
s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0;
s->hdlctx.in_hdlc_tx = 0;
s->hdlctx.tx_state = 1;
@@ -1006,7 +939,7 @@ MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
__initfunc(int init_module(void))
{
printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
- printk(KERN_INFO "hdlcdrv: version 0.5 compiled " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "hdlcdrv: version 0.6 compiled " __TIME__ " " __DATE__ "\n");
#if LINUX_VERSION_CODE < 0x20115
register_symtab(&hdlcdrv_syms);
#endif
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 21cdbf5c6..4d7b96c40 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -10,7 +10,7 @@
* This module implements the AX.25 protocol for kernel-based
* devices like TTYs. It interfaces between a raw TTY, and the
* kernel's AX.25 protocol layers, just like slip.c.
- * AX.25 needs to be seperated from slip.c while slip.c is no
+ * AX.25 needs to be separated from slip.c while slip.c is no
* longer a static kernel device since it is a module.
* This method clears the way to implement other kiss protocols
* like mkiss smack g8bpq ..... so far only mkiss is implemented.
@@ -19,6 +19,9 @@
*
* History
* Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15.
+ * Matthias (DG2FEF) Added support for FlexNet CRC (on special request)
+ * Fixed bug in ax25_close(): dev_lock_wait() was
+ * called twice, causing a deadlock.
*/
#include <linux/config.h>
@@ -91,8 +94,80 @@ static int ax25_init(struct device *);
static int mkiss_init(void);
static int mkiss_write(struct tty_struct *, int, const unsigned char *, int);
static int kiss_esc(unsigned char *, unsigned char *, int);
+static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int);
static void kiss_unesc(struct ax_disp *, unsigned char);
+/*---------------------------------------------------------------------------*/
+
+static const unsigned short Crc_flex_table[] = {
+ 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
+ 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
+ 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
+ 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
+ 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
+ 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
+ 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
+ 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
+ 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
+ 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
+ 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
+ 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
+ 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
+ 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
+ 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
+ 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
+ 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
+ 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
+ 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
+ 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
+ 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
+ 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
+ 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
+ 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
+ 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
+ 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
+ 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
+ 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
+ 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
+ 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
+ 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
+ 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
+};
+
+/*---------------------------------------------------------------------------*/
+
+static unsigned short
+calc_crc_flex(unsigned char *cp, int size)
+{
+ unsigned short crc = 0xffff;
+
+ while (size--)
+ crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
+
+ return crc;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int
+check_crc_flex(unsigned char *cp, int size)
+{
+ unsigned short crc = 0xffff;
+
+ if (size < 3)
+ return -1;
+
+ while (size--)
+ crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
+
+ if ((crc & 0xffff) != 0x7070)
+ return -1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
/* Find a free channel, and link in this `tty' line. */
static inline struct ax_disp *ax_alloc(void)
{
@@ -272,6 +347,13 @@ static void ax_bump(struct ax_disp *ax)
mkiss= ax->mkiss->tty->driver_data;
if (mkiss->magic == MKISS_DRIVER_MAGIC)
tmp_ax = ax->mkiss;
+ } else if (ax->rbuff[0] & 0x20) {
+ ax->crcmode = CRC_MODE_FLEX;
+ if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
+ ax->rx_errors++;
+ return;
+ }
+ ax->rcount -= 2;
}
}
@@ -312,7 +394,19 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
p = icp;
if (mkiss->magic != MKISS_DRIVER_MAGIC) {
- count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
+ switch (ax->crcmode) {
+ unsigned short crc;
+
+ case CRC_MODE_FLEX:
+ *p |= 0x20;
+ crc = calc_crc_flex(p, len);
+ count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
+ break;
+
+ default:
+ count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
+ break;
+ }
ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
actual = ax->tty->driver.write(ax->tty, 0, ax->xbuff, count);
ax->tx_packets++;
@@ -629,12 +723,8 @@ static void ax25_close(struct tty_struct *tty)
return;
mkiss = ax->mode;
- if (ax->dev->flags & IFF_UP)
- {
- dev_lock_wait();
- dev_close(ax->dev);
- dev_unlock_list();
- }
+
+ dev_close(ax->dev);
tty->disc_data = 0;
ax->tty = NULL;
@@ -704,6 +794,45 @@ int kiss_esc(unsigned char *s, unsigned char *d, int len)
return ptr - d;
}
+/*
+ * MW:
+ * OK its ugly, but tell me a better solution without copying the
+ * packet to a temporary buffer :-)
+ */
+static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len)
+{
+ unsigned char *ptr = d;
+ unsigned char c;
+
+ *ptr++ = END;
+ while (len > 0) {
+ if (len > 2)
+ c = *s++;
+ else if (len > 1)
+ c = crc >> 8;
+ else if (len > 0)
+ c = crc & 0xff;
+
+ len--;
+
+ switch (c) {
+ case END:
+ *ptr++ = ESC;
+ *ptr++ = ESC_END;
+ break;
+ case ESC:
+ *ptr++ = ESC;
+ *ptr++ = ESC_ESC;
+ break;
+ default:
+ *ptr++ = c;
+ break;
+ }
+ }
+ *ptr++ = END;
+ return ptr - d;
+}
+
static void kiss_unesc(struct ax_disp *ax, unsigned char s)
{
switch (s) {
@@ -746,14 +875,8 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s)
int ax_set_mac_address(struct device *dev, void *addr)
{
- int err;
-
- if ((err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN)) != 0)
- return err;
-
- /* addr is an AX.25 shifted ASCII mac address */
- copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN);
-
+ if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN))
+ return -EFAULT;
return 0;
}
@@ -780,20 +903,15 @@ static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *ar
switch (cmd) {
case SIOCGIFNAME:
- if ((err = verify_area(VERIFY_WRITE, arg, strlen(ax->dev->name) + 1)) != 0)
- return err;
- copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1);
+ if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1))
+ return -EFAULT;
return 0;
case SIOCGIFENCAP:
- if ((err = verify_area(VERIFY_WRITE, arg, sizeof(int))) != 0)
- return err;
put_user(4, (int *)arg);
return 0;
case SIOCSIFENCAP:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
- return err;
get_user(tmp, (int *)arg);
ax->mode = tmp;
ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */
diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h
index 0e32aa82b..e1531b728 100644
--- a/drivers/net/hamradio/mkiss.h
+++ b/drivers/net/hamradio/mkiss.h
@@ -50,6 +50,10 @@ struct ax_disp {
#define AXF_OUTWAIT 4 /* is outpacket was flag */
int mode;
+ int crcmode; /* MW: for FlexNet, SMACK etc. */
+#define CRC_MODE_NONE 0
+#define CRC_MODE_FLEX 1
+#define CRC_MODE_SMACK 2
};
#define AX25_MAGIC 0x5316
diff --git a/drivers/net/hamradio/soundmodem/Makefile b/drivers/net/hamradio/soundmodem/Makefile
index 1aabdd9e8..a5adf62d0 100644
--- a/drivers/net/hamradio/soundmodem/Makefile
+++ b/drivers/net/hamradio/soundmodem/Makefile
@@ -46,7 +46,7 @@ all: all_targets
.PHONY: all
gentbl: gentbl.c
- $(HOSTCC) -Wall $< -o $@ -lm
+ $(HOSTCC) $(HOSTCFLAGS) $< -o $@ -lm
TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h
TBLHDR += sm_tbl_afsk2666.h sm_tbl_psk4800.h
diff --git a/drivers/net/hamradio/soundmodem/gentbl.c b/drivers/net/hamradio/soundmodem/gentbl.c
index e67733831..a481a56f9 100644
--- a/drivers/net/hamradio/soundmodem/gentbl.c
+++ b/drivers/net/hamradio/soundmodem/gentbl.c
@@ -438,7 +438,7 @@ static void gentbl_hapn4800(FILE *f)
{
int i, j, k, l;
float s;
- float c[40];
+ float c[44];
float min, max;
fprintf(f, "\n/*\n * hapn4800 specific tables\n */\n\n");
diff --git a/drivers/net/hamradio/soundmodem/sm.c b/drivers/net/hamradio/soundmodem/sm.c
index 3423807ac..fbfbb7e36 100644
--- a/drivers/net/hamradio/soundmodem/sm.c
+++ b/drivers/net/hamradio/soundmodem/sm.c
@@ -3,7 +3,7 @@
/*
* sm.c -- soundcard radio modem driver.
*
- * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-1998 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
* 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round)
* 0.6 16.04.97 init code/data tagged
* 0.7 30.07.97 fixed halfduplex interrupt handlers/hotfix for CS423X
+ * 0.8 14.04.98 cleanups
*/
/*****************************************************************************/
@@ -53,6 +54,8 @@
#include <linux/net.h>
#include <linux/in.h>
#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/bitops.h>
@@ -62,59 +65,9 @@
/* --------------------------------------------------------------------- */
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_READ, from, n);
- if (i)
- return i;
- memcpy_fromfs(to, from, n);
- return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_WRITE, to, n);
- if (i)
- return i;
- memcpy_tofs(to, from, n);
- return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
/*static*/ const char sm_drvname[] = "soundmodem";
-static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
+static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1998 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "soundmodem: version 0.8 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -685,51 +638,6 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr,
/* --------------------------------------------------------------------- */
-#ifdef __i386__
-
-int sm_x86_capability = 0;
-
-__initfunc(static void i386_capability(void))
-{
- unsigned long flags;
- unsigned long fl1;
- union {
- struct {
- unsigned int ebx, edx, ecx;
- } r;
- unsigned char s[13];
- } id;
- unsigned int eax;
-
- save_flags(flags);
- flags |= 0x200000;
- restore_flags(flags);
- save_flags(flags);
- fl1 = flags;
- flags &= ~0x200000;
- restore_flags(flags);
- save_flags(flags);
- if (!(fl1 & 0x200000) || (flags & 0x200000)) {
- printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname);
- return;
- }
- __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) :
- "0" (0));
- id.s[12] = 0;
- if (eax < 1) {
- printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability "
- "list\n", sm_drvname, id.s);
- return;
- }
- printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s);
- __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx");
- printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15,
- eax & 15, sm_x86_capability);
-}
-#endif /* __i386__ */
-
-/* --------------------------------------------------------------------- */
-
#ifdef MODULE
__initfunc(static int sm_init(void))
#else /* MODULE */
@@ -742,9 +650,6 @@ __initfunc(int sm_init(void))
char ifname[HDLCDRV_IFNAMELEN];
printk(sm_drvinfo);
-#ifdef __i386__
- i386_capability();
-#endif /* __i386__ */
/*
* register net devices
*/
diff --git a/drivers/net/hamradio/soundmodem/sm.h b/drivers/net/hamradio/soundmodem/sm.h
index 25bbc8ba9..66e8f936c 100644
--- a/drivers/net/hamradio/soundmodem/sm.h
+++ b/drivers/net/hamradio/soundmodem/sm.h
@@ -3,7 +3,7 @@
/*
* sm.h -- soundcard radio modem driver internal header.
*
- * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-1998 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,6 +32,8 @@
#include <linux/hdlcdrv.h>
#include <linux/soundmodem.h>
+#include <asm/processor.h>
+#include <linux/bitops.h>
#define SM_DEBUG
@@ -71,7 +73,7 @@ struct sm_state {
* state of the modem code
*/
union {
- long m[32/sizeof(long)];
+ long m[48/sizeof(long)];
} m;
union {
long d[256/sizeof(long)];
@@ -228,6 +230,7 @@ static inline void diag_add_constellation(struct sm_state *sm, int vali, int val
* ===================== utility functions ===============================
*/
+#if 0
extern inline unsigned int hweight32(unsigned int w)
__attribute__ ((unused));
extern inline unsigned int hweight16(unsigned short w)
@@ -259,6 +262,8 @@ extern inline unsigned int hweight8(unsigned char w)
return (res & 0x0F) + ((res >> 4) & 0x0F);
}
+#endif
+
extern inline unsigned int gcd(unsigned int x, unsigned int y)
__attribute__ ((unused));
extern inline unsigned int lcm(unsigned int x, unsigned int y)
@@ -291,13 +296,13 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
#ifdef __i386__
-extern int sm_x86_capability;
+#include <asm/processor.h>
-#define HAS_RDTSC (sm_x86_capability & 0x10)
+#define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC)
/*
- * only do 32bit cycle counter arithmetic; we hope we won't overflow :-)
- * in fact, overflowing modems would require over 2THz clock speeds :-)
+ * only do 32bit cycle counter arithmetic; we hope we won't overflow.
+ * in fact, overflowing modems would require over 2THz CPU clock speeds :-)
*/
#define time_exec(var,cmd) \
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2666.c b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
new file mode 100644
index 000000000..2aa2972e4
--- /dev/null
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
@@ -0,0 +1,356 @@
+/*****************************************************************************/
+
+/*
+ * sm_afsk2666.c -- soundcard radio modem driver, 2666 baud AFSK modem
+ *
+ * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ */
+
+#include "sm.h"
+#include "sm_tbl_afsk2666.h"
+
+/* --------------------------------------------------------------------- */
+
+struct demod_state_afsk26 {
+ unsigned int shreg;
+ unsigned long descram;
+ int dem_sum[8];
+ int dem_sum_mean;
+ int dem_cnt;
+ unsigned int bit_pll;
+ unsigned char last_sample;
+ unsigned int dcd_shreg;
+ int dcd_sum0, dcd_sum1, dcd_sum2;
+ unsigned int dcd_time;
+};
+
+struct mod_state_afsk26 {
+ unsigned int shreg;
+ unsigned long scram;
+ unsigned int bit_pll;
+ unsigned int phinc;
+ unsigned int tx_seq;
+};
+
+/* --------------------------------------------------------------------- */
+
+#define DESCRAM_TAP1 0x20000
+#define DESCRAM_TAP2 0x01000
+#define DESCRAM_TAP3 0x00001
+
+#define DESCRAM_TAPSH1 17
+#define DESCRAM_TAPSH2 12
+#define DESCRAM_TAPSH3 0
+
+#define SCRAM_TAP1 0x20000 /* X^17 */
+#define SCRAM_TAPN 0x00021 /* X^0+X^5 */
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_2666_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+ struct mod_state_afsk26 *st = (struct mod_state_afsk26 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = ((st->scram << 1) | (st->scram & 1));
+ st->scram ^= (!(st->shreg & 1));
+ st->shreg >>= 1;
+ if (st->scram & (SCRAM_TAP1 << 1))
+ st->scram ^= SCRAM_TAPN << 1;
+ st->phinc = afsk26_carfreq[!(st->scram & (SCRAM_TAP1 << 2))];
+ }
+ if (st->tx_seq >= 6)
+ st->tx_seq = 0;
+ *buf = OFFSCOS(st->bit_pll);
+ st->bit_pll += st->phinc;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_2666_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_afsk26 *st = (struct mod_state_afsk26 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = ((st->scram << 1) | (st->scram & 1));
+ st->scram ^= (!(st->shreg & 1));
+ st->shreg >>= 1;
+ if (st->scram & (SCRAM_TAP1 << 1))
+ st->scram ^= SCRAM_TAPN << 1;
+ st->phinc = afsk26_carfreq[!(st->scram & (SCRAM_TAP1 << 2))];
+ }
+ if (st->tx_seq >= 6)
+ st->tx_seq = 0;
+ *buf = COS(st->bit_pll);
+ st->bit_pll += st->phinc;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
+{
+ int sum = -0x80 * csum;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+ sum += (st[-8] * coeff[8]);
+ sum += (st[-9] * coeff[9]);
+ sum += (st[-10] * coeff[10]);
+ sum += (st[-11] * coeff[11]);
+
+ return sum;
+}
+
+extern __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
+{
+ int sum = 0;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+ sum += (st[-8] * coeff[8]);
+ sum += (st[-9] * coeff[9]);
+ sum += (st[-10] * coeff[10]);
+ sum += (st[-11] * coeff[11]);
+
+ sum >>= 8;
+ return sum;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+static int binexp(unsigned int i)
+{
+ int ret = 31;
+
+ if (!i)
+ return 0;
+ if (i < 0x10000LU) {
+ i <<= 16;
+ ret -= 16;
+ }
+ if (i < 0x1000000LU) {
+ i <<= 8;
+ ret -= 8;
+ }
+ if (i < 0x10000000LU) {
+ i <<= 4;
+ ret -= 4;
+ }
+ if (i < 0x40000000LU) {
+ i <<= 2;
+ ret -= 2;
+ }
+ if (i < 0x80000000LU)
+ ret -= 1;
+ return ret;
+}
+
+static const sqrt_tab[16] = {
+ 00000, 16384, 23170, 28378, 32768, 36636, 40132, 43348,
+ 46341, 49152, 51811, 54340, 56756, 59073, 61303, 63455
+};
+
+
+static unsigned int int_sqrt_approx(unsigned int i)
+{
+ unsigned int j;
+
+ if (i < 16)
+ return sqrt_tab[i] >> 14;
+ j = binexp(i) >> 1;
+ i >>= (j * 2 - 2);
+ return (sqrt_tab[i & 0xf] << j) >> 15;
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+extern unsigned int est_pwr(int i, int q)
+{
+ unsigned int ui = abs(i);
+ unsigned int uq = abs(q);
+
+ if (uq > ui) {
+ unsigned int tmp;
+ tmp = ui;
+ ui = uq;
+ uq = tmp;
+ }
+ if (uq > (ui >> 1))
+ return 7*(ui>>3) + 9*(uq>>4);
+ else
+ return ui + (uq>>2);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_one_sample(struct sm_state *sm, struct demod_state_afsk26 *st, int curval,
+ int loi, int loq, int hii, int hiq)
+{
+ static const int pll_corr[2] = { -0xa00, 0xa00 };
+ unsigned char curbit;
+ unsigned int descx;
+ int val;
+
+ /*
+ * estimate power
+ */
+ val = est_pwr(hii, hiq) - est_pwr(loi, loq);
+ /*
+ * estimate center value
+ */
+ st->dem_sum[0] += val >> 8;
+ if ((++st->dem_cnt) >= 256) {
+ st->dem_cnt = 0;
+ st->dem_sum_mean = (st->dem_sum[0]+st->dem_sum[1]+
+ st->dem_sum[2]+st->dem_sum[3]+
+ st->dem_sum[4]+st->dem_sum[5]+
+ st->dem_sum[6]+st->dem_sum[7]) >> 3;
+ memmove(st->dem_sum+1, st->dem_sum,
+ sizeof(st->dem_sum)-sizeof(st->dem_sum[0]));
+ st->dem_sum[0] = 0;
+ }
+ /*
+ * decision and bit clock regen
+ */
+ val -= st->dem_sum_mean;
+ diag_add(sm, curval, val);
+
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x1555;
+ curbit = (val > 0);
+ if (st->last_sample ^ curbit) {
+ st->dcd_shreg |= 1;
+ st->bit_pll += pll_corr[st->bit_pll < (0x8000+0x1555)];
+ st->dcd_sum0 += 4*hweight8(st->dcd_shreg & 0x1e) -
+ hweight16(st->dcd_shreg & 0xfe00);
+ }
+ st->last_sample = curbit;
+ hdlcdrv_channelbit(&sm->hdrv, curbit);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 400;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffffu;
+ st->descram = (st->descram << 1) | curbit;
+ descx = st->descram ^ (st->descram >> 1);
+ descx ^= ((descx >> DESCRAM_TAPSH1) ^
+ (descx >> DESCRAM_TAPSH2));
+ st->shreg >>= 1;
+ st->shreg |= (!(descx & 1)) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ diag_trigger(sm);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2666_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+ struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d);
+
+ for (; buflen > 0; buflen--, buf++) {
+ demod_one_sample(sm, st, (*buf-0x80)<<8,
+ convolution12_u8(buf, afsk26_dem_tables[0][0].i, AFSK26_DEM_SUM_I_0_0),
+ convolution12_u8(buf, afsk26_dem_tables[0][0].q, AFSK26_DEM_SUM_Q_0_0),
+ convolution12_u8(buf, afsk26_dem_tables[0][1].i, AFSK26_DEM_SUM_I_0_1),
+ convolution12_u8(buf, afsk26_dem_tables[0][1].q, AFSK26_DEM_SUM_Q_0_1));
+ demod_one_sample(sm, st, (*buf-0x80)<<8,
+ convolution12_u8(buf, afsk26_dem_tables[1][0].i, AFSK26_DEM_SUM_I_1_0),
+ convolution12_u8(buf, afsk26_dem_tables[1][0].q, AFSK26_DEM_SUM_Q_1_0),
+ convolution12_u8(buf, afsk26_dem_tables[1][1].i, AFSK26_DEM_SUM_I_1_1),
+ convolution12_u8(buf, afsk26_dem_tables[1][1].q, AFSK26_DEM_SUM_Q_1_1));
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2666_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+ struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d);
+
+ for (; buflen > 0; buflen--, buf++) {
+ demod_one_sample(sm, st, *buf,
+ convolution12_s16(buf, afsk26_dem_tables[0][0].i, AFSK26_DEM_SUM_I_0_0),
+ convolution12_s16(buf, afsk26_dem_tables[0][0].q, AFSK26_DEM_SUM_Q_0_0),
+ convolution12_s16(buf, afsk26_dem_tables[0][1].i, AFSK26_DEM_SUM_I_0_1),
+ convolution12_s16(buf, afsk26_dem_tables[0][1].q, AFSK26_DEM_SUM_Q_0_1));
+ demod_one_sample(sm, st, *buf,
+ convolution12_s16(buf, afsk26_dem_tables[1][0].i, AFSK26_DEM_SUM_I_1_0),
+ convolution12_s16(buf, afsk26_dem_tables[1][0].q, AFSK26_DEM_SUM_Q_1_0),
+ convolution12_s16(buf, afsk26_dem_tables[1][1].i, AFSK26_DEM_SUM_I_1_1),
+ convolution12_s16(buf, afsk26_dem_tables[1][1].q, AFSK26_DEM_SUM_Q_1_1));
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_init_2666(struct sm_state *sm)
+{
+ struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d);
+
+ st->dcd_time = 400;
+ st->dcd_sum0 = 2;
+}
+
+/* --------------------------------------------------------------------- */
+
+const struct modem_tx_info sm_afsk2666_tx = {
+ "afsk2666", sizeof(struct mod_state_afsk26), AFSK26_SAMPLERATE, 2666,
+ modulator_2666_u8, modulator_2666_s16, NULL
+};
+
+const struct modem_rx_info sm_afsk2666_rx = {
+ "afsk2666", sizeof(struct demod_state_afsk26), AFSK26_SAMPLERATE, 2666, 12, 6,
+ demodulator_2666_u8, demodulator_2666_s16, demod_init_2666
+};
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/soundmodem/sm_psk4800.c b/drivers/net/hamradio/soundmodem/sm_psk4800.c
new file mode 100644
index 000000000..cbb49042b
--- /dev/null
+++ b/drivers/net/hamradio/soundmodem/sm_psk4800.c
@@ -0,0 +1,418 @@
+/*****************************************************************************/
+
+/*
+ * sm_psk4800.c -- soundcard radio modem driver, 4800 baud 8PSK modem
+ *
+ * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ */
+
+#include "sm.h"
+#include "sm_tbl_psk4800.h"
+
+/* --------------------------------------------------------------------- */
+
+#define DESCRAM_TAP1 0x20000
+#define DESCRAM_TAP2 0x01000
+#define DESCRAM_TAP3 0x00001
+
+#define DESCRAM_TAPSH1 17
+#define DESCRAM_TAPSH2 12
+#define DESCRAM_TAPSH3 0
+
+#define SCRAM_TAP1 0x20000 /* X^17 */
+#define SCRAM_TAPN 0x00021 /* X^0+X^5 */
+
+#define SCRAM_SHIFT 17
+
+/* --------------------------------------------------------------------- */
+
+struct demod_state_psk48 {
+ /*
+ * input mixer and lowpass
+ */
+ short infi[PSK48_RXF_LEN/2], infq[PSK48_RXF_LEN/2];
+ unsigned int downmixer;
+ int ovrphase;
+ short magi, magq;
+ /*
+ * sampling instant recovery
+ */
+ int pwrhist[5];
+ unsigned int s_phase;
+ int cur_sync;
+ /*
+ * phase recovery
+ */
+ short cur_phase_dev;
+ short last_ph_err;
+ unsigned short pskph;
+ unsigned int phase;
+ unsigned short last_pskph;
+ unsigned char cur_raw, last_raw, rawbits;
+ /*
+ * decoding
+ */
+ unsigned int shreg;
+ unsigned long descram;
+ unsigned int bit_pll;
+ unsigned char last_sample;
+ unsigned int dcd_shreg;
+ int dcd_sum0, dcd_sum1, dcd_sum2;
+ unsigned int dcd_time;
+};
+
+struct mod_state_psk48 {
+ unsigned char txbits[PSK48_TXF_NUMSAMPLES];
+ unsigned short txphase;
+ unsigned int shreg;
+ unsigned long scram;
+ const short *tbl;
+ unsigned int txseq;
+};
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_4800_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+ struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m);
+ int i, j;
+ int si, sq;
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->txseq++) {
+ memmove(st->txbits+1, st->txbits,
+ sizeof(st->txbits)-sizeof(st->txbits[0]));
+ for (i = 0; i < 3; i++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = (st->scram << 1) |
+ (st->shreg & 1);
+ st->shreg >>= 1;
+ if (st->scram & SCRAM_TAP1)
+ st->scram ^= SCRAM_TAPN;
+ }
+ j = (st->scram >> (SCRAM_SHIFT+3)) & 7;
+ st->txbits[0] -= (j ^ (j >> 1));
+ st->txbits[0] &= 7;
+ st->tbl = psk48_tx_table;
+ }
+ if (st->txseq >= PSK48_TXF_OVERSAMPLING)
+ st->txseq = 0;
+ for (j = si = sq = 0; j < PSK48_TXF_NUMSAMPLES; j++, st->tbl += 16) {
+ si += st->tbl[st->txbits[j]];
+ sq += st->tbl[st->txbits[j]+8];
+ }
+ *buf = ((si*COS(st->txphase)+ sq*SIN(st->txphase)) >> 23) + 0x80;
+ st->txphase = (st->txphase + PSK48_PHASEINC) & 0xffffu;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_4800_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m);
+ int i, j;
+ int si, sq;
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->txseq++) {
+ memmove(st->txbits+1, st->txbits,
+ sizeof(st->txbits)-sizeof(st->txbits[0]));
+ for (i = 0; i < 3; i++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = (st->scram << 1) |
+ (st->shreg & 1);
+ st->shreg >>= 1;
+ if (st->scram & SCRAM_TAP1)
+ st->scram ^= SCRAM_TAPN;
+ }
+ j = (st->scram >> (SCRAM_SHIFT+3)) & 7;
+ st->txbits[0] -= (j ^ (j >> 1));
+ st->txbits[0] &= 7;
+ st->tbl = psk48_tx_table;
+ }
+ if (st->txseq >= PSK48_TXF_OVERSAMPLING)
+ st->txseq = 0;
+ for (j = si = sq = 0; j < PSK48_TXF_NUMSAMPLES; j++, st->tbl += 16) {
+ si += st->tbl[st->txbits[j]];
+ sq += st->tbl[st->txbits[j]+8];
+ }
+ *buf = (si*COS(st->txphase)+ sq*SIN(st->txphase)) >> 15;
+ st->txphase = (st->txphase + PSK48_PHASEINC) & 0xffffu;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static __inline__ unsigned short tbl_atan(short q, short i)
+{
+ short tmp;
+ unsigned short argoffs = 0;
+
+ if (i == 0 && q == 0)
+ return 0;
+ switch (((q < 0) << 1) | (i < 0)) {
+ case 0:
+ break;
+ case 1:
+ tmp = q;
+ q = -i;
+ i = tmp;
+ argoffs = 0x4000;
+ break;
+ case 3:
+ q = -q;
+ i = -i;
+ argoffs = 0x8000;
+ break;
+ case 2:
+ tmp = -q;
+ q = i;
+ i = tmp;
+ argoffs = 0xc000;
+ break;
+ }
+ if (q > i) {
+ tmp = i / q * ATAN_TABLEN;
+ return (argoffs+0x4000-atan_tab[((i<<15)/q*ATAN_TABLEN>>15)])
+ &0xffffu;
+ }
+ return (argoffs+atan_tab[((q<<15)/i*ATAN_TABLEN)>>15])&0xffffu;
+}
+
+#define ATAN(q,i) tbl_atan(q, i)
+
+/* --------------------------------------------------------------------- */
+
+static void demod_psk48_baseband(struct sm_state *sm, struct demod_state_psk48 *st,
+ short vali, short valq)
+{
+ int i, j;
+
+ st->magi = vali;
+ st->magq = valq;
+ memmove(st->pwrhist+1, st->pwrhist,
+ sizeof(st->pwrhist)-sizeof(st->pwrhist[0]));
+ st->pwrhist[0] = st->magi * st->magi +
+ st->magq * st->magq;
+ st->cur_sync = ((st->pwrhist[4] >> 2) > st->pwrhist[2] &&
+ (st->pwrhist[0] >> 2) > st->pwrhist[2] &&
+ st-> pwrhist[3] > st->pwrhist[2] &&
+ st->pwrhist[1] > st->pwrhist[2]);
+ st->s_phase &= 0xffff;
+ st->s_phase += PSK48_SPHASEINC;
+ st->dcd_shreg <<= 1;
+ if (st->cur_sync) {
+ if (st->s_phase >= (0x8000 + 5*PSK48_SPHASEINC/2))
+ st->s_phase -= PSK48_SPHASEINC/6;
+ else
+ st->s_phase += PSK48_SPHASEINC/6;
+ st->dcd_sum0 = 4*hweight8(st->dcd_shreg & 0xf8)-
+ hweight16(st->dcd_shreg & 0x1f00);
+ }
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 240;
+ }
+ if (st->s_phase < 0x10000)
+ return;
+ /*
+ * sample one constellation
+ */
+ st->last_pskph = st->pskph;
+ st->pskph = (ATAN(st->magq, st->magi)-
+ st->phase) & 0xffffu;
+ st->last_ph_err = (st->pskph & 0x1fffu) - 0x1000;
+ st->phase += st->last_ph_err/16;
+ st->last_raw = st->cur_raw;
+ st->cur_raw = ((st->pskph >> 13) & 7);
+ i = (st->cur_raw - st->last_raw) & 7;
+ st->rawbits = i ^ (i >> 1) ^ (i >> 2);
+ st->descram = (st->descram << 3) | (st->rawbits);
+ hdlcdrv_channelbit(&sm->hdrv, st->descram & 4);
+ hdlcdrv_channelbit(&sm->hdrv, st->descram & 2);
+ hdlcdrv_channelbit(&sm->hdrv, st->descram & 1);
+ i = (((st->descram >> DESCRAM_TAPSH1) & 7) ^
+ ((st->descram >> DESCRAM_TAPSH2) & 7) ^
+ ((st->descram >> DESCRAM_TAPSH3) & 7));
+ for (j = 4; j; j >>= 1) {
+ st->shreg >>= 1;
+ st->shreg |= (!!(i & j)) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ }
+
+#if 0
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x4000;
+ curbit = (*buf >= 0x80);
+ if (st->last_sample ^ curbit) {
+ st->dcd_shreg |= 1;
+ st->bit_pll += pll_corr
+ [st->bit_pll < 0xa000];
+ st->dcd_sum0 += 8 *
+ hweight8(st->dcd_shreg & 0x0c) -
+ !!(st->dcd_shreg & 0x10);
+ }
+ st->last_sample = curbit;
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 240;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffffu;
+ st->descram = (st->descram << 1) | curbit;
+ descx = st->descram ^ (st->descram >> 1);
+ descx ^= ((descx >> DESCRAM_TAPSH1) ^
+ (descx >> DESCRAM_TAPSH2));
+ st->shreg >>= 1;
+ st->shreg |= (!(descx & 1)) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ diag_trigger(sm);
+ }
+ diag_add_one(sm, ((short)(*buf - 0x80)) << 8);
+#endif
+
+ diag_trigger(sm);
+ diag_add_constellation(sm, (vali*COS(st->phase)+ valq*SIN(st->phase)) >> 13,
+ (valq*COS(st->phase) - vali*SIN(st->phase)) >> 13);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_4800_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+ struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d);
+ int i, si, sq;
+ const short *coeff;
+
+ for (; buflen > 0; buflen--, buf++) {
+ memmove(st->infi+1, st->infi,
+ sizeof(st->infi)-sizeof(st->infi[0]));
+ memmove(st->infq+1, st->infq,
+ sizeof(st->infq)-sizeof(st->infq[0]));
+ si = *buf;
+ si &= 0xff;
+ si -= 128;
+ diag_add_one(sm, si << 8);
+ st->infi[0] = (si * COS(st->downmixer))>>7;
+ st->infq[0] = (si * SIN(st->downmixer))>>7;
+ st->downmixer = (st->downmixer-PSK48_PHASEINC)&0xffffu;
+ for (i = si = sq = 0, coeff = psk48_rx_coeff; i < (PSK48_RXF_LEN/2);
+ i++, coeff += 2) {
+ si += st->infi[i] * (*coeff);
+ sq += st->infq[i] * (*coeff);
+ }
+ demod_psk48_baseband(sm, st, si >> 15, sq >> 15);
+ for (i = si = sq = 0, coeff = psk48_rx_coeff + 1; i < (PSK48_RXF_LEN/2);
+ i++, coeff += 2) {
+ si += st->infi[i] * (*coeff);
+ sq += st->infq[i] * (*coeff);
+ }
+ demod_psk48_baseband(sm, st, si >> 15, sq >> 15);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_4800_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+ struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d);
+ int i, si, sq;
+ const short *coeff;
+
+ for (; buflen > 0; buflen--, buf++) {
+ memmove(st->infi+1, st->infi,
+ sizeof(st->infi)-sizeof(st->infi[0]));
+ memmove(st->infq+1, st->infq,
+ sizeof(st->infq)-sizeof(st->infq[0]));
+ si = *buf;
+ diag_add_one(sm, si);
+ st->infi[0] = (si * COS(st->downmixer))>>15;
+ st->infq[0] = (si * SIN(st->downmixer))>>15;
+ st->downmixer = (st->downmixer-PSK48_PHASEINC)&0xffffu;
+ for (i = si = sq = 0, coeff = psk48_rx_coeff; i < (PSK48_RXF_LEN/2);
+ i++, coeff += 2) {
+ si += st->infi[i] * (*coeff);
+ sq += st->infq[i] * (*coeff);
+ }
+ demod_psk48_baseband(sm, st, si >> 15, sq >> 15);
+ for (i = si = sq = 0, coeff = psk48_rx_coeff + 1; i < (PSK48_RXF_LEN/2);
+ i++, coeff += 2) {
+ si += st->infi[i] * (*coeff);
+ sq += st->infq[i] * (*coeff);
+ }
+ demod_psk48_baseband(sm, st, si >> 15, sq >> 15);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void mod_init_4800(struct sm_state *sm)
+{
+ struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m);
+
+ st->scram = 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_init_4800(struct sm_state *sm)
+{
+ struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d);
+
+ st->dcd_time = 120;
+ st->dcd_sum0 = 2;
+}
+
+/* --------------------------------------------------------------------- */
+
+const struct modem_tx_info sm_psk4800_tx = {
+ "psk4800", sizeof(struct mod_state_psk48),
+ PSK48_SAMPLERATE, 4800,
+ modulator_4800_u8, modulator_4800_s16, mod_init_4800
+};
+
+const struct modem_rx_info sm_psk4800_rx = {
+ "psk4800", sizeof(struct demod_state_psk48),
+ PSK48_SAMPLERATE, 4800, 1, PSK48_TXF_OVERSAMPLING,
+ demodulator_4800_u8, demodulator_4800_s16, demod_init_4800
+};
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 84289fcba..55506e0ef 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -159,6 +159,9 @@ __initfunc(int hpp_probe1(struct device *dev, int ioaddr))
|| (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300)
return ENODEV;
+ if (load_8390_module("hp-plus.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("hp-plus.c: Passed a NULL device.\n");
@@ -260,7 +263,7 @@ hpp_open(struct device *dev)
int ioaddr = dev->base_addr - NIC_OFFSET;
int option_reg;
- if (request_irq(dev->irq, &ei_interrupt, 0, "hp-plus", dev)) {
+ if (request_irq(dev->irq, ei_interrupt, 0, "hp-plus", dev)) {
return -EAGAIN;
}
@@ -447,12 +450,15 @@ init_module(void)
}
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -464,14 +470,16 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
struct device *dev = &dev_hpp[this_dev];
if (dev->priv != NULL) {
- /* NB: hpp_close() handles free_irq */
int ioaddr = dev->base_addr - NIC_OFFSET;
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
+ /* NB: hpp_close() handles free_irq */
release_region(ioaddr, HP_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 55ac7de0f..a7dcba56b 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -131,6 +131,9 @@ __initfunc(int hp_probe1(struct device *dev, int ioaddr))
wordmode = 0;
}
+ if (load_8390_module("hp.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("hp.c: Passed a NULL device.\n");
@@ -140,6 +143,12 @@ __initfunc(int hp_probe1(struct device *dev, int ioaddr))
if (ei_debug && version_printed++ == 0)
printk(version);
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk (" unable to get memory for dev->priv.\n");
+ return -ENOMEM;
+ }
+
printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
for(i = 0; i < ETHER_ADDR_LEN; i++)
@@ -158,7 +167,7 @@ __initfunc(int hp_probe1(struct device *dev, int ioaddr))
outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
if (irq == autoirq_report(0) /* It's a good IRQ line! */
- && request_irq (irq, &ei_interrupt, 0, "hp", dev) == 0) {
+ && request_irq (irq, ei_interrupt, 0, "hp", dev) == 0) {
printk(" selecting IRQ %d.\n", irq);
dev->irq = *irqp;
break;
@@ -167,6 +176,8 @@ __initfunc(int hp_probe1(struct device *dev, int ioaddr))
} while (*++irqp);
if (*irqp == 0) {
printk(" no free IRQ lines.\n");
+ kfree(dev->priv);
+ dev->priv = NULL;
return EBUSY;
}
} else {
@@ -174,17 +185,12 @@ __initfunc(int hp_probe1(struct device *dev, int ioaddr))
dev->irq = 9;
if (request_irq(dev->irq, ei_interrupt, 0, "hp", dev)) {
printk (" unable to get IRQ %d.\n", dev->irq);
+ kfree(dev->priv);
+ dev->priv = NULL;
return EBUSY;
}
}
- /* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (ethdev_init(dev)) {
- printk (" unable to get memory for dev->priv.\n");
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
-
/* Grab the region so we can find another board if something fails. */
request_region(ioaddr, HP_IO_EXTENT,"hp");
@@ -415,12 +421,15 @@ init_module(void)
}
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -433,13 +442,15 @@ cleanup_module(void)
struct device *dev = &dev_hp[this_dev];
if (dev->priv != NULL) {
int ioaddr = dev->base_addr - NIC_OFFSET;
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
free_irq(dev->irq, dev);
release_region(ioaddr, HP_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index bd97a51b3..d39e02ee8 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -338,7 +338,7 @@ static void hp100_RegisterDump( struct device *dev );
/* TODO: This function should not really be needed in a good design... */
static void wait( void )
{
- udelay( 1000 );
+ mdelay(1);
}
/*
@@ -1899,7 +1899,7 @@ static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
if ( lp->lan_type == HP100_LAN_100 )
lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
hp100_start_interface( dev );
- udelay(1000);
+ mdelay(1);
}
}
dev->trans_start = jiffies;
diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
index 436dd3700..9b05f837b 100644
--- a/drivers/net/hp100.h
+++ b/drivers/net/hp100.h
@@ -529,7 +529,7 @@
*/
#define MAX_RX_PDL 30 /* Card limit = 31 */
-#define MAX_RX_FRAG 2 /* Dont need more... */
+#define MAX_RX_FRAG 2 /* Don't need more... */
#define MAX_TX_PDL 29
#define MAX_TX_FRAG 2 /* Limit = 31 */
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
new file mode 100644
index 000000000..fb7f61729
--- /dev/null
+++ b/drivers/net/hplance.c
@@ -0,0 +1,247 @@
+/* hplance.c : the Linux/hp300/lance ethernet driver
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ * Uses the generic 7990.c LANCE code.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "hplance.h"
+
+/* We have 16834 bytes of RAM for the init block and buffers. This places
+ * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
+ * buffers and 2 Tx buffers.
+ */
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+
+#include "7990.h" /* use generic LANCE code */
+
+/* Our private data structure */
+struct hplance_private {
+ struct lance_private lance;
+ unsigned int scode;
+ void *base;
+};
+
+/* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+ * plus board-specific init, open and close actions.
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+int hplance_probe(struct device *dev);
+static int hplance_init(struct device *dev, int scode);
+static int hplance_open(struct device *dev);
+static int hplance_close(struct device *dev);
+static void hplance_writerap(struct hplance_private *lp, unsigned short value);
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value);
+static unsigned short hplance_readrdp(struct hplance_private *lp);
+
+#ifdef MODULE
+static struct hplance_private *root_hplance_dev = NULL;
+#endif
+
+/* Find all the HP Lance boards and initialise them... */
+__initfunc(int hplance_probe(struct device *dev))
+{
+ int cards = 0, called = 0;
+
+ if (!MACH_IS_HP300 || called)
+ return(ENODEV);
+ called++;
+
+ /* Isn't DIO nice? */
+ for(;;)
+ {
+ int v, scode = dio_find(DIO_ID_LAN);
+
+ if (!scode)
+ break;
+
+ if(cards)
+ dev = NULL; /* don't trash previous device, make a new one */
+ cards++;
+
+ v = hplance_init(dev, scode);
+ if (v) /* error, abort immediately */
+ return v;
+ }
+ /* OK, return success, or ENODEV if we didn't find any cards */
+ if (!cards)
+ return ENODEV;
+ return 0;
+}
+
+/* Initialise a single lance board at the given select code */
+__initfunc (static int hplance_init(struct device *dev, int scode))
+{
+ /* const char *name = dio_scodetoname(scode); */
+ static const char name[] = "HP LANCE";
+ void *va = dio_scodetoviraddr(scode);
+ struct hplance_private *lp;
+ int i;
+
+ if (dev == NULL)
+ dev = init_etherdev(0, sizeof(struct hplance_private));
+ else
+ {
+ dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct hplance_private));
+ }
+ printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
+
+ /* reset the board */
+ writeb(0xff,va+DIO_IDOFF);
+ udelay(100); /* ariba! ariba! udelay! udelay! */
+
+ /* Fill the dev fields */
+ dev->base_addr = (unsigned long)va;
+ dev->open = &hplance_open;
+ dev->stop = &hplance_close;
+ dev->hard_start_xmit = &lance_start_xmit;
+ dev->get_stats = &lance_get_stats;
+ dev->set_multicast_list = &lance_set_multicast;
+ dev->dma = 0;
+
+ for (i=0; i<6; i++)
+ {
+ /* The NVRAM holds our ethernet address, one nibble per byte,
+ * at bytes NVRAMOFF+1,3,5,7,9...
+ */
+ dev->dev_addr[i] = ((readb(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
+ | (readb(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+ printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
+ }
+
+ lp = (struct hplance_private *)dev->priv;
+ lp->lance.name = (char*)name; /* discards const, shut up gcc */
+ lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
+ lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
+ lp->lance.lance_init_block = 0; /* LANCE addr of same RAM */
+ lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
+ lp->lance.irq = dio_scodetoipl(scode);
+ lp->lance.writerap = hplance_writerap;
+ lp->lance.writerdp = hplance_writerdp;
+ lp->lance.readrdp = hplance_readrdp;
+ lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
+ lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+ lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+ lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+ lp->scode = scode;
+ lp->base = va;
+ ether_setup(dev);
+ printk(", irq %d\n", lp->lance.irq);
+
+#ifdef MODULE
+ dev->ifindex = dev_new_index();
+ lp->next_module = root_hplance_dev;
+ root_hplance_dev = lp;
+#endif /* MODULE */
+
+ dio_config_board(scode); /* tell bus scanning code this one's taken */
+ return 0;
+}
+
+/* This is disgusting. We have to check the DIO status register for ack every
+ * time we read or write the LANCE registers.
+ */
+static void hplance_writerap(struct hplance_private *lp, unsigned short value)
+{
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ do {
+ lp->lance.ll->rap = value;
+ } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value)
+{
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ do {
+ lp->lance.ll->rdp = value;
+ } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static unsigned short hplance_readrdp(struct hplance_private *lp)
+{
+ unsigned short val;
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ do {
+ val = lp->lance.ll->rdp;
+ } while ((hpregs->status & LE_ACK) == 0);
+ return val;
+}
+
+static int hplance_open(struct device *dev)
+{
+ int status;
+ struct hplance_private *lp = (struct hplance_private *)dev->priv;
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+
+ status = lance_open(dev); /* call generic lance open code */
+ if (status)
+ return status;
+ /* enable interrupts at board level. */
+ writeb(LE_IE, &(hpregs->status));
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int hplance_close(struct device *dev)
+{
+ struct hplance_private *lp = (struct hplance_private *)dev->priv;
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ writeb(0,&(hpregs->status)); /* disable interrupts at boardlevel */
+ lance_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ root_lance_dev = NULL;
+ return hplance_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+ /* Walk the chain of devices, unregistering them */
+ struct hplance_private *lp;
+ while (root_hplance_dev) {
+ lp = root_hplance_dev->next_module;
+ dio_unconfig_board(lp->scode);
+ unregister_netdev(root_lance_dev->dev);
+ kfree(root_lance_dev->dev);
+ root_lance_dev = lp;
+ }
+}
+
+#endif /* MODULE */
diff --git a/drivers/net/hplance.h b/drivers/net/hplance.h
new file mode 100644
index 000000000..3af4c4d1f
--- /dev/null
+++ b/drivers/net/hplance.h
@@ -0,0 +1,31 @@
+/* Random defines and structures for the HP Lance driver.
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ */
+
+/* Registers */
+struct hplance_reg
+{
+ u_char pad0;
+ volatile u_char id; /* DIO register: ID byte */
+ u_char pad1;
+ volatile u_char status; /* DIO register: interrupt enable */
+};
+
+/* Control and status bits for the hplance->status register */
+#define LE_IE 0x80 /* interrupt enable */
+#define LE_IR 0x40 /* interrupt requested */
+#define LE_LOCK 0x08 /* lock status register */
+#define LE_ACK 0x04 /* ack of lock */
+#define LE_JAB 0x02 /* loss of tx clock (???) */
+/* We can also extract the IPL from the status register with the standard
+ * DIO_IPL(hplance) macro, or using dio_scodetoipl()
+ */
+
+/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
+ * memory and NVRAM:
+ */
+#define HPLANCE_IDOFF 0 /* board baseaddr, struct hplance_reg */
+#define HPLANCE_REGOFF 0x4000 /* struct lance_regs */
+#define HPLANCE_MEMOFF 0x8000 /* struct lance_init_block */
+#define HPLANCE_NVRAMOFF 0xC008 /* etheraddress as one *nibble* per byte */
diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c
index dad41c2dd..527cd0443 100644
--- a/drivers/net/ibmtr.c
+++ b/drivers/net/ibmtr.c
@@ -59,9 +59,12 @@
* Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
* + Now compiles ok as a module again.
*
- * Changes by Paul Norton (pnorton@cts.com) :
+ * Changes by Paul Norton (p.norton@computer.org) :
* + moved the header manipulation code in tr_tx and tr_rx to
* net/802/tr.c. (July 12 1997)
+ * + add retry and timeout on open if cable disconnected. (May 5 1998)
+ * + lifted 2000 byte mtu limit. now depends on shared-RAM size.
+ * May 25 1998)
*/
#ifdef PCMCIA
@@ -91,7 +94,7 @@
/* version and credits */
static char *version =
"ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-" v2.1.42 7/12/97 Paul Norton <pnorton@cts.com>\n";
+" v2.1.106 6/22/98 Paul Norton <p.norton@computer.org>\n";
static char pcchannelid[] = {
0x05, 0x00, 0x04, 0x09,
@@ -138,6 +141,8 @@ static char mcchannelid[] = {
#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#if TR_NEWFORMAT
/* this allows displaying full adapter information */
@@ -185,6 +190,7 @@ static int tok_send_packet(struct sk_buff *skb, struct device *dev);
static struct net_device_stats * tok_get_stats(struct device *dev);
void ibmtr_readlog(struct device *dev);
void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev);
+int ibmtr_change_mtu(struct device *dev, int mtu);
static unsigned int ibmtr_portlist[] __initdata = {
0xa20, 0xa24, 0
@@ -469,10 +475,36 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
/* Available DHB 4Mb size: F=2048, E=4096, D=4464 */
- ti->dhb_size4mb = readb(ti->mmio + AIP4MBDHB);
+ switch (readb(ti->mmio + AIP4MBDHB)) {
+ case 0xe :
+ ti->dhb_size4mb = 4096;
+ break;
+ case 0xd :
+ ti->dhb_size4mb = 4464;
+ break;
+ default :
+ ti->dhb_size4mb = 2048;
+ break;
+ }
/* Available DHB 16Mb size: F=2048, E=4096, D=8192, C=16384, B=17960 */
- ti->dhb_size16mb = readb(ti->mmio + AIP16MBDHB);
+ switch (readb(ti->mmio + AIP16MBDHB)) {
+ case 0xe :
+ ti->dhb_size16mb = 4096;
+ break;
+ case 0xd :
+ ti->dhb_size16mb = 8192;
+ break;
+ case 0xc :
+ ti->dhb_size16mb = 16384;
+ break;
+ case 0xb :
+ ti->dhb_size16mb = 17960;
+ break;
+ default :
+ ti->dhb_size16mb = 2048;
+ break;
+ }
#if !TR_NEWFORMAT
DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, "
@@ -598,6 +630,62 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
#endif
+ /* Calculate the maximum DHB we can use */
+ switch (ti->mapped_ram_size) {
+ case 16 : /* 8KB shared RAM */
+ ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048);
+ ti->rbuf_len4 = 2048;
+ ti->rbuf_cnt4 = 1;
+ ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
+ ti->rbuf_len16 = 2048;
+ ti->rbuf_cnt16 = 1;
+ break;
+ case 32 : /* 16KB shared RAM */
+ ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
+ ti->rbuf_len4 = 512;
+ ti->rbuf_cnt4 = 9;
+ ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096);
+ ti->rbuf_len16 = 2048;
+ ti->rbuf_cnt16 = 2;
+ break;
+ case 64 : /* 32KB shared RAM */
+ ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
+ ti->rbuf_len4 = 2048;
+ ti->rbuf_cnt4 = 3;
+ ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240);
+ ti->rbuf_len16 = 2048;
+ ti->rbuf_cnt16 = 5;
+ break;
+ case 127 : /* 63KB shared RAM */
+ ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
+ ti->rbuf_len4 = 2048;
+ ti->rbuf_cnt4 = 3;
+ ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384);
+ ti->rbuf_len16 = 2048;
+ ti->rbuf_cnt16 = 8;
+ break;
+ case 128 : /* 64KB shared RAM */
+ ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
+ ti->rbuf_len4 = 2048;
+ ti->rbuf_cnt4 = 3;
+ ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960);
+ ti->rbuf_len16 = 2048;
+ ti->rbuf_cnt16 = 9;
+ break;
+ default :
+ ti->dhb_size4mb = 2048;
+ ti->rbuf_len4 = 2048;
+ ti->rbuf_cnt4 = 1;
+ ti->dhb_size16mb = 2048;
+ ti->rbuf_len16 = 2048;
+ ti->rbuf_cnt16 = 1;
+ break;
+ }
+
+ ti->maxmtu16 = ti->dhb_size16mb-((ti->rbuf_cnt16)<<3)-TR_HLEN;
+ ti->maxmtu4 = ti->dhb_size4mb-((ti->rbuf_cnt4)<<3)-TR_HLEN;
+ DPRINTK("Maximum MTU 16Mbps: %d, 4Mbps: %d\n",
+ ti->maxmtu16, ti->maxmtu4);
dev->base_addr=PIOaddr; /* set the value for device */
@@ -639,9 +727,9 @@ __initfunc(static int trdev_init(struct device *dev))
dev->open = tok_open;
dev->stop = tok_close;
dev->hard_start_xmit = tok_send_packet;
- dev->get_stats = NULL;
dev->get_stats = tok_get_stats;
dev->set_multicast_list = NULL;
+ dev->change_mtu = ibmtr_change_mtu;
#ifndef MODULE
tr_setup(dev);
@@ -842,9 +930,12 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
DPRINTK("No signal detected for Auto Speed Detection.\n");
else if (open_error_code==0x11)
{
- ti->open_status=FAILURE;
- DPRINTK("Ring broken/disconnected.\n");
- wake_up(&ti->wait_for_reset);
+ if (ti->retry_count--)
+ DPRINTK("Ring broken/disconnected, retrying...\n");
+ else {
+ DPRINTK("Ring broken/disconnected, open failed.\n");
+ ti->open_status = FAILURE;
+ }
}
else DPRINTK("Unrecoverable error: error code = %04x.\n",
open_error_code);
@@ -1111,13 +1202,13 @@ static void initial_tok_int(struct device *dev)
#endif
encoded_addr=(ti->sram + ntohs(hw_encoded_addr));
-
+ ti->ring_speed = readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4;
#if !TR_NEWFORMAT
DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr,
ntohs(hw_encoded_addr), encoded_addr);
#else
- DPRINTK("Initial interrupt : %s Mbps, shared RAM base %08x.\n",
- (readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01) ? "16" : "4", ti->sram);
+ DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
+ ti->ring_speed, ti->sram);
#endif
ti->auto_ringspeedsave=readb(ti->init_srb
@@ -1217,13 +1308,22 @@ void tok_open_adapter(unsigned long dev_addr)
ti->init_srb + offsetof(struct dir_open_adapter, command));
writew(htons(OPEN_PASS_BCON_MAC),
ti->init_srb + offsetof(struct dir_open_adapter, open_options));
- writew(htons(NUM_RCV_BUF),
- ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
- writew(htons(RCV_BUF_LEN),
- ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
- writew(htons(DHB_LENGTH),
- ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
- writeb(NUM_DHB,
+ if (ti->ring_speed == 16) {
+ writew(htons(ti->dhb_size16mb),
+ ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
+ writew(htons(ti->rbuf_cnt16),
+ ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
+ writew(htons(ti->rbuf_len16),
+ ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
+ } else {
+ writew(htons(ti->dhb_size4mb),
+ ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
+ writew(htons(ti->rbuf_cnt4),
+ ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
+ writew(htons(ti->rbuf_len4),
+ ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
+ }
+ writeb(NUM_DHB, /* always 2 */
ti->init_srb + offsetof(struct dir_open_adapter, num_dhb));
writeb(DLC_MAX_SAP,
ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap));
@@ -1260,10 +1360,10 @@ static void tr_tx(struct device *dev)
/* Figure out the size of the 802.5 header */
if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */
- hdr_len=sizeof(struct trh_hdr)-18;
+ hdr_len=sizeof(struct trh_hdr)-TR_MAXRIFLEN;
else
hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8)
- +sizeof(struct trh_hdr)-18;
+ +sizeof(struct trh_hdr)-TR_MAXRIFLEN;
llc = (struct trllc *)(ti->current_skb->data + hdr_len);
@@ -1304,6 +1404,7 @@ static void tr_tx(struct device *dev)
memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len);
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+ ti->tr_stats.tx_bytes+=ti->current_skb->len;
dev->tbusy=0;
dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
@@ -1364,8 +1465,8 @@ static void tr_rx(struct device *dev)
return;
}
- if ((readb(llc + offsetof(struct trllc, dsap))==0xAA) &&
- (readb(llc + offsetof(struct trllc, ssap))==0xAA)) {
+ if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) &&
+ (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP)) {
IPv4_p = 1;
}
@@ -1452,9 +1553,9 @@ static void tr_rx(struct device *dev)
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+ ti->tr_stats.rx_bytes += skb->len;
ti->tr_stats.rx_packets++;
- tr_reformat(skb, lan_hdr_len);
skb->protocol = tr_type_trans(skb,dev);
if (IPv4_p){
@@ -1527,6 +1628,17 @@ static struct net_device_stats * tok_get_stats(struct device *dev) {
return (struct net_device_stats *) &toki->tr_stats;
}
+int ibmtr_change_mtu(struct device *dev, int mtu) {
+ struct tok_info *ti = (struct tok_info *) dev->priv;
+
+ if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
+ return -EINVAL;
+ if (ti->ring_speed == 4 && mtu > ti->maxmtu4)
+ return -EINVAL;
+ dev->mtu = mtu;
+ return 0;
+}
+
#ifdef MODULE
/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
diff --git a/drivers/net/ibmtr.h b/drivers/net/ibmtr.h
index 0c162b586..079907731 100644
--- a/drivers/net/ibmtr.h
+++ b/drivers/net/ibmtr.h
@@ -7,6 +7,7 @@
#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6 /* number of open retries */
#define TR_ISA 1
#define TR_MCA 2
@@ -182,8 +183,14 @@ struct tok_info {
unsigned char token_release;
unsigned char avail_shared_ram;
unsigned char shared_ram_paging;
- unsigned char dhb_size4mb;
- unsigned char dhb_size16mb;
+ unsigned short dhb_size4mb;
+ unsigned short rbuf_len4;
+ unsigned short rbuf_cnt4;
+ unsigned short maxmtu4;
+ unsigned short dhb_size16mb;
+ unsigned short rbuf_len16;
+ unsigned short rbuf_cnt16;
+ unsigned short maxmtu16;
/* Additions by David Morris */
unsigned char do_tok_int;
struct wait_queue *wait_for_tok_int;
@@ -207,7 +214,9 @@ struct tok_info {
unsigned char readlog_pending;
unsigned short adapter_int_enable; /* Adapter-specific int enable */
struct timer_list tr_timer;
+ unsigned char ring_speed;
__u32 func_addr;
+ unsigned int retry_count;
};
/* token ring adapter commands */
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 367654ea3..5a7d1fee5 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -276,6 +276,12 @@ static struct lance_chip_type {
{0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */
LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+ {0x2623, "PCnet/FAST 79C971", /* 79C971 PCInetFAST. */
+ LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
+ LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+ {0x2624, "PCnet/FAST+ 79C972", /* 79C972 PCInetFAST+. */
+ LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
+ LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
{0x0, "PCnet (unknown)",
LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
LANCE_HAS_MISSED_FRAME},
@@ -315,13 +321,12 @@ __initfunc(int lance_init(void))
if (virt_to_bus(high_memory) <= 16*1024*1024)
lance_need_isa_bounce_buffers = 0;
-#if defined(CONFIG_PCI) && !defined(CONFIG_PCNET32)
+#if defined(CONFIG_PCI) && !(defined(CONFIG_PCNET32) || defined(CONFIG_PCNET32_MODULE))
if (pci_present()) {
struct pci_dev *pdev = NULL;
if (lance_debug > 1)
printk("lance.c: PCI is present, checking for devices...\n");
- while (pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev)) {
- unsigned char pci_bus, pci_device_fn;
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
unsigned int pci_ioaddr;
unsigned short pci_command;
@@ -421,7 +426,7 @@ __initfunc(void lance_probe1(int ioaddr))
}
}
-#ifdef CONFIG_PCNET32
+#if defined(CONFIG_PCNET32) || defined (CONFIG_PCNET32_MODULE)
/*
* if pcnet32 is configured and the chip is capable of 32bit mode
* leave the card alone
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
new file mode 100644
index 000000000..df14d510c
--- /dev/null
+++ b/drivers/net/lne390.c
@@ -0,0 +1,438 @@
+/*
+ lne390.c
+
+ Linux driver for Mylex LNE390 EISA Network Adapter
+
+ Copyright (C) 1996-1998, Paul Gortmaker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Information and Code Sources:
+
+ 1) Based upon framework of es3210 driver.
+ 2) The existing myriad of other Linux 8390 drivers by Donald Becker.
+ 3) Russ Nelson's asm packet driver provided additional info.
+ 4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
+
+ The LNE390 is an EISA shared memory NS8390 implementation. Note
+ that all memory copies to/from the board must be 32bit transfers.
+ There are two versions of the card: the lne390a and the lne390b.
+ Going by the EISA cfg files, the "a" has jumpers to select between
+ BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
+ The shared memory address selection is also slightly different.
+ Note that shared memory address > 1MB are supported with this driver.
+
+ You can try <http://www.mylex.com> if you want more info, as I've
+ never even seen one of these cards. :)
+
+*/
+
+static const char *version =
+ "lne390.c: Driver revision v0.99, 12/05/98\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+int lne390_probe(struct device *dev);
+int lne390_probe1(struct device *dev, int ioaddr);
+
+static int lne390_open(struct device *dev);
+static int lne390_close(struct device *dev);
+
+static void lne390_reset_8390(struct device *dev);
+
+static void lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
+static void lne390_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset);
+static void lne390_block_output(struct device *dev, int count, const unsigned char *buf, const int start_page);
+
+#define LNE390_START_PG 0x00 /* First page of TX buffer */
+#define LNE390_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+#define LNE390_ID_PORT 0xc80 /* Same for all EISA cards */
+#define LNE390_IO_EXTENT 0x20
+#define LNE390_SA_PROM 0x16 /* Start of e'net addr. */
+#define LNE390_RESET_PORT 0xc84 /* From the pkt driver source */
+#define LNE390_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
+
+#define LNE390_ADDR0 0x00 /* 3 byte vendor prefix */
+#define LNE390_ADDR1 0x80
+#define LNE390_ADDR2 0xe5
+
+#define LNE390_ID0 0x10009835 /* 0x3598 = 01101 01100 11000 = mlx */
+#define LNE390_ID1 0x11009835 /* above is the 390A, this is 390B */
+
+#define LNE390_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
+#define LNE390_CFG2 0xc90
+
+/*
+ * You can OR any of the following bits together and assign it
+ * to LNE390_DEBUG to get verbose driver info during operation.
+ * Currently only the probe one is implemented.
+ */
+
+#define LNE390_D_PROBE 0x01
+#define LNE390_D_RX_PKT 0x02
+#define LNE390_D_TX_PKT 0x04
+#define LNE390_D_IRQ 0x08
+
+#define LNE390_DEBUG 0
+
+static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
+static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
+static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
+
+/*
+ * Probe for the card. The best way is to read the EISA ID if it
+ * is known. Then we can check the prefix of the station address
+ * PROM for a match against the value assigned to Mylex.
+ */
+
+__initfunc(int lne390_probe(struct device *dev))
+{
+ unsigned short ioaddr = dev->base_addr;
+
+ if (ioaddr > 0x1ff) /* Check a single specified location. */
+ return lne390_probe1(dev, ioaddr);
+ else if (ioaddr > 0) /* Don't probe at all. */
+ return ENXIO;
+
+ if (!EISA_bus) {
+#if LNE390_DEBUG & LNE390_D_PROBE
+ printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
+#endif
+ return ENXIO;
+ }
+
+ /* EISA spec allows for up to 16 slots, but 8 is typical. */
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ if (check_region(ioaddr , LNE390_IO_EXTENT))
+ continue;
+ if (lne390_probe1(dev, ioaddr) == 0)
+ return 0;
+ }
+
+ return ENODEV;
+}
+
+__initfunc(int lne390_probe1(struct device *dev, int ioaddr))
+{
+ int i, revision;
+ unsigned long eisa_id;
+
+ if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
+
+#if LNE390_DEBUG & LNE390_D_PROBE
+ printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
+ printk("lne390-debug: config regs: %#x %#x\n",
+ inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
+#endif
+
+
+/* Check the EISA ID of the card. */
+ eisa_id = inl(ioaddr + LNE390_ID_PORT);
+ if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
+ return ENODEV;
+ }
+
+ revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
+
+#if 0
+/* Check the Mylex vendor ID as well. Not really required. */
+ if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
+ || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
+ || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
+ printk("lne390.c: card not found");
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
+ printk(" (invalid prefix).\n");
+ return ENODEV;
+ }
+#endif
+
+ if (load_8390_module("lne390.c"))
+ return -ENOSYS;
+
+ /* We should have a "dev" from Space.c or the static module table. */
+ if (dev == NULL) {
+ printk("lne390.c: Passed a NULL device.\n");
+ dev = init_etherdev(0, 0);
+ }
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk ("lne390.c: unable to allocate memory for dev->priv!\n");
+ return -ENOMEM;
+ }
+
+ printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i)));
+ printk(".\nlne390.c: ");
+
+ /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
+ if (dev->irq == 0) {
+ unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
+ dev->irq = irq_map[irq_reg & 0x07];
+ printk("using");
+ } else {
+ /* This is useless unless we reprogram the card here too */
+ if (dev->irq == 2) dev->irq = 9; /* Doh! */
+ printk("assigning");
+ }
+ printk(" IRQ %d,", dev->irq);
+
+ if (request_irq(dev->irq, ei_interrupt, 0, "lne390", NULL)) {
+ printk (" unable to get IRQ %d.\n", dev->irq);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return EAGAIN;
+ }
+
+ if (dev->mem_start == 0) {
+ unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
+
+ if (revision) /* LNE390B */
+ dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
+ else /* LNE390A */
+ dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
+ printk(" using ");
+ } else {
+ /* Should check for value in shmem_map and reprogram the card to use it */
+ dev->mem_start &= 0xfff0000;
+ printk(" assigning ");
+ }
+
+ printk("%dkB memory at physical address %#lx\n",
+ LNE390_STOP_PG/4, dev->mem_start);
+
+ /*
+ BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
+ the card mem within the region covered by `normal' RAM !!!
+ */
+ if (dev->mem_start > 1024*1024) { /* phys addr > 1MB */
+ if (dev->mem_start < (unsigned long)high_memory) {
+ printk(KERN_CRIT "lne390.c: Card RAM overlaps with normal memory!!!\n");
+ printk(KERN_CRIT "lne390.c: Use EISA SCU to set card memory below 1MB,\n");
+ printk(KERN_CRIT "lne390.c: or to an address above %p.\n", high_memory);
+ printk(KERN_CRIT "lne390.c: Driver NOT installed.\n");
+ free_irq(dev->irq, dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return EINVAL;
+ }
+ dev->mem_start = (unsigned long)ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
+ if (dev->mem_start == 0) {
+ printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
+ printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
+ printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
+ free_irq(dev->irq, dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return EAGAIN;
+ }
+ printk("lne390.c: remapped %dkB card memory to virtual address %#lx\n",
+ LNE390_STOP_PG/4, dev->mem_start);
+ }
+
+ dev->mem_end = dev->rmem_end = dev->mem_start
+ + (LNE390_STOP_PG - LNE390_START_PG)*256;
+ dev->rmem_start = dev->mem_start + TX_PAGES*256;
+
+ /* The 8390 offset is zero for the LNE390 */
+ dev->base_addr = ioaddr;
+ request_region(dev->base_addr, LNE390_IO_EXTENT, "lne390");
+
+ ei_status.name = "LNE390";
+ ei_status.tx_start_page = LNE390_START_PG;
+ ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
+ ei_status.stop_page = LNE390_STOP_PG;
+ ei_status.word16 = 1;
+
+ if (ei_debug > 0)
+ printk(version);
+
+ ei_status.reset_8390 = &lne390_reset_8390;
+ ei_status.block_input = &lne390_block_input;
+ ei_status.block_output = &lne390_block_output;
+ ei_status.get_8390_hdr = &lne390_get_8390_hdr;
+
+ dev->open = &lne390_open;
+ dev->stop = &lne390_close;
+ NS8390_init(dev, 0);
+ return 0;
+}
+
+/*
+ * Reset as per the packet driver method. Judging by the EISA cfg
+ * file, this just toggles the "Board Enable" bits (bit 2 and 0).
+ */
+
+static void lne390_reset_8390(struct device *dev)
+{
+ unsigned short ioaddr = dev->base_addr;
+
+ outb(0x04, ioaddr + LNE390_RESET_PORT);
+ if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
+
+ mdelay(2);
+
+ ei_status.txing = 0;
+ outb(0x01, ioaddr + LNE390_RESET_PORT);
+ if (ei_debug > 1) printk("reset done\n");
+
+ return;
+}
+
+/*
+ * Note: In the following three functions is the implicit assumption
+ * that the associated memcpy will only use "rep; movsl" as long as
+ * we keep the counts as some multiple of doublewords. This is a
+ * requirement of the hardware, and also prevents us from using
+ * eth_io_copy_and_sum() since we can't guarantee it will limit
+ * itself to doubleword access.
+ */
+
+/*
+ * Grab the 8390 specific header. Similar to the block_input routine, but
+ * we don't need to be concerned with ring wrap as the header will be at
+ * the start of a page, so we optimize accordingly. (A single doubleword.)
+ */
+
+static void
+lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ unsigned long hdr_start = dev->mem_start + ((ring_page - LNE390_START_PG)<<8);
+ memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+ hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
+}
+
+/*
+ * Block input and output are easy on shared memory ethercards, the only
+ * complication is when the ring buffer wraps. The count will already
+ * be rounded up to a doubleword value via lne390_get_8390_hdr() above.
+ */
+
+static void lne390_block_input(struct device *dev, int count, struct sk_buff *skb,
+ int ring_offset)
+{
+ unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8);
+
+ if (xfer_start + count > dev->rmem_end) {
+ /* Packet wraps over end of ring buffer. */
+ int semi_count = dev->rmem_end - xfer_start;
+ memcpy_fromio(skb->data, xfer_start, semi_count);
+ count -= semi_count;
+ memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ } else {
+ /* Packet is in one chunk. */
+ memcpy_fromio(skb->data, xfer_start, count);
+ }
+}
+
+static void lne390_block_output(struct device *dev, int count,
+ const unsigned char *buf, int start_page)
+{
+ unsigned long shmem = dev->mem_start + ((start_page - LNE390_START_PG)<<8);
+
+ count = (count + 3) & ~3; /* Round up to doubleword */
+ memcpy_toio(shmem, buf, count);
+}
+
+static int lne390_open(struct device *dev)
+{
+ ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int lne390_close(struct device *dev)
+{
+
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+ ei_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef MODULE
+#define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */
+#define NAMELEN 8 /* # of chars for storing dev->name */
+static char namelist[NAMELEN * MAX_LNE_CARDS] = { 0, };
+static struct device dev_lne[MAX_LNE_CARDS] = {
+ {
+ NULL, /* assign a chunk of namelist[] below */
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL
+ },
+};
+
+static int io[MAX_LNE_CARDS] = { 0, };
+static int irq[MAX_LNE_CARDS] = { 0, };
+static int mem[MAX_LNE_CARDS] = { 0, };
+
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+
+int init_module(void)
+{
+ int this_dev, found = 0;
+
+ for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
+ struct device *dev = &dev_lne[this_dev];
+ dev->name = namelist+(NAMELEN*this_dev);
+ dev->irq = irq[this_dev];
+ dev->base_addr = io[this_dev];
+ dev->mem_start = mem[this_dev];
+ dev->init = lne390_probe;
+ /* Default is to only install one card. */
+ if (io[this_dev] == 0 && this_dev != 0) break;
+ if (register_netdev(dev) != 0) {
+ printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
+ return -ENXIO;
+ }
+ found++;
+ }
+ lock_8390_module();
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int this_dev;
+
+ for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
+ struct device *dev = &dev_lne[this_dev];
+ if (dev->priv != NULL) {
+ void *priv = dev->priv;
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, LNE390_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
+ }
+ }
+ unlock_8390_module();
+}
+#endif /* MODULE */
+
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 63723afb5..b2aa9b27b 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -52,7 +52,7 @@
#include <linux/if_ether.h> /* For the statistics structure. */
#include <linux/if_arp.h> /* For ARPHRD_ETHER */
-#define LOOPBACK_MTU (PAGE_SIZE*7/8)
+#define LOOPBACK_MTU (PAGE_SIZE - 172)
/*
* The higher levels take care of making this non-reentrant (it's
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index ea836aaa0..1c7f3b9bc 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -573,6 +573,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((fs & XMTSV) == 0) {
printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
fs, xcount, dstat);
+ return;
}
cp = mp->tx_cmds + NCMDS_TX * i;
stat = ld_le16(&cp->xfer_status);
@@ -765,7 +766,14 @@ static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
if (frame_status & RS_FCSERR)
++mp->stats.rx_crc_errors;
} else {
- nb -= 8;
+ /* Mace feature AUTO_STRIP_RCV is on by default, dropping the
+ * FCS on frames with 802.3 headers. This means that Ethernet
+ * frames have 8 extra octets at the end, while 802.3 frames
+ * have only 4. We need to correctly account for this. */
+ if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */
+ nb -= 4;
+ else /* Ethernet header; mace includes FCS */
+ nb -= 8;
skb_put(skb, nb);
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 52d3a5089..bdc46d635 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1044,27 +1044,11 @@ static inline int myri_ether_init(struct device *dev, struct linux_sbus_device *
dev->hard_start_xmit = &myri_start_xmit;
dev->get_stats = &myri_get_stats;
dev->set_multicast_list = &myri_set_multicast;
- dev->irq = sdev->irqs[0].pri;
+ dev->irq = sdev->irqs[0];
dev->dma = 0;
/* Register interrupt handler now. */
DET(("Requesting MYRIcom IRQ line.\n"));
-#ifdef __sparc_v9__
- if(sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = dev;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = sdev->my_bus;
- if(request_irq(dev->irq, &myri_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- "MyriCOM Ethernet", &dcookie)) {
- printk("MyriCOM: Cannot register interrupt handler.\n");
- return ENODEV;
- }
- } else
-#endif
if(request_irq(dev->irq, &myri_interrupt,
SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
printk("MyriCOM: Cannot register interrupt handler.\n");
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index ddadd80f2..b069a346c 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -171,7 +171,7 @@ struct myri_txd {
#define MYRINET_MTU 8432
#define RX_ALLOC_SIZE 8448
#define MYRI_PAD_LEN 2
-#define RX_COPY_THRESHOLD 128
+#define RX_COPY_THRESHOLD 256
/* These numbers are cast in stone, new firmware is needed if
* you want to change them.
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 10cf51941..ab284bf09 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -25,6 +25,9 @@
Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c
Paul Gortmaker : Allow users with bad cards to avoid full probe.
Paul Gortmaker : PCI probe changes, more PCI cards supported.
+ rjohnson@analogic.com : Changed init order so an interrupt will only
+ occur after memory is allocated for dev->priv. Deallocated memory
+ last in cleanup_modue()
*/
@@ -79,6 +82,7 @@ pci_clone_list[] __initdata = {
{PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, "KTI ET32P2" },
{PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, "NetVin NV5000" },
{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926, "VIA 82C926 Amazon" },
+ {PCI_VENDOR_ID_SURECOM, PCI_DEVICE_ID_SURECOM_NE34, "SureCom NE34"},
{0,}
};
#endif
@@ -222,6 +226,7 @@ __initfunc(static int ne_probe_pci(struct device *dev))
printk("ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n",
pci_clone_list[i].name,
pci_ioaddr, pci_irq_line);
+ printk("*\n* Use of the PCI-NE2000 driver with this card is recommended!\n*\n");
if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */
printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
pci_irq_line = 0;
@@ -262,6 +267,9 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr))
}
}
+ if (load_8390_module("ne.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk(KERN_ERR "ne.c: Passed a NULL device.\n");
@@ -401,7 +409,7 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr))
outb_p(0x00, ioaddr + EN0_RCNTLO);
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
- udelay(10000); /* wait 10ms for interrupt to propagate */
+ mdelay(10); /* wait 10ms for interrupt to propagate */
outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */
dev->irq = autoirq_report(0);
if (ei_debug > 2)
@@ -416,6 +424,12 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr))
return EAGAIN;
}
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk (" unable to get memory for dev->priv.\n");
+ return -ENOMEM;
+ }
+
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{
@@ -423,19 +437,13 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr))
pci_irq_line ? SA_SHIRQ : 0, name, dev);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
+
+ kfree(dev->priv);
+ dev->priv = NULL;
return EAGAIN;
}
}
-
dev->base_addr = ioaddr;
-
- /* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (ethdev_init(dev)) {
- printk (" unable to get memory for dev->priv.\n");
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
-
request_region(ioaddr, NE_IO_EXTENT, name);
for(i = 0; i < ETHER_ADDR_LEN; i++) {
@@ -522,7 +530,7 @@ ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_get_8390_hdr "
- "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+ "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
dev->name, ei_status.dmaing, ei_status.irqlock,
dev->interrupt);
return;
@@ -562,7 +570,7 @@ ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offs
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_block_input "
- "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+ "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
dev->name, ei_status.dmaing, ei_status.irqlock,
dev->interrupt);
return;
@@ -631,7 +639,7 @@ ne_block_output(struct device *dev, int count,
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_block_output."
- "[DMAstat:%d][irqlock:%d][intr:%d]\n",
+ "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
dev->name, ei_status.dmaing, ei_status.irqlock,
dev->interrupt);
return;
@@ -753,15 +761,17 @@ init_module(void)
found++;
continue;
}
- if (found != 0) /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
return 0;
+ }
if (io[this_dev] != 0)
printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
else
printk(KERN_NOTICE "ne.c: No PCI cards found. Use \"io=0xNNN\" value(s) for ISA cards.\n");
return -ENXIO;
}
-
+ lock_8390_module();
return 0;
}
@@ -773,13 +783,15 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
struct device *dev = &dev_ne[this_dev];
if (dev->priv != NULL) {
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
free_irq(dev->irq, dev);
release_region(dev->base_addr, NE_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
new file mode 100644
index 000000000..8f152673c
--- /dev/null
+++ b/drivers/net/ne2k-pci.c
@@ -0,0 +1,600 @@
+/* ne2k-pci.c: A NE2000 clone on PCI bus driver for Linux. */
+/*
+ A Linux device driver for PCI NE2000 clones.
+
+ Authorship and other copyrights:
+ 1992-1998 by Donald Becker, NE2000 core and various modifications.
+ 1995-1998 by Paul Gortmaker, core modifications and PCI support.
+
+ Copyright 1993 assigned to the 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.
+
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ People are making PCI ne2000 clones! Oh the horror, the horror...
+
+ Issues remaining:
+ No full-duplex support.
+*/
+
+/* Our copyright info must remain in the binary. */
+static const char *version =
+"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+/* Set statically or when loading the driver module. */
+static int debug = 1;
+
+/* Some defines that people can play with if so inclined. */
+
+/* Use 32 bit data-movement operations instead of 16 bit. */
+#define USE_LONGIO
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
+/* #define PACKETBUF_MEMSIZE 0x40 */
+
+static struct {
+ unsigned short vendor, dev_id;
+ char *name;
+}
+pci_clone_list[] __initdata = {
+ {0x10ec, 0x8029, "RealTek RTL-8029"},
+ {0x1050, 0x0940, "Winbond 89C940"},
+ {0x11f6, 0x1401, "Compex RL2000"},
+ {0x8e2e, 0x3000, "KTI ET32P2"},
+ {0x4a14, 0x5000, "NetVin NV5000SC"},
+ {0x1106, 0x0926, "Via 82C926"},
+ {0x10bd, 0x0e34, "SureCom NE34"},
+ {0,}
+};
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE (dev->base_addr)
+#define NE_CMD 0x00
+#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
+#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT 0x20
+
+#define NESM_START_PG 0x40 /* First page of TX buffer */
+#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+int ne2k_pci_probe(struct device *dev);
+static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq);
+
+static int ne2k_pci_open(struct device *dev);
+static int ne2k_pci_close(struct device *dev);
+
+static void ne2k_pci_reset_8390(struct device *dev);
+static void ne2k_pci_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void ne2k_pci_block_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void ne2k_pci_block_output(struct device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+
+
+
+/* No room in the standard 8390 structure for extra info we need. */
+struct ne2k_pci_card {
+ struct ne2k_pci_card *next;
+ struct device *dev;
+ struct pci_dev *pci_dev;
+};
+/* A list of all installed devices, for removing the driver module. */
+static struct ne2k_pci_card *ne2k_card_list = NULL;
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+ int retval;
+
+ /* We must emit version information. */
+ if (debug)
+ printk(KERN_INFO "%s", version);
+
+ retval = ne2k_pci_probe(0);
+
+ if (retval) {
+ printk(KERN_NOTICE "ne2k-pci.c: no (useable) cards found, driver NOT installed.\n");
+ return retval;
+ }
+ lock_8390_module();
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ struct device *dev;
+ struct ne2k_pci_card *this_card;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ while (ne2k_card_list) {
+ dev = ne2k_card_list->dev;
+ unregister_netdev(dev);
+ release_region(dev->base_addr, NE_IO_EXTENT);
+ kfree(dev);
+ this_card = ne2k_card_list;
+ ne2k_card_list = ne2k_card_list->next;
+ kfree(this_card);
+ }
+ unlock_8390_module();
+}
+
+#endif /* MODULE */
+
+/*
+ NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
+ buffer memory space. By-the-spec NE2000 clones have 0x57,0x57 in bytes
+ 0x0e,0x0f of the SAPROM, while other supposed NE2000 clones must be
+ detected by their SA prefix.
+
+ Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+ mode results in doubled values, which can be detected and compensated for.
+
+ The probe is also responsible for initializing the card and filling
+ in the 'dev' and 'ei_status' structures.
+*/
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry netcard_drv =
+{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
+#endif
+
+__initfunc (int ne2k_pci_probe(struct device *dev))
+{
+ struct pci_dev *pdev = NULL;
+ int cards_found = 0;
+ int i;
+
+ if ( ! pci_present())
+ return -ENODEV;
+
+ while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) {
+ u8 pci_irq_line;
+ u16 pci_command, new_command;
+ u32 pci_ioaddr;
+
+ /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */
+ for (i = 0; pci_clone_list[i].vendor != 0; i++)
+ if (pci_clone_list[i].vendor == pdev->vendor
+ && pci_clone_list[i].dev_id == pdev->device)
+ break;
+ if (pci_clone_list[i].vendor == 0)
+ continue;
+
+ pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ pci_irq_line = pdev->irq;
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+
+ /* Avoid already found cards from previous calls */
+ if (check_region(pci_ioaddr, NE_IO_EXTENT))
+ continue;
+
+#ifndef MODULE
+ {
+ static unsigned version_printed = 0;
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+ }
+#endif
+
+ /* Activate the card: fix for brain-damaged Win98 BIOSes. */
+ new_command = pci_command | PCI_COMMAND_IO;
+ if (pci_command != new_command) {
+ printk(KERN_INFO " The PCI BIOS has not enabled this"
+ " NE2k clone! Updating PCI command %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pci_write_config_word(pdev, PCI_COMMAND, new_command);
+ }
+
+ if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS)
+ printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k"
+ " card to IRQ %d, which is unlikely to work!.\n"
+ KERN_WARNING " You should use the PCI BIOS setup to assign"
+ " a valid IRQ line.\n", pci_irq_line);
+
+ printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n",
+ pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
+ dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line);
+ if (dev == 0) {
+ /* Should not happen. */
+ printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n",
+ pci_ioaddr);
+ continue;
+ } else {
+ struct ne2k_pci_card *ne2k_card =
+ kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL);
+ ne2k_card->next = ne2k_card_list;
+ ne2k_card_list = ne2k_card;
+ ne2k_card->dev = dev;
+ ne2k_card->pci_dev = pdev;
+ }
+ dev = 0;
+
+ cards_found++;
+ }
+
+ return cards_found ? 0 : -ENODEV;
+}
+
+__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq))
+{
+ int i;
+ unsigned char SA_prom[32];
+ const char *name = NULL;
+ int start_page, stop_page;
+ int reg0 = inb(ioaddr);
+
+ if (reg0 == 0xFF)
+ return 0;
+
+ /* Do a preliminary verification that we have a 8390. */
+ {
+ int regd;
+ outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+ regd = inb(ioaddr + 0x0d);
+ outb(0xff, ioaddr + 0x0d);
+ outb(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+ inb(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+ if (inb(ioaddr + EN0_COUNTER0) != 0) {
+ outb(reg0, ioaddr);
+ outb(regd, ioaddr + 0x0d); /* Restore the old values. */
+ return 0;
+ }
+ }
+
+ /* Reset card. Who knows what dain-bramaged state it was left in. */
+ {
+ unsigned long reset_start_time = jiffies;
+
+ outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+ /* This looks like a horrible timing loop, but it should never take
+ more than a few cycles.
+ */
+ while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+ /* Limit wait: '2' avoids jiffy roll-over. */
+ if (jiffies - reset_start_time > 2) {
+ printk("ne2k-pci: Card failure (no reset ack).\n");
+ return 0;
+ }
+
+ outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
+ }
+
+ if (load_8390_module("ne2k-pci.c")) {
+ return 0;
+ }
+
+ /* Read the 16 bytes of station address PROM.
+ We must first initialize registers, similar to NS8390_init(eifdev, 0).
+ We can't reliably read the SAPROM address without this.
+ (I learned the hard way!). */
+ {
+ struct {unsigned char value, offset; } program_seq[] = {
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+ {0x49, EN0_DCFG}, /* Set word-wide access. */
+ {0x00, EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_IMR}, /* Mask completion irq. */
+ {0xFF, EN0_ISR},
+ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
+ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
+ {32, EN0_RCNTLO},
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
+ {0x00, EN0_RSARHI},
+ {E8390_RREAD+E8390_START, E8390_CMD},
+ };
+ for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ outb(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+ }
+
+#ifdef notdef
+ /* Some broken PCI cards don't respect the byte-wide
+ request in program_seq above, and hence don't have doubled up values.
+ */
+ for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
+ SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+ SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
+ if (SA_prom[i] != SA_prom[i+1])
+ sa_prom_doubled = 0;
+ }
+
+ if (sa_prom_doubled)
+ for (i = 0; i < 16; i++)
+ SA_prom[i] = SA_prom[i+i];
+#else
+ for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
+ SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+
+#endif
+
+ /* We always set the 8390 registers for word mode. */
+ outb(0x49, ioaddr + EN0_DCFG);
+ start_page = NESM_START_PG;
+ stop_page = NESM_STOP_PG;
+
+ /* Set up the rest of the parameters. */
+ name = "PCI NE2000";
+
+ dev = init_etherdev(dev, 0);
+
+ dev->irq = irq;
+ dev->base_addr = ioaddr;
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk ("%s: unable to get memory for dev->priv.\n", dev->name);
+ kfree(dev);
+ return 0;
+ }
+
+ request_region(ioaddr, NE_IO_EXTENT, dev->name);
+
+ printk("%s: %s found at %#x, IRQ %d, ",
+ dev->name, name, ioaddr, dev->irq);
+ for(i = 0; i < 6; i++) {
+ printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
+ dev->dev_addr[i] = SA_prom[i];
+ }
+
+ ei_status.name = name;
+ ei_status.tx_start_page = start_page;
+ ei_status.stop_page = stop_page;
+ ei_status.word16 = 1;
+
+ ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+ /* Allow the packet buffer size to be overridden by know-it-alls. */
+ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+ ei_status.reset_8390 = &ne2k_pci_reset_8390;
+ ei_status.block_input = &ne2k_pci_block_input;
+ ei_status.block_output = &ne2k_pci_block_output;
+ ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr;
+ dev->open = &ne2k_pci_open;
+ dev->stop = &ne2k_pci_close;
+ NS8390_init(dev, 0);
+ return dev;
+}
+
+static int
+ne2k_pci_open(struct device *dev)
+{
+ if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev))
+ return -EAGAIN;
+ ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+ne2k_pci_close(struct device *dev)
+{
+ ei_close(dev);
+ free_irq(dev->irq, dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* Hard reset the card. This used to pause for the same period that a
+ 8390 reset command required, but that shouldn't be necessary. */
+static void
+ne2k_pci_reset_8390(struct device *dev)
+{
+ unsigned long reset_start_time = jiffies;
+
+ if (debug > 1) printk("%s: Resetting the 8390 t=%ld...",
+ dev->name, jiffies);
+
+ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+ ei_status.txing = 0;
+ ei_status.dmaing = 0;
+
+ /* This check _should_not_ be necessary, omit eventually. */
+ while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2) {
+ printk("%s: ne2k_pci_reset_8390() did not complete.\n", dev->name);
+ break;
+ }
+ outb(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+static void
+ne2k_pci_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+
+ int nic_base = dev->base_addr;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr "
+ "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+ outb(0, nic_base + EN0_RCNTHI);
+ outb(0, nic_base + EN0_RSARLO); /* On page boundary */
+ outb(ring_page, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+#if defined(USE_LONGIO)
+ *(u32*)hdr = inl(NE_BASE + NE_DATAPORT);
+#else
+ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+#endif
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver. If you
+ are porting to a new ethercard, look at the packet driver source for hints.
+ The NEx000 doesn't share the on-board packet memory -- you have to put
+ the packet out through the "remote DMA" dataport using outb. */
+
+static void
+ne2k_pci_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+ int nic_base = dev->base_addr;
+ char *buf = skb->data;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_block_input "
+ "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb(count & 0xff, nic_base + EN0_RCNTLO);
+ outb(count >> 8, nic_base + EN0_RCNTHI);
+ outb(ring_offset & 0xff, nic_base + EN0_RSARLO);
+ outb(ring_offset >> 8, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+#if defined(USE_LONGIO)
+ insl(NE_BASE + NE_DATAPORT, buf, count>>2);
+ if (count & 3) {
+ buf += count & ~3;
+ if (count & 2)
+ *((u16*)buf)++ = inw(NE_BASE + NE_DATAPORT);
+ if (count & 1)
+ *buf = inb(NE_BASE + NE_DATAPORT);
+ }
+#else
+ insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+ if (count & 0x01) {
+ buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+ }
+#endif
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+static void
+ne2k_pci_block_output(struct device *dev, int count,
+ const unsigned char *buf, const int start_page)
+{
+ int nic_base = NE_BASE;
+ unsigned long dma_start;
+
+ /* On little-endian it's always safe to round the count up for
+ word writes. */
+ if (count & 0x01)
+ count++;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_block_output."
+ "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ /* We should already be in page 0, but to be safe... */
+ outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE8390_RW_BUGFIX
+ /* Handle the read-before-write bug the same way as the
+ Crynwr packet driver -- the NatSemi method doesn't work.
+ Actually this doesn't always work either, but if you have
+ problems with your NEx000 this is better than nothing! */
+ outb(0x42, nic_base + EN0_RCNTLO);
+ outb(0x00, nic_base + EN0_RCNTHI);
+ outb(0x42, nic_base + EN0_RSARLO);
+ outb(0x00, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+#endif
+ outb(ENISR_RDC, nic_base + EN0_ISR);
+
+ /* Now the normal output. */
+ outb(count & 0xff, nic_base + EN0_RCNTLO);
+ outb(count >> 8, nic_base + EN0_RCNTHI);
+ outb(0x00, nic_base + EN0_RSARLO);
+ outb(start_page, nic_base + EN0_RSARHI);
+ outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+#if defined(USE_LONGIO)
+ outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
+ if (count & 3) {
+ buf += count & ~3;
+ if (count & 2)
+ outw(*((u16*)buf)++, NE_BASE + NE_DATAPORT);
+ }
+#else
+ outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+#endif
+
+ dma_start = jiffies;
+
+ while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+ if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */
+ printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+ ne2k_pci_reset_8390(dev);
+ NS8390_init(dev,1);
+ break;
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+ return;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
+ * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * version-control: t
+ * kept-new-versions: 5
+ * End:
+ */
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
index 5a9c1cc3b..360f62166 100644
--- a/drivers/net/net_init.c
+++ b/drivers/net/net_init.c
@@ -35,9 +35,10 @@
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/hippidevice.h>
#include <linux/trdevice.h>
#include <linux/if_arp.h>
-#include <linux/fddidevice.h>
#include <linux/if_ltalk.h>
#include <linux/rtnetlink.h>
@@ -162,6 +163,63 @@ static int fddi_change_mtu(struct device *dev, int new_mtu)
#endif
+#ifdef CONFIG_HIPPI
+static int hippi_change_mtu(struct device *dev, int new_mtu)
+{
+ /*
+ * HIPPI's got these nice large MTUs.
+ */
+ if ((new_mtu < 68) || (new_mtu > 65280))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return(0);
+}
+
+
+/*
+ * For HIPPI we will actually use the lower 4 bytes of the hardware
+ * address as the I-FIELD rather than the actual hardware address.
+ */
+static int hippi_mac_addr(struct device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ if(dev->start)
+ return -EBUSY;
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ return 0;
+}
+
+
+struct device *init_hippi_dev(struct device *dev, int sizeof_priv)
+{
+ struct device *tmp_dev; /* pointer to a device structure */
+
+ /* Find next free HIPPI entry */
+
+ for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next)
+ if ((strncmp(tmp_dev->name, "hip", 3) == 0) &&
+ (tmp_dev->base_addr == 0))
+ break;
+
+ if (tmp_dev == NULL)
+ {
+ printk("Could not find free HIPPI device structure.\n");
+ return NULL;
+ }
+
+ tmp_dev->init = NULL;
+ sizeof_priv = (sizeof_priv + 3) & ~3;
+ tmp_dev->priv = sizeof_priv ? kmalloc(sizeof_priv, GFP_KERNEL) : NULL;
+
+ if (tmp_dev->priv)
+ memset(dev->priv, 0, sizeof_priv);
+
+ /* Initialize remaining device structure information */
+
+ hippi_setup(tmp_dev);
+ return tmp_dev;
+}
+#endif
void ether_setup(struct device *dev)
{
@@ -235,6 +293,40 @@ void fddi_setup(struct device *dev)
#endif
+#ifdef CONFIG_HIPPI
+void hippi_setup(struct device *dev)
+{
+ dev->set_multicast_list = NULL;
+ dev->change_mtu = hippi_change_mtu;
+ dev->hard_header = hippi_header;
+ dev->rebuild_header = hippi_rebuild_header;
+ dev->set_mac_address = hippi_mac_addr;
+ dev->hard_header_parse = NULL;
+ dev->hard_header_cache = NULL;
+ dev->header_cache_update = NULL;
+
+ /*
+ * We don't support HIPPI `ARP' for the time being, and probably
+ * never will unless someone else implements it. However we
+ * still need a fake ARPHRD to make ifconfig and friends play ball.
+ */
+ dev->type = ARPHRD_HIPPI;
+ dev->hard_header_len = HIPPI_HLEN;
+ dev->mtu = 65280;
+ dev->addr_len = HIPPI_ALEN;
+ dev->tx_queue_len = 25 /* 5 */;
+ memset(dev->broadcast, 0xFF, HIPPI_ALEN);
+
+ /* New-style flags. */
+ dev->flags = IFF_NODYNARP; /*
+ * HIPPI doesn't support
+ * broadcast+multicast and we only
+ * use static ARP tables.
+ */
+ dev_init_buffers(dev);
+}
+#endif
+
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
static int ltalk_change_mtu(struct device *dev, int mtu)
@@ -298,7 +390,7 @@ static int etherdev_get_index(struct device *dev)
for (i = 0; i < MAX_ETH_CARDS; ++i) {
if (ethdev_index[i] == NULL) {
sprintf(dev->name, "eth%d", i);
- printk("loading device '%s'...\n", dev->name);
+/* printk("loading device '%s'...\n", dev->name);*/
ethdev_index[i] = dev;
return i;
}
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 1f2330133..7c3e60bb3 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -366,11 +366,11 @@ __initfunc(int ni52_probe(struct device *dev))
#endif
int base_addr = dev->base_addr;
- if (base_addr > 0x1ff) /* Check a single specified location. */
+ if (base_addr > 0x1ff) { /* Check a single specified location. */
if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
(inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
return ni52_probe1(dev, base_addr);
- else if (base_addr > 0) /* Don't probe at all. */
+ } else if (base_addr > 0) /* Don't probe at all. */
return ENXIO;
#ifdef MODULE
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 63d862a45..c778255cb 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -512,7 +512,7 @@ static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int m
for(i=0;i<32;i++)
{
- udelay(4000);
+ mdelay(4);
if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )
break; /* init ok ? */
}
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 57d8cef9e..db00ab8c5 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1,6 +1,6 @@
/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
/*
- * Copyright 1996,97 Thomas Bogendoerfer
+ * Copyright 1996,97,98 Thomas Bogendoerfer
*
* Derived from the lance driver written 1993,1994,1995 by Donald Becker.
*
@@ -13,9 +13,14 @@
* This driver is for PCnet32 and PCnetPCI based ethercards
*/
-static const char *version = "pcnet32.c:v0.23 8.2.97 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.00 30.5.98 tsbogend@alpha.franken.de\n";
#include <linux/config.h>
+#include <linux/module.h>
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -25,6 +30,7 @@ static const char *version = "pcnet32.c:v0.23 8.2.97 tsbogend@alpha.franken.de\n
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <asm/bitops.h>
#ifdef __mips__
@@ -41,12 +47,15 @@ static const char *version = "pcnet32.c:v0.23 8.2.97 tsbogend@alpha.franken.de\n
static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
-#ifdef PCNET32_DEBUG
-static int pcnet32_debug = PCNET32_DEBUG;
-#else
static int pcnet32_debug = 1;
+
+#ifdef MODULE
+static struct device *pcnet32_dev = NULL;
#endif
+static const int max_interrupt_work = 20;
+static const int rx_copybreak = 200;
+
/*
* Theory of Operation
*
@@ -63,7 +72,7 @@ static int pcnet32_debug = 1;
* only tested on Alpha Noname Board
* v0.02: changed IRQ handling for new interrupt scheme (dev_id)
* tested on a ASUS SP3G
- * v0.10: fixed an odd problem with the 79C794 in a Compaq Deskpro XL
+ * v0.10: fixed an odd problem with the 79C974 in a Compaq Deskpro XL
* looks like the 974 doesn't like stopping and restarting in a
* short period of time; now we do a reinit of the lance; the
* bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
@@ -82,7 +91,18 @@ static int pcnet32_debug = 1;
* in arch/i386/bios32.c
* v0.21: added endian conversion for ppc, from work by cort@cs.nmt.edu
* v0.22: added printing of status to ring dump
- * v0.23: changed enet_statistics to net_device_stats
+ * v0.23: changed enet_statistics to net_devive_stats
+ * v0.90: added multicast filter
+ * added module support
+ * changed irq probe to new style
+ * added PCnetFast chip id
+ * added fix for receive stalls with Intel saturn chipsets
+ * added in-place rx skbs like in the tulip driver
+ * minor cleanups
+ * v0.91: added PCnetFast+ chip id
+ * back port to 2.0.x
+ * v1.00: added some stuff from Donald Becker's 2.0.34 version
+ * added support for byte counters in net_dev_stats
*/
@@ -113,6 +133,8 @@ static int pcnet32_debug = 1;
#define PCNET32_BUS_IF 0x16
#define PCNET32_TOTAL_SIZE 0x18
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
@@ -150,14 +172,17 @@ struct pcnet32_private {
struct pcnet32_init_block init_block;
const char *name;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- unsigned long rx_buffs; /* Address of Rx and Tx buffers. */
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
int cur_rx, cur_tx; /* The next free ring entry */
int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
struct net_device_stats stats;
char tx_full;
unsigned long lock;
char shared_irq; /* shared irq possible */
+#ifdef MODULE
+ struct device *next;
+#endif
};
int pcnet32_probe(struct device *dev);
@@ -209,9 +234,6 @@ __initfunc(int pcnet32_probe (struct device *dev))
pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
}
-#ifdef __powerpc__
- irq_line = 15;
-#endif
#ifdef CONFIG_SNI_RM200_PCI
if (mips_machgroup == MACH_GROUP_SNI_RM
&& mips_machtype == MACH_SNI_RM200_PCI)
@@ -285,17 +307,20 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
case 0x2621:
chipname = "PCnet/PCI II 79C970A";
break;
+ case 0x2623:
+ chipname = "PCnet/FAST 79C971";
+ break;
+ case 0x2624:
+ chipname = "PCnet/FAST+ 79C972";
+ break;
default:
printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
return ENODEV;
}
}
- /* We should have a "dev" from Space.c or the static module table. */
- if (dev == NULL) {
- printk(KERN_ERR "pcnet32.c: Passed a NULL device.\n");
+ if (dev == NULL)
dev = init_etherdev(0, 0);
- }
printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
@@ -324,7 +349,6 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
dev->priv = lp;
lp->name = chipname;
lp->shared_irq = shared;
- lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
@@ -355,17 +379,18 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
if (dev->irq >= 2)
printk(" assigned IRQ %d.\n", dev->irq);
else {
+ unsigned long irq_mask = probe_irq_on();
+
/*
* To auto-IRQ we enable the initialization-done and DMA error
* interrupts. For ISA boards we get a DMA error, but VLB and PCI
* boards will work.
*/
- autoirq_setup(0);
-
/* Trigger an initialization just for the interrupt. */
outw(0x0041, ioaddr+PCNET32_DATA);
-
- dev->irq = autoirq_report(1);
+ mdelay (1);
+
+ dev->irq = probe_irq_off (irq_mask);
if (dev->irq)
printk(", probed IRQ %d.\n", dev->irq);
else {
@@ -388,6 +413,11 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
dev->stop = &pcnet32_close;
dev->get_stats = &pcnet32_get_stats;
dev->set_multicast_list = &pcnet32_set_multicast_list;
+
+#ifdef MODULE
+ lp->next = pcnet32_dev;
+ pcnet32_dev = dev;
+#endif
/* Fill in the generic fields of the device structure. */
ether_setup(dev);
@@ -461,6 +491,8 @@ pcnet32_open(struct device *dev)
printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA));
+ MOD_INC_USE_COUNT;
+
return 0; /* Always succeed */
}
@@ -498,15 +530,23 @@ pcnet32_init_ring(struct device *dev)
{
struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
int i;
+ struct sk_buff *skb;
lp->lock = 0, lp->tx_full = 0;
lp->cur_rx = lp->cur_tx = 0;
lp->dirty_rx = lp->dirty_tx = 0;
for (i = 0; i < RX_RING_SIZE; i++) {
- lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ));
+ skb = dev_alloc_skb (PKT_BUF_SZ);
+ if (skb) {
+ lp->rx_skbuff[i] = skb;
+ skb_reserve (skb, 2);
+ lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(skb->tail));
lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
- lp->rx_ring[i].status = le16_to_cpu(0x8000);
+ lp->rx_ring[i].status = le16_to_cpu(0x8000);
+ }
+ else
+ break;
}
/* The Tx buffer address is filled in as needed, but we do need to clear
the upper ownership bit. */
@@ -523,7 +563,7 @@ pcnet32_init_ring(struct device *dev)
}
static void
-pcnet32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
+pcnet32_restart(struct device *dev, unsigned int csr0_bits)
{
int i;
unsigned int ioaddr = dev->base_addr;
@@ -577,9 +617,9 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
printk("\n");
}
#endif
- pcnet32_restart(dev, 0x0042, 1);
+ pcnet32_restart(dev, 0x0042);
- dev->tbusy=0;
+ dev->tbusy = 0;
dev->trans_start = jiffies;
return 0;
@@ -626,6 +666,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len);
lp->cur_tx++;
+ lp->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
outw(0x0000, ioaddr+PCNET32_ADDR);
@@ -637,7 +678,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
cli();
lp->lock = 0;
if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
- dev->tbusy=0;
+ clear_bit (0, (void *)&dev->tbusy);
else
lp->tx_full = 1;
restore_flags(flags);
@@ -652,8 +693,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct device *dev = (struct device *)dev_id;
struct pcnet32_private *lp;
unsigned int csr0, ioaddr;
- int boguscnt=10;
- int must_restart;
+ int boguscnt = max_interrupt_work;
if (dev == NULL) {
printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
@@ -668,13 +708,10 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
dev->interrupt = 1;
outw(0x00, dev->base_addr + PCNET32_ADDR);
- while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600
- && --boguscnt >= 0) {
+ while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600 && --boguscnt >= 0) {
/* Acknowledge all of the current interrupt sources ASAP. */
outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA);
- must_restart = 0;
-
if (pcnet32_debug > 5)
printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
dev->name, csr0, inw(dev->base_addr + PCNET32_DATA));
@@ -707,8 +744,10 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* Remove this verbosity later! */
printk("%s: Tx FIFO error! Status %4.4x.\n",
dev->name, csr0);
- /* Restart the chip. */
- must_restart = 1;
+ /* stop the chip to clear the error condition, then restart */
+ outw(0x0000, dev->base_addr + PCNET32_ADDR);
+ outw(0x0004, dev->base_addr + PCNET32_DATA);
+ pcnet32_restart(dev, 0x0002);
}
} else {
if (status & 0x1800)
@@ -736,28 +775,31 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
/* The ring is no longer full, clear tbusy. */
lp->tx_full = 0;
- dev->tbusy = 0;
+ clear_bit(0, (void *)&dev->tbusy);
mark_bh(NET_BH);
}
-
lp->dirty_tx = dirty_tx;
}
/* Log misc errors. */
if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
- if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & 0x1000) {
+ /*
+ * this happens when our receive ring is full. This shouldn't
+ * be a problem as we will see normal rx interrupts for the frames
+ * in the receive ring. But there are some PCI chipsets (I can reproduce
+ * this on SP3G with Intel saturn chipset) which have sometimes problems
+ * and will fill up the receive ring with error descriptors. In this
+ * situation we don't get a rx interrupt, but a missed frame interrupt sooner
+ * or later. So we try to clean up our receive ring here.
+ */
+ pcnet32_rx(dev);
+ lp->stats.rx_errors++; /* Missed a Rx frame. */
+ }
if (csr0 & 0x0800) {
printk("%s: Bus master arbitration failure, status %4.4x.\n",
dev->name, csr0);
- /* Restart the chip. */
- must_restart = 1;
- }
-
- if (must_restart) {
- /* stop the chip to clear the error condition, then restart */
- outw(0x0000, dev->base_addr + PCNET32_ADDR);
- outw(0x0004, dev->base_addr + PCNET32_DATA);
- pcnet32_restart(dev, 0x0002, 0);
+ /* unlike for the lance, there is no restart needed */
}
}
@@ -780,7 +822,7 @@ pcnet32_rx(struct device *dev)
struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
int entry = lp->cur_rx & RX_RING_MOD_MASK;
int i;
-
+
/* If we own the next entry, it's a new packet. Send it up. */
while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
@@ -804,39 +846,54 @@ pcnet32_rx(struct device *dev)
short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
struct sk_buff *skb;
- if(pkt_len<60)
- {
+ if(pkt_len < 60) {
printk("%s: Runt packet!\n",dev->name);
lp->stats.rx_errors++;
- }
- else
- {
+ } else {
+ int rx_in_place = 0;
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+
+ if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
+ skb_reserve (newskb, 2);
+ skb = lp->rx_skbuff[entry];
+ skb_put (skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
+ rx_in_place = 1;
+ } else
+ skb = NULL;
+ } else
skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL)
- {
- printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- for (i=0; i < RX_RING_SIZE; i++)
- if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
- break;
-
- if (i > RX_RING_SIZE -2)
- {
- lp->stats.rx_dropped++;
- lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
- lp->cur_rx++;
- }
+
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+ for (i=0; i < RX_RING_SIZE; i++)
+ if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
break;
+
+ if (i > RX_RING_SIZE -2) {
+ lp->stats.rx_dropped++;
+ lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+ lp->cur_rx++;
}
- skb->dev = dev;
+ break;
+ }
+ skb->dev = dev;
+ if (!rx_in_place) {
skb_reserve(skb,2); /* 16 byte align */
skb_put(skb,pkt_len); /* Make room */
eth_copy_and_sum(skb,
(unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
pkt_len,0);
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dma_cache_inv(bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)), pkt_len);
- lp->stats.rx_packets++;
+ }
+ lp->stats.rx_bytes += skb->len;
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dma_cache_inv(bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)), pkt_len);
+ lp->stats.rx_packets++;
}
}
/* The docs say that the buffer length isn't touched, but Andrew Boyd
@@ -857,9 +914,10 @@ pcnet32_close(struct device *dev)
{
unsigned int ioaddr = dev->base_addr;
struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+ int i;
dev->start = 0;
- dev->tbusy = 1;
+ set_bit (0, (void *)&dev->tbusy);
outw(112, ioaddr+PCNET32_ADDR);
lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
@@ -875,6 +933,22 @@ pcnet32_close(struct device *dev)
outw(0x0004, ioaddr+PCNET32_DATA);
free_irq(dev->irq, dev);
+
+ /* free all allocated skbuffs */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ lp->rx_ring[i].status = 0;
+ if (lp->rx_skbuff[i])
+ dev_kfree_skb(lp->rx_skbuff[i]);
+ lp->rx_skbuff[i] = NULL;
+ }
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (lp->tx_skbuff[i])
+ dev_kfree_skb(lp->tx_skbuff[i]);
+ lp->rx_skbuff[i] = NULL;
+ }
+
+ MOD_DEC_USE_COUNT;
return 0;
}
@@ -898,6 +972,57 @@ pcnet32_get_stats(struct device *dev)
return &lp->stats;
}
+
+/* taken from the sunlance driver, which it took from the depca driver */
+static void pcnet32_load_multicast (struct device *dev)
+{
+ struct pcnet32_private *lp = (struct pcnet32_private *) dev->priv;
+ volatile struct pcnet32_init_block *ib = &lp->init_block;
+ volatile u16 *mcast_table = (u16 *)&ib->filter;
+ struct dev_mc_list *dmi=dev->mc_list;
+ char *addrs;
+ int i, j, bit, byte;
+ u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+ /* set all multicast bits */
+ if (dev->flags & IFF_ALLMULTI){
+ ib->filter [0] = 0xffffffff;
+ ib->filter [1] = 0xffffffff;
+ return;
+ }
+ /* clear the multicast filter */
+ ib->filter [0] = 0;
+ ib->filter [1] = 0;
+
+ /* Add addresses */
+ for (i = 0; i < dev->mc_count; i++){
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ /* multicast address? */
+ if (!(*addrs & 1))
+ continue;
+
+ crc = 0xffffffff;
+ for (byte = 0; byte < 6; byte++)
+ for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+
+ if (test) {
+ crc = crc ^ poly;
+ }
+ }
+
+ crc = crc >> 26;
+ mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+ }
+ return;
+}
+
+
/* Set or clear the multicast filter for this adaptor.
*/
@@ -909,23 +1034,54 @@ static void pcnet32_set_multicast_list(struct device *dev)
if (dev->flags&IFF_PROMISC) {
/* Log any net taps. */
printk("%s: Promiscuous mode enabled.\n", dev->name);
- lp->init_block.mode = 0x8000;
+ lp->init_block.mode = le16_to_cpu(0x8000);
} else {
- int num_addrs=dev->mc_count;
- if(dev->flags&IFF_ALLMULTI)
- num_addrs=1;
- /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
- memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
- lp->init_block.mode = 0x0000;
+ lp->init_block.mode = 0x0000;
+ pcnet32_load_multicast (dev);
}
outw(0, ioaddr+PCNET32_ADDR);
outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance. */
- pcnet32_restart(dev, 0x0042, 0); /* Resume normal operation */
+ pcnet32_restart(dev, 0x0042); /* Resume normal operation */
+}
+
+#ifdef MODULE
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(rx_copybreak, "i");
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+int
+init_module(void)
+{
+ if (debug > 0)
+ pcnet32_debug = debug;
+
+ pcnet32_dev = NULL;
+ return pcnet32_probe(NULL);
}
+void
+cleanup_module(void)
+{
+ struct device *next_dev;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ while (pcnet32_dev) {
+ next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
+ unregister_netdev(pcnet32_dev);
+ release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
+ kfree(pcnet32_dev->priv);
+ kfree(pcnet32_dev);
+ pcnet32_dev = next_dev;
+ }
+}
+#endif /* MODULE */
+
+
/*
* Local variables:
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 4341a3449..6aea631f0 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -382,7 +382,7 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
return TIMEOUT;
}
c0 = inb(PAR_STATUS(dev));
- printk("%s: transmit timeout(%d,%02x)\n",
+ printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",
dev->name, snd->state, c0);
}
nl->enet_stats.tx_errors++;
@@ -400,7 +400,7 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
return TIMEOUT;
}
c0 = inb(PAR_STATUS(dev));
- printk("%s: receive timeout(%d,%02x)\n",
+ printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",
dev->name, rcv->state, c0);
}
nl->enet_stats.rx_dropped++;
@@ -501,7 +501,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
dev->interrupt = 0;
outb(0x01, PAR_DATA(dev)); /* send ACK */
if (net_debug > 2)
- printk("%s: receive start\n", dev->name);
+ printk(KERN_DEBUG "%s: receive start\n", dev->name);
rcv->state = PLIP_PK_LENGTH_LSB;
rcv->nibble = PLIP_NB_BEGIN;
@@ -531,13 +531,13 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
return TIMEOUT;
if (rcv->length.h > dev->mtu + dev->hard_header_len
|| rcv->length.h < 8) {
- printk("%s: bogus packet size %d.\n", dev->name, rcv->length.h);
+ printk(KERN_WARNING "%s: bogus packet size %d.\n", dev->name, rcv->length.h);
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);
+ printk(KERN_WARNING "%s: Memory squeeze.\n", dev->name);
return ERROR;
}
skb_put(rcv->skb,rcv->length.h);
@@ -565,7 +565,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
if (rcv->data != rcv->checksum) {
nl->enet_stats.rx_crc_errors++;
if (net_debug)
- printk("%s: checksum error\n", dev->name);
+ printk(KERN_DEBUG "%s: checksum error\n", dev->name);
return ERROR;
}
rcv->state = PLIP_PK_DONE;
@@ -574,10 +574,11 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
/* Inform the upper layer for the arrival of a packet. */
rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
netif_rx(rcv->skb);
+ nl->enet_stats.rx_bytes += rcv->length.h;
nl->enet_stats.rx_packets++;
rcv->skb = NULL;
if (net_debug > 2)
- printk("%s: receive end\n", dev->name);
+ printk(KERN_DEBUG "%s: receive end\n", dev->name);
/* Close the connection. */
outb (0x00, PAR_DATA(dev));
@@ -661,7 +662,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
unsigned int cx;
if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
- printk("%s: send skb lost\n", dev->name);
+ printk(KERN_ERR "%s: send skb lost\n", dev->name);
snd->state = PLIP_PK_DONE;
snd->skb = NULL;
return ERROR;
@@ -698,7 +699,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
}
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
if (net_debug > 2)
- printk("%s: send start\n", dev->name);
+ printk(KERN_DEBUG "%s: send start\n", dev->name);
snd->state = PLIP_PK_LENGTH_LSB;
snd->nibble = PLIP_NB_BEGIN;
nl->timeout_count = 0;
@@ -741,6 +742,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
&snd->nibble, snd->checksum))
return TIMEOUT;
+ nl->enet_stats.tx_bytes += snd->skb->len;
dev_kfree_skb(snd->skb);
nl->enet_stats.tx_packets++;
snd->state = PLIP_PK_DONE;
@@ -750,7 +752,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
outb (0x00, data_addr);
snd->skb = NULL;
if (net_debug > 2)
- printk("%s: send end\n", dev->name);
+ printk(KERN_DEBUG "%s: send end\n", dev->name);
nl->connection = PLIP_CN_CLOSING;
nl->is_deferred = 1;
queue_task(&nl->deferred, &tq_timer);
@@ -789,7 +791,7 @@ plip_error(struct device *dev, struct net_local *nl,
status = inb(PAR_STATUS(dev));
if ((status & 0xf8) == 0x80) {
if (net_debug > 2)
- printk("%s: reset interface.\n", dev->name);
+ printk(KERN_DEBUG "%s: reset interface.\n", dev->name);
nl->connection = PLIP_CN_NONE;
nl->should_relinquish = 0;
dev->tbusy = 0;
@@ -815,7 +817,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
unsigned char c0;
if (dev == NULL) {
- printk("plip_interrupt: irq %d for unknown device.\n", irq);
+ printk(KERN_ERR "plip_interrupt: irq %d for unknown device.\n", irq);
return;
}
@@ -828,12 +830,12 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
c0 = inb(PAR_STATUS(dev));
if ((c0 & 0xf8) != 0xc0) {
if (net_debug > 1)
- printk("%s: spurious interrupt\n", dev->name);
+ printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name);
return;
}
dev->interrupt = 1;
if (net_debug > 3)
- printk("%s: interrupt.\n", dev->name);
+ printk(KERN_DEBUG "%s: interrupt.\n", dev->name);
spin_lock_irq(&nl->lock);
switch (nl->connection) {
@@ -859,7 +861,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
case PLIP_CN_ERROR:
spin_unlock_irq(&nl->lock);
- printk("%s: receive interrupt in error state\n", dev->name);
+ printk(KERN_WARNING "%s: receive interrupt in error state\n", dev->name);
break;
}
}
@@ -897,18 +899,18 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
}
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
+ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
return 1;
}
if (skb->len > dev->mtu + dev->hard_header_len) {
- printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
+ printk(KERN_WARNING "%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);
+ printk(KERN_DEBUG "%s: send request\n", dev->name);
spin_lock_irq(&nl->lock);
dev->trans_start = jiffies;
@@ -1081,8 +1083,7 @@ plip_get_stats(struct device *dev)
return r;
}
-static int
-plip_config(struct device *dev, struct ifmap *map)
+static int plip_config(struct device *dev, struct ifmap *map)
{
struct net_local *nl = (struct net_local *) dev->priv;
struct pardevice *pardev = nl->pardev;
@@ -1090,8 +1091,8 @@ plip_config(struct device *dev, struct ifmap *map)
if (dev->flags & IFF_UP)
return -EBUSY;
- printk(KERN_WARNING "plip: Warning, changing irq with ifconfig will be obsoleted.\n");
- printk("plip: Next time, please set with /proc/parport/*/irq instead.\n");
+ printk(KERN_INFO "plip: Warning, changing irq with ifconfig will be obsoleted.\n");
+ printk(KERN_INFO "plip: Next time, please set with /proc/parport/*/irq instead.\n");
if (map->irq != (unsigned char)-1) {
pardev->port->irq = dev->irq = map->irq;
diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c
index 9d4a237c7..6d3c23dfb 100644
--- a/drivers/net/ppp.c
+++ b/drivers/net/ppp.c
@@ -2,13 +2,9 @@
*
* Michael Callahan <callahan@maths.ox.ac.uk>
* Al Longyear <longyear@netcom.com>
- * Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
- * Cyrus Durgin <cider@speakeasy.org> (changes for kmod)
+ * Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
*
- * Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
- * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
- *
- * ==FILEVERSION 980501==
+ * ==FILEVERSION 980704==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the
@@ -45,21 +41,22 @@
*/
#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2)
-
#define CHECK_CHARACTERS 1
-#define PPP_COMPRESS 1
-/* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */
+#define PPP_MAX_RCV_QLEN 32 /* max # frames we queue up for pppd */
-#include <linux/config.h> /* for CONFIG_KMOD */
+/* $Id: ppp.c,v 1.19 1998/07/07 04:27:37 paulus Exp $ */
+
+#include <linux/version.h>
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
-#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
+#include <linux/poll.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/tty.h>
@@ -70,18 +67,13 @@
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
+
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
#include <linux/inet.h>
#include <linux/ioctl.h>
-#include <linux/init.h>
-
-typedef struct sk_buff sk_buff;
-#define skb_data(skb) ((__u8 *) (skb)->data)
-
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_arp.h>
@@ -99,49 +91,38 @@ typedef struct sk_buff sk_buff;
#include <linux/kmod.h>
#endif
-#ifndef PPP_IPX
-#define PPP_IPX 0x2b /* IPX protocol over PPP */
-#endif
-
-#ifndef PPP_LQR
-#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
-#endif
+/*
+ * Local functions
+ */
#ifdef CONFIG_MODULES
static int ppp_register_compressor (struct compressor *cp);
static void ppp_unregister_compressor (struct compressor *cp);
#endif
-/*
- * Local functions
- */
+static void ppp_async_init(struct ppp *ppp);
+static void ppp_async_release(struct ppp *ppp);
+static int ppp_tty_push(struct ppp *ppp);
+static int ppp_async_encode(struct ppp *ppp);
+static int ppp_async_send(struct ppp *, struct sk_buff *);
+
+static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
+static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
+static void ppp_proto_ccp(struct ppp *ppp, __u8 *dp, int len, int rcvd);
+static void ppp_ccp_closed(struct ppp *ppp);
+static int ppp_receive_frame(struct ppp *, struct sk_buff *);
+static void ppp_receive_error(struct ppp *ppp);
+static void ppp_output_wakeup(struct ppp *ppp);
+static void ppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb);
+static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
+static struct sk_buff *ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb);
-static struct compressor *find_compressor (int type);
-static void ppp_init_ctrl_blk (register struct ppp *);
-static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
-static struct ppp *ppp_alloc (void);
static struct ppp *ppp_find (int pid_value);
-static void ppp_print_buffer (const __u8 *, const __u8 *, int);
-extern inline void ppp_stuff_char (struct ppp *ppp,
- register struct ppp_buffer *buf,
- register __u8 chr);
-extern inline int lock_buffer (register struct ppp_buffer *buf);
-static int ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf,
- __u8 *data, int len, enum NPmode npmode);
-
-static int rcv_proto_ip (struct ppp *, __u16, __u8 *, int);
-static int rcv_proto_ipx (struct ppp *, __u16, __u8 *, int);
-static int rcv_proto_vjc_comp (struct ppp *, __u16, __u8 *, int);
-static int rcv_proto_vjc_uncomp (struct ppp *, __u16, __u8 *, int);
-static int rcv_proto_unknown (struct ppp *, __u16, __u8 *, int);
-static int rcv_proto_lqr (struct ppp *, __u16, __u8 *, int);
-static void ppp_doframe_lower (struct ppp *, __u8 *, int);
-static int ppp_doframe (struct ppp *);
-
-static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd);
-static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
-
-#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (__u8)(c))
+static struct ppp *ppp_alloc (void);
+static void ppp_generic_init(struct ppp *ppp);
+static void ppp_release(struct ppp *ppp);
+static void ppp_print_buffer (const char *, const __u8 *, int);
+static struct compressor *find_compressor (int type);
#ifndef OPTIMIZE_FLAG_TIME
#define OPTIMIZE_FLAG_TIME 0
@@ -154,67 +135,26 @@ static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
static int flag_time = OPTIMIZE_FLAG_TIME;
MODULE_PARM(flag_time, "i");
-/*
- * The "main" procedure to the ppp device
- */
-
-int ppp_init (struct device *);
-
-/*
- * Network device driver callback routines
- */
-
-static int ppp_dev_open (struct device *);
-static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
-static int ppp_dev_close (struct device *);
-static int ppp_dev_xmit (sk_buff *, struct device *);
-static struct net_device_stats *ppp_dev_stats (struct device *);
-
-/*
- * TTY callbacks
- */
-
-static ssize_t ppp_tty_read (struct tty_struct *, struct file *, __u8 *,
- size_t);
-static ssize_t ppp_tty_write (struct tty_struct *, struct file *,
- const __u8 *, size_t);
-static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
- unsigned long);
-static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp,
- poll_table * wait);
-static int ppp_tty_open (struct tty_struct *);
-static void ppp_tty_close (struct tty_struct *);
-static int ppp_tty_room (struct tty_struct *tty);
-static void ppp_tty_receive (struct tty_struct *tty, const __u8 * cp,
- char *fp, int count);
-static void ppp_tty_wakeup (struct tty_struct *tty);
-
#define CHECK_PPP_MAGIC(ppp) do { \
if (ppp->magic != PPP_MAGIC) { \
- printk(KERN_WARNING "bad magic for ppp %p at %s:%d\n", \
- ppp, __FILE__, __LINE__); \
+ printk(ppp_magic_warn, ppp, __FILE__, __LINE__); \
} \
} while (0)
#define CHECK_PPP(a) do { \
CHECK_PPP_MAGIC(ppp); \
if (!ppp->inuse) { \
- printk (ppp_warning, __LINE__); \
+ printk(ppp_warning, __LINE__); \
return a; \
} \
} while (0)
#define CHECK_PPP_VOID() do { \
CHECK_PPP_MAGIC(ppp); \
if (!ppp->inuse) { \
- printk (ppp_warning, __LINE__); \
+ printk(ppp_warning, __LINE__); \
+ return; \
} \
} while (0)
-#define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
-#define in_rmap(ppp,c) ((((unsigned int) (__u8) (c)) < 0x20) && \
- ppp->recv_async_map & (1 << (c)))
-
-#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
#define tty2ppp(tty) ((struct ppp *) ((tty)->disc_data))
#define dev2ppp(dev) ((struct ppp *) ((dev)->priv))
#define ppp2tty(ppp) ((ppp)->tty)
@@ -223,39 +163,43 @@ static void ppp_tty_wakeup (struct tty_struct *tty);
static struct ppp *ppp_list = NULL;
static struct ppp *ppp_last = NULL;
-/* Buffer types */
-#define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */
-#define BUFFER_TYPE_TTY_WR 1 /* tty write buffer */
-#define BUFFER_TYPE_DEV_WR 2 /* ppp write buffer */
-#define BUFFER_TYPE_TTY_RD 3 /* tty read buffer */
-#define BUFFER_TYPE_VJ 4 /* vj compression buffer */
-
-/* Define this string only once for all macro invocations */
+/* Define these strings only once for all macro invocations */
static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
+static char ppp_magic_warn[] = KERN_WARNING "bad magic for ppp %p at %s:%d\n";
static char szVersion[] = PPP_VERSION;
-/*
- * Information for the protocol decoder
- */
+EXPORT_SYMBOL(ppp_register_compressor);
+EXPORT_SYMBOL(ppp_unregister_compressor);
-typedef int (*pfn_proto) (struct ppp *, __u16, __u8 *, int);
+/*************************************************************
+ * LINE DISCIPLINE SUPPORT
+ * The following code implements the PPP line discipline
+ * and supports using PPP on an async serial line.
+ *************************************************************/
-typedef struct ppp_proto_struct {
- int proto;
- pfn_proto func;
-} ppp_proto_type;
+#define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
+#define in_rmap(ppp,c) ((((unsigned int) (__u8) (c)) < 0x20) && \
+ ppp->recv_async_map & (1 << (c)))
-static
-ppp_proto_type proto_list[] = {
- { PPP_IP, rcv_proto_ip },
- { PPP_IPX, rcv_proto_ipx },
- { PPP_VJC_COMP, rcv_proto_vjc_comp },
- { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
- { PPP_LQR, rcv_proto_lqr },
- { PPP_CCP, rcv_proto_ccp },
- { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
-};
+/*
+ * TTY callbacks
+ */
+
+static ssize_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
+ size_t);
+static ssize_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
+ size_t);
+static int ppp_tty_ioctl(struct tty_struct *, struct file *, unsigned int,
+ unsigned long);
+static unsigned int ppp_tty_poll(struct tty_struct *tty, struct file *filp,
+ poll_table * wait);
+static int ppp_tty_open (struct tty_struct *);
+static void ppp_tty_close (struct tty_struct *);
+static int ppp_tty_room (struct tty_struct *tty);
+static void ppp_tty_receive (struct tty_struct *tty, const __u8 * cp,
+ char *fp, int count);
+static void ppp_tty_wakeup (struct tty_struct *tty);
__u16 ppp_crc16_table[256] =
{
@@ -292,6 +236,7 @@ __u16 ppp_crc16_table[256] =
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
+EXPORT_SYMBOL(ppp_crc16_table);
#ifdef CHECK_CHARACTERS
static __u32 paritytab[8] =
@@ -301,43 +246,29 @@ static __u32 paritytab[8] =
};
#endif
-/* local function to store a value into the LQR frame */
-extern inline __u8 * store_long (register __u8 *p, register int value) {
- *p++ = (__u8) (value >> 24);
- *p++ = (__u8) (value >> 16);
- *p++ = (__u8) (value >> 8);
- *p++ = (__u8) value;
- return p;
-}
-
-/*************************************************************
- * INITIALIZATION
- *************************************************************/
-
-/* This procedure is called once and once only to define who we are to
- * the operating system and the various procedures that it may use in
- * accessing the ppp protocol.
+/*
+ * This procedure is called at initialization time to register
+ * the PPP line discipline.
*/
-
-__initfunc(static int
-ppp_first_time (void))
+static int
+ppp_first_time(void)
{
static struct tty_ldisc ppp_ldisc;
int status;
- printk (KERN_INFO
- "PPP: version %s (demand dialling)"
- "\n", szVersion);
+ printk(KERN_INFO
+ "PPP: version %s (demand dialling)"
+ "\n", szVersion);
#ifndef MODULE /* slhc module logic has its own copyright announcement */
- printk (KERN_INFO
- "TCP compression code copyright 1989 Regents of the "
- "University of California\n");
+ printk(KERN_INFO
+ "TCP compression code copyright 1989 Regents of the "
+ "University of California\n");
#endif
-/*
- * Register the tty discipline
- */
+ /*
+ * Register the tty discipline
+ */
(void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
ppp_ldisc.magic = TTY_LDISC_MAGIC;
ppp_ldisc.name = "ppp";
@@ -353,91 +284,20 @@ ppp_first_time (void))
status = tty_register_ldisc (N_PPP, &ppp_ldisc);
if (status == 0)
- printk (KERN_INFO "PPP line discipline registered.\n");
+ printk(KERN_INFO "PPP line discipline registered.\n");
else
- printk (KERN_ERR "error registering line discipline: %d\n",
- status);
+ printk(KERN_ERR "error registering line discipline: %d\n",
+ status);
return status;
}
-/*************************************************************
- * INITIALIZATION
- *************************************************************/
-
-/* called when the device is actually created */
-
-static int
-ppp_init_dev (struct device *dev)
-{
- dev->hard_header_len = PPP_HDRLEN;
-
- /* device INFO */
- dev->mtu = PPP_MTU;
- dev->hard_start_xmit = ppp_dev_xmit;
- dev->open = ppp_dev_open;
- dev->stop = ppp_dev_close;
- dev->get_stats = ppp_dev_stats;
- dev->do_ioctl = ppp_dev_ioctl;
- dev->addr_len = 0;
- dev->tx_queue_len = 10;
- dev->type = ARPHRD_PPP;
-
- dev_init_buffers(dev);
-
- /* New-style flags */
- dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-
- return 0;
-}
+#ifndef MODULE
/*
- * Local procedure to initialize the ppp structure
+ * Called at boot time if the PPP driver is compiled into the kernel.
*/
-
-static void
-ppp_init_ctrl_blk (register struct ppp *ppp)
-{
- ppp->magic = PPP_MAGIC;
- ppp->toss = 0xE0;
- ppp->escape = 0;
-
- ppp->flags = 0;
- ppp->mtu = PPP_MTU;
- ppp->mru = PPP_MRU;
-
- memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
- ppp->xmit_async_map[0] = 0xffffffff;
- ppp->xmit_async_map[3] = 0x60000000;
- ppp->recv_async_map = 0x00000000;
-
- ppp->rbuf = NULL;
- ppp->wbuf = NULL;
- ppp->ubuf = NULL;
- ppp->cbuf = NULL;
- ppp->slcomp = NULL;
- ppp->read_wait = NULL;
- ppp->write_wait = NULL;
- ppp->last_xmit = jiffies - flag_time;
- ppp->last_recv = jiffies;
-
- /* clear statistics */
- memset(&ppp->stats, 0, sizeof (struct pppstat));
- memset(&ppp->estats, 0, sizeof(ppp->estats));
-
- /* PPP compression data */
- ppp->sc_xc_state =
- ppp->sc_rc_state = NULL;
-}
-
-EXPORT_SYMBOL(ppp_register_compressor);
-EXPORT_SYMBOL(ppp_unregister_compressor);
-EXPORT_SYMBOL(ppp_crc16_table);
-
-/* called at boot/load time for each ppp device defined in the kernel */
-
-#ifndef MODULE
int
-ppp_init (struct device *dev)
+ppp_init(struct device *dev)
{
static int first_time = 1;
int answer = 0;
@@ -452,597 +312,678 @@ ppp_init (struct device *dev)
}
#endif
-#define BUFFER_MAGIC 0x1d10
-#define CHECK_BUF_MAGIC(buf) do { \
- if (buf->magic != BUFFER_MAGIC) { \
- printk(KERN_WARNING "bad magic for ppp buffer %p at %s:%d\n", \
- buf, __FILE__, __LINE__); \
- } \
-} while (0)
-
/*
- * Routine to allocate a buffer for later use by the driver.
+ * Initialize the async-specific parts of the ppp structure.
*/
-
-static struct ppp_buffer *
-ppp_alloc_buf (int size, int type)
+static void
+ppp_async_init(struct ppp *ppp)
{
- struct ppp_buffer *buf;
-
- buf = (struct ppp_buffer *) kmalloc (size + sizeof (struct ppp_buffer),
- GFP_ATOMIC);
-
- if (buf != NULL) {
- buf->size = size - 1; /* Mask for the buffer size */
- buf->type = type;
- buf->locked = 0;
- buf->count = 0;
- buf->head = 0;
- buf->tail = 0;
- buf->fcs = PPP_INITFCS;
- buf->magic = BUFFER_MAGIC;
- }
- return (buf);
-}
+ ppp->escape = 0;
+ ppp->toss = 0xE0;
+ ppp->tty_pushing = 0;
-/*
- * Routine to release the allocated buffer.
- */
+ memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
+ ppp->xmit_async_map[0] = 0xffffffff;
+ ppp->xmit_async_map[3] = 0x60000000;
+ ppp->recv_async_map = 0xffffffff;
-static void
-ppp_free_buf (struct ppp_buffer *ptr)
-{
- if (ptr != NULL) {
- CHECK_BUF_MAGIC(ptr);
- kfree (ptr);
- }
+ ppp->tpkt = NULL;
+ ppp->tfcs = PPP_INITFCS;
+ ppp->optr = ppp->obuf;
+ ppp->olim = ppp->obuf;
+
+ ppp->rpkt = NULL;
+ ppp->rfcs = PPP_INITFCS;
+
+ ppp->tty = NULL;
+ ppp->backup_tty = NULL;
+
+ ppp->bytes_sent = 0;
+ ppp->bytes_rcvd = 0;
}
/*
- * Lock the indicated transmit buffer
+ * Clean up the async-specific parts of the ppp structure.
*/
-
-extern inline int
-lock_buffer (register struct ppp_buffer *buf)
+static void
+ppp_async_release(struct ppp *ppp)
{
- unsigned long state;
- unsigned long flags;
-/*
- * Save the current state and if free then set it to the "busy" state
- */
- CHECK_BUF_MAGIC(buf);
- save_flags (flags);
- cli ();
- state = buf->locked;
- if (state == 0)
- buf->locked = 2;
-
- restore_flags (flags);
- return (state);
+ struct sk_buff *skb;
+
+ if ((skb = ppp->rpkt) != NULL)
+ kfree_skb(skb);
+ ppp->rpkt = NULL;
+ if ((skb = ppp->tpkt) != NULL)
+ kfree_skb(skb);
+ ppp->tpkt = NULL;
}
/*
- * MTU has been changed by the IP layer. Unfortunately we are not told
- * about this, but we spot it ourselves and fix things up. We could be
- * in an upcall from the tty driver, or in an ip packet queue.
+ * TTY callback.
+ *
+ * Called when the tty discipline is switched to PPP.
*/
static int
-ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
+ppp_tty_open (struct tty_struct *tty)
{
- struct device *dev;
- unsigned long flags;
+ struct ppp *ppp;
- struct ppp_buffer *new_rbuf;
- struct ppp_buffer *new_wbuf;
- struct ppp_buffer *new_cbuf;
- struct ppp_buffer *new_tbuf;
+ /*
+ * Allocate a ppp structure to use.
+ */
+ tty->disc_data = NULL;
+ ppp = ppp_find(current->pid);
+ if (ppp != NULL) {
+ /*
+ * If we are taking over a ppp unit which is currently
+ * connected to a loopback pty, there's not much to do.
+ */
+ CHECK_PPP(-EINVAL);
- struct ppp_buffer *old_rbuf;
- struct ppp_buffer *old_wbuf;
- struct ppp_buffer *old_cbuf;
- struct ppp_buffer *old_tbuf;
+ } else {
+ ppp = ppp_alloc();
+ if (ppp == NULL) {
+ printk(KERN_ERR "ppp_alloc failed\n");
+ return -ENFILE;
+ }
- int mtu, mru;
-/*
- * Allocate the buffer from the kernel for the data
- */
- CHECK_PPP(0);
- dev = ppp2dev (ppp);
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s: changedmtu %d %d\n", ppp->name,
- new_mtu, new_mru);
- mru = new_mru;
- /* allow for possible escaping of every character */
- mtu = (new_mtu * 2) + 20;
-
- /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
- if (mru < PPP_MRU)
- mru = PPP_MRU;
-
- mru += 10;
-
- new_wbuf = ppp_alloc_buf (mtu+PPP_HDRLEN, BUFFER_TYPE_DEV_WR);
- new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
- new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD);
- new_cbuf = ppp_alloc_buf (mru+PPP_HDRLEN, BUFFER_TYPE_VJ);
-/*
- * If the buffers failed to allocate then complain and release the partial
- * allocations.
- */
- if (new_wbuf == NULL || new_tbuf == NULL ||
- new_rbuf == NULL || new_cbuf == NULL) {
- printk (KERN_ERR "ppp: failed to allocate new buffers\n");
-
- ppp_free_buf (new_wbuf);
- ppp_free_buf (new_tbuf);
- ppp_free_buf (new_rbuf);
- ppp_free_buf (new_cbuf);
- return 0;
- }
-/*
- * Update the pointers to the new buffer structures.
- */
- save_flags(flags);
- cli ();
- old_wbuf = ppp->wbuf;
- old_rbuf = ppp->rbuf;
- old_cbuf = ppp->cbuf;
- old_tbuf = ppp->tbuf;
-
- ppp->wbuf = new_wbuf;
- ppp->rbuf = new_rbuf;
- ppp->cbuf = new_cbuf;
- ppp->tbuf = new_tbuf;
-
- if (old_wbuf)
- new_wbuf->locked = old_wbuf->locked;
-
- ppp->rbuf->size -= 80; /* reserve space for vj header expansion */
-
- dev->mem_start = (unsigned long) buf_base (new_wbuf);
- dev->mem_end = (unsigned long) (dev->mem_start + mtu);
- dev->rmem_start = (unsigned long) buf_base (new_rbuf);
- dev->rmem_end = (unsigned long) (dev->rmem_start + mru);
-/*
- * Update the parameters for the new buffer sizes
- */
- ppp->toss = 0xE0; /* To ignore characters until new FLAG */
- ppp->escape = 0; /* No pending escape character */
+ /*
+ * Initialize the control block
+ */
+ ppp_generic_init(ppp);
+ ppp_async_init(ppp);
- dev->mtu =
- ppp->mtu = new_mtu;
- ppp->mru = new_mru;
+ MOD_INC_USE_COUNT;
+ }
- ppp->s1buf = NULL;
- ppp->s2buf = NULL;
- ppp->xbuf = NULL;
+ tty->disc_data = ppp;
+ ppp->tty = tty;
- ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- ppp->flags &= ~SC_XMIT_BUSY;
+ /*
+ * Flush any pending characters in the driver
+ */
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer (tty);
- restore_flags(flags);
-/*
- * Release old buffer pointers
- */
- ppp_free_buf (old_rbuf);
- ppp_free_buf (old_wbuf);
- ppp_free_buf (old_cbuf);
- ppp_free_buf (old_tbuf);
- return 1;
+ return ppp->line;
}
/*
- * CCP is down; free (de)compressor state if necessary.
+ * TTY callback.
+ *
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
*/
static void
-ppp_ccp_closed (struct ppp *ppp)
+ppp_tty_close (struct tty_struct *tty)
{
- unsigned long flags;
+ struct ppp *ppp = tty2ppp(tty);
- save_flags(flags);
- cli();
- ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
- restore_flags(flags);
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s: ccp closed\n", ppp->name);
- if (ppp->sc_xc_state) {
- (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
- ppp->sc_xc_state = NULL;
+ if (ppp == NULL)
+ return;
+ tty->disc_data = NULL;
+ if (ppp->magic != PPP_MAGIC) {
+ printk(KERN_WARNING "ppp_tty_close: bogus\n");
+ return;
+ }
+ if (!ppp->inuse) {
+ printk(KERN_WARNING "ppp_tty_close: not inuse\n");
+ ppp->tty = ppp->backup_tty = 0;
+ return;
}
+ if (tty == ppp->backup_tty)
+ ppp->backup_tty = 0;
+ if (tty != ppp->tty)
+ return;
+ if (ppp->backup_tty) {
+ ppp->tty = ppp->backup_tty;
+ } else {
+ ppp->tty = 0;
+ ppp->sc_xfer = 0;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO "ppp: channel %s closing.\n",
+ ppp2dev(ppp)->name);
- if (ppp->sc_rc_state) {
- (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
- ppp->sc_rc_state = NULL;
+ ppp_async_release(ppp);
+ ppp_release(ppp);
+ ppp->inuse = 0;
+ MOD_DEC_USE_COUNT;
}
}
/*
- * Called to release all of the information in the current PPP structure.
- *
- * It is called when the ppp device goes down or if it is unable to go
- * up.
+ * Read a PPP frame from the rcv_q list,
+ * waiting if necessary
*/
-
-static void
-ppp_release (struct ppp *ppp)
+static ssize_t
+ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
+ size_t nr)
{
- struct tty_struct *tty;
- struct device *dev;
+ struct ppp *ppp = tty2ppp (tty);
+ struct sk_buff *skb;
+ ssize_t len, err;
- CHECK_PPP_MAGIC(ppp);
- tty = ppp2tty (ppp);
- dev = ppp2dev (ppp);
+ /*
+ * Validate the pointers
+ */
+ if (!ppp)
+ return -EIO;
+ CHECK_PPP(-ENXIO);
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s released\n", ppp->name);
+ /*
+ * Before we attempt to write the frame to the user, ensure that the
+ * user has access to the pages for the total buffer length.
+ */
+ err = verify_area(VERIFY_WRITE, buf, nr);
+ if (err != 0)
+ return (err);
- ppp_ccp_closed (ppp);
+ /*
+ * Wait for a frame to arrive if necessary.
+ * We increment the module use count so that the module
+ * can't go away while we're sleeping.
+ */
+ MOD_INC_USE_COUNT;
+ skb = NULL;
+ for (;;) {
+ ppp = tty2ppp(tty);
+ err = 0;
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
+ || tty != ppp->tty)
+ break;
- /* Ensure that the pppd process is not hanging on poll() */
- wake_up_interruptible (&ppp->read_wait);
- wake_up_interruptible (&ppp->write_wait);
-
- if (tty != NULL && tty->disc_data == ppp)
- tty->disc_data = NULL; /* Break the tty->ppp link */
-
- ppp_free_buf (ppp->rbuf);
- ppp_free_buf (ppp->wbuf);
- ppp_free_buf (ppp->cbuf);
- ppp_free_buf (ppp->ubuf);
- ppp_free_buf (ppp->tbuf);
-
- ppp->rbuf =
- ppp->wbuf =
- ppp->cbuf =
- ppp->tbuf =
- ppp->xbuf =
- ppp->s1buf =
- ppp->s2buf =
- ppp->ubuf = NULL;
+ skb = skb_dequeue(&ppp->rcv_q);
+ if (skb != 0)
+ break;
- if (ppp->slcomp) {
- slhc_free (ppp->slcomp);
- ppp->slcomp = NULL;
+ /*
+ * If no frame is available, return -EAGAIN or wait.
+ */
+ err = -EAGAIN;
+ if (file->f_flags & O_NONBLOCK)
+ break;
+
+ current->timeout = 0;
+ interruptible_sleep_on(&ppp->read_wait);
+ err = -EINTR;
+ if (signal_pending(current))
+ break;
}
+ MOD_DEC_USE_COUNT;
+ if (skb == 0)
+ return err;
- ppp->inuse = 0;
- ppp->tty = NULL;
- ppp->backup_tty = NULL;
+ /*
+ * Ensure that the frame will fit within the caller's buffer.
+ * If not, just discard the frame.
+ */
+ len = skb->len;
+ if (len > nr) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG
+ "ppp: read of %lu bytes too small for %ld "
+ "frame\n", (unsigned long) nr, (long) len);
+ ppp->stats.ppp_ierrors++;
+ err = -EOVERFLOW;
+ goto out;
+ }
+
+ /*
+ * Copy the received data from the buffer to the caller's area.
+ */
+ err = len;
+ if (copy_to_user(buf, skb->data, len))
+ err = -EFAULT;
+
+out:
+ kfree_skb(skb);
+ return err;
}
/*
- * TTY callback.
- *
- * Called when the line discipline is changed to something
- * else, the tty is closed, or the tty detects a hangup.
+ * Writing to a tty in ppp line discipline sends a PPP frame.
+ * Used by pppd to send control packets (LCP, etc.).
*/
-
-static void
-ppp_tty_close (struct tty_struct *tty)
+static ssize_t
+ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
+ size_t count)
{
struct ppp *ppp = tty2ppp (tty);
+ __u8 *new_data;
+ struct sk_buff *skb;
- if (ppp != NULL) {
- if (ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp: trying to close unopened tty!\n");
- return;
- }
- CHECK_PPP_VOID();
- tty->disc_data = NULL;
- if (tty == ppp->backup_tty)
- ppp->backup_tty = 0;
- if (tty != ppp->tty)
- return;
- if (ppp->backup_tty) {
- ppp->tty = ppp->backup_tty;
- } else {
- ppp->sc_xfer = 0;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp: channel %s closing.\n",
- ppp2dev(ppp)->name);
- ppp_release (ppp);
- MOD_DEC_USE_COUNT;
- }
+ /*
+ * Verify the pointers.
+ */
+ if (!ppp)
+ return -EIO;
+
+ if (ppp->magic != PPP_MAGIC)
+ return -EIO;
+
+ CHECK_PPP(-ENXIO);
+
+ /*
+ * Ensure that the caller does not wish to send too much.
+ */
+ if (count > PPP_MTU + PPP_HDRLEN) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_WARNING
+ "ppp_tty_write: truncating user packet "
+ "from %lu to mtu %d\n", (unsigned long) count,
+ PPP_MTU + PPP_HDRLEN);
+ count = PPP_MTU + PPP_HDRLEN;
+ }
+
+ /*
+ * Allocate a buffer for the data and fetch it from the user space.
+ */
+ skb = alloc_skb(count, GFP_KERNEL);
+ if (skb == NULL) {
+ printk(KERN_ERR "ppp_tty_write: no memory\n");
+ return 0;
+ }
+ new_data = skb_put(skb, count);
+
+ /*
+ * Retrieve the user's buffer
+ */
+ if (copy_from_user(new_data, data, count)) {
+ kfree_skb(skb);
+ return -EFAULT;
}
+
+ /*
+ * Send the frame
+ */
+ ppp_send_ctrl(ppp, skb);
+
+ return (ssize_t) count;
}
/*
- * TTY callback.
- *
- * Called when the tty discipline is switched to PPP.
+ * Process the IOCTL call for the tty device.
+ * Only the ioctls that relate to using ppp on async serial lines
+ * are processed here; the rest are handled by ppp_ioctl.
*/
-
static int
-ppp_tty_open (struct tty_struct *tty)
+ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
+ unsigned int param2, unsigned long param3)
{
struct ppp *ppp = tty2ppp (tty);
- int indx;
-/*
- * There should not be an existing table for this slot.
- */
- if (ppp) {
- printk (KERN_ERR
- "ppp_tty_open: gack! tty already associated to %s!\n",
- ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
- : "unknown");
- return -EEXIST;
- }
-/*
- * Allocate the structure from the system
- */
- ppp = ppp_find(current->pid);
- if (ppp != NULL) {
+ register int temp_i = 0;
+ int error = -EFAULT;
+
+ /*
+ * Verify the status of the PPP device.
+ */
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
+ return -ENXIO;
+
+ /*
+ * The user must have an euid of root to do these requests.
+ */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ switch (param2) {
+ case PPPIOCGASYNCMAP:
/*
- * If we are taking over a ppp unit which is currently
- * connected to a loopback pty, there's not much to do.
+ * Retrieve the transmit async map
*/
- CHECK_PPP(-EINVAL);
- tty->disc_data = ppp;
- ppp->tty = tty;
+ if (put_user(ppp->xmit_async_map[0], (int *) param3))
+ break;
+ error = 0;
+ break;
- } else {
- ppp = ppp_alloc();
- if (ppp == NULL) {
- printk (KERN_ERR "ppp_alloc failed\n");
- return -ENFILE;
- }
-/*
- * Initialize the control block
- */
- ppp_init_ctrl_blk (ppp);
- tty->disc_data = ppp;
- ppp->tty = tty;
-/*
- * Allocate space for the default VJ header compression slots
- */
- ppp->slcomp = slhc_init (16, 16);
- if (ppp->slcomp == NULL) {
- printk (KERN_ERR "ppp_tty_open: "
- "no space for compression buffers!\n");
- ppp_release (ppp);
- return -ENOMEM;
- }
-/*
- * Allocate space for the MTU and MRU buffers
- */
- if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
- ppp_release (ppp);
- return -ENOMEM;
- }
-/*
- * Allocate space for a user level buffer
- */
- ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
- if (ppp->ubuf == NULL) {
- printk (KERN_ERR "ppp_tty_open: "
- "no space for user receive buffer\n");
- ppp_release (ppp);
- return -ENOMEM;
- }
+ case PPPIOCSASYNCMAP:
+ /*
+ * Set the transmit async map
+ */
+ if (get_user(temp_i, (int *) param3))
+ break;
+ ppp->xmit_async_map[0] = temp_i;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO
+ "ppp_tty_ioctl: set xmit asyncmap %x\n",
+ ppp->xmit_async_map[0]);
+ error = 0;
+ break;
+ case PPPIOCSRASYNCMAP:
+ /*
+ * Set the receive async map
+ */
+ if (get_user(temp_i, (int *) param3))
+ break;
+ ppp->recv_async_map = temp_i;
if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp: channel %s open\n",
- ppp2dev(ppp)->name);
+ printk(KERN_INFO
+ "ppp_tty_ioctl: set rcv asyncmap %x\n",
+ ppp->recv_async_map);
+ error = 0;
+ break;
- for (indx = 0; indx < NUM_NP; ++indx)
- ppp->sc_npmode[indx] = NPMODE_PASS;
+ case PPPIOCGXASYNCMAP:
+ /*
+ * Get the map of characters to be escaped on transmission.
+ */
+ if (copy_to_user((void *) param3, ppp->xmit_async_map,
+ sizeof (ppp->xmit_async_map)))
+ break;
+ error = 0;
+ break;
- MOD_INC_USE_COUNT;
- }
-/*
- * Flush any pending characters in the driver and discipline.
- */
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
+ case PPPIOCSXASYNCMAP:
+ /*
+ * Set the map of characters to be escaped on transmission.
+ */
+ {
+ __u32 temp_tbl[8];
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer (tty);
- return (ppp->line);
-}
+ if (copy_from_user(temp_tbl, (void *) param3,
+ sizeof (temp_tbl)))
+ break;
-/*
- * Local function to send the next portion of the buffer.
- *
- * Called by the tty driver's tty_wakeup function should it be entered
- * because the partial buffer was transmitted.
- *
- * Called by kick_tty to send the initial portion of the buffer.
- *
- * Completion processing of the buffer transmission is handled here.
- */
+ temp_tbl[1] = 0x00000000;
+ temp_tbl[2] &= ~0x40000000;
+ temp_tbl[3] |= 0x60000000;
-static void
-ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
- struct ppp_buffer *xbuf)
-{
- register int count, actual;
- unsigned long flags;
+ memcpy(ppp->xmit_async_map, temp_tbl,
+ sizeof (ppp->xmit_async_map));
+
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO
+ "ppp_tty_ioctl: set xasyncmap\n");
+ error = 0;
+ }
+ break;
+
+ case PPPIOCXFERUNIT:
+ /*
+ * Set up this PPP unit to be used next time this
+ * process sets a tty to PPP line discipline.
+ */
+ ppp->backup_tty = tty;
+ ppp->sc_xfer = current->pid;
+ error = 0;
+ break;
+
+ case TCGETS:
+ case TCGETA:
+ /*
+ * Allow users to read, but not set, the serial port parameters
+ */
+ error = n_tty_ioctl (tty, file, param2, param3);
+ break;
+
+ case FIONREAD:
+ /*
+ * Returns how many bytes are available for a read().
+ */
+ {
+ unsigned long flags;
+ struct sk_buff *skb;
+ int count = 0;
- CHECK_PPP_VOID();
- CHECK_BUF_MAGIC(xbuf);
-/*
- * Prevent re-entrancy by ensuring that this routine is called only once.
- */
- save_flags(flags);
- cli ();
- if (ppp->flags & SC_XMIT_BUSY) {
- restore_flags(flags);
- return;
- }
- ppp->flags |= SC_XMIT_BUSY;
- restore_flags(flags);
-/*
- * Send the next block of data to the modem
- */
- count = xbuf->count - xbuf->tail;
- actual = tty->driver.write (tty, 0,
- buf_base (xbuf) + xbuf->tail, count);
-/*
- * Terminate transmission of any block which may have an error.
- * This could occur should the carrier drop.
- */
- if (actual < 0) {
- ppp->stats.ppp_oerrors++;
- actual = count;
- } else
- ppp->bytes_sent += actual;
-/*
- * If the buffer has been transmitted then clear the indicators.
- */
- xbuf->tail += actual;
- if (actual == count) {
- xbuf = NULL;
- ppp->flags &= ~SC_XMIT_BUSY;
-/*
- * Complete the transmission on the current buffer.
- */
- xbuf = ppp->xbuf;
- if (xbuf != NULL) {
- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- xbuf->locked = 0;
- ppp->xbuf = NULL;
-/*
- * If the completed buffer came from the device write, then complete the
- * transmission block.
- */
- ppp2dev (ppp)->tbusy = 0;
- mark_bh (NET_BH);
-/*
- * Wake up the transmission queue for all completion events.
- */
- wake_up_interruptible (&ppp->write_wait);
-/*
- * Look at the priorities. Choose a daemon write over the device driver.
- */
save_flags(flags);
cli();
- xbuf = ppp->s1buf;
- ppp->s1buf = NULL;
- if (xbuf == NULL) {
- xbuf = ppp->s2buf;
- ppp->s2buf = NULL;
- }
-/*
- * If there is a pending buffer then transmit it now.
- */
- if (xbuf != NULL) {
- ppp->flags &= ~SC_XMIT_BUSY;
- ppp_kick_tty (ppp, xbuf);
- restore_flags(flags);
- return;
- }
+ skb = skb_peek(&ppp->rcv_q);
+ if (skb != 0)
+ count = skb->len;
restore_flags(flags);
+ if (put_user(count, (int *) param3))
+ break;
+ error = 0;
}
+ break;
+
+ default:
+ /*
+ * All other ioctl() events will come here.
+ */
+ error = ppp_ioctl(ppp, param2, param3);
+ break;
}
+ return error;
+}
+
/*
- * Clear the re-entry flag
+ * TTY callback.
+ *
+ * Process the poll() statement for the PPP device.
*/
- save_flags(flags); /* &=~ may not be atomic */
- cli ();
- ppp->flags &= ~SC_XMIT_BUSY;
- restore_flags(flags);
+
+static unsigned int
+ppp_tty_poll(struct tty_struct *tty, struct file *filp, poll_table * wait)
+{
+ struct ppp *ppp = tty2ppp(tty);
+ unsigned int mask = 0;
+
+ if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) {
+ CHECK_PPP(0);
+
+ poll_wait(filp, &ppp->read_wait, wait);
+
+ if (skb_peek(&ppp->rcv_q) != NULL)
+ mask |= POLLIN | POLLRDNORM;
+ if (tty->flags & (1 << TTY_OTHER_CLOSED)
+ || tty_hung_up_p(filp))
+ mask |= POLLHUP;
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ return mask;
}
/*
* This function is called by the tty driver when the transmit buffer has
* additional space. It is used by the ppp code to continue to transmit
* the current buffer should the buffer have been partially sent.
- *
- * In addition, it is used to send the first part of the buffer since the
- * logic and the inter-locking would be identical.
*/
-
static void
ppp_tty_wakeup (struct tty_struct *tty)
{
- struct ppp_buffer *xbuf;
struct ppp *ppp = tty2ppp (tty);
+ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
if (!ppp)
return;
CHECK_PPP_VOID();
-
- if (tty != ppp->tty) {
- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ if (tty != ppp->tty)
return;
- }
-/*
- * Ensure that there is a transmission pending. Clear the re-entry flag if
- * there is no pending buffer. Otherwise, send the buffer.
- */
- xbuf = ppp->xbuf;
- if (xbuf == NULL)
- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- else
- ppp_tty_wakeup_code (ppp, tty, xbuf);
+
+ if (ppp_tty_push(ppp))
+ ppp_output_wakeup(ppp);
}
/*
- * This function is called to transmit a buffer to the remote. The buffer
- * is placed on the pending queue if there is presently a buffer being
- * sent or it is transmitted with the aid of ppp_tty_wakeup.
+ * Send a packet to the peer over an async tty line.
+ * Returns -1 iff the packet could not be accepted at present,
+ * 0 if the packet was accepted but we can't accept another yet, or
+ * 1 if we can accept another packet immediately.
+ * If this procedure returns 0, ppp_output_wakeup will be called
+ * exactly once.
*/
-
-static void
-ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
+static int
+ppp_async_send(struct ppp *ppp, struct sk_buff *skb)
{
- unsigned long flags;
+ CHECK_PPP(0);
+
+ ppp_tty_push(ppp);
+
+ if (ppp->tpkt != NULL)
+ return -1;
+ ppp->tpkt = skb;
+ ppp->tpkt_pos = 0;
+
+ return ppp_tty_push(ppp);
+}
- CHECK_PPP_VOID();
- CHECK_BUF_MAGIC(xbuf);
-/*
- * Hold interrupts.
- */
- save_flags (flags);
- cli ();
/*
- * Control the flags which are best performed with the interrupts masked.
+ * Push as much data as possible out to the tty.
+ * Returns 1 if we finished encoding the current frame, 0 otherwise.
*/
- xbuf->locked = 1;
- xbuf->tail = 0;
+static int
+ppp_tty_push(struct ppp *ppp)
+{
+ int avail, sent, done = 0;
+ struct tty_struct *tty = ppp2tty(ppp);
+
+ CHECK_PPP(0);
+ if (ppp->tty_pushing)
+ return 0;
+ if (tty == NULL || tty->disc_data != (void *) ppp)
+ goto flush;
+ while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
+ ppp->tty_pushing = 1;
+ avail = ppp->olim - ppp->optr;
+ if (avail > 0) {
+ tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+ sent = tty->driver.write(tty, 0, ppp->optr, avail);
+ if (sent < 0)
+ goto flush; /* error, e.g. loss of CD */
+ ppp->stats.ppp_obytes += sent;
+ ppp->optr += sent;
+ if (sent < avail) {
+ ppp->tty_pushing = 0;
+ return done;
+ }
+ }
+ if (ppp->tpkt != 0)
+ done = ppp_async_encode(ppp);
+ ppp->tty_pushing = 0;
+ }
+ return done;
+
+flush:
+ ppp->tty_pushing = 1;
+ ppp->stats.ppp_oerrors++;
+ if (ppp->tpkt != 0) {
+ kfree_skb(ppp->tpkt);
+ ppp->tpkt = 0;
+ done = 1;
+ }
+ ppp->optr = ppp->olim;
+ ppp->tty_pushing = 0;
+ return done;
+}
+
/*
- * If the transmitter is busy then place the buffer on the appropriate
- * priority queue.
+ * Procedure to encode the data for async serial transmission.
+ * Does octet stuffing (escaping) and address/control
+ * and protocol compression.
+ * Assumes ppp->opkt != 0 on entry.
+ * Returns 1 if we finished the current frame, 0 otherwise.
*/
- if (ppp->xbuf != NULL) {
- if (xbuf->type == BUFFER_TYPE_TTY_WR)
- ppp->s1buf = xbuf;
- else
- ppp->s2buf = xbuf;
- restore_flags (flags);
- return;
+static int
+ppp_async_encode(struct ppp *ppp)
+{
+ int fcs, i, count, c;
+ unsigned char *buf, *buflim;
+ unsigned char *data;
+ int islcp;
+
+ CHECK_PPP(0);
+
+ buf = ppp->obuf;
+ ppp->olim = buf;
+ ppp->optr = buf;
+ i = ppp->tpkt_pos;
+ data = ppp->tpkt->data;
+ count = ppp->tpkt->len;
+ fcs = ppp->tfcs;
+
+ /*
+ * LCP packets with code values between 1 (configure-reqest)
+ * and 7 (code-reject) must be sent as though no options
+ * had been negotiated.
+ */
+ islcp = PPP_PROTOCOL(data) == PPP_LCP
+ && 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7;
+
+ if (i == 0) {
+ /*
+ * Start of a new packet - insert the leading FLAG
+ * character if necessary.
+ */
+ if (islcp || flag_time == 0
+ || jiffies - ppp->last_xmit >= flag_time)
+ *buf++ = PPP_FLAG;
+ /* only reset idle time for data packets */
+ if (PPP_PROTOCOL(data) < 0x8000)
+ ppp->last_xmit = jiffies;
+ fcs = PPP_INITFCS;
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += count;
+
+ /*
+ * Do address/control compression
+ */
+ if ((ppp->flags & SC_COMP_AC) != 0 && !islcp
+ && PPP_ADDRESS(data) == PPP_ALLSTATIONS
+ && PPP_CONTROL(data) == PPP_UI)
+ i += 2;
}
-/*
- * If the transmitter is not busy then this is the highest priority frame
- */
- ppp->flags &= ~SC_XMIT_BUSY;
- ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- ppp->xbuf = xbuf;
- restore_flags (flags);
-/*
- * Do the "tty wakeup_code" to actually send this buffer.
- */
- ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
-}
-/*************************************************************
- * TTY INPUT
- * The following functions handle input that arrives from
- * the TTY. It recognizes PPP frames and either hands them
- * to the network layer or queues them for delivery to a
- * user process reading this TTY.
- *************************************************************/
+ /*
+ * Once we put in the last byte, we need to put in the FCS
+ * and closing flag, so make sure there is at least 7 bytes
+ * of free space in the output buffer.
+ */
+ buflim = buf + OBUFSIZE - 6;
+ while (i < count && buf < buflim) {
+ c = data[i++];
+ if (i == 3 && c == 0 && (ppp->flags & SC_COMP_PROT))
+ continue; /* compress protocol field */
+ fcs = PPP_FCS(fcs, c);
+ if (in_xmap(ppp, c) || (islcp && c < 0x20)) {
+ *buf++ = PPP_ESCAPE;
+ c ^= 0x20;
+ }
+ *buf++ = c;
+ }
+
+ if (i == count) {
+ /*
+ * We have finished the packet. Add the FCS and flag.
+ */
+ fcs = ~fcs;
+ c = fcs & 0xff;
+ if (in_xmap(ppp, c) || (islcp && c < 0x20)) {
+ *buf++ = PPP_ESCAPE;
+ c ^= 0x20;
+ }
+ *buf++ = c;
+ c = (fcs >> 8) & 0xff;
+ if (in_xmap(ppp, c) || (islcp && c < 0x20)) {
+ *buf++ = PPP_ESCAPE;
+ c ^= 0x20;
+ }
+ *buf++ = c;
+ *buf++ = PPP_FLAG;
+ ppp->olim = buf;
+
+ kfree_skb(ppp->tpkt);
+ ppp->tpkt = 0;
+ return 1;
+ }
+
+ /*
+ * Remember where we are up to in this packet.
+ */
+ ppp->olim = buf;
+ ppp->tpkt_pos = i;
+ ppp->tfcs = fcs;
+ return 0;
+}
/*
* Callback function from tty driver. Return the amount of space left
* in the receiver's buffer to decide if remote transmitter is to be
* throttled.
*/
-
static int
ppp_tty_room (struct tty_struct *tty)
{
@@ -1057,8 +998,9 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
char *flags, int count)
{
register struct ppp *ppp = tty2ppp (tty);
- register struct ppp_buffer *buf = NULL;
- __u8 chr;
+ struct sk_buff *skb;
+ int chr, flg;
+ unsigned char *p;
if (ppp != 0)
CHECK_PPP_VOID();
@@ -1067,41 +1009,37 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
*/
if (ppp == 0 || tty != ppp->tty)
return;
-/*
- * Fetch the pointer to the buffer. Be careful about race conditions.
- */
- buf = ppp->rbuf;
- if (buf == NULL)
- return;
-/*
- * Verify the table pointer and ensure that the line is
- * still in PPP discipline.
- */
+ /*
+ * Verify the table pointer and ensure that the line is
+ * still in PPP discipline.
+ */
if (ppp->magic != PPP_MAGIC) {
if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "PPP: tty_receive called but couldn't find "
- "PPP struct.\n");
+ printk(KERN_DEBUG
+ "PPP: tty_receive called but couldn't find "
+ "PPP struct.\n");
return;
}
- CHECK_PPP_VOID ();
-/*
- * Print the buffer if desired
- */
+ /*
+ * Print the buffer if desired
+ */
if (ppp->flags & SC_LOG_RAWIN)
ppp_print_buffer ("receive buffer", data, count);
-/*
- * Collect the character and error condition for the character. Set the toss
- * flag for the first character error.
- */
+ ppp->stats.ppp_ibytes += count;
+ skb = ppp->rpkt;
while (count-- > 0) {
- ppp->bytes_rcvd++;
+ /*
+ * Collect the character and error condition for the character.
+ * Set the toss flag for the first character error.
+ */
chr = *data++;
if (flags) {
- if (*flags && ppp->toss == 0) {
- ppp->toss = *flags;
- switch (ppp->toss) {
+ flg = *flags++;
+ if (flg) {
+ if (ppp->toss == 0)
+ ppp->toss = flg;
+ switch (flg) {
case TTY_OVERRUN:
++ppp->estats.rx_fifo_errors;
break;
@@ -1110,15 +1048,16 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
++ppp->estats.rx_frame_errors;
break;
}
+ continue;
}
- ++flags;
}
-/*
- * Set the flags for d7 being 0/1 and parity being even/odd so that
- * the normal processing would have all flags set at the end of the
- * session. A missing flag bit indicates an error condition.
- */
+ /*
+ * Set the flags for d7 being 0/1 and parity being
+ * even/odd so that the normal processing would have
+ * all flags set at the end of the session. A
+ * missing flag bit indicates an error condition.
+ */
#ifdef CHECK_CHARACTERS
if (chr & 0x80)
@@ -1131,425 +1070,595 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
else
ppp->flags |= SC_RCV_EVNP;
#endif
-/*
- * Branch on the character.
- */
- switch (chr) {
-/*
- * FLAG. This is the end of the block. If the block terminated by ESC FLAG,
- * then the block is to be ignored. In addition, characters before the very
- * first FLAG are also tossed by this procedure.
- */
- case PPP_FLAG: /* PPP_FLAG: end of frame */
- ppp->stats.ppp_ibytes += ppp->rbuf->count;
+
+ if (chr == PPP_FLAG) {
+ /*
+ * FLAG. This is the end of the block. If the block
+ * ends with ESC FLAG, then the block is to be ignored.
+ */
if (ppp->escape)
ppp->toss |= 0x80;
-/*
- * Process frames which are not to be ignored. If the processing failed,
- * then clean up the VJ tables.
- */
- if (ppp_doframe (ppp) == 0) {
- ++ppp->stats.ppp_ierrors;
- slhc_toss (ppp->slcomp);
- }
-/*
- * Reset all indicators for the new frame to follow.
- */
- buf->count = 0;
- buf->fcs = PPP_INITFCS;
- ppp->escape = 0;
- ppp->toss = 0;
- break;
-/*
- * All other characters in the data come here. If the character is in the
- * receive mask then ignore the character.
- */
- default:
- /* If we're tossing, look no further. */
- if (ppp->toss != 0)
- break;
-
- /* If this is a control char to be ignored, do so */
- if (in_rmap (ppp, chr))
- break;
-
/*
- * Modify the next character if preceded by escape.
- * The escape character (0x7d) could be an escaped
- * 0x5d, if it follows an escape :-)
+ * Process the frame if it was received correctly.
+ * If there was an error, let the VJ decompressor know.
+ * There are 4 cases here:
+ * skb != NULL, toss != 0: error in frame
+ * skb != NULL, toss == 0: frame ok
+ * skb == NULL, toss != 0: very first frame,
+ * error on 1st char, or alloc_skb failed
+ * skb == NULL, toss == 0: empty frame (~~)
*/
- if (ppp->escape) {
- chr ^= PPP_TRANS;
- ppp->escape = 0;
- } else if (chr == PPP_ESCAPE) {
- ppp->escape = PPP_TRANS;
- break;
+ if (ppp->toss || !ppp_receive_frame(ppp, skb)) {
+ if (ppp->toss && (ppp->flags & SC_DEBUG))
+ printk(KERN_DEBUG
+ "ppp: tossing frame (%x)\n",
+ ppp->toss);
+ if (skb != NULL)
+ kfree_skb(skb);
+ if (!(ppp->toss == 0xE0 || ppp->toss == 0x80))
+ ++ppp->stats.ppp_ierrors;
+ ppp_receive_error(ppp);
}
-
/*
- * Decompress A/C and protocol compression here.
+ * Reset for the next frame.
*/
- if (buf->count == 0 && chr != PPP_ALLSTATIONS) {
- buf_base(buf)[0] = PPP_ALLSTATIONS;
- buf_base(buf)[1] = PPP_UI;
- buf->count = 2;
- }
- if (buf->count == 2 && (chr & 1) != 0) {
- buf_base(buf)[2] = 0;
- buf->count = 3;
- }
-/*
- * If the count sent is within reason then store the character, bump the
- * count, and update the FCS for the character.
- */
- if (buf->count < buf->size) {
- buf_base (buf)[buf->count++] = chr;
- buf->fcs = PPP_FCS (buf->fcs, chr);
- break;
- }
-/*
- * The peer sent too much data. Set the flags to discard the current frame
- * and wait for the re-synchronization FLAG to be sent.
- */
- ++ppp->estats.rx_length_errors;
- ppp->toss |= 0xC0;
- break;
+ skb = NULL;
+ ppp->rfcs = PPP_INITFCS;
+ ppp->escape = 0;
+ ppp->toss = 0;
+ continue;
}
- }
-}
-
-/* on entry, a received frame is in ppp->rbuf.bufr
- check it and dispose as appropriate */
-static int
-ppp_doframe (struct ppp *ppp)
-{
- __u8 *data = buf_base (ppp->rbuf);
- int count = ppp->rbuf->count;
- int proto;
- int new_count;
- __u8 *new_data;
+ /* If we're tossing, look no further. */
+ if (ppp->toss != 0)
+ continue;
- CHECK_PPP(0);
- CHECK_BUF_MAGIC(ppp->rbuf);
+ /* If this is a control char to be ignored, do so */
+ if (in_rmap(ppp, chr))
+ continue;
-/*
- * If there is a pending error from the receiver then log it and discard
- * the damaged frame.
- */
- if (ppp->toss) {
- if ((ppp->flags & SC_DEBUG) && count > 0)
- printk (KERN_DEBUG
- "ppp_toss: tossing frame, reason = %x\n",
- ppp->toss);
- return 0;
- }
-/*
- * An empty frame is ignored. This occurs if the FLAG sequence precedes and
- * follows each frame.
- */
- if (count == 0)
- return 1;
-/*
- * Generate an error if the frame is too small.
- */
- if (count < PPP_HDRLEN + 2) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp: got runt ppp frame, %d chars\n", count);
- ++ppp->estats.rx_length_errors;
- return 0;
- }
-/*
- * Verify the CRC of the frame and discard the CRC characters from the
- * end of the buffer.
- */
- if (ppp->rbuf->fcs != PPP_GOODFCS) {
- if (ppp->flags & SC_DEBUG) {
- printk (KERN_DEBUG
- "ppp: frame with bad fcs, length = %d\n",
- count);
- ppp_print_buffer("bad frame", data, count);
+ /*
+ * Modify the next character if preceded by escape.
+ * The escape character (0x7d) could be an escaped
+ * 0x5d, if it follows an escape :-)
+ */
+ if (ppp->escape) {
+ chr ^= PPP_TRANS;
+ ppp->escape = 0;
+ } else if (chr == PPP_ESCAPE) {
+ ppp->escape = PPP_TRANS;
+ continue;
}
- ++ppp->estats.rx_crc_errors;
- return 0;
- }
- count -= 2; /* ignore the fcs characters */
-/*
- * Obtain the protocol from the frame
- */
- proto = PPP_PROTOCOL(data);
-/*
- * Process the active decompressor.
- */
- if ((ppp->sc_rc_state != (void *) 0) &&
- (ppp->flags & SC_DECOMP_RUN) &&
- ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
- if (proto == PPP_COMP) {
-/*
- * If the frame is compressed then decompress it.
- */
- new_data = kmalloc (ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
- if (new_data == NULL) {
- printk (KERN_ERR "ppp_doframe: no memory\n");
- new_count = DECOMP_ERROR;
- } else {
- new_count = (*ppp->sc_rcomp->decompress)
- (ppp->sc_rc_state, data, count,
- new_data, ppp->mru + PPP_HDRLEN);
- }
- switch (new_count) {
- default:
- ppp_doframe_lower (ppp, new_data, new_count);
- kfree (new_data);
- return 1;
-
- case DECOMP_ERROR:
- ppp->flags |= SC_DC_ERROR;
- break;
- case DECOMP_FATALERROR:
- ppp->flags |= SC_DC_FERROR;
- printk(KERN_ERR "ppp: fatal decomp error\n");
- break;
+ /*
+ * Allocate an skbuff on the first character received.
+ * The 128 is room for VJ header expansion and FCS.
+ */
+ if (skb == NULL) {
+ skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN);
+ if (skb == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "couldn't "
+ "alloc skb for recv\n");
+ ppp->toss = 1;
+ continue;
}
-/*
- * Log the error condition and discard the frame.
- */
- if (new_data != 0)
- kfree (new_data);
- slhc_toss (ppp->slcomp);
- ++ppp->stats.ppp_ierrors;
- } else {
-/*
- * The frame is not special. Pass it through the compressor without
- * actually compressing the data
- */
- (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
- data, count);
}
- } else if (proto == PPP_COMP && (ppp->flags & SC_DEBUG)) {
- printk(KERN_DEBUG "ppp: frame not decompressed: "
- "flags=%x, count=%d, sc_rc_state=%p\n",
- ppp->flags, count, ppp->sc_rc_state);
+
+ /*
+ * Decompress A/C and protocol compression here.
+ */
+ if (skb->len == 0 && chr != PPP_ALLSTATIONS) {
+ p = skb_put(skb, 2);
+ p[0] = PPP_ALLSTATIONS;
+ p[1] = PPP_UI;
+ }
+ if (skb->len == 2 && (chr & 1) != 0) {
+ p = skb_put(skb, 1);
+ p[0] = 0;
+ }
+
+ /*
+ * Check if we've overflowed the MRU
+ */
+ if (skb->len >= ppp->mru + PPP_HDRLEN + 2
+ || skb_tailroom(skb) <= 0) {
+ ++ppp->estats.rx_length_errors;
+ ppp->toss = 0xC0;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "rcv frame too long: "
+ "len=%d mru=%d hroom=%d troom=%d\n",
+ skb->len, ppp->mru, skb_headroom(skb),
+ skb_tailroom(skb));
+ continue;
+ }
+
+ /*
+ * Store the character and update the FCS.
+ */
+ p = skb_put(skb, 1);
+ *p = chr;
+ ppp->rfcs = PPP_FCS(ppp->rfcs, chr);
}
-/*
- * Process the uncompressed frame.
- */
- ppp_doframe_lower (ppp, data, count);
- return 1;
+ ppp->rpkt = skb;
}
-static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
-{
- __u16 proto = PPP_PROTOCOL (data);
- ppp_proto_type *proto_ptr;
+/*************************************************************
+ * PPP NETWORK INTERFACE SUPPORT
+ * The following code implements the PPP network
+ * interface device and handles those parts of
+ * the PPP processing which are independent of the
+ * type of hardware link being used, including
+ * VJ and packet compression.
+ *************************************************************/
- CHECK_PPP_VOID();
/*
- * Ignore empty frames
- */
- if (count <= PPP_HDRLEN)
- return;
-/*
- * Count the frame and print it
- */
- ++ppp->stats.ppp_ipackets;
- if (ppp->flags & SC_LOG_INPKT)
- ppp_print_buffer ("receive frame", data, count);
-/*
- * Find the procedure to handle this protocol. The last one is marked
- * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
+ * Network device driver callback routines
*/
- proto_ptr = proto_list;
- while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
- ++proto_ptr;
+
+static int ppp_init_dev(struct device *dev);
+static int ppp_dev_open(struct device *);
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static int ppp_dev_close(struct device *);
+static int ppp_dev_xmit(struct sk_buff *, struct device *);
+static struct net_device_stats *ppp_dev_stats (struct device *);
+
/*
- * Update the appropriate statistic counter.
+ * Information for the protocol decoder
*/
- if ((*proto_ptr->func) (ppp, proto,
- &data[PPP_HDRLEN],
- count - PPP_HDRLEN))
- ppp->stats.ppp_ioctects += count;
- else
- ++ppp->stats.ppp_discards;
-}
+
+typedef int (*pfn_proto) (struct ppp *, struct sk_buff *);
+
+typedef struct ppp_proto_struct {
+ int proto;
+ pfn_proto func;
+} ppp_proto_type;
+
+static int rcv_proto_ip (struct ppp *, struct sk_buff *);
+static int rcv_proto_ipx (struct ppp *, struct sk_buff *);
+static int rcv_proto_at (struct ppp *, struct sk_buff *);
+static int rcv_proto_vjc_comp (struct ppp *, struct sk_buff *);
+static int rcv_proto_vjc_uncomp (struct ppp *, struct sk_buff *);
+static int rcv_proto_ccp (struct ppp *, struct sk_buff *);
+static int rcv_proto_unknown (struct ppp *, struct sk_buff *);
+
+static
+ppp_proto_type proto_list[] = {
+ { PPP_IP, rcv_proto_ip },
+ { PPP_IPX, rcv_proto_ipx },
+ { PPP_AT, rcv_proto_at },
+ { PPP_VJC_COMP, rcv_proto_vjc_comp },
+ { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
+ { PPP_CCP, rcv_proto_ccp },
+ { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
+};
/*
- * Put the input frame into the networking system for the indicated protocol
+ * Called when the PPP network interface device is actually created.
*/
-
static int
-ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
+ppp_init_dev (struct device *dev)
{
- sk_buff *skb = dev_alloc_skb (count);
-/*
- * Generate a skb buffer for the new frame.
- */
- if (skb == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_do_ip: packet dropped on %s (no memory)!\n",
- ppp2dev (ppp)->name);
- return 0;
- }
-/*
- * Move the received data from the input buffer to the skb buffer.
- */
- skb->dev = ppp2dev (ppp); /* We are the device */
- skb->protocol = proto;
- skb->mac.raw = skb_data(skb);
- memcpy (skb_put(skb,count), data, count); /* move data */
-/*
- * Tag the frame and kick it to the proper receive routine
- */
- ppp->last_recv = jiffies;
- netif_rx (skb);
- return 1;
+ dev->hard_header_len = PPP_HDRLEN;
+
+ /* device INFO */
+ dev->mtu = PPP_MTU;
+ dev->hard_start_xmit = ppp_dev_xmit;
+ dev->open = ppp_dev_open;
+ dev->stop = ppp_dev_close;
+ dev->get_stats = ppp_dev_stats;
+ dev->do_ioctl = ppp_dev_ioctl;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 10;
+ dev->type = ARPHRD_PPP;
+
+ dev_init_buffers(dev);
+
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+
+ return 0;
}
/*
- * Process the receipt of an IP frame
+ * Callback from the network layer when the device goes up.
*/
static int
-rcv_proto_ip (struct ppp *ppp, __u16 proto, __u8 * data, int count)
+ppp_dev_open (struct device *dev)
{
- CHECK_PPP(0);
- if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0))
- if (ppp->sc_npmode[NP_IP] == NPMODE_PASS)
- return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
+ struct ppp *ppp = dev2ppp(dev);
+
+ if (!ppp->inuse || ppp2tty(ppp) == NULL) {
+ printk(KERN_ERR "ppp: %s not active\n", dev->name);
+ return -ENXIO;
+ }
+
+ MOD_INC_USE_COUNT;
+
return 0;
}
/*
- * Process the receipt of an IPX frame
+ * Callback from the network layer when the ppp device goes down.
*/
static int
-rcv_proto_ipx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
+ppp_dev_close (struct device *dev)
{
- CHECK_PPP(0);
- if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0))
- return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
+ struct ppp *ppp = dev2ppp (dev);
+
+ CHECK_PPP_MAGIC(ppp);
+
+ MOD_DEC_USE_COUNT;
+
return 0;
}
+static inline void
+get_vj_stats(struct vjstat *vj, struct slcompress *slc)
+{
+ vj->vjs_packets = slc->sls_o_compressed + slc->sls_o_uncompressed;
+ vj->vjs_compressed = slc->sls_o_compressed;
+ vj->vjs_searches = slc->sls_o_searches;
+ vj->vjs_misses = slc->sls_o_misses;
+ vj->vjs_errorin = slc->sls_i_error;
+ vj->vjs_tossed = slc->sls_i_tossed;
+ vj->vjs_uncompressedin = slc->sls_i_uncompressed;
+ vj->vjs_compressedin = slc->sls_i_compressed;
+}
+
/*
- * Process the receipt of an VJ Compressed frame
+ * Callback from the network layer to process the sockioctl functions.
*/
-
static int
-rcv_proto_vjc_comp (struct ppp *ppp, __u16 proto,
- __u8 *data, int count)
+ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
{
- CHECK_PPP(0);
- if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
- int new_count = slhc_uncompress (ppp->slcomp, data, count);
- if (new_count >= 0) {
- return rcv_proto_ip (ppp, PPP_IP, data, new_count);
- }
- if (ppp->flags & SC_DEBUG)
- printk (KERN_NOTICE
- "ppp: error in VJ decompression\n");
+ struct ppp *ppp = dev2ppp(dev);
+ int nb;
+ union {
+ struct ppp_stats stats;
+ struct ppp_comp_stats cstats;
+ char vers[32];
+ } u;
+
+ CHECK_PPP_MAGIC(ppp);
+
+ memset(&u, 0, sizeof(u));
+ switch (cmd) {
+ case SIOCGPPPSTATS:
+ u.stats.p = ppp->stats;
+ if (ppp->slcomp != NULL)
+ get_vj_stats(&u.stats.vj, ppp->slcomp);
+ nb = sizeof(u.stats);
+ break;
+
+ case SIOCGPPPCSTATS:
+ if (ppp->sc_xc_state != NULL)
+ (*ppp->sc_xcomp->comp_stat)
+ (ppp->sc_xc_state, &u.cstats.c);
+ if (ppp->sc_rc_state != NULL)
+ (*ppp->sc_rcomp->decomp_stat)
+ (ppp->sc_rc_state, &u.cstats.d);
+ nb = sizeof(u.cstats);
+ break;
+
+ case SIOCGPPPVER:
+ strcpy(u.vers, szVersion);
+ nb = strlen(u.vers) + 1;
+ break;
+
+ default:
+ return -EINVAL;
}
+
+ if (copy_to_user((void *) ifr->ifr_ifru.ifru_data, &u, nb))
+ return -EFAULT;
return 0;
}
/*
- * Process the receipt of an VJ Un-compressed frame
+ * Process the generic PPP ioctls, i.e. those which are not specific
+ * to any particular type of hardware link.
*/
-
static int
-rcv_proto_vjc_uncomp (struct ppp *ppp, __u16 proto,
- __u8 *data, int count)
+ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3)
{
- CHECK_PPP(0);
- if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
- if (slhc_remember (ppp->slcomp, data, count) > 0) {
- return rcv_proto_ip (ppp, PPP_IP, data, count);
+ register int temp_i = 0, oldflags;
+ int error = -EFAULT;
+ unsigned long flags;
+ struct ppp_idle cur_ddinfo;
+ struct npioctl npi;
+
+ CHECK_PPP(-ENXIO);
+
+ /*
+ * The user must have an euid of root to do these requests.
+ */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ switch (param2) {
+ case PPPIOCSMRU:
+ /*
+ * Set the MRU value
+ */
+ if (get_user(temp_i, (int *) param3))
+ break;
+ if (temp_i < PPP_MRU)
+ temp_i = PPP_MRU;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO
+ "ppp_ioctl: set mru to %x\n", temp_i);
+ error = 0;
+ break;
+
+ case PPPIOCGFLAGS:
+ /*
+ * Fetch the current flags
+ */
+ temp_i = ppp->flags & SC_MASK;
+#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
+ temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
+ SC_RCV_ODDP | SC_RCV_EVNP;
+#endif
+ if (put_user(temp_i, (int *) param3))
+ break;
+ error = 0;
+ break;
+
+ case PPPIOCSFLAGS:
+ /*
+ * Set the flags for the various options
+ */
+ if (get_user(temp_i, (int *) param3))
+ break;
+
+ if (ppp->flags & ~temp_i & SC_CCP_OPEN)
+ ppp_ccp_closed(ppp);
+
+ save_flags(flags);
+ cli();
+ oldflags = ppp->flags;
+ temp_i = (temp_i & SC_MASK) | (oldflags & ~SC_MASK);
+ ppp->flags = temp_i;
+ restore_flags(flags);
+
+ if ((oldflags | temp_i) & SC_DEBUG)
+ printk(KERN_INFO
+ "ppp_ioctl: set flags to %x\n", temp_i);
+ error = 0;
+ break;
+
+ case PPPIOCSCOMPRESS:
+ /*
+ * Set the compression mode
+ */
+ error = ppp_set_compression
+ (ppp, (struct ppp_option_data *) param3);
+ break;
+
+ case PPPIOCGUNIT:
+ /*
+ * Obtain the unit number for this device.
+ */
+ if (put_user(ppp->line, (int *) param3))
+ break;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO
+ "ppp_ioctl: get unit: %d\n", ppp->line);
+ error = 0;
+ break;
+
+ case PPPIOCSDEBUG:
+ /*
+ * Set the debug level
+ */
+ if (get_user(temp_i, (int *) param3))
+ break;
+ temp_i = (temp_i & 0x1F) << 16;
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk(KERN_INFO
+ "ppp_ioctl: set dbg flags to %x\n", temp_i);
+
+ save_flags(flags);
+ cli();
+ ppp->flags = (ppp->flags & ~0x1F0000) | temp_i;
+ restore_flags(flags);
+ error = 0;
+ break;
+
+ case PPPIOCGDEBUG:
+ /*
+ * Get the debug level
+ */
+ temp_i = (ppp->flags >> 16) & 0x1F;
+ if (put_user(temp_i, (int *) param3))
+ break;
+ error = 0;
+ break;
+
+ case PPPIOCGIDLE:
+ /*
+ * Get the times since the last send/receive frame operation
+ */
+ /* change absolute times to relative times. */
+ cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user((void *) param3, &cur_ddinfo,
+ sizeof (cur_ddinfo)))
+ break;
+ error = 0;
+ break;
+
+ case PPPIOCSMAXCID:
+ /*
+ * Set the maximum VJ header compression slot number.
+ */
+ if (get_user(temp_i, (int *) param3))
+ break;
+ error = -EINVAL;
+ if (temp_i < 2 || temp_i > 255)
+ break;
+ ++temp_i;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO "ppp_ioctl: set maxcid to %d\n",
+ temp_i);
+ if (ppp->slcomp != NULL)
+ slhc_free(ppp->slcomp);
+ ppp->slcomp = slhc_init(16, temp_i);
+
+ error = -ENOMEM;
+ if (ppp->slcomp == NULL) {
+ printk(KERN_ERR "ppp: no memory for VJ compression\n");
+ break;
+ }
+ error = 0;
+ break;
+
+ case PPPIOCGNPMODE:
+ case PPPIOCSNPMODE:
+ if (copy_from_user(&npi, (void *) param3, sizeof(npi)))
+ break;
+
+ switch (npi.protocol) {
+ case PPP_IP:
+ npi.protocol = NP_IP;
+ break;
+ case PPP_IPX:
+ npi.protocol = NP_IPX;
+ break;
+ case PPP_AT:
+ npi.protocol = NP_AT;
+ break;
+ default:
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "pppioc[gs]npmode: "
+ "invalid proto %d\n", npi.protocol);
+ error = -EINVAL;
+ goto out;
+ }
+
+ if (param2 == PPPIOCGNPMODE) {
+ npi.mode = ppp->sc_npmode[npi.protocol];
+ if (copy_to_user((void *) param3, &npi, sizeof(npi)))
+ break;
+ } else {
+ ppp->sc_npmode[npi.protocol] = npi.mode;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "ppp: set np %d to %d\n",
+ npi.protocol, npi.mode);
+ mark_bh(NET_BH);
}
+ error = 0;
+ break;
+
+ default:
+ /*
+ * All other ioctl() events will come here.
+ */
if (ppp->flags & SC_DEBUG)
- printk (KERN_NOTICE
- "ppp: error in VJ memorizing\n");
+ printk(KERN_ERR
+ "ppp_ioctl: invalid ioctl: %x, addr %lx\n",
+ param2, param3);
+
+ error = -ENOIOCTLCMD;
+ break;
}
- return 0;
+out:
+ return error;
}
/*
- * Receive all unclassified protocols.
+ * Process the set-compression ioctl.
*/
-
static int
-rcv_proto_unknown (struct ppp *ppp, __u16 proto,
- __u8 *data, int len)
+ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
{
- int totlen;
- register int current_idx;
-
-#define PUTC(c) \
-{ \
- buf_base (ppp->ubuf) [current_idx++] = (__u8) (c); \
- current_idx &= ppp->ubuf->size; \
- if (current_idx == ppp->ubuf->tail) \
- goto failure; \
-}
+ struct compressor *cp;
+ int error, nb;
+ unsigned long flags;
+ __u8 *ptr;
+ __u8 ccp_option[CCP_MAX_OPTION_LENGTH];
+ struct ppp_option_data data;
- CHECK_PPP(0);
-/*
- * The total length includes the protocol data.
- * Lock the user information buffer.
- */
- if (test_and_set_bit (0, &ppp->ubuf->locked)) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp: rcv_proto_unknown: can't get lock\n");
- } else {
- CHECK_BUF_MAGIC(ppp->ubuf);
- current_idx = ppp->ubuf->head;
-/*
- * Insert the buffer length (not counted), the protocol, and the data
- */
- totlen = len + 2;
- PUTC (totlen >> 8);
- PUTC (totlen);
+ /*
+ * Fetch the compression parameters
+ */
+ error = -EFAULT;
+ if (copy_from_user(&data, odp, sizeof (data)))
+ goto out;
- PUTC (proto >> 8);
- PUTC (proto);
+ nb = data.length;
+ ptr = data.ptr;
+ if ((unsigned) nb >= CCP_MAX_OPTION_LENGTH)
+ nb = CCP_MAX_OPTION_LENGTH;
- totlen -= 2;
- while (totlen-- > 0) {
- PUTC (*data++);
- }
-#undef PUTC
-/*
- * The frame is complete. Update the head pointer and wakeup the pppd
- * process.
- */
- ppp->ubuf->head = current_idx;
+ if (copy_from_user(ccp_option, ptr, nb))
+ goto out;
- clear_bit (0, &ppp->ubuf->locked);
- wake_up_interruptible (&ppp->read_wait);
- if (ppp->tty->fasync != NULL)
- kill_fasync (ppp->tty->fasync, SIGIO);
+ error = -EINVAL;
+ if (ccp_option[1] < 2) /* preliminary check on the length byte */
+ goto out;
- return 1;
-/*
- * The buffer is full. Unlock the header
- */
-failure:
- clear_bit (0, &ppp->ubuf->locked);
+ save_flags(flags);
+ cli();
+ ppp->flags &= ~(data.transmit? SC_COMP_RUN: SC_DECOMP_RUN);
+ restore_flags(flags);
+
+ cp = find_compressor (ccp_option[0]);
+#ifdef CONFIG_KMOD
+ if (cp == NULL) {
+ char modname[32];
+ sprintf(modname, "ppp-compress-%d", ccp_option[0]);
+ request_module(modname);
+ cp = find_compressor(ccp_option[0]);
+ }
+#endif /* CONFIG_KMOD */
+
+ if (cp == NULL) {
if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp: rcv_proto_unknown: buffer overflow\n");
+ printk(KERN_DEBUG
+ "%s: no compressor for [%x %x %x], %x\n",
+ ppp->name, ccp_option[0], ccp_option[1],
+ ccp_option[2], nb);
+ goto out; /* compressor not loaded */
}
-/*
- * Discard the frame. There are no takers for this protocol.
- */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp: rcv_proto_unknown: dropping packet\n");
- return 0;
+
+ /*
+ * Found a handler for the protocol - try to allocate
+ * a compressor or decompressor.
+ */
+ error = 0;
+ if (data.transmit) {
+ if (ppp->sc_xc_state != NULL)
+ (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+ ppp->sc_xc_state = NULL;
+
+ ppp->sc_xcomp = cp;
+ ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+ if (ppp->sc_xc_state == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: comp_alloc failed\n",
+ ppp->name);
+ error = -ENOBUFS;
+ }
+ } else {
+ if (ppp->sc_rc_state != NULL)
+ (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
+ ppp->sc_rc_state = NULL;
+
+ ppp->sc_rcomp = cp;
+ ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
+ if (ppp->sc_rc_state == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: decomp_alloc failed\n",
+ ppp->name);
+ error = -ENOBUFS;
+ }
+ }
+out:
+ return error;
}
/*
@@ -1560,7 +1669,7 @@ failure:
* immediate or the compressors will become confused on the peer.
*/
-static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
+static void ppp_proto_ccp(struct ppp *ppp, __u8 *dp, int len, int rcvd)
{
int slen = CCP_LENGTH(dp);
__u8 *opt = dp + CCP_HDRLEN;
@@ -1570,14 +1679,17 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
if (slen > len)
return;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "ppp_proto_ccp rcvd=%d code=%x flags=%x\n",
+ rcvd, CCP_CODE(dp), ppp->flags);
save_flags(flags);
switch (CCP_CODE(dp)) {
case CCP_CONFREQ:
case CCP_TERMREQ:
case CCP_TERMACK:
-/*
- * CCP must be going down - disable compression
- */
+ /*
+ * CCP must be going down - disable compression
+ */
if (ppp->flags & SC_CCP_UP) {
cli();
ppp->flags &= ~(SC_CCP_UP |
@@ -1595,20 +1707,17 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
break;
if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
break;
-/*
- * we're agreeing to send compressed packets.
- */
if (!rcvd) {
+ /*
+ * we're agreeing to send compressed packets.
+ */
if (ppp->sc_xc_state == NULL)
break;
if ((*ppp->sc_xcomp->comp_init)
(ppp->sc_xc_state,
- opt,
- opt_len,
- ppp2dev (ppp)->base_addr,
- 0,
- ppp->flags & SC_DEBUG)) {
+ opt, opt_len,
+ ppp->line, 0, ppp->flags & SC_DEBUG)) {
if (ppp->flags & SC_DEBUG)
printk(KERN_DEBUG "%s: comp running\n",
ppp->name);
@@ -1617,20 +1726,17 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
}
break;
}
-/*
- * peer is agreeing to send compressed packets.
- */
+
+ /*
+ * peer is agreeing to send compressed packets.
+ */
if (ppp->sc_rc_state == NULL)
break;
if ((*ppp->sc_rcomp->decomp_init)
(ppp->sc_rc_state,
- opt,
- opt_len,
- ppp2dev (ppp)->base_addr,
- 0,
- ppp->mru,
- ppp->flags & SC_DEBUG)) {
+ opt, opt_len,
+ ppp->line, 0, ppp->mru, ppp->flags & SC_DEBUG)) {
if (ppp->flags & SC_DEBUG)
printk(KERN_DEBUG "%s: decomp running\n",
ppp->name);
@@ -1639,10 +1745,12 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
}
break;
-/*
- * CCP Reset-ack resets compressors and decompressors as it passes through.
- */
+
case CCP_RESETACK:
+ /*
+ * CCP Reset-ack resets compressors and decompressors
+ * as it passes through.
+ */
if ((ppp->flags & SC_CCP_UP) == 0)
break;
@@ -1665,1127 +1773,628 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
}
break;
}
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "ppp_proto_ccp: %s code %d, flags=%x\n",
- (rcvd? "rcvd": "sent"), CCP_CODE(dp), ppp->flags);
restore_flags(flags);
}
-static int
-rcv_proto_ccp (struct ppp *ppp, __u16 proto, __u8 *dp, int len)
-{
- CHECK_PPP(0);
- ppp_proto_ccp (ppp, dp, len, 1);
- return rcv_proto_unknown (ppp, proto, dp, len);
-}
-
/*
- * Handle a LQR packet.
+ * CCP is down; free (de)compressor state if necessary.
*/
-static int
-rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
+static void
+ppp_ccp_closed(struct ppp *ppp)
{
- return rcv_proto_unknown (ppp, proto, data, len);
-}
-
-/*************************************************************
- * LINE DISCIPLINE SUPPORT
- * The following functions form support user programs
- * which read and write data on a TTY with the PPP line
- * discipline. Reading is done from a circular queue,
- * filled by the lower TTY levels.
- *************************************************************/
+ unsigned long flags;
-/* read a PPP frame from the us_rbuff circular buffer,
- waiting if necessary
-*/
+ save_flags(flags);
+ cli();
+ ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
+ restore_flags(flags);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: ccp closed\n", ppp->name);
+ if (ppp->sc_xc_state) {
+ (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
+ ppp->sc_xc_state = NULL;
+ }
-static ssize_t
-ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
-{
- struct ppp *ppp = tty2ppp (tty);
- __u8 c;
- int error;
- ssize_t len, ret;
-
-#define GETC(c) \
-{ \
- c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \
- ppp->ubuf->tail &= ppp->ubuf->size; \
+ if (ppp->sc_rc_state) {
+ (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
+ ppp->sc_rc_state = NULL;
+ }
}
-/*
- * Validate the pointers
- */
- if (!ppp)
- return -EIO;
-
- /* if (ppp->magic != PPP_MAGIC)
- return -EIO; */
-
- CHECK_PPP (-ENXIO);
-
-/*
- * Before we attempt to write the frame to the user, ensure that the
- * user has access to the pages for the total buffer length.
- */
- error = verify_area (VERIFY_WRITE, buf, nr);
- if (error != 0)
- return (error);
+/*************************************************************
+ * RECEIVE-SIDE ROUTINES
+ *************************************************************/
/*
- * Acquire the read lock.
+ * On entry, a received frame is in skb.
+ * Check it and dispose as appropriate.
*/
- for (;;) {
- ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
- || tty != ppp->tty)
- return 0;
+static int
+ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
+{
+ __u8 *data;
+ int count;
+ int proto;
+ int new_count;
+ struct sk_buff *new_skb;
+ ppp_proto_type *proto_ptr;
- if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
-#if 0
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(ubuf)\n");
-#endif
- current->timeout = 0;
- current->state = TASK_INTERRUPTIBLE;
- schedule ();
+ /*
+ * An empty frame is ignored. This occurs if the FLAG sequence
+ * precedes and follows each frame.
+ */
+ if (skb == NULL)
+ return 1;
+ if (skb->len == 0) {
+ kfree_skb(skb);
+ return 1;
+ }
+ data = skb->data;
+ count = skb->len;
- if (signal_pending(current))
- return -EINTR;
- continue;
- }
+ /*
+ * Generate an error if the frame is too small.
+ */
+ if (count < PPP_HDRLEN + 2) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG
+ "ppp: got runt ppp frame, %d chars\n", count);
+ ++ppp->estats.rx_length_errors;
+ return 0;
+ }
-/*
- * Fetch the length of the buffer from the first two bytes.
- */
- if (ppp->ubuf->head == ppp->ubuf->tail)
- len = 0;
- else {
- GETC (c);
- len = c << 8;
- GETC (c);
- len += c;
- if (len)
- break;
+ /*
+ * Verify the FCS of the frame and discard the FCS characters
+ * from the end of the buffer.
+ */
+ if (ppp->rfcs != PPP_GOODFCS) {
+ if (ppp->flags & SC_DEBUG) {
+ printk(KERN_DEBUG
+ "ppp: frame with bad fcs, length = %d\n",
+ count);
+ ppp_print_buffer("bad frame", data, count);
}
-
-/*
- * If there is no length then wait for the data to arrive.
- */
- /* no data */
- clear_bit (0, &ppp->ubuf->locked);
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- current->timeout = 0;
-#if 0
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(read_wait)\n");
-#endif
- interruptible_sleep_on (&ppp->read_wait);
- if (signal_pending(current))
- return -EINTR;
+ ++ppp->estats.rx_crc_errors;
+ return 0;
}
+ count -= 2; /* ignore the fcs characters */
+ skb_trim(skb, count);
-/*
- * Ensure that the frame will fit within the caller's buffer. If not, then
- * discard the frame from the input buffer.
- */
- if (len + 2 > nr) {
- /* Can't copy it, update us_rbuff_head */
+ /*
+ * Process the active decompressor.
+ */
+ if (ppp->sc_rc_state != NULL &&
+ (ppp->flags & SC_DECOMP_RUN) &&
+ ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
+ if (PPP_PROTOCOL(data) == PPP_COMP) {
+ /*
+ * If the frame is compressed then decompress it.
+ */
+ new_skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN);
+ if (new_skb == NULL) {
+ printk(KERN_ERR "ppp_recv_frame: no memory\n");
+ new_count = DECOMP_ERROR;
+ } else {
+ new_count = (*ppp->sc_rcomp->decompress)
+ (ppp->sc_rc_state, data, count,
+ new_skb->data, ppp->mru + PPP_HDRLEN);
+ }
+ if (new_count > 0) {
+ /* Frame was decompressed OK */
+ kfree_skb(skb);
+ skb = new_skb;
+ count = new_count;
+ data = skb_put(skb, count);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp: read of %lu bytes too small for %ld "
- "frame\n", (unsigned long) nr, (long) len + 2);
- ppp->stats.ppp_ierrors++;
- error = -EOVERFLOW;
- goto out;
- }
+ } else {
+ /*
+ * On a decompression error, we pass the
+ * compressed frame up to pppd as an
+ * error indication.
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO "%s: decomp err %d\n",
+ ppp->name, new_count);
+ if (new_skb != 0)
+ kfree_skb(new_skb);
+ if (ppp->slcomp != 0)
+ slhc_toss(ppp->slcomp);
+ ++ppp->stats.ppp_ierrors;
+ if (new_count == DECOMP_FATALERROR) {
+ ppp->flags |= SC_DC_FERROR;
+ } else {
+ ppp->flags |= SC_DC_ERROR;
+ }
+ }
-/*
- * Fake the insertion of the ADDRESS and CONTROL information because these
- * were not saved in the buffer.
- */
- error = put_user((u_char) PPP_ALLSTATIONS, buf);
- if (error)
- goto out;
- ++buf;
- error = put_user((u_char) PPP_UI, buf);
- if (error)
- goto out;
- ++buf;
-/*
- * Copy the received data from the buffer to the caller's area.
- */
- ret = len + 2; /* Account for ADDRESS and CONTROL bytes */
- while (len-- > 0) {
- GETC (c);
- error = put_user(c, buf);
- if (error)
- goto out;
- ++buf;
+ } else {
+ /*
+ * The frame is not compressed. Pass it to the
+ * decompression code so it can update its
+ * dictionary if necessary.
+ */
+ (*ppp->sc_rcomp->incomp)(ppp->sc_rc_state,
+ data, count);
+ }
}
+ else if (PPP_PROTOCOL(data) == PPP_COMP && (ppp->flags & SC_DEBUG))
+ printk(KERN_INFO "%s: not decomp, rc_state=%p flags=%x\n",
+ ppp->name, ppp->sc_rc_state, ppp->flags);
- clear_bit (0, &ppp->ubuf->locked);
- return ret;
-
-out:
- ppp->ubuf->tail += len;
- ppp->ubuf->tail &= ppp->ubuf->size;
- clear_bit (0, &ppp->ubuf->locked);
- return error;
-#undef GETC
-}
+ /*
+ * Count the frame and print it
+ */
+ ++ppp->stats.ppp_ipackets;
+ ppp->stats.ppp_ioctects += count;
+ if (ppp->flags & SC_LOG_INPKT)
+ ppp_print_buffer ("receive frame", data, count);
-/* stuff a character into the transmit buffer, using PPP's way of escaping
- special characters.
- also, update fcs to take account of new character */
+ /*
+ * Find the procedure to handle this protocol.
+ * The last one is marked as protocol 0 which is the 'catch-all'
+ * to feed it to the pppd daemon.
+ */
+ proto = PPP_PROTOCOL(data);
+ proto_ptr = proto_list;
+ while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
+ ++proto_ptr;
-extern inline void
-ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
- register __u8 chr)
-{
-/*
- * The buffer should not be full.
- */
- if (ppp->flags & SC_DEBUG) {
- if ((buf->count < 0) || (buf->count > 3000))
- printk (KERN_DEBUG "ppp_stuff_char: %d %x\n",
- (unsigned int) buf->count,
- (unsigned int) chr);
- }
-/*
- * Update the FCS and if the character needs to be escaped, do it.
- */
- buf->fcs = PPP_FCS (buf->fcs, chr);
- if (in_xmap (ppp, chr)) {
- chr ^= PPP_TRANS;
- ins_char (buf, PPP_ESCAPE);
+ /*
+ * Update the appropriate statistic counter.
+ */
+ if (!(*proto_ptr->func)(ppp, skb)) {
+ kfree_skb(skb);
+ ++ppp->stats.ppp_discards;
}
-/*
- * Add the character to the buffer.
- */
- ins_char (buf, chr);
+
+ return 1;
}
/*
- * Procedure to encode the data with the proper escaping and send the
- * data to the remote system.
+ * An input error has been detected, so we need to inform
+ * the VJ decompressor.
*/
-
static void
-ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
- __u8 *data, int count, int non_ip)
+ppp_receive_error(struct ppp *ppp)
{
- __u16 write_fcs;
- int address, control;
- int proto;
-
CHECK_PPP_VOID();
- CHECK_BUF_MAGIC(buf);
- ++ppp->stats.ppp_opackets;
- ppp->stats.ppp_ooctects += count;
-
-/*
- * Insert the leading FLAG character
- */
- buf->count = 0;
-
- if (non_ip || flag_time == 0)
- ins_char (buf, PPP_FLAG);
- else {
- if (jiffies - ppp->last_xmit >= flag_time)
- ins_char (buf, PPP_FLAG);
- }
- ppp->last_xmit = jiffies;
- buf->fcs = PPP_INITFCS;
-/*
- * Emit the address/control information if needed
- */
- address = PPP_ADDRESS (data);
- control = PPP_CONTROL (data);
- proto = PPP_PROTOCOL (data);
- if (address != PPP_ALLSTATIONS ||
- control != PPP_UI ||
- (ppp->flags & SC_COMP_AC) == 0) {
- ppp_stuff_char (ppp, buf, address);
- ppp_stuff_char (ppp, buf, control);
- }
-/*
- * Emit the protocol (compressed if possible)
- */
- if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
- ppp_stuff_char (ppp, buf, proto >> 8);
+ if (ppp->slcomp != 0)
+ slhc_toss(ppp->slcomp);
+}
- ppp_stuff_char (ppp, buf, proto);
/*
- * Insert the data
+ * Put the input frame into the networking system for the indicated protocol
*/
- data += 4;
- count -= 4;
+static int
+ppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb)
+{
- while (count-- > 0)
- ppp_stuff_char (ppp, buf, *data++);
-/*
- * Add the trailing CRC and the final flag character
- */
- write_fcs = buf->fcs ^ 0xFFFF;
- ppp_stuff_char (ppp, buf, write_fcs);
- ppp_stuff_char (ppp, buf, write_fcs >> 8);
-/*
- * Add the trailing flag character
- */
- ins_char (buf, PPP_FLAG);
-/*
- * Send the block to the tty driver.
- */
- ppp->stats.ppp_obytes += buf->count;
- ppp_kick_tty (ppp, buf);
+ /*
+ * Fill in a few fields of the skb and give it to netif_rx().
+ */
+ skb->dev = ppp2dev(ppp); /* We are the device */
+ skb->protocol = htons(proto);
+ skb->mac.raw = skb->data;
+ skb_pull(skb, PPP_HDRLEN); /* pull off ppp header */
+ ppp->last_recv = jiffies;
+ netif_rx (skb);
+ return 1;
}
/*
- * Compress and send an frame to the peer.
- *
- * Return 0 if frame was queued for transmission.
- * 1 if frame must be re-queued for later driver support.
+ * Process the receipt of an IP frame
*/
-
static int
-ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
- __u8 *data, int count)
+rcv_proto_ip(struct ppp *ppp, struct sk_buff *skb)
{
- int proto;
- int address, control;
- __u8 *new_data;
- int new_count;
-
CHECK_PPP(0);
- CHECK_BUF_MAGIC(buf);
-/*
- * Print the buffer
- */
- if (ppp->flags & SC_LOG_OUTPKT)
- ppp_print_buffer ("write frame", data, count);
-/*
- * Determine if the frame may be compressed. Attempt to compress the
- * frame if possible.
- */
- proto = PPP_PROTOCOL (data);
- address = PPP_ADDRESS (data);
- control = PPP_CONTROL (data);
-
- if (((ppp->flags & SC_COMP_RUN) != 0) &&
- (ppp->sc_xc_state != (void *) 0) &&
- (address == PPP_ALLSTATIONS) &&
- (control == PPP_UI) &&
- (proto != PPP_LCP) &&
- (proto != PPP_CCP)) {
- new_data = kmalloc (ppp->mtu + PPP_HDRLEN, GFP_ATOMIC);
- if (new_data == NULL) {
- printk (KERN_ERR "ppp_dev_xmit_frame: no memory\n");
- return 1;
- }
-
- new_count = (*ppp->sc_xcomp->compress)
- (ppp->sc_xc_state, data, new_data, count,
- ppp->mtu + PPP_HDRLEN);
-
- if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
- ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0);
- kfree (new_data);
- return 0;
- }
-/*
- * The frame could not be compressed, or it could not be sent in
- * compressed form because CCP is not yet up.
- */
- kfree (new_data);
- }
-/*
- * Go to the escape encoding
- */
- ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
+ if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0)
+ && ppp->sc_npmode[NP_IP] == NPMODE_PASS)
+ return ppp_rcv_rx(ppp, ETH_P_IP, skb);
return 0;
}
/*
- * Revise the tty frame for specific protocols.
+ * Process the receipt of an IPX frame
*/
-
static int
-send_revise_frame (register struct ppp *ppp, __u8 *data, int len)
+rcv_proto_ipx(struct ppp *ppp, struct sk_buff *skb)
{
- __u8 *p;
-
- switch (PPP_PROTOCOL (data)) {
-/*
- * Update the LQR frame with the current MIB information. This saves having
- * the daemon read old MIB data from the driver.
- */
- case PPP_LQR:
- len = 48; /* total size of this frame */
- p = (__u8 *) &data [40]; /* Point to last two items. */
- p = store_long (p, ppp->stats.ppp_opackets + 1);
- p = store_long (p, ppp->stats.ppp_ooctects + len);
- break;
-/*
- * Outbound compression frames
- */
- case PPP_CCP:
- ppp_proto_ccp (ppp,
- data + PPP_HDRLEN,
- len - PPP_HDRLEN,
- 0);
- break;
-
- default:
- break;
- }
-
- return len;
+ CHECK_PPP(0);
+ if (((ppp2dev(ppp)->flags & IFF_UP) != 0) && (skb->len > 0)
+ && ppp->sc_npmode[NP_IPX] == NPMODE_PASS)
+ return ppp_rcv_rx(ppp, ETH_P_IPX, skb);
+ return 0;
}
/*
- * write a frame with NR chars from BUF to TTY
- * we have to put the FCS field on ourselves
+ * Process the receipt of an Appletalk frame
*/
-
-static ssize_t
-ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
- size_t count)
+static int
+rcv_proto_at(struct ppp *ppp, struct sk_buff *skb)
{
- struct ppp *ppp = tty2ppp (tty);
- __u8 *new_data;
- int error;
- struct wait_queue wait = {current, NULL};
+ CHECK_PPP(0);
+ if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0)
+ && ppp->sc_npmode[NP_AT] == NPMODE_PASS)
+ return ppp_rcv_rx(ppp, ETH_P_PPPTALK, skb);
+ return 0;
+}
/*
- * Verify the pointers.
+ * Process the receipt of an VJ Compressed frame
*/
- error = -EIO;
- if (!ppp)
- goto out;
- if (ppp->magic != PPP_MAGIC)
- goto out;
+static int
+rcv_proto_vjc_comp(struct ppp *ppp, struct sk_buff *skb)
+{
+ int new_count;
- CHECK_PPP (-ENXIO);
-/*
- * Ensure that the caller does not wish to send too much.
- */
- if (count > PPP_MTU + PPP_HDRLEN) {
+ CHECK_PPP(0);
+ if ((ppp->flags & SC_REJ_COMP_TCP) || ppp->slcomp == NULL)
+ return 0;
+ new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN,
+ skb->len - PPP_HDRLEN);
+ if (new_count < 0) {
if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_tty_write: truncating user packet "
- "from %lu to mtu %d\n", (unsigned long) count,
- PPP_MTU + PPP_HDRLEN);
- count = PPP_MTU + PPP_HDRLEN;
- }
-/*
- * Allocate a buffer for the data and fetch it from the user space.
- */
- new_data = kmalloc (count, GFP_KERNEL);
- if (new_data == NULL) {
- printk (KERN_ERR "ppp_tty_write: no memory\n");
+ printk(KERN_NOTICE
+ "ppp: error in VJ decompression\n");
return 0;
}
-/*
- * Retrieve the user's buffer
- */
- error = -EFAULT;
- if (copy_from_user(new_data, data, count))
- goto out_free;
-/*
- * Lock this PPP unit so we will be the only writer,
- * sleeping if necessary.
- *
- * Note that we add our task to the wait queue before
- * attempting to lock, as the lock flag may be cleared
- * from an interrupt.
- */
- add_wait_queue(&ppp->write_wait, &wait);
- while (1) {
- error = 0;
- current->timeout = 0;
- current->state = TASK_INTERRUPTIBLE;
- if (lock_buffer(ppp->tbuf) == 0)
- break;
- schedule();
-
- error = -EINVAL;
- ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC ||
- !ppp->inuse || tty != ppp->tty) {
- printk("ppp_tty_write: %p invalid after wait!\n", ppp);
- break;
- }
- error = -EINTR;
- if (signal_pending(current))
- break;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&ppp->write_wait, &wait);
- if (error)
- goto out_free;
+ skb_put(skb, new_count + PPP_HDRLEN - skb->len);
+ return rcv_proto_ip(ppp, skb);
+}
/*
- * Change the LQR frame
- */
- count = send_revise_frame (ppp, new_data, count);
-/*
- * Send the data
+ * Process the receipt of an VJ Un-compressed frame
*/
- if (PPP_PROTOCOL(new_data) == PPP_IP) {
- /*
- * IP frames can be sent by pppd when we're doing
- * demand-dialling. We send them via ppp_dev_xmit_ip
- * to make sure that VJ compression happens properly.
- */
- ppp_dev_xmit_ip(ppp, ppp->tbuf, new_data + PPP_HDRLEN,
- count - PPP_HDRLEN, NPMODE_PASS);
-
- } else {
- ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+static int
+rcv_proto_vjc_uncomp(struct ppp *ppp, struct sk_buff *skb)
+{
+ CHECK_PPP(0);
+ if ((ppp->flags & SC_REJ_COMP_TCP) || ppp->slcomp == NULL)
+ return 0;
+ if (slhc_remember(ppp->slcomp, skb->data + PPP_HDRLEN,
+ skb->len - PPP_HDRLEN) <= 0) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_NOTICE "ppp: error in VJ memorizing\n");
+ return 0;
}
- error = count;
-
-out_free:
- kfree (new_data);
-out:
- return error;
+ return rcv_proto_ip(ppp, skb);
}
-/*
- * Process the set-compression ioctl.
- */
-
static int
-ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
+rcv_proto_ccp(struct ppp *ppp, struct sk_buff *skb)
{
- struct compressor *cp;
- int error, nb;
- unsigned long flags;
- __u8 *ptr;
- __u8 ccp_option[CCP_MAX_OPTION_LENGTH];
- struct ppp_option_data data;
+ CHECK_PPP(0);
+ ppp_proto_ccp (ppp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN, 1);
+ return rcv_proto_unknown(ppp, skb);
+}
/*
- * Fetch the compression parameters
+ * Receive all unclassified protocols.
*/
- error = -EFAULT;
- if (copy_from_user(&data, odp, sizeof (data)))
- goto out;
-
- nb = data.length;
- ptr = data.ptr;
- if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
- nb = CCP_MAX_OPTION_LENGTH;
-
- if (copy_from_user(ccp_option, ptr, nb))
- goto out;
-
- error = -EINVAL;
- if (ccp_option[1] < 2) /* preliminary check on the length byte */
- goto out;
-
- save_flags(flags);
- cli();
- ppp->flags &= ~(data.transmit? SC_COMP_RUN: SC_DECOMP_RUN);
- restore_flags(flags);
-
- cp = find_compressor (ccp_option[0]);
-#ifdef CONFIG_KMOD
- if (cp == NULL) {
- char modname[32];
- sprintf(modname, "ppp-compress-%d", ccp_option[0]);
- request_module(modname);
- cp = find_compressor(ccp_option[0]);
- }
-#endif /* CONFIG_KMOD */
+static int
+rcv_proto_unknown(struct ppp *ppp, struct sk_buff *skb)
+{
+ CHECK_PPP(0);
- if (cp == NULL)
- goto out_no_comp;
/*
- * Found a handler for the protocol - try to allocate
- * a compressor or decompressor.
+ * Limit queue length by dropping old frames.
*/
- error = 0;
- if (data.transmit) {
- if (ppp->sc_xc_state != NULL)
- (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
- ppp->sc_xc_state = NULL;
+ skb_queue_tail(&ppp->rcv_q, skb);
+ while (ppp->rcv_q.qlen > PPP_MAX_RCV_QLEN) {
+ struct sk_buff *skb = skb_dequeue(&ppp->rcv_q);
+ if (skb)
+ kfree_skb(skb);
+ }
- ppp->sc_xcomp = cp;
- ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
- if (ppp->sc_xc_state == NULL) {
- printk(KERN_WARNING "%s: comp_alloc failed\n",
- ppp->name);
- error = -ENOBUFS;
- } else if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s: comp_alloc -> %p\n",
- ppp->name, ppp->sc_xc_state);
- } else {
- if (ppp->sc_rc_state != NULL)
- (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
- ppp->sc_rc_state = NULL;
+ wake_up_interruptible (&ppp->read_wait);
+ if (ppp->tty->fasync != NULL)
+ kill_fasync (ppp->tty->fasync, SIGIO);
- ppp->sc_rcomp = cp;
- ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
- if (ppp->sc_rc_state == NULL) {
- printk(KERN_WARNING "%s: decomp_alloc failed\n",
- ppp->name);
- error = -ENOBUFS;
- } else if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s: decomp_alloc -> %p\n",
- ppp->name, ppp->sc_rc_state);
- }
-out:
- return error;
+ return 1;
+}
-out_no_comp:
- error = -EINVAL; /* no handler found */
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n",
- ppp->name, ccp_option[0], ccp_option[1],
- ccp_option[2], nb);
- goto out;
+/*************************************************************
+ * TRANSMIT-SIDE ROUTINES
+ *************************************************************/
+
+/* local function to store a value into the LQR frame */
+extern inline __u8 * store_long (register __u8 *p, register int value) {
+ *p++ = (__u8) (value >> 24);
+ *p++ = (__u8) (value >> 16);
+ *p++ = (__u8) (value >> 8);
+ *p++ = (__u8) value;
+ return p;
}
/*
- * Process the IOCTL event for the tty device.
+ * Compress and send an frame to the peer.
+ * Should be called with dev->tbusy == 1, having been set by the caller.
+ * That is, we use dev->tbusy as a lock to prevent reentry of this
+ * procedure.
*/
-
-static int
-ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
- unsigned int param2, unsigned long param3)
+static void
+ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
{
- struct ppp *ppp = tty2ppp (tty);
- register int temp_i = 0, oldflags;
- int error = 0;
- unsigned long flags;
-/*
- * Verify the status of the PPP device.
- */
- if (!ppp)
- return -EBADF;
+ int proto;
+ __u8 *data;
+ int count;
+ __u8 *p;
+ int ret;
- if (ppp->magic != PPP_MAGIC)
- return -EBADF;
+ CHECK_PPP_VOID();
+ data = skb->data;
+ count = skb->len;
- CHECK_PPP (-ENXIO);
-/*
- * The user must have an euid of root to do these requests.
- */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-/*
- * Set the MRU value
- */
- switch (param2) {
- case PPPIOCSMRU:
- error = get_user(temp_i, (int *) param3);
- if (error != 0)
- break;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set mru to %x\n", temp_i);
+ /* dump the buffer */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("write frame", data, count);
- if (ppp->mru != temp_i)
- ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
- break;
-/*
- * Fetch the flags
- */
- case PPPIOCGFLAGS:
- temp_i = (ppp->flags & SC_MASK);
-#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
- temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
- SC_RCV_ODDP | SC_RCV_EVNP;
-#endif
- error = put_user(temp_i, (int *) param3);
+ /*
+ * Handle various types of protocol-specific compression
+ * and other processing, including:
+ * - VJ TCP header compression
+ * - updating LQR packets
+ * - updating CCP state on CCP packets
+ */
+ proto = PPP_PROTOCOL(data);
+ switch (proto) {
+ case PPP_IP:
+ if ((ppp->flags & SC_COMP_TCP) && ppp->slcomp != NULL)
+ skb = ppp_vj_compress(ppp, skb);
break;
-/*
- * Set the flags for the various options
- */
- case PPPIOCSFLAGS:
- error = get_user(temp_i, (int *) param3);
- if (error != 0)
- break;
- temp_i &= SC_MASK;
-
- if ((ppp->flags & SC_CCP_OPEN) && (temp_i & SC_CCP_OPEN) == 0)
- ppp_ccp_closed(ppp);
- save_flags(flags);
- cli();
- oldflags = ppp->flags;
- ppp->flags = temp_i |= (ppp->flags & ~SC_MASK);
- restore_flags(flags);
- if ((oldflags | temp_i) & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set flags to %x\n", temp_i);
- break;
-/*
- * Set the compression mode
- */
- case PPPIOCSCOMPRESS:
- error = ppp_set_compression (ppp,
- (struct ppp_option_data *) param3);
- break;
-/*
- * Retrieve the transmit async map
- */
- case PPPIOCGASYNCMAP:
- error = put_user(ppp->xmit_async_map[0], (int *) param3);
- break;
-/*
- * Set the transmit async map
- */
- case PPPIOCSASYNCMAP:
- error = get_user(temp_i, (int *) param3);
- if (error != 0)
- break;
- ppp->xmit_async_map[0] = temp_i;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set xmit asyncmap %x\n",
- ppp->xmit_async_map[0]);
- break;
-/*
- * Set the receive async map
- */
- case PPPIOCSRASYNCMAP:
- error = get_user(temp_i, (int *) param3);
- if (error != 0)
- break;
- ppp->recv_async_map = temp_i;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set rcv asyncmap %x\n",
- ppp->recv_async_map);
- break;
-/*
- * Obtain the unit number for this device.
- */
- case PPPIOCGUNIT:
- error = put_user(ppp2dev (ppp)->base_addr, (int *) param3);
- if (error != 0)
- break;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get unit: %ld\n",
- ppp2dev (ppp)->base_addr);
- break;
-/*
- * Set the debug level
- */
- case PPPIOCSDEBUG:
- error = get_user(temp_i, (int *) param3);
- if (error != 0)
+ case PPP_LQR:
+ /*
+ * Update the LQR frame with the current MIB information.
+ * This way the information is accurate and up-to-date.
+ */
+ if (count < 48)
break;
- temp_i = (temp_i & 0x1F) << 16;
- temp_i |= (ppp->flags & ~0x1F0000);
-
- if ((ppp->flags | temp_i) & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set flags to %x\n", temp_i);
- ppp->flags = temp_i;
- break;
-/*
- * Get the debug level
- */
- case PPPIOCGDEBUG:
- temp_i = (ppp->flags >> 16) & 0x1F;
- error = put_user(temp_i, (int *) param3);
- break;
-/*
- * Get the times since the last send/receive frame operation
- */
- case PPPIOCGIDLE:
- {
- struct ppp_idle cur_ddinfo;
-
- /* change absolute times to relative times. */
- cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
- cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ;
- error = -EFAULT;
- if (!copy_to_user((void *) param3, &cur_ddinfo,
- sizeof (cur_ddinfo)))
- error = 0;
- }
+ p = data + 40; /* Point to last two items. */
+ p = store_long(p, ppp->stats.ppp_opackets + 1);
+ p = store_long(p, ppp->stats.ppp_ooctects + count);
+ ++ppp->stats.ppp_olqrs;
break;
-/*
- * Retrieve the extended async map
- */
- case PPPIOCGXASYNCMAP:
- error = -EFAULT;
- if (!copy_to_user((void *) param3, ppp->xmit_async_map,
- sizeof (ppp->xmit_async_map)))
- error = 0;
- break;
-/*
- * Set the async extended map
- */
- case PPPIOCSXASYNCMAP:
- {
- __u32 temp_tbl[8];
-
- error = -EFAULT;
- if (copy_from_user(temp_tbl, (void *) param3,
- sizeof (temp_tbl)))
- break;
- temp_tbl[1] = 0x00000000;
- temp_tbl[2] &= ~0x40000000;
- temp_tbl[3] |= 0x60000000;
-
- error = 0;
- if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
- (temp_tbl[4] & temp_tbl[5]) != 0 ||
- (temp_tbl[6] & temp_tbl[7]) != 0)
- error = -EINVAL;
- else {
- memcpy (ppp->xmit_async_map,
- temp_tbl,
- sizeof (ppp->xmit_async_map));
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set xasyncmap\n");
- }
- }
+ case PPP_CCP:
+ /*
+ * Outbound compression control frames
+ */
+ ppp_proto_ccp(ppp, data + PPP_HDRLEN, count - PPP_HDRLEN, 0);
break;
-/*
- * Set the maximum VJ header compression slot number.
- */
- case PPPIOCSMAXCID:
- error = get_user(temp_i, (int *) param3);
- if (error != 0)
- break;
- temp_i = (temp_i & 255) + 1;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set maxcid to %d\n", temp_i);
- if (ppp->slcomp != NULL)
- slhc_free (ppp->slcomp);
- ppp->slcomp = NULL;
+ }
+ data = skb->data;
+ count = skb->len;
- ppp->slcomp = slhc_init (16, temp_i);
- if (ppp->slcomp == NULL) {
- printk (KERN_ERR "ppp_tty_ioctl: "
- "no space for compression buffers!\n");
- ppp_release (ppp);
- error = -ENOMEM;
+ /*
+ * Compress the whole frame if possible.
+ */
+ if (((ppp->flags & SC_COMP_RUN) != 0) &&
+ (ppp->sc_xc_state != (void *) 0) &&
+ (proto != PPP_LCP) &&
+ (proto != PPP_CCP)) {
+ struct sk_buff *new_skb;
+ int new_count;
+
+ /* Allocate an skb for the compressed frame. */
+ new_skb = alloc_skb(ppp->mtu + PPP_HDRLEN, GFP_ATOMIC);
+ if (new_skb == NULL) {
+ printk(KERN_ERR "ppp_send_frame: no memory\n");
+ kfree_skb(skb);
+ ppp->dev.tbusy = 0;
+ return;
}
- break;
-
- case PPPIOCXFERUNIT:
- ppp->backup_tty = tty;
- ppp->sc_xfer = current->pid;
- break;
- case PPPIOCGNPMODE:
- case PPPIOCSNPMODE:
- {
- struct npioctl npi;
-
- error = -EFAULT;
- if (copy_from_user(&npi, (void *) param3, sizeof(npi)))
- break;
-
- if (npi.protocol != PPP_IP) {
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "pppioc[gs]npmode: "
- "invalid protocol %d\n",
- npi.protocol);
- error = -EINVAL;
- break;
- }
- npi.protocol = NP_IP;
-
- if (param2 == PPPIOCGNPMODE) {
- npi.mode = ppp->sc_npmode[npi.protocol];
- if (copy_to_user((void *) param3, &npi,
- sizeof (npi)))
- break;
- }
+ /* Compress the frame. */
+ new_count = (*ppp->sc_xcomp->compress)
+ (ppp->sc_xc_state, data, new_skb->data,
+ count, ppp->mtu + PPP_HDRLEN);
- ppp->sc_npmode[npi.protocol] = npi.mode;
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "ppp: set np %d to %d\n",
- npi.protocol, npi.mode);
- /* N.B. Why is the busy flag cleared here? */
- ppp2dev(ppp)->tbusy = 0;
- mark_bh(NET_BH);
- error = 0;
+ /* Did it compress? */
+ if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
+ skb_put(new_skb, new_count);
+ kfree_skb(skb);
+ skb = new_skb;
+ } else {
+ /*
+ * The frame could not be compressed, or it could not
+ * be sent in compressed form because CCP is down.
+ */
+ kfree_skb(new_skb);
}
- break;
-/*
- * Allow users to read, but not set, the serial port parameters
- */
- case TCGETS:
- case TCGETA:
- error = n_tty_ioctl (tty, file, param2, param3);
- break;
+ }
- case FIONREAD:
- {
- int count = ppp->ubuf->tail - ppp->ubuf->head;
- if (count < 0)
- count += (ppp->ubuf->size + 1);
- error = put_user(count, (int *) param3);
- }
- break;
-/*
- * All other ioctl() events will come here.
- */
- default:
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING "ppp_tty_ioctl: "
- "invalid ioctl=%x, addr=%lx\n", param2, param3);
- error = -ENOIOCTLCMD;
- break;
+ /*
+ * Send the frame
+ */
+ ret = ppp_async_send(ppp, skb);
+ if (ret > 0) {
+ /* we can release the lock */
+ ppp->dev.tbusy = 0;
+ } else if (ret < 0) {
+ /* this can't happen, since the caller got the tbusy lock */
+ printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n");
}
- return error;
}
/*
- * TTY callback.
- *
- * Process the poll() statement for the PPP device.
+ * Apply VJ TCP header compression to a packet.
*/
-
-static unsigned int
-ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait)
+static struct sk_buff *
+ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb)
{
- struct ppp *ppp = tty2ppp (tty);
- unsigned int mask = 0;
-
- if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) {
- CHECK_PPP (0);
+ __u8 *orig_data, *data;
+ struct sk_buff *new_skb;
+ int len, proto;
- poll_wait(filp, &ppp->read_wait, wait);
- poll_wait(filp, &ppp->write_wait, wait);
-
- /* Must lock the user buffer area while checking. */
- CHECK_BUF_MAGIC(ppp->ubuf);
- if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) {
- if(ppp->ubuf->head != ppp->ubuf->tail)
- mask |= POLLIN | POLLRDNORM;
- clear_bit(0, &ppp->ubuf->locked);
- }
- if(tty->flags & (1 << TTY_OTHER_CLOSED))
- mask |= POLLHUP;
- if(tty_hung_up_p(filp))
- mask |= POLLHUP;
- if(ppp->tbuf->locked == 0)
- mask |= POLLOUT | POLLWRNORM;
+ new_skb = alloc_skb(skb->len, GFP_ATOMIC);
+ if (new_skb == NULL) {
+ printk(KERN_ERR "ppp: no memory for vj compression\n");
+ return skb;
}
- return mask;
-}
-/*************************************************************
- * NETWORK OUTPUT
- * This routine accepts requests from the network layer
- * and attempts to deliver the packets.
- * It also includes various routines we are compelled to
- * have to make the network layer work (arp, etc...).
- *************************************************************/
+ orig_data = data = skb->data + PPP_HDRLEN;
+ len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN,
+ new_skb->data + PPP_HDRLEN, &data,
+ (ppp->flags & SC_NO_TCP_CCID) == 0);
-/*
- * Callback from the network layer when the device goes up.
- */
-
-static int
-ppp_dev_open (struct device *dev)
-{
- struct ppp *ppp = dev2ppp (dev);
+ if (data == orig_data) {
+ /* Couldn't compress the data */
+ kfree_skb(new_skb);
+ return skb;
+ }
- if (ppp2tty (ppp) == NULL) {
- printk (KERN_ERR
- "ppp: %s not connected to a TTY! can't go open!\n",
- dev->name);
- return -ENXIO;
+ /* The data has been changed */
+ if (data[0] & SL_TYPE_COMPRESSED_TCP) {
+ proto = PPP_VJC_COMP;
+ data[0] ^= SL_TYPE_COMPRESSED_TCP;
+ } else {
+ if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+ proto = PPP_VJC_UNCOMP;
+ else
+ proto = PPP_IP;
+ data[0] = orig_data[0];
}
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp: channel %s going up for IP packets!\n",
- dev->name);
+ data = skb_put(new_skb, len + PPP_HDRLEN);
+ data[0] = PPP_ALLSTATIONS;
+ data[1] = PPP_UI;
+ data[2] = 0;
+ data[3] = proto;
- CHECK_PPP (-ENXIO);
- return 0;
+ kfree_skb(skb);
+ return new_skb;
}
-/*
- * Callback from the network layer when the ppp device goes down.
- */
-
-static int
-ppp_dev_close (struct device *dev)
+static inline void
+ppp_send_frames(struct ppp *ppp)
{
- struct ppp *ppp = dev2ppp (dev);
+ struct sk_buff *skb;
- if (ppp2tty (ppp) == NULL) {
- return -ENXIO;
+ while (!test_and_set_bit(0, &ppp->dev.tbusy)) {
+ skb = skb_dequeue(&ppp->xmt_q);
+ if (skb == NULL) {
+ ppp->dev.tbusy = 0;
+ mark_bh(NET_BH);
+ break;
+ }
+ ppp_send_frame(ppp, skb);
}
-/*
- * We don't do anything about the device going down. It is not important
- * for us.
- */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp: channel %s going down for IP packets!\n",
- dev->name);
- CHECK_PPP (-ENXIO);
- return 0;
}
/*
- * IOCTL operation to read the version of the driver.
+ * Called from the hardware (tty) layer when it can accept
+ * another packet.
*/
-
-static int
-ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
+static void
+ppp_output_wakeup(struct ppp *ppp)
{
- int error;
- char *result = (char *) ifr->ifr_ifru.ifru_data;
- int len = strlen (szVersion) + 1;
-/*
- * Move the version data
- */
- error = -EFAULT;
- if (!copy_to_user(result, szVersion, len))
- error = 0;
- return error;
+ CHECK_PPP_VOID();
+
+ if (!ppp->dev.tbusy) {
+ printk(KERN_ERR "ppp_output_wakeup called but tbusy==0\n");
+ return;
+ }
+ ppp->dev.tbusy = 0;
+ ppp_send_frames(ppp);
}
/*
- * IOCTL to read the statistics for the pppstats program.
+ * Send a control frame (from pppd).
*/
-
-static int
-ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+static void
+ppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb)
{
- struct ppp_stats *result, temp;
- int error;
-/*
- * Supply the information for the caller. First move the version data
- * then move the ppp stats; and finally the vj stats.
- */
- memset (&temp, 0, sizeof(temp));
- if (dev->flags & IFF_UP) {
- memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
- if (ppp->slcomp != NULL) {
- temp.vj.vjs_packets = ppp->slcomp->sls_o_compressed+
- ppp->slcomp->sls_o_uncompressed;
- temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
- temp.vj.vjs_searches = ppp->slcomp->sls_o_searches;
- temp.vj.vjs_misses = ppp->slcomp->sls_o_misses;
- temp.vj.vjs_errorin = ppp->slcomp->sls_i_error;
- temp.vj.vjs_tossed = ppp->slcomp->sls_i_tossed;
- temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
- temp.vj.vjs_compressedin = ppp->slcomp->sls_i_compressed;
- }
- }
-
- result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+ CHECK_PPP_VOID();
- error = -EFAULT;
- if (!copy_to_user(result, &temp, sizeof (temp)))
- error = 0;
- return error;
+ /*
+ * Put the packet on the queue, then send as many as we can.
+ */
+ skb_queue_tail(&ppp->xmt_q, skb);
+ ppp_send_frames(ppp);
}
+
+/*************************************************************
+ * NETWORK OUTPUT
+ * This routine accepts requests from the network layer
+ * and attempts to deliver the packets.
+ *************************************************************/
/*
- * IOCTL to read the compression statistics for the pppstats program.
+ * Send a frame to the peer.
+ * Returns 1 iff the frame was not accepted.
*/
-
static int
-ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
{
- struct ppp_comp_stats *result, temp;
- int error;
-/*
- * Supply the information for the caller.
- */
- memset (&temp, 0, sizeof(temp));
- if (dev->flags & IFF_UP) {
- if (ppp->sc_xc_state != NULL)
- (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
- &temp.c);
-
- if (ppp->sc_rc_state != NULL)
- (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
- &temp.d);
+ struct ppp *ppp = dev2ppp(dev);
+ struct tty_struct *tty = ppp2tty(ppp);
+ enum NPmode npmode;
+ int proto;
+ unsigned char *hdr;
+
+ /* just a little sanity check. */
+ if (skb == NULL)
+ return 0;
+ if (skb->data == NULL) {
+ kfree_skb(skb);
+ return 0;
}
-/*
- * Move the data to the caller's buffer
- */
- result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
- error = -EFAULT;
- if (!copy_to_user(result, &temp, sizeof (temp)))
- error = 0;
- return error;
-}
-
-/*
- * Callback from the network layer to process the sockioctl functions.
- */
+ /*
+ * Avoid timing problem should tty hangup while data is
+ * queued to be sent.
+ */
+ if (!ppp->inuse) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
-static int
-ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
-{
- struct ppp *ppp = dev2ppp (dev);
- int error;
+ /*
+ * Validate the tty interface
+ */
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ dev_kfree_skb(skb);
+ return 0;
+ }
- CHECK_PPP_MAGIC(ppp);
-/*
- * Process the requests
- */
- switch (cmd) {
- case SIOCGPPPSTATS:
- error = ppp_dev_ioctl_stats (ppp, ifr, dev);
+ /*
+ * Work out the appropriate network-protocol mode for this packet.
+ */
+ npmode = NPMODE_PASS; /* default */
+ switch (ntohs(skb->protocol)) {
+ case ETH_P_IP:
+ proto = PPP_IP;
+ npmode = ppp->sc_npmode[NP_IP];
break;
-
- case SIOCGPPPCSTATS:
- error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
+ case ETH_P_IPX:
+ proto = PPP_IPX;
+ npmode = ppp->sc_npmode[NP_IPX];
break;
-
- case SIOCGPPPVER:
- error = ppp_dev_ioctl_version (ppp, ifr);
+ case ETH_P_PPPTALK:
+ case ETH_P_ATALK:
+ proto = PPP_AT;
+ npmode = ppp->sc_npmode[NP_AT];
break;
-
default:
- error = -EINVAL;
- break;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_INFO "%s: packet for unknown proto %x\n",
+ ppp->name, ntohs(skb->protocol));
+ dev_kfree_skb(skb);
+ return 0;
}
- return error;
-}
-
-/*
- * Send an IP frame to the remote with vj header compression.
- *
- * Return 0 if frame was queued for transmission.
- * 1 if frame must be re-queued for later driver support.
- * -1 if frame should be dropped.
- */
-static int
-ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf,
- __u8 *data, int len, enum NPmode npmode)
-{
- int proto = PPP_IP;
- __u8 *hdr;
-/*
- * Branch on the type of processing for the IP frame.
- */
+ /*
+ * Drop, accept or reject the packet depending on the mode.
+ */
switch (npmode) {
case NPMODE_PASS:
break;
@@ -2797,199 +2406,62 @@ ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf,
* network system to be queued and retransmitted later.
*/
if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "%s: returning frame\n",
- ppp->name);
- return -1;
+ printk(KERN_DEBUG "%s: returning frame\n", ppp->name);
+ dev_kfree_skb(skb);
+ return 0;
case NPMODE_ERROR:
case NPMODE_DROP:
if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_dev_xmit: npmode = %d on %s\n",
- ppp->sc_npmode[NP_IP], ppp->name);
- return -1;
-
- default:
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_dev_xmit: unknown npmode %d on %s\n",
- ppp->sc_npmode[NP_IP], ppp->name);
- return -1;
- }
-/*
- * At this point, the buffer will be transmitted. There is no other exit.
- *
- * Try to compress the header.
- */
- if (ppp->flags & SC_COMP_TCP) {
- len = slhc_compress (ppp->slcomp, data, len,
- buf_base (ppp->cbuf) + PPP_HDRLEN,
- &data,
- (ppp->flags & SC_NO_TCP_CCID) == 0);
-
- if (data[0] & SL_TYPE_COMPRESSED_TCP) {
- proto = PPP_VJC_COMP;
- data[0] ^= SL_TYPE_COMPRESSED_TCP;
- } else {
- if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
- proto = PPP_VJC_UNCOMP;
- data[0] = (data[0] & 0x0f) | 0x40;
- }
+ printk(KERN_DEBUG
+ "ppp_dev_xmit: dropping (npmode = %d) on %s\n",
+ npmode, ppp->name);
+ dev_kfree_skb(skb);
+ return 0;
}
-/*
- * Send the frame
- */
- len += PPP_HDRLEN;
- hdr = data - PPP_HDRLEN;
- hdr[0] = PPP_ALLSTATIONS;
- hdr[1] = PPP_UI;
- hdr[2] = 0;
- hdr[3] = proto;
+ /*
+ * The dev->tbusy field acts as a lock to allow only
+ * one packet to be processed at a time. If we can't
+ * get the lock, try again later.
+ */
+ if (test_and_set_bit(0, &dev->tbusy))
+ return 1;
- return ppp_dev_xmit_frame (ppp, buf, hdr, len);
-}
+ /*
+ * Put the 4-byte PPP header on the packet.
+ * If there isn't room for it, we have to copy the packet.
+ */
+ if (skb_headroom(skb) < PPP_HDRLEN) {
+ struct sk_buff *new_skb;
-/*
- * Send a non-IP data frame (such as an IPX frame) to the remote.
- *
- * Return 0 if frame was queued for transmission.
- * 1 if frame must be re-queued for later driver support.
- */
-static int
-ppp_dev_xmit_other (struct device *dev, struct ppp *ppp,
- __u8 *data, int len, int proto)
-{
- __u8 *hdr;
-/*
- * Send the frame
- */
- len += PPP_HDRLEN;
- hdr = data - PPP_HDRLEN;
+ new_skb = alloc_skb(skb->len + PPP_HDRLEN, GFP_ATOMIC);
+ if (new_skb == NULL) {
+ printk(KERN_ERR "%s: skb hdr alloc failed\n",
+ ppp->name);
+ dev_kfree_skb(skb);
+ dev->tbusy = 0;
+ return 0;
+ }
+ skb_reserve(new_skb, PPP_HDRLEN);
+ memcpy(skb_put(new_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb(skb);
+ skb = new_skb;
+ }
+ hdr = skb_push(skb, PPP_HDRLEN);
hdr[0] = PPP_ALLSTATIONS;
hdr[1] = PPP_UI;
hdr[2] = proto >> 8;
hdr[3] = proto;
- return ppp_dev_xmit_frame (ppp, ppp->wbuf, hdr, len);
-}
-
-/*
- * Send a frame to the remote.
- */
-
-static int
-ppp_dev_xmit (sk_buff *skb, struct device *dev)
-{
- int answer, len;
- __u8 *data;
- struct ppp *ppp = dev2ppp (dev);
- struct tty_struct *tty = ppp2tty (ppp);
-/*
- * just a little sanity check.
- */
- if (skb == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
- return 0;
- }
-/*
- * Avoid timing problem should tty hangup while data is queued to be sent
- */
- if (!ppp->inuse) {
- dev_kfree_skb (skb);
- return 0;
- }
-/*
- * Validate the tty interface
- */
- if (tty == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_dev_xmit: %s not connected to a TTY!\n",
- dev->name);
- dev_kfree_skb (skb);
- return 0;
- }
-/*
- * Fetch the pointer to the data
- */
- len = skb->len;
- data = skb_data(skb);
-
- if (data == (__u8 *) 0) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n",
- dev->name);
- dev_kfree_skb (skb);
- return 0;
- }
-/*
- * Detect a change in the transfer size
- */
- if (ppp->mtu != ppp2dev (ppp)->mtu) {
- ppp_changedmtu (ppp,
- ppp2dev (ppp)->mtu,
- ppp->mru);
- }
-/*
- * Acquire the lock on the transmission buffer. If the buffer was busy then
- * mark the device as busy.
- * We also require that ppp->tbuf be unlocked, in order to serialize
- * calls to ppp_dev_xmit_frame (which does compression) and the output
- * of frames w.r.t. tty writes from pppd.
- */
- CHECK_BUF_MAGIC(ppp->wbuf);
- if (ppp->tbuf->locked || lock_buffer (ppp->wbuf) != 0) {
- dev->tbusy = 1;
- if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "dev_xmit blocked, t=%lu w=%lu\n",
- ppp->tbuf->locked, ppp->wbuf->locked);
- return 1;
- }
-/*
- * Look at the protocol in the skb to determine the difference between
- * an IP frame and an IPX frame.
- */
- switch (ntohs (skb->protocol)) {
- case ETH_P_IPX:
- answer = ppp_dev_xmit_other (dev, ppp, data, len, PPP_IPX);
- break;
-
- case ETH_P_IP:
- answer = ppp_dev_xmit_ip (ppp, ppp->wbuf, data, len,
- ppp->sc_npmode[NP_IP]);
- break;
-
- default: /* All others have no support at this time. */
- dev_kfree_skb (skb);
- return 0;
- }
-/*
- * This is the end of the transmission. Release the buffer if it was sent.
- */
- if (answer == 0) {
- /* packet queued OK */
- dev_kfree_skb (skb);
- } else {
- ppp->wbuf->locked = 0;
- if (answer < 0) {
- /* packet should be dropped */
- dev_kfree_skb (skb);
- answer = 0;
- } else {
- /* packet should be queued for later */
- dev->tbusy = 1;
- }
- }
- return answer;
+ ppp_send_frame(ppp, skb);
+ return 0;
}
/*
* Generate the statistic information for the /proc/net/dev listing.
*/
-
static struct net_device_stats *
ppp_dev_stats (struct device *dev)
{
@@ -3012,7 +2484,7 @@ ppp_dev_stats (struct device *dev)
/* Locate the previous instance of the PPP channel */
static struct ppp *
-ppp_find (int pid_value)
+ppp_find(int pid_value)
{
struct ppp *ppp;
@@ -3026,102 +2498,152 @@ ppp_find (int pid_value)
return ppp;
}
-/* Collect hanged up channels */
-
-static void ppp_sync(void)
-{
- struct device *dev;
- struct ppp *ppp;
-
- rtnl_lock();
- for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
- if (!ppp->inuse) {
- dev = ppp2dev(ppp);
- if (dev->flags&IFF_UP)
- dev_close(dev);
- }
- }
- rtnl_unlock();
-}
-
-
/* allocate or create a PPP channel */
static struct ppp *
-ppp_alloc (void)
+ppp_alloc(void)
{
int if_num;
int status;
struct device *dev;
struct ppp *ppp;
- ppp_sync();
-
/* try to find an free device */
- if_num = 0;
for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
if (!test_and_set_bit(0, &ppp->inuse)) {
-
- /* Reregister device */
-
dev = ppp2dev(ppp);
- unregister_netdev (dev);
-
- if (register_netdev (dev)) {
- printk(KERN_DEBUG "cannot reregister ppp device\n");
- return NULL;
+ if (dev->flags & IFF_UP) {
+ clear_bit(0, &ppp->inuse);
+ continue;
}
- return ppp;
+ /* Reregister device */
+ unregister_netdev(dev);
+ if (register_netdev(dev) == 0)
+ return ppp;
+ printk(KERN_DEBUG "could not reregister ppp device\n");
+ /* leave inuse set in this case */
}
- ++if_num;
}
-/*
- * There are no available units, so make a new one.
- */
- ppp = (struct ppp *) kmalloc (sizeof(struct ppp), GFP_KERNEL);
- if (ppp == 0)
+
+ /*
+ * There are no available units, so make a new one.
+ */
+ ppp = (struct ppp *) kmalloc(sizeof(struct ppp), GFP_KERNEL);
+ if (ppp == 0) {
+ printk(KERN_ERR "ppp: struct ppp allocation failed\n");
return 0;
+ }
memset(ppp, 0, sizeof(*ppp));
/* initialize channel control data */
- set_bit(0, &ppp->inuse);
-
- ppp->line = if_num;
- ppp->tty = NULL;
- ppp->backup_tty = NULL;
- if (ppp_last == 0)
- ppp_list = ppp;
- else
- ppp_last->next = ppp;
- ppp_last = ppp;
- ppp->next = 0;
+ ppp->magic = PPP_MAGIC;
+ ppp->next = NULL;
+ ppp->inuse = 1;
+ ppp->read_wait = NULL;
+ /*
+ * Make up a suitable name for this device
+ */
dev = ppp2dev(ppp);
- dev->next = NULL;
- dev->init = ppp_init_dev;
- dev->name = ppp->name;
- sprintf(dev->name, "ppp%d", if_num);
- dev->base_addr = (__u32) if_num;
- dev->priv = (void *) ppp;
+ dev->name = ppp->name;
+ if_num = dev_alloc_name(dev, "ppp%d");
+ if (if_num < 0) {
+ printk(KERN_ERR "ppp: dev_alloc_name failed (%d)\n", if_num);
+ kfree(ppp);
+ return 0;
+ }
+ ppp->line = if_num;
+ ppp->slcomp = NULL;
+
+ dev->next = NULL;
+ dev->init = ppp_init_dev;
+ dev->name = ppp->name;
+ dev->priv = (void *) ppp;
/* register device so that we can be ifconfig'd */
/* ppp_init_dev() will be called as a side-effect */
status = register_netdev (dev);
if (status == 0) {
- printk (KERN_INFO "registered device %s\n", dev->name);
+ printk(KERN_INFO "registered device %s\n", dev->name);
} else {
- printk (KERN_ERR
+ printk(KERN_ERR
"ppp_alloc - register_netdev(%s) = %d failure.\n",
- dev->name, status);
+ dev->name, status);
+ kfree(ppp);
ppp = NULL;
- /* This one will forever be busy as it is not initialized */
}
+
+ /* link this unit into our list */
+ if (ppp_list == 0)
+ ppp_list = ppp;
+ else
+ ppp_last->next = ppp;
+ ppp_last = ppp;
+
return ppp;
}
/*
- * Utility procedures to print a buffer in hex/ascii
+ * Initialize the generic parts of the ppp structure.
*/
+static void
+ppp_generic_init(struct ppp *ppp)
+{
+ int indx;
+ ppp->flags = 0;
+ ppp->mtu = PPP_MTU;
+ ppp->mru = PPP_MRU;
+
+ skb_queue_head_init(&ppp->xmt_q);
+ skb_queue_head_init(&ppp->rcv_q);
+
+ ppp->last_xmit = jiffies;
+ ppp->last_recv = jiffies;
+
+ /* clear statistics */
+ memset(&ppp->stats, 0, sizeof (struct pppstat));
+ memset(&ppp->estats, 0, sizeof(struct net_device_stats));
+
+ /* PPP compression data */
+ ppp->sc_xc_state = NULL;
+ ppp->sc_rc_state = NULL;
+
+ for (indx = 0; indx < NUM_NP; ++indx)
+ ppp->sc_npmode[indx] = NPMODE_PASS;
+}
+
+/*
+ * Called to clean up the generic parts of the ppp structure.
+ */
+static void
+ppp_release(struct ppp *ppp)
+{
+ struct sk_buff *skb;
+
+ CHECK_PPP_MAGIC(ppp);
+
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s released\n", ppp->name);
+
+ ppp_ccp_closed(ppp);
+
+ /* Ensure that the pppd process is not hanging on select()/poll() */
+ wake_up_interruptible(&ppp->read_wait);
+
+ if (ppp->slcomp) {
+ slhc_free(ppp->slcomp);
+ ppp->slcomp = NULL;
+ }
+
+ while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
+ kfree_skb(skb);
+ while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
+ kfree_skb(skb);
+}
+
+/*
+ * Utility procedures to print a buffer in hex/ascii
+ */
static void
ppp_print_hex (register __u8 * out, const __u8 * in, int count)
{
@@ -3156,18 +2678,18 @@ ppp_print_char (register __u8 * out, const __u8 * in, int count)
}
static void
-ppp_print_buffer (const __u8 * name, const __u8 * buf, int count)
+ppp_print_buffer (const char *name, const __u8 *buf, int count)
{
__u8 line[44];
- if (name != (__u8 *) NULL)
- printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
+ if (name != NULL)
+ printk(KERN_DEBUG "ppp: %s, count = %d\n", name, count);
while (count > 8) {
memset (line, 32, 44);
ppp_print_hex (line, buf, 8);
ppp_print_char (&line[8 * 3], buf, 8);
- printk (KERN_DEBUG "%s\n", line);
+ printk(KERN_DEBUG "%s\n", line);
count -= 8;
buf += 8;
}
@@ -3176,7 +2698,7 @@ ppp_print_buffer (const __u8 * name, const __u8 * buf, int count)
memset (line, 32, 44);
ppp_print_hex (line, buf, count);
ppp_print_char (&line[8 * 3], buf, count);
- printk (KERN_DEBUG "%s\n", line);
+ printk(KERN_DEBUG "%s\n", line);
}
}
@@ -3218,7 +2740,8 @@ static int ppp_register_compressor (struct compressor *cp)
struct compressor_link *new;
unsigned long flags;
- new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
+ new = (struct compressor_link *)
+ kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
if (new == (struct compressor_link *) 0)
return 1;
@@ -3279,63 +2802,49 @@ init_module(void)
/* register our line disciplines */
status = ppp_first_time();
if (status != 0)
- printk (KERN_INFO
- "PPP: ppp_init() failure %d\n", status);
- return (status);
+ printk(KERN_INFO "PPP: ppp_init() failure %d\n", status);
+
+ return status;
}
void
cleanup_module(void)
{
int status;
- struct device *dev;
struct ppp *ppp, *next_ppp;
- int busy_flag = 0;
-/*
- * Ensure that the devices are not in operation.
- */
- for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
- if (ppp->inuse && ppp->tty != NULL) {
- busy_flag = 1;
- break;
- }
+ int busy = 0;
- dev = ppp2dev (ppp);
- if (dev->start || dev->flags & IFF_UP) {
- busy_flag = 1;
- break;
- }
+ /*
+ * Ensure that the devices are not in operation.
+ */
+ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
+ CHECK_PPP_MAGIC(ppp);
+ if (ppp->inuse || (ppp->dev.flags & IFF_UP))
+ ++busy;
}
-/*
- * Ensure that there are no compressor modules registered
- */
- if (ppp_compressors != NULL)
- busy_flag = 1;
+ if (busy)
+ printk(KERN_CRIT "PPP: removing despite %d units in use!\n",
+ busy);
- if (busy_flag) {
- printk (KERN_INFO
- "PPP: device busy, remove delayed\n");
- return;
- }
-/*
- * Release the tty registration of the line discipline so that no new entries
- * may be created.
- */
+ /*
+ * Release the tty registration of the line discipline so that
+ * ttys can no longer be put into PPP line discipline.
+ */
status = tty_register_ldisc (N_PPP, NULL);
if (status != 0)
- printk (KERN_INFO
- "PPP: Unable to unregister ppp line discipline "
- "(err = %d)\n", status);
+ printk(KERN_ERR
+ "PPP: Unable to unregister ppp line discipline "
+ "(err = %d)\n", status);
else
- printk (KERN_INFO
+ printk(KERN_INFO
"PPP: ppp line discipline successfully unregistered\n");
-/*
- * De-register the devices so that there is no problem with them
- */
+
+ /*
+ * De-register the devices so that there is no problem with them
+ */
for (ppp = ppp_list; ppp != 0; ppp = next_ppp) {
next_ppp = ppp->next;
- ppp_release (ppp);
- unregister_netdev (&ppp->dev);
+ unregister_netdev(&ppp->dev);
kfree (ppp);
}
}
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
new file mode 100644
index 000000000..69ed516f0
--- /dev/null
+++ b/drivers/net/rtl8139.c
@@ -0,0 +1,1356 @@
+/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
+/*
+ Written 1997 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+ All other rights reserved.
+
+ This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
+ chips.
+
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Support and updates available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
+*/
+
+static const char *version =
+"rtl8139.c:v0.14 12/9/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+
+/* A few user-configurable values. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 10;
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE 1536
+
+/* PCI Tuning Parameters
+ Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */
+#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST 4
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT ((4000*HZ)/1000)
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#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/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+#include <linux/version.h> /* Evil, but neccessary */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x) /* What to put in timer->expires. */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr) ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+
+#else /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
+#ifdef MODULE
+#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#undef MOD_INC_USE_COUNT
+#define MOD_INC_USE_COUNT
+#undef MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+#endif /* 1.3.38 */
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+
+#ifdef SA_SHIRQ
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#include <linux/bios32.h>
+#endif
+
+/* The I/O extent. */
+#define RTL8129_TOTAL_SIZE 0x80
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry rtl8139_drv =
+{"RTL8139", rtl8139_probe, RTL8129_TOTAL_SIZE, NULL};
+#endif
+
+static int rtl8129_debug = 1;
+
+/*
+ Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the RealTek RTL8129, the RealTek Fast
+Ethernet controllers for PCI. This chip is used on a few clone boards.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Rx Ring buffers
+
+The receive unit uses a single linear ring buffer rather than the more
+common (and more efficient) descriptor-based architecture. Incoming frames
+are sequentially stored into the Rx region, and the host copies them into
+skbuffs.
+
+Comment: While it is theoretically possible to process many frames in place,
+any delay in Rx processing would cause us to drop frames. More importantly,
+the Linux protocol stack is not designed to operate in this manner.
+
+IIIb. Tx operation
+
+The RTL8129 uses a fixed set of four Tx descriptors in register space.
+In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux
+aligns the IP header on word boundaries, and 14 byte ethernet header means
+that almost all frames will need to be copied to an alignment buffer.
+
+IVb. References
+
+http://www.realtek.com.tw/cn/cn.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+*/
+
+#ifndef PCI_VENDOR_ID_REALTEK
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+#endif
+#ifndef PCI_DEVICE_ID_REALTEK_8129
+#define PCI_DEVICE_ID_REALTEK_8129 0x8129
+#endif
+#ifndef PCI_DEVICE_ID_REALTEK_8139
+#define PCI_DEVICE_ID_REALTEK_8139 0x8139
+#endif
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
+
+/* Symbolic offsets to registers. */
+enum RTL8129_registers {
+ MAC0=0, /* Ethernet hardware address. */
+ MAR0=8, /* Multicast filter. */
+ TxStat0=0x10, /* Transmit status (Four 32bit registers). */
+ TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
+ ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
+ IntrMask=0x3C, IntrStatus=0x3E,
+ TxConfig=0x40, RxConfig=0x44,
+ Timer=0x48, /* A general-purpose counter. */
+ RxMissed=0x4C, /* 24 bits valid, write clears. */
+ Cfg9346=0x50, Config0=0x51, Config1=0x52,
+ FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
+ MultiIntr=0x5C, TxSummary=0x60,
+ BMCR=0x62, BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A,
+};
+
+enum ChipCmdBits {
+ CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+ PCIErr=0x8000, PCSTimeout=0x4000,
+ RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
+ TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
+};
+enum TxStatusBits {
+ TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
+ TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,
+};
+enum RxStatusBits {
+ RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
+ RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
+ RxBadAlign=0x0002, RxStatusOK=0x0001,
+};
+
+struct rtl8129_private {
+ char devname[8]; /* Used only for kernel debugging. */
+ const char *product_name;
+ struct device *next_module;
+ int chip_id;
+ int chip_revision;
+ struct enet_statistics stats;
+ struct timer_list timer; /* Media selection timer. */
+ unsigned int cur_rx, cur_tx; /* The next free and used entries */
+ unsigned int dirty_rx, dirty_tx;
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff* tx_skbuff[NUM_TX_DESC];
+ unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
+ unsigned char *rx_ring;
+ unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ unsigned char mc_filter[8]; /* Current multicast filter. */
+ char phys[4]; /* MII device addresses. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int media2:4; /* Secondary monitored media port. */
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+};
+
+#ifdef MODULE
+/* Used to pass the full-duplex flag, etc. */
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(max_interrupt_work, "i");
+#endif
+#endif
+
+static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
+ int chip_id, int options, int card_idx);
+static int rtl8129_open(struct device *dev);
+static int read_eeprom(int ioaddr, int location);
+static int mdio_read(int ioaddr, int phy_id, int location);
+static void rtl8129_timer(unsigned long data);
+static void rtl8129_tx_timeout(struct device *dev);
+static void rtl8129_init_ring(struct device *dev);
+static int rtl8129_start_xmit(struct sk_buff *skb, struct device *dev);
+static int rtl8129_rx(struct device *dev);
+static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int rtl8129_close(struct device *dev);
+static struct enet_statistics *rtl8129_get_stats(struct device *dev);
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev);
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+
+#ifdef MODULE
+/* A list of all installed RTL8129 devices, for removing the driver module. */
+static struct device *root_rtl8129_dev = NULL;
+#endif
+
+int rtl8139_probe(struct device *dev)
+{
+ int cards_found = 0;
+ static int pci_index = 0; /* Static, for multiple probe calls. */
+
+ /* Ideally we would detect all network cards in slot order. That would
+ be best done a central PCI probe dispatch, which wouldn't work
+ well with the current structure. So instead we detect just the
+ Rtl81*9 cards in slot order. */
+
+ if (pci_present()) {
+ unsigned char pci_bus, pci_device_fn;
+
+ for (;pci_index < 0xff; pci_index++) {
+ unsigned char pci_latency;
+#if LINUX_VERSION_CODE >= 0x20155
+ unsigned int pci_irq_line;
+ struct pci_dev *pdev;
+#else
+ unsigned char pci_irq_line;
+#endif
+ unsigned short pci_command, new_command, vendor, device;
+ unsigned int pci_ioaddr;
+
+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+#ifdef REVERSE_PROBE_ORDER
+ 0xff - pci_index,
+#else
+ pci_index,
+#endif
+ &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ break;
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ if (vendor != PCI_VENDOR_ID_REALTEK)
+ continue;
+
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+#if LINUX_VERSION_CODE >= 0x20155
+ pdev = pci_find_slot(pci_bus, pci_device_fn);
+ pci_irq_line = pdev->irq;
+ pci_ioaddr = pdev->base_address[0];
+#else
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+#endif
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
+
+ if (device != PCI_DEVICE_ID_REALTEK_8129
+ && device != PCI_DEVICE_ID_REALTEK_8139) {
+ printk(KERN_NOTICE"Unknown RealTek PCI ethernet chip type "
+ "%4.4x detected: not configured.\n", device);
+ continue;
+ }
+ if (check_region(pci_ioaddr, RTL8129_TOTAL_SIZE))
+ continue;
+
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ if (pci_command != new_command) {
+ printk(KERN_INFO " The PCI BIOS has not enabled this"
+ " device! Updating PCI config %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);
+ }
+
+#ifdef MODULE
+ dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
+ options[cards_found], cards_found);
+#else
+ dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
+ dev ? dev->mem_start : 0, -1);
+#endif
+
+ if (dev) {
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < 32) {
+ printk(KERN_NOTICE" PCI latency timer (CFLT) is "
+ "unreasonably low at %d. Setting to 64 clocks.\n",
+ pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 64);
+ } else if (rtl8129_debug > 1)
+ printk(KERN_INFO" PCI latency timer (CFLT) is %#x.\n",
+ pci_latency);
+ dev = 0;
+ cards_found++;
+ }
+ }
+ }
+
+#if defined (MODULE)
+ return cards_found;
+#else
+ return cards_found ? 0 : -ENODEV;
+#endif
+}
+
+static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
+ int chip_id, int options, int card_idx)
+{
+ static int did_version = 0; /* Already printed version info. */
+ struct rtl8129_private *tp;
+ int i;
+
+ if (rtl8129_debug > 0 && did_version++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ dev = init_etherdev(dev, 0);
+
+ printk(KERN_INFO "%s: RealTek RTL%x at %#3x, IRQ %d, ",
+ dev->name, chip_id, ioaddr, irq);
+
+ /* Bring the chip out of low-power mode. */
+ outb(0x00, ioaddr + Config1);
+
+ /* Perhaps this should be read from the EEPROM? */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
+
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x.\n", dev->dev_addr[i]);
+
+ if (rtl8129_debug > 1) {
+ printk(KERN_INFO "%s: EEPROM contents\n", dev->name);
+ for (i = 0; i < 64; i++)
+ printk(" %4.4x%s", read_eeprom(ioaddr, i),
+ i%16 == 15 ? "\n"KERN_INFO : "");
+ }
+
+ /* We do a request_region() to register /proc/ioports info. */
+ request_region(ioaddr, RTL8129_TOTAL_SIZE, "RealTek RTL8129/39 Fast Ethernet");
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ /* Some data structures must be quadword aligned. */
+ tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+ memset(tp, 0, sizeof(*tp));
+ dev->priv = tp;
+
+#ifdef MODULE
+ tp->next_module = root_rtl8129_dev;
+ root_rtl8129_dev = dev;
+#endif
+
+ tp->chip_id = chip_id;
+
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later, but
+ takes too much time. */
+ if (chip_id == 0x8129) {
+ int phy, phy_idx;
+ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+ phy++) {
+ int mii_status = mdio_read(ioaddr, phy, 1);
+
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ tp->phys[phy_idx++] = phy;
+ printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
+ dev->name, phy);
+ }
+ }
+ if (phy_idx == 0) {
+ printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
+ "transceiver.\n",
+ dev->name);
+ tp->phys[0] = -1;
+ }
+ } else {
+ tp->phys[0] = -1;
+ }
+
+ /* Put the chip into low-power mode. */
+ outb(0xC0, ioaddr + Cfg9346);
+ outb(0x03, ioaddr + Config1);
+ outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */
+
+ /* The lower four bits are the media type. */
+ if (options > 0) {
+ tp->full_duplex = (options & 16) ? 1 : 0;
+ tp->default_port = options & 15;
+ if (tp->default_port)
+ tp->medialock = 1;
+ }
+#ifdef MODULE
+ if (card_idx >= 0) {
+ if (full_duplex[card_idx] >= 0)
+ tp->full_duplex = full_duplex[card_idx];
+ }
+#endif
+
+ /* The Rtl8129-specific entries in the device structure. */
+ dev->open = &rtl8129_open;
+ dev->hard_start_xmit = &rtl8129_start_xmit;
+ dev->stop = &rtl8129_close;
+ dev->get_stats = &rtl8129_get_stats;
+ dev->set_multicast_list = &set_rx_mode;
+
+ return dev;
+}
+
+/* Serial EEPROM section. */
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
+#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
+#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
+#define EE_ENB (0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ The 1.2 code is a "nasty" timing loop, but PC compatible machines are
+ *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */
+#ifdef _LINUX_DELAY_H
+#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000)
+#else
+#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5 << 6)
+#define EE_READ_CMD (6 << 6)
+#define EE_ERASE_CMD (7 << 6)
+
+static int read_eeprom(int ioaddr, int location)
+{
+ int i;
+ unsigned short retval = 0;
+ short ee_addr = ioaddr + Cfg9346;
+ int read_cmd = location | EE_READ_CMD;
+
+ outb(EE_ENB & ~EE_CS, ee_addr);
+ outb(EE_ENB, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 10; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outb(EE_ENB | dataval, ee_addr);
+ eeprom_delay(100);
+ outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay(150);
+ outb(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
+ eeprom_delay(250);
+ }
+ outb(EE_ENB, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay(100);
+ retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outb(EE_ENB, ee_addr);
+ eeprom_delay(100);
+ }
+
+ /* Terminate the EEPROM access. */
+ outb(~EE_CS, ee_addr);
+ return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+ serial MDIO protocol. The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_DIR 0x80
+#define MDIO_DATA_OUT 0x04
+#define MDIO_DATA_IN 0x02
+#define MDIO_CLK 0x01
+#ifdef _LINUX_DELAY_H
+#define mdio_delay() udelay(1) /* Really 400ns. */
+#else
+#define mdio_delay() __SLOW_DOWN_IO;
+#endif
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync(int ioaddr)
+{
+ int i;
+ int mdio_addr = ioaddr + MII_SMI;
+
+ for (i = 32; i >= 0; i--) {
+ outb(MDIO_DIR | MDIO_DATA_OUT, mdio_addr);
+ mdio_delay();
+ outb(MDIO_DIR | MDIO_DATA_OUT | MDIO_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return;
+}
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int retval = 0;
+ int mdio_addr = ioaddr + MII_SMI;
+
+ mdio_sync(ioaddr);
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval =
+ (read_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+ outb(MDIO_DIR | dataval, mdio_addr);
+ mdio_delay();
+ outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+ mdio_delay();
+ }
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outb(0, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
+ outb(MDIO_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return (retval>>1) & 0xffff;
+}
+
+static int
+rtl8129_open(struct device *dev)
+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int i;
+ int full_duplex = 0;
+
+ /* Soft reset the chip. */
+ outb(CmdReset, ioaddr + ChipCmd);
+
+#ifdef SA_SHIRQ
+ if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ,
+ "RealTek RTL8129/39 Fast Ethernet", dev)) {
+ return -EAGAIN;
+ }
+#else
+ if (irq2dev_map[dev->irq] != NULL
+ || (irq2dev_map[dev->irq] = dev) == NULL
+ || dev->irq == 0
+ || request_irq(dev->irq, &rtl8129_interrupt, 0, "RTL8129")) {
+ return -EAGAIN;
+ }
+#endif
+
+ MOD_INC_USE_COUNT;
+
+ tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
+ tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
+ if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
+ if (tp->tx_bufs)
+ kfree(tp->tx_bufs);
+ if (rtl8129_debug > 0)
+ printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
+ dev->name, RX_BUF_LEN);
+ return -ENOMEM;
+ }
+ rtl8129_init_ring(dev);
+
+#ifndef final_version
+ /* Used to monitor rx ring overflow. */
+ memset(tp->rx_ring + RX_BUF_LEN, 0xcc, 16);
+#endif
+
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--)
+ if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
+ break;
+#ifndef final_version
+ if (rtl8129_debug > 2)
+ printk(KERN_DEBUG"%s: reset finished with status %2.2x after %d loops.\n",
+ dev->name, inb(ioaddr + ChipCmd), 1000-i);
+#endif
+
+ for (i = 0; i < 6; i++)
+ outb(dev->dev_addr[i], ioaddr + MAC0 + i);
+
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+ outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
+ ioaddr + RxConfig);
+ outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+
+ full_duplex = tp->full_duplex;
+ if (tp->phys[0] >= 0 || tp->chip_id == 0x8139) {
+ u16 mii_reg5;
+ if (tp->chip_id == 0x8139)
+ mii_reg5 = inw(ioaddr + NWayLPAR);
+ else
+ mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+ if (mii_reg5 == 0xffff)
+ ; /* Not there */
+ else if ((mii_reg5 & 0x0100) == 0x0100
+ || (mii_reg5 & 0x00C0) == 0x0040)
+ full_duplex = 1;
+ if (rtl8129_debug > 1)
+ printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+ " auto-negotiated partner ability %4.4x.\n", dev->name,
+ mii_reg5 == 0 ? "" :
+ (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
+ full_duplex ? "full" : "half", mii_reg5);
+ }
+
+ outb(0xC0, ioaddr + Cfg9346);
+ outb(full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+ outb(0x00, ioaddr + Cfg9346);
+
+ outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
+
+ /* Start the chip's Tx and Rx process. */
+ outl(0, ioaddr + RxMissed);
+ set_rx_mode(dev);
+
+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+#ifndef final_version
+ if (rtl8129_debug > 1)
+ printk(KERN_DEBUG"%s: In rtl8129_open() Tx/Rx Config %8.8x/%8.8x"
+ " Chip Config %2.2x/%2.2x.\n",
+ dev->name, inl(ioaddr + TxConfig), inl(ioaddr + RxConfig),
+ inb(ioaddr + Config0), inb(ioaddr + Config1));
+#endif
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ /* Enable all known interrupts by setting the interrupt mask. */
+ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+ | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+
+ if (rtl8129_debug > 1)
+ printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %4.4x IRQ %d"
+ " GP Pins %2.2x %s-duplex.\n",
+ dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
+ full_duplex ? "full" : "half");
+
+ /* Set the timer to switch to check for link beat and perhaps switch
+ to an alternate media type. */
+ init_timer(&tp->timer);
+ tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = &rtl8129_timer; /* timer handler */
+ add_timer(&tp->timer);
+
+ return 0;
+}
+
+static void rtl8129_timer(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int next_tick = 0;
+
+ if (tp->chip_id == 0x8139) {
+ u16 mii_reg5 = inw(ioaddr + NWayLPAR);
+ if ((mii_reg5 & 0x0100) == 0x0100
+ || (mii_reg5 & 0x00C0) == 0x0040)
+ if ( ! tp->full_duplex) {
+ tp->full_duplex = 1;
+ if (rtl8129_debug > 0)
+ printk(KERN_INFO "%s: Switching to full-duplex based on "
+ "link partner ability of %4.4x.\n",
+ dev->name, mii_reg5);
+ outb(0xC0, ioaddr + Cfg9346);
+ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+ outb(0x00, ioaddr + Cfg9346);
+ }
+ }
+ if (rtl8129_debug > 2) {
+ if (tp->chip_id == 0x8129)
+ printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
+ dev->name, inb(ioaddr + GPPinData));
+ else
+ printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
+ dev->name, inw(ioaddr + NWayLPAR));
+ printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x"
+ " RxStatus %4.4x.\n",
+ dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
+ inl(ioaddr + RxEarlyStatus));
+ printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n",
+ dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
+ }
+
+ if (next_tick) {
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+ }
+}
+
+static void rtl8129_tx_timeout(struct device *dev)
+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int i;
+
+ if (rtl8129_debug > 0)
+ printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x.\n",
+ dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus));
+ for (i = 0; i < NUM_TX_DESC; i++)
+ printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n",
+ dev->name, i, inl(ioaddr + TxStat0 + i*4),
+ i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
+ if (tp->chip_id == 0x8129) {
+ int mii_reg;
+ printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
+ for (mii_reg = 0; mii_reg < 8; mii_reg++)
+ printk(" %4.4x", mdio_read(ioaddr, tp->phys[0], mii_reg));
+ printk(".\n");
+ } else {
+ printk(KERN_DEBUG"%s: MII status register is %4.4x.\n",
+ dev->name, inw(ioaddr + BMSR));
+ }
+ /* Restart the chip Tx process. */
+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+ /* Continue from any transmit abort. */
+ outl((TX_DMA_BURST<<8) || 0x03000001, ioaddr + TxConfig);
+
+ dev->trans_start = jiffies;
+ tp->stats.tx_errors++;
+ return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+rtl8129_init_ring(struct device *dev)
+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int i;
+
+ tp->tx_full = 0;
+ tp->cur_rx = tp->cur_tx = 0;
+ tp->dirty_rx = tp->dirty_tx = 0;
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ tp->tx_skbuff[i] = 0;
+ tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
+ }
+}
+
+static int
+rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int entry;
+
+#ifndef final_version
+ if (skb == NULL || skb->len <= 0) {
+ printk(KERN_ERR"%s: Obsolete driver Tx request made: skbuff==NULL.\n",
+ dev->name);
+#if 0
+ dev_tint(dev);
+#endif
+ return 0;
+ }
+#endif
+
+ /* 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 (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (jiffies - dev->trans_start < TX_TIMEOUT)
+ return 1;
+ rtl8129_tx_timeout(dev);
+ return 1;
+ }
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % NUM_TX_DESC;
+
+ tp->tx_skbuff[entry] = skb;
+ if ((long)skb->data & 3) { /* Must use alignment buffer. */
+ memcpy(tp->tx_buf[entry], skb->data, skb->len);
+ outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4);
+ } else
+ outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
+ /* Note: the chip doesn't have auto-pad! */
+ outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
+ (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+ ioaddr + TxStat0 + entry*4);
+
+ if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+ dev->tbusy = 0;
+ } else {
+ tp->tx_full = 1;
+ }
+
+ dev->trans_start = jiffies;
+ if (rtl8129_debug > 4)
+ printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
+ dev->name, skb->data, skb->len, entry);
+
+ return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+static void rtl8129_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+{
+#ifdef SA_SHIRQ
+ struct device *dev = (struct device *)dev_instance;
+#else
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+ struct rtl8129_private *tp;
+ int ioaddr, boguscnt = max_interrupt_work;
+ int status;
+
+ if (dev == NULL) {
+ printk (KERN_ERR"rtl8139_interrupt(): IRQ %d for unknown device.\n",
+ irq);
+ return;
+ }
+
+ ioaddr = dev->base_addr;
+ tp = (struct rtl8129_private *)dev->priv;
+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+ printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+ return;
+ }
+
+ do {
+ status = inw(ioaddr + IntrStatus);
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outw(status, ioaddr + IntrStatus);
+
+ if (rtl8129_debug > 4)
+ printk(KERN_DEBUG"%s: interrupt status=%#4.4x new intstat=%#4.4x.\n",
+ dev->name, status, inw(ioaddr + IntrStatus));
+
+ if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver
+ |TxErr|TxOK|RxErr|RxOK)) == 0)
+ break;
+
+ if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */
+ rtl8129_rx(dev);
+
+ if (status & (TxOK | TxErr)) {
+ unsigned int dirty_tx;
+
+ for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
+ int entry = dirty_tx % NUM_TX_DESC;
+ int txstatus = inl(ioaddr + TxStat0 + entry*4);
+
+ if ( ! (txstatus & TxHostOwns))
+ break; /* It still hasn't been Txed */
+
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ if (txstatus & (TxOutOfWindow | TxAborted)) {
+ /* There was an major error, log it. */
+#ifndef final_version
+ if (rtl8129_debug > 1)
+ printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, txstatus);
+#endif
+ tp->stats.tx_errors++;
+ if (txstatus&TxAborted) {
+ tp->stats.tx_aborted_errors++;
+ outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);
+ }
+ if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;
+ if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;
+#ifdef ETHER_STATS
+ if ((txstatus & 0x0f000000) == 0x0f000000)
+ tp->stats.collisions16++;
+#endif
+ } else {
+#ifdef ETHER_STATS
+ /* No count for tp->stats.tx_deferred */
+#endif
+ if (txstatus & TxUnderrun) {
+ /* Todo: increase the Tx FIFO threshold. */
+ tp->stats.tx_fifo_errors++;
+ }
+ tp->stats.collisions += (txstatus >> 24) & 15;
+ tp->stats.tx_packets++;
+ }
+
+ /* Free the original skb. */
+ dev_kfree_skb(tp->tx_skbuff[entry]);
+ tp->tx_skbuff[entry] = 0;
+ }
+
+#ifndef final_version
+ if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+ printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+ dirty_tx += NUM_TX_DESC;
+ }
+#endif
+
+ if (tp->tx_full && dev->tbusy
+ && dirty_tx > tp->cur_tx - NUM_TX_DESC) {
+ /* The ring is no longer full, clear tbusy. */
+ tp->tx_full = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+
+ tp->dirty_tx = dirty_tx;
+ }
+
+ /* Check uncommon events with one test. */
+ if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
+ |TxErr|RxErr)) {
+
+#ifndef final_version
+ if (rtl8129_debug > 0)
+ printk(KERN_DEBUG"%s: Unusual error, status %4.4x.\n",
+ dev->name, status);
+#endif
+
+ /* Update the error count. */
+ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+ outl(0, ioaddr + RxMissed);
+
+ if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+ tp->stats.rx_errors++;
+
+ if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
+ if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;
+ if (status & RxOverflow) {
+ tp->stats.rx_over_errors++;
+ tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
+ outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
+ }
+ /* Error sources cleared above. */
+ }
+ if (--boguscnt < 0) {
+ printk(KERN_WARNING"%s: Too much work at interrupt, "
+ "IntrStatus=0x%4.4x.\n",
+ dev->name, status);
+ /* Clear all interrupt sources. */
+ outw(0xffff, ioaddr + IntrStatus);
+ break;
+ }
+ } while (1);
+
+ if (rtl8129_debug > 3)
+ printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
+ dev->name, inl(ioaddr + IntrStatus));
+
+#ifndef final_version
+ /* Code that should never be run! Perhaps remove after testing.. */
+ {
+ static int stopit = 10;
+ if (dev->start == 0 && --stopit < 0) {
+ printk(KERN_ERR"%s: Emergency stop, looping startup interrupt.\n",
+ dev->name);
+ FREE_IRQ(irq, dev);
+ }
+ }
+#endif
+
+ dev->interrupt = 0;
+ return;
+}
+
+/* Todo: The data sheet doesn't describe the Rx ring at all, so I'm winging
+ it here until I have a chip to play with. 8/30/97 */
+static int
+rtl8129_rx(struct device *dev)
+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned char *rx_ring = tp->rx_ring;
+ u16 cur_rx = tp->cur_rx;
+
+ if (rtl8129_debug > 4)
+ printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n",
+ dev->name, cur_rx, inw(ioaddr + RxBufAddr),
+ inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
+
+ while ((inb(ioaddr + ChipCmd) & 1) == 0) {
+ u16 ring_offset = cur_rx % RX_BUF_LEN;
+ u32 rx_status = *(u32*)(rx_ring + ring_offset);
+ u16 rx_size = rx_status >> 16;
+
+ if (rtl8129_debug > 4) {
+ int i;
+ printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",
+ dev->name, rx_status, rx_size, cur_rx);
+ printk(KERN_DEBUG"%s: Frame contents ", dev->name);
+ for (i = 0; i < 70; i++)
+ printk(" %2.2x", rx_ring[ring_offset + i]);
+ printk(".\n");
+ }
+ if (rx_status & RxTooLong) {
+ if (rtl8129_debug > 0)
+ printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",
+ dev->name, rx_status);
+ tp->stats.rx_length_errors++;
+ } else if (rx_status &
+ (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
+ if (rtl8129_debug > 1)
+ printk(KERN_DEBUG"%s: Ethernet frame had errors,"
+ " status %4.4x.\n", dev->name, rx_status);
+ tp->stats.rx_errors++;
+ if (rx_status & (RxBadSymbol|RxBadAlign))
+ tp->stats.rx_frame_errors++;
+ if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;
+ if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
+ } else {
+ /* Malloc up new buffer, compatible with net-2e. */
+ /* Omit the four octet CRC from the length. */
+ struct sk_buff *skb;
+
+ skb = DEV_ALLOC_SKB(rx_size + 2);
+ if (skb == NULL) {
+ printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ /* We should check that some rx space is free.
+ If not, free one and mark stats->rx_dropped++. */
+ tp->stats.rx_dropped++;
+ break;
+ }
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP fields. */
+ if (ring_offset+rx_size+4 > RX_BUF_LEN) {
+ int semi_count = RX_BUF_LEN - ring_offset - 4;
+ memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
+ semi_count);
+ memcpy(skb_put(skb, rx_size-semi_count), rx_ring,
+ rx_size-semi_count);
+ if (rtl8129_debug > 4) {
+ int i;
+ printk(KERN_DEBUG"%s: Frame wrap @%d", dev->name, semi_count);
+ for (i = 0; i < 16; i++)
+ printk(" %2.2x", rx_ring[i]);
+ printk(".\n");
+ memset(rx_ring, 0xcc, 16);
+ }
+ } else
+ memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
+ rx_size);
+#if LINUX_VERSION_CODE >= 0x10300
+ skb->protocol = eth_type_trans(skb, dev);
+#else
+ skb->len = rx_size;
+#endif
+ netif_rx(skb);
+ tp->stats.rx_packets++;
+ }
+
+ cur_rx += rx_size + 4;
+ cur_rx = (cur_rx + 3) & ~3;
+ outw(cur_rx - 16, ioaddr + RxBufPtr);
+ }
+ if (rtl8129_debug > 4)
+ printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n",
+ dev->name, cur_rx, inw(ioaddr + RxBufAddr),
+ inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
+ tp->cur_rx = cur_rx;
+ return 0;
+}
+
+static int
+rtl8129_close(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int i;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ if (rtl8129_debug > 1)
+ printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
+ dev->name, inw(ioaddr + IntrStatus));
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ outw(0x0000, ioaddr + IntrMask);
+
+ /* Stop the chip's Tx and Rx DMA processes. */
+ outb(0x00, ioaddr + ChipCmd);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+ outl(0, ioaddr + RxMissed);
+
+ del_timer(&tp->timer);
+
+#ifdef SA_SHIRQ
+ free_irq(dev->irq, dev);
+#else
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = 0;
+#endif
+
+#ifndef final_version
+ /* Used to monitor rx ring overflow. */
+ for (i = 0; i < 16; i++)
+ if (tp->rx_ring[RX_BUF_LEN+i] != 0xcc) {
+ printk(KERN_WARNING"%s: Rx ring overflowed! Values are ",
+ dev->name);
+ for (i = 0; i < 16; i++)
+ printk(" %2.2x", tp->rx_ring[RX_BUF_LEN + i]);
+ printk(".\n");
+ break;
+ }
+#endif
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ if (tp->tx_skbuff[i])
+ dev_kfree_skb(tp->tx_skbuff[i]);
+ tp->tx_skbuff[i] = 0;
+ }
+ kfree(tp->rx_ring);
+ kfree(tp->tx_bufs);
+
+ /* Green! Put the chip in low-power mode. */
+ outb(0xC0, ioaddr + Cfg9346);
+ outb(0x03, ioaddr + Config1);
+ outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static struct enet_statistics *
+rtl8129_get_stats(struct device *dev)
+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if (dev->start) {
+ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+ outl(0, ioaddr + RxMissed);
+ }
+
+ return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ Note that we only use exclusion around actually queueing the
+ new frame, not around filling tp->setup_frame. This is non-deterministic
+ when re-entered but still correct. */
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+ N.B. Do not use for bulk data, use a table-based routine instead.
+ This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+ unsigned int crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+
+
+static void
+#ifdef NEW_MULTICAST
+set_rx_mode(struct device *dev)
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+{
+ int ioaddr = dev->base_addr;
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ unsigned char mc_filter[8]; /* Multicast hash filter */
+ int i;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ /* Unconditionally log net taps. */
+ printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ outb(0x0F, ioaddr + RxConfig);
+ } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter perfectly -- accept all multicasts. */
+ memset(mc_filter, 0xff, sizeof(mc_filter));
+ outb(0x0E, ioaddr + RxConfig);
+ } else if (dev->mc_count == 0) {
+ outb(0x0A, ioaddr + RxConfig);
+ return;
+ } else {
+ struct dev_mc_list *mclist;
+
+ memset(mc_filter, 0, sizeof(mc_filter));
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+ mc_filter);
+ }
+ /* ToDo: perhaps we need to stop the Tx and Rx process here? */
+ if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {
+ for (i = 0; i < 2; i++)
+ outl(((u32 *)mc_filter)[i], ioaddr + MAR0 + i*4);
+ memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));
+ }
+ if (rtl8129_debug > 3)
+ printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+ dev->name, dev->flags, inl(ioaddr + RxConfig));
+ return;
+}
+
+#ifdef MODULE
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+ int cards_found;
+
+ if (debug >= 0)
+ rtl8129_debug = debug;
+
+ root_rtl8129_dev = NULL;
+ cards_found = rtl8139_probe(0);
+
+ return cards_found ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+ struct device *next_dev;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ while (root_rtl8129_dev) {
+ next_dev = ((struct rtl8129_private *)root_rtl8129_dev->priv)->next_module;
+ unregister_netdev(root_rtl8129_dev);
+ release_region(root_rtl8129_dev->base_addr, RTL8129_TOTAL_SIZE);
+ kfree(root_rtl8129_dev);
+ root_rtl8129_dev = next_dev;
+ }
+}
+
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c
index 1186d587c..c8740a8d1 100644
--- a/drivers/net/sdla.c
+++ b/drivers/net/sdla.c
@@ -451,7 +451,7 @@ static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags,
save_flags(pflags);
cli();
SDLA_WINDOW(dev, window);
- waiting = ((volatile)(cmd_buf->opp_flag));
+ waiting = ((volatile int)(cmd_buf->opp_flag));
restore_flags(pflags);
}
}
@@ -565,11 +565,12 @@ int sdla_assoc(struct device *slave, struct device *master)
flp->dlci[i] = -*(short *)(master->dev_addr);
master->mtu = slave->mtu;
- if (slave->start)
+ if (slave->start) {
if (flp->config.station == FRAD_STATION_CPE)
sdla_reconfig(slave);
else
sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+ }
return(0);
}
@@ -593,11 +594,12 @@ int sdla_deassoc(struct device *slave, struct device *master)
MOD_DEC_USE_COUNT;
- if (slave->start)
+ if (slave->start) {
if (flp->config.station == FRAD_STATION_CPE)
sdla_reconfig(slave);
else
sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+ }
return(0);
}
@@ -622,13 +624,14 @@ int sdla_dlci_conf(struct device *slave, struct device *master, int get)
ret = SDLA_RET_OK;
len = sizeof(struct dlci_conf);
- if (slave->start)
+ if (slave->start) {
if (get)
ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
NULL, 0, &dlp->config, &len);
else
ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
&dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+ }
return(ret == SDLA_RET_OK ? 0 : -EIO);
}
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
index 36b74b90e..303fac4c1 100644
--- a/drivers/net/sdla_fr.c
+++ b/drivers/net/sdla_fr.c
@@ -53,7 +53,7 @@
* This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy)
* forever.
* The code got into this stage due to an
-* interrupt occuring within the if clause for
+* interrupt occurring within the if clause for
* set_bit(0,dev->tbusy). Since an interrupt
* disables furhter transmit interrupt and
* makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause.
@@ -1224,7 +1224,7 @@ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_
} /* switch_net_numbers */
/*============================================================================
- * Get ethernet-style interface statistics.
+ * Get Ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
@@ -2158,7 +2158,7 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
/****** Firmware Asynchronous Event Handlers ********************************/
/*============================================================================
- * Main asyncronous event/error handler.
+ * Main asynchronous event/error handler.
* This routine is called whenever firmware command returns non-zero
* return code.
*
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
index fa4f98d61..6b15441b5 100644
--- a/drivers/net/sdla_ppp.c
+++ b/drivers/net/sdla_ppp.c
@@ -841,7 +841,7 @@ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_
} /* switch_net_numbers */
/*============================================================================
- * Get ethernet-style interface statistics.
+ * Get Ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
@@ -2183,7 +2183,7 @@ static int intr_test(sdla_t * card)
{
ppp_mbox_t *mb = card->mbox;
int err, i;
- /* The critical flag is unset because during intialization (if_open)
+ /* The critical flag is unset because during initialization (if_open)
* we want the interrupts to be enabled so that when the wpp_isr is
* called it does not exit due to critical flag set.
*/
diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
index af7d31844..77567ebcc 100644
--- a/drivers/net/sdla_x25.c
+++ b/drivers/net/sdla_x25.c
@@ -167,7 +167,7 @@ static int x25_fetch_events (sdla_t* card);
static int x25_error (sdla_t* card, int err, int cmd, int lcn);
/* X.25 asynchronous event handlers */
-static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
@@ -822,7 +822,7 @@ tx_done:
}
/*============================================================================
- * Get ethernet-style interface statistics.
+ * Get Ethernet-style interface statistics.
* Return a pointer to struct net_device_stats
*/
@@ -1177,7 +1177,7 @@ static void poll_active (sdla_t* card)
/* If there is a packet queued for transmission then kick
* the channel's send routine. When transmission is complete
- * or if error has occured, release socket buffer and reset
+ * or if error has occurred, release socket buffer and reset
* 'tbusy' flag.
*/
if (skb && (chan_send(dev, skb) == 0))
@@ -1204,8 +1204,8 @@ static void poll_active (sdla_t* card)
/****** SDLA Firmware-Specific Functions *************************************
* Almost all X.25 commands can unexpetedly fail due to so called 'X.25
- * asynchronous events' such as restart, interrupt, incomming call request,
- * call clear request, etc. They can't be ignored and have to be delt with
+ * asynchronous events' such as restart, interrupt, incoming call request,
+ * call clear request, etc. They can't be ignored and have to be dealt with
* immediately. To tackle with this problem we execute each interface command
* in a loop until good return code is received or maximum number of retries
* is reached. Each interface command returns non-zero return code, an
@@ -1643,8 +1643,8 @@ static int x25_error (sdla_t* card, int err, int cmd, int lcn)
mb->data[dlen] = '\0';
switch (mb->cmd.pktType & 0x7F)
{
- case 0x30: /* incomming call */
- retry = incomming_call(card, cmd, lcn, mb);
+ case 0x30: /* incoming call */
+ retry = incoming_call(card, cmd, lcn, mb);
break;
case 0x31: /* connected */
@@ -1728,7 +1728,7 @@ static int x25_error (sdla_t* card, int err, int cmd, int lcn)
*/
/*============================================================================
- * Handle X.25 incomming call request.
+ * Handle X.25 incoming call request.
* RFC 1356 establishes the following rules:
* 1. The first octet in the Call User Data (CUD) field of the call
* request packet contains NLPID identifying protocol encapsulation.
@@ -1736,12 +1736,12 @@ static int x25_error (sdla_t* card, int err, int cmd, int lcn)
* protocol encapsulation.
* 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when
* clearing a call because protocol encapsulation is not supported.
- * 4. If an incomming call is received while a call request is pending
- * (i.e. call collision has occured), the incomming call shall be
+ * 4. If an incoming call is received while a call request is pending
+ * (i.e. call collision has occurred), the incoming call shall be
* rejected and call request shall be retried.
*/
-static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
wan_device_t* wandev = &card->wandev;
int new_lcn = mb->cmd.lcn;
@@ -1754,7 +1754,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
if (dev != NULL)
{
printk(KERN_INFO
- "%s: X.25 incomming call collision on LCN %d!\n",
+ "%s: X.25 incoming call collision on LCN %d!\n",
card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
return 1;
@@ -1764,7 +1764,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
if (mb->cmd.qdm & 0x02)
{
printk(KERN_INFO
- "%s: X.25 incomming call on LCN %d with D-bit set!\n",
+ "%s: X.25 incoming call on LCN %d with D-bit set!\n",
card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
return 1;
@@ -1775,13 +1775,13 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
if (info == NULL)
{
printk(KERN_ERR
- "%s: not enough memory to parse X.25 incomming call "
+ "%s: not enough memory to parse X.25 incoming call "
"on LCN %d!\n", card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
return 1;
}
parse_call_info(mb->data, info);
- printk(KERN_INFO "%s: X.25 incomming call on LCN %d! Call data: %s\n",
+ printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n",
card->devname, new_lcn, mb->data);
/* Find available channel */
@@ -1793,7 +1793,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
continue;
if (strcmp(info->src, chan->addr) == 0)
break;
- /* If just an '@' is specified, accept all incomming calls */
+ /* If just an '@' is specified, accept all incoming calls */
if (strcmp(chan->addr, "") == 0)
break;
}
@@ -1809,7 +1809,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
else if (info->nuser == 0)
{
printk(KERN_INFO
- "%s: no user data in incomming call on LCN %d!\n",
+ "%s: no user data in incoming call on LCN %d!\n",
card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
}
@@ -1831,7 +1831,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
break;
default:
printk(KERN_INFO
- "%s: unsupported NLPID 0x%02X in incomming call "
+ "%s: unsupported NLPID 0x%02X in incoming call "
"on LCN %d!\n", card->devname, info->user[0], new_lcn);
x25_clear_call(card, new_lcn, 0, 249);
}
diff --git a/drivers/net/sdladrv.c b/drivers/net/sdladrv.c
index 3adc0ba8e..baa18b3d4 100644
--- a/drivers/net/sdladrv.c
+++ b/drivers/net/sdladrv.c
@@ -495,7 +495,7 @@ int sdla_down (sdlahw_t* hw)
}
/*============================================================================
- * Map shared memory window into SDLA adress space.
+ * Map shared memory window into SDLA address space.
*/
EXPORT_SYMBOL(sdla_mapmem);
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 6dbaec6d2..b571dc28c 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -372,6 +372,7 @@ static int
seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
{
int ioaddr = dev->base_addr;
+ struct net_local *lp = (struct net_local *)dev->priv;
if (dev->tbusy) {
/* If we get here, some higher level has decided we are broken.
@@ -397,6 +398,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
hardware_send_packet(dev, buf, length);
dev->trans_start = jiffies;
+ lp->stats.tx_bytes += length;
}
dev_kfree_skb (skb);
@@ -547,6 +549,7 @@ seeq8005_rx(struct device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
}
} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 82f75efbb..ada43b198 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,11 +1,9 @@
-/*
+/* $Id: sgiseeq.c,v 1.3 1997/11/16 13:57:45 alan Exp $
+ *
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: sgiseeq.c,v 1.3 1997/11/16 13:57:45 alan Exp $
*/
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -695,6 +693,7 @@ int sgiseeq_init(struct device *dev, struct sgiseeq_regs *sregs,
dev->irq = irq;
dev->dma = 0;
ether_setup(dev);
+
return 0;
}
@@ -724,15 +723,20 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str)
int sgiseeq_probe(struct device *dev)
{
+ static int initialized;
char *ep;
+ if (initialized) /* Already initialized? */
+ return 0;
+ initialized++;
+
/* First get the ethernet address of the onboard
* interface from ARCS.
+ * (This is fragile; PROM doesn't like running from cache.)
*/
ep = romvec->get_evar("eaddr");
str2eaddr(onboard_eth_addr, ep);
return sgiseeq_init(dev,
(struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),
&hpc3c0->ethregs, 3);
-
}
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index e536318a1..9879f3de0 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -128,6 +128,7 @@ static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb)
static void shaper_setspeed(struct shaper *shaper, int bitspersec)
{
+ shaper->bitspersec=bitspersec;
shaper->bytespertick=(bitspersec/HZ)/8;
if(!shaper->bytespertick)
shaper->bytespertick++;
@@ -326,7 +327,8 @@ static void shaper_kick(struct shaper *shaper)
*/
skb_unlink(skb);
- shaper->recovery=jiffies+skb->shapelen;
+ if (shaper->recovery < skb->shapeclock + skb->shapelen)
+ shaper->recovery = skb->shapeclock + skb->shapelen;
restore_flags(flags);
/*
@@ -548,18 +550,28 @@ static int shaper_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
{
struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data;
struct shaper *sh=dev->priv;
- struct device *them=dev_get(ss->ss_name);
switch(ss->ss_cmd)
{
case SHAPER_SET_DEV:
+ {
+ struct device *them=dev_get(ss->ss_name);
if(them==NULL)
return -ENODEV;
if(sh->dev)
return -EBUSY;
return shaper_attach(dev,dev->priv, them);
+ }
+ case SHAPER_GET_DEV:
+ if(sh->dev==NULL)
+ return -ENODEV;
+ memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+ return 0;
case SHAPER_SET_SPEED:
shaper_setspeed(sh,ss->ss_speed);
return 0;
+ case SHAPER_GET_SPEED:
+ ss->ss_speed=sh->bitspersec;
+ return 0;
default:
return -EINVAL;
}
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 4dbaad977..ac6736cab 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -1250,6 +1250,8 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev)
*/
dev->tbusy = 0;
}
+
+ p->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
return 0;
@@ -1585,6 +1587,7 @@ static void SK_rxintr(struct device *dev)
writeb(RX_OWN, rmdp->u.s.status);
p->stats.rx_packets++;
+ p->stats.rx_bytes += len;
p->rmdnum++;
@@ -1808,7 +1811,7 @@ __initfunc(unsigned int SK_rom_addr(void))
void SK_reset_board(void)
{
writeb(0x00, SK_PORT); /* Reset active */
- udelay(5000); /* Delay min 5ms */
+ mdelay(5); /* Delay min 5ms */
writeb(SK_RESET, SK_PORT); /* Set back to normal operation */
} /* End of SK_reset_board() */
@@ -2002,7 +2005,7 @@ void SK_print_dev(struct device *dev, char *text)
printk("## Device Name: %s Base Address: %#06lx IRQ: %d\n",
dev->name, dev->base_addr, dev->irq);
- printk("## FLAGS: start: %d tbusy: %ld int: %d\n",
+ printk("## FLAGS: start: %d tbusy: %ld int: %ld\n",
dev->start, dev->tbusy, dev->interrupt);
printk("## next device: %#08x init function: %#08x\n",
diff --git a/drivers/net/sktr.c b/drivers/net/sktr.c
new file mode 100644
index 000000000..828807033
--- /dev/null
+++ b/drivers/net/sktr.c
@@ -0,0 +1,2695 @@
+/*
+ * sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters.
+ *
+ * Written 1997 by Christoph Goos
+ *
+ * A fine result of the Linux Systems Network Architecture Project.
+ * http://samba.anu.edu.au/linux-sna/
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * This device driver works with the following SysKonnect adapters:
+ * - SysKonnect TR4/16(+) ISA (SK-4190)
+ * - SysKonnect TR4/16(+) PCI (SK-4590)
+ * - SysKonnect TR4/16 PCI (SK-4591)
+ *
+ * Sources:
+ * - The hardware related parts of this driver are take from
+ * the SysKonnect Token Ring driver for Windows NT.
+ * - I used the IBM Token Ring driver 'ibmtr.c' as a base for this
+ * driver, as well as the 'skeleton.c' driver by Donald Becker.
+ * - Also various other drivers in the linux source tree were taken
+ * as samples for some tasks.
+ *
+ * Maintainer(s):
+ * JS Jay Schulist jschlst@samba.anu.edu.au
+ * CG Christoph Goos cgoos@syskonnect.de
+ *
+ * Modification History:
+ * 29-Aug-97 CG Created
+ * 04-Apr-98 CG Fixed problems caused by tok_timer_check
+ * 10-Apr-98 CG Fixed lockups at cable disconnection
+ * 27-May-98 JS Formated to Linux Kernel Format
+ * 31-May-98 JS Hacked in PCI support
+ * 16-Jun-98 JS Modulized for multiple cards with one driver
+ *
+ * To do:
+ * 1. Selectable 16 Mbps or 4Mbps
+ * 2. Multi/Broadcast packet handling
+ *
+ */
+
+static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n";
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/trdevice.h>
+
+#include "sktr.h" /* Our Stuff */
+#include "sktr_firmware.h" /* SysKonnect adapter firmware */
+
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int sktr_portlist[] __initdata = {
+ 0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,
+ 0
+};
+
+/* A zero-terminated list of IRQs to be probed.
+ * Used again after initial probe for sktr_chipset_init, called from sktr_open.
+ */
+static unsigned short sktr_irqlist[] = {
+ 3, 5, 9, 10, 11, 12, 15,
+ 0
+};
+
+/* A zero-terminated list of DMAs to be probed. */
+static int sktr_dmalist[] __initdata = {
+ 5, 6, 7,
+ 0
+};
+
+/* Card names */
+static char *pci_cardname = "SK NET TR 4/16 PCI\0";
+static char *isa_cardname = "SK NET TR 4/16 ISA\0";
+static char *AdapterName;
+
+/* Use 0 for production, 1 for verification, 2 for debug, and
+ * 3 for very verbose debug.
+ */
+#ifndef SKTR_DEBUG
+#define SKTR_DEBUG 1
+#endif
+static unsigned int sktr_debug = SKTR_DEBUG;
+
+/* The number of low I/O ports used by the tokencard. */
+#define SKTR_IO_EXTENT 32
+
+/* Index to functions, as function prototypes.
+ * Alphabetical by function name.
+ */
+
+/* "B" */
+static int sktr_bringup_diags(struct device *dev);
+/* "C" */
+static void sktr_cancel_tx_queue(struct net_local* tp);
+static int sktr_chipset_init(struct device *dev);
+static void sktr_chk_irq(struct device *dev);
+static unsigned char sktr_chk_frame(struct device *dev, unsigned char *Addr);
+static void sktr_chk_outstanding_cmds(struct device *dev);
+static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);
+static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType);
+static int sktr_close(struct device *dev);
+static void sktr_cmd_status_irq(struct device *dev);
+/* "D" */
+static void sktr_disable_interrupts(struct device *dev);
+static void sktr_dump(unsigned char *Data, int length);
+/* "E" */
+static void sktr_enable_interrupts(struct device *dev);
+static void sktr_exec_cmd(struct device *dev, unsigned short Command);
+static void sktr_exec_sifcmd(struct device *dev, unsigned int WriteValue);
+/* "F" */
+static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen);
+/* "G" */
+static struct enet_statistics *sktr_get_stats(struct device *dev);
+/* "H" */
+static void sktr_hardware_send_packet(struct device *dev,
+ struct net_local* tp);
+/* "I" */
+static int sktr_init_adapter(struct device *dev);
+static int sktr_init_card(struct device *dev);
+static void sktr_init_ipb(struct net_local *tp);
+static void sktr_init_net_local(struct device *dev);
+static void sktr_init_opb(struct net_local *tp);
+static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int sktr_isa_chk_card(struct device *dev, int ioaddr);
+static int sktr_isa_chk_ioaddr(int ioaddr);
+/* "O" */
+static int sktr_open(struct device *dev);
+static void sktr_open_adapter(struct device *dev);
+/* "P" */
+static int sktr_pci_chk_card(struct device *dev);
+int sktr_probe(struct device *dev);
+static int sktr_probe1(struct device *dev, int ioaddr);
+/* "R" */
+static void sktr_rcv_status_irq(struct device *dev);
+static void sktr_read_addr(struct device *dev, unsigned char *Address);
+static void sktr_read_ptr(struct device *dev);
+static void sktr_read_ram(struct device *dev, unsigned char *Data,
+ unsigned short Address, int Length);
+static int sktr_reset_adapter(struct device *dev);
+static void sktr_reset_interrupt(struct device *dev);
+static void sktr_ring_status_irq(struct device *dev);
+/* "S" */
+static int sktr_send_packet(struct sk_buff *skb, struct device *dev);
+static void sktr_set_multicast_list(struct device *dev);
+/* "T" */
+static void sktr_timer_chk(unsigned long data);
+static void sktr_timer_end_wait(unsigned long data);
+static void sktr_tx_status_irq(struct device *dev);
+/* "U" */
+static void sktr_update_rcv_stats(struct net_local *tp,
+ unsigned char DataPtr[], unsigned int Length);
+/* "W" */
+static void sktr_wait(unsigned long time);
+static void sktr_write_rpl_status(RPL *rpl, unsigned int Status);
+static void sktr_write_tpl_status(TPL *tpl, unsigned int Status);
+
+/*
+ * Check for a network adapter of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ */
+__initfunc(int sktr_probe(struct device *dev))
+{
+ int i;
+ int base_addr = dev ? dev->base_addr : 0;
+
+ if(base_addr > 0x1ff) /* Check a single specified location. */
+ return (sktr_probe1(dev, base_addr));
+ else if(base_addr != 0) /* Don't probe at all. */
+ return (-ENXIO);
+
+ for(i = 0; sktr_portlist[i]; i++)
+ {
+ int ioaddr = sktr_portlist[i];
+ if(check_region(ioaddr, SKTR_IO_EXTENT))
+ continue;
+ if(sktr_probe1(dev, ioaddr))
+ {
+#ifndef MODULE
+ tr_freedev(dev);
+#endif
+ }
+ else
+ return (0);
+ }
+
+ return (-ENODEV);
+}
+
+/*
+ * Detect and setup the PCI SysKonnect TR cards in slot order.
+ */
+__initfunc(static int sktr_pci_chk_card(struct device *dev))
+{
+ static int pci_index = 0;
+ unsigned char pci_bus, pci_device_fn;
+
+ if(!pci_present())
+ return (-1); /* No PCI present. */
+
+ for(; pci_index < 0xff; pci_index++)
+ {
+ unsigned int pci_irq_line;
+ struct pci_dev *pdev;
+ unsigned short pci_command, new_command, vendor, device;
+ unsigned int pci_ioaddr;
+
+ if(pcibios_find_class(PCI_CLASS_NETWORK_TOKEN_RING << 8,
+ pci_index, &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ {
+ break;
+ }
+
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+
+ pdev = pci_find_slot(pci_bus, pci_device_fn);
+ pci_irq_line = pdev->irq;
+ pci_ioaddr = pdev->base_address[0];
+
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
+
+ if(vendor != PCI_VENDOR_ID_SK)
+ continue;
+ if(device != PCI_DEVICE_ID_SK_TR)
+ continue;
+ if(check_region(pci_ioaddr, SKTR_IO_EXTENT))
+ continue;
+ request_region(pci_ioaddr, SKTR_IO_EXTENT, pci_cardname);
+ if(request_irq(pdev->irq, sktr_interrupt, SA_SHIRQ,
+ pci_cardname, dev))
+ return (-ENODEV); /* continue; ?? */
+
+ AdapterName = pci_cardname;
+
+ new_command = (pci_command|PCI_COMMAND_MASTER|PCI_COMMAND_IO);
+
+ if(pci_command != new_command)
+ {
+ printk("The PCI BIOS has not enabled this"
+ "device! Updating PCI command %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);
+ }
+
+ /* At this point we have found a valid PCI TR card. */
+ dev->base_addr = pci_ioaddr;
+ dev->irq = pci_irq_line;
+ dev->dma = 0;
+
+ printk("%s: %s found at %#4x, using IRQ %d.\n",
+ dev->name, AdapterName, pci_ioaddr, dev->irq);
+
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * Detect and setup the ISA SysKonnect TR cards.
+ */
+__initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr))
+{
+ int i, err;
+
+ err = sktr_isa_chk_ioaddr(ioaddr);
+ if(err < 0)
+ return (-ENODEV);
+
+ if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local)))
+ > ISA_MAX_ADDRESS)
+ {
+ printk("%s: Memory not accessible for DMA\n", dev->name);
+ kfree(dev->priv);
+ return (-EAGAIN);
+ }
+
+ AdapterName = isa_cardname;
+
+ /* Grab the region so that no one else tries to probe our ioports. */
+ request_region(ioaddr, SKTR_IO_EXTENT, AdapterName);
+ dev->base_addr = ioaddr;
+
+ /* Autoselect IRQ and DMA if dev->irq == 0 */
+ if(dev->irq == 0)
+ {
+ for(i = 0; sktr_irqlist[i] != 0; i++)
+ {
+ dev->irq = sktr_irqlist[i];
+ err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);
+ if(!err)
+ break;
+ }
+
+ if(sktr_irqlist[i] == 0)
+ {
+ printk("%s: AutoSelect no IRQ available\n", dev->name);
+ return (-EAGAIN);
+ }
+ }
+ else
+ {
+ err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);
+ if(err)
+ {
+ printk("%s: Selected IRQ not available\n", dev->name);
+ return (-EAGAIN);
+ }
+ }
+
+ /* Always allocate the DMA channel after IRQ and clean up on failure */
+ if(dev->dma == 0)
+ {
+ for(i = 0; sktr_dmalist[i] != 0; i++)
+ {
+ dev->dma = sktr_dmalist[i];
+ err = request_dma(dev->dma, AdapterName);
+ if(!err)
+ break;
+ }
+
+ if(dev->dma == 0)
+ {
+ printk("%s: AutoSelect no DMA available\n", dev->name);
+ free_irq(dev->irq, NULL);
+ return (-EAGAIN);
+ }
+ }
+ else
+ {
+ err = request_dma(dev->dma, AdapterName);
+ if(err)
+ {
+ printk("%s: Selected DMA not available\n", dev->name);
+ free_irq(dev->irq, NULL);
+ return (-EAGAIN);
+ }
+ }
+
+ disable_dma(dev->dma);
+ set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+ enable_dma(dev->dma);
+
+ printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n",
+ dev->name, AdapterName, ioaddr, dev->irq, dev->dma);
+
+ return (0);
+}
+
+__initfunc(static int sktr_probe1(struct device *dev, int ioaddr))
+{
+ static unsigned version_printed = 0;
+ struct net_local *tp;
+ int err;
+
+ if(sktr_debug && version_printed++ == 0)
+ printk("%s", version);
+
+#ifndef MODULE
+ dev = init_trdev(dev, 0);
+ if(dev == NULL)
+ return (-ENOMEM);
+#endif
+
+ err = sktr_pci_chk_card(dev);
+ if(err < 0)
+ {
+ err = sktr_isa_chk_card(dev, ioaddr);
+ if(err < 0)
+ return (-ENODEV);
+ }
+
+ /* Setup this devices private information structure */
+ tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);
+ if(tp == NULL)
+ return (-ENOMEM);
+ memset(tp, 0, sizeof(struct net_local));
+
+ dev->priv = tp;
+ dev->init = sktr_init_card;
+ dev->open = sktr_open;
+ dev->stop = sktr_close;
+ dev->hard_start_xmit = sktr_send_packet;
+ dev->get_stats = sktr_get_stats;
+ dev->set_multicast_list = &sktr_set_multicast_list;
+
+ return (0);
+}
+
+/* Dummy function */
+__initfunc(static int sktr_init_card(struct device *dev))
+{
+ if(sktr_debug > 3)
+ printk("%s: sktr_init_card\n", dev->name);
+
+ return (0);
+}
+
+/*
+ * This function tests if an adapter is really installed at the
+ * given I/O address. Return negative if no adapter at IO addr.
+ */
+__initfunc(static int sktr_isa_chk_ioaddr(int ioaddr))
+{
+ unsigned char old, chk1, chk2;
+
+ old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */
+
+ chk1 = 0; /* Begin with check value 0 */
+ do {
+ /* Write new SIFADR value */
+ outb(chk1, ioaddr + SIFADR);
+
+ /* Read, invert and write */
+ chk2 = inb(ioaddr + SIFADD);
+ chk2 ^= 0x0FE;
+ outb(chk2, ioaddr + SIFADR);
+
+ /* Read, invert and compare */
+ chk2 = inb(ioaddr + SIFADD);
+ chk2 ^= 0x0FE;
+
+ if(chk1 != chk2)
+ return (-1); /* No adapter */
+
+ chk1 -= 2;
+ } while(chk1 != 0); /* Repeat 128 times (all byte values) */
+
+ /* Restore the SIFADR value */
+ outb(old, ioaddr + SIFADR);
+
+ return (0);
+}
+
+/*
+ * Open/initialize the board. This is called sometime after
+ * booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int sktr_open(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ int err;
+
+ /* Reset the hardware here. Don't forget to set the station address. */
+ err = sktr_chipset_init(dev);
+ if(err)
+ {
+ printk(KERN_INFO "%s: Chipset initialization error\n",
+ dev->name);
+ return (-1);
+ }
+
+ dev->addr_len = 6;
+ sktr_read_addr(dev, (unsigned char*)dev->dev_addr);
+
+ init_timer(&tp->timer);
+ tp->timer.expires = jiffies + 30*HZ;
+ tp->timer.function = sktr_timer_end_wait;
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.next = NULL;
+ tp->timer.prev = NULL;
+ add_timer(&tp->timer);
+
+ sktr_read_ptr(dev);
+ sktr_enable_interrupts(dev);
+ sktr_open_adapter(dev);
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 0;
+
+ /* Wait for interrupt from hardware. If interrupt does not come,
+ * there will be a timeout from the timer.
+ */
+ tp->Sleeping = 1;
+ interruptible_sleep_on(&tp->wait_for_tok_int);
+ del_timer(&tp->timer);
+
+ /* If AdapterVirtOpenFlag is 1, the adapter is now open for use */
+ if(tp->AdapterVirtOpenFlag == 0)
+ {
+ sktr_disable_interrupts(dev);
+ return (-1);
+ }
+
+ dev->start = 1;
+
+ tp->StartTime = jiffies;
+
+ /* Start function control timer */
+ tp->timer.expires = jiffies + 2*HZ;
+ tp->timer.function = sktr_timer_chk;
+ tp->timer.data = (unsigned long)dev;
+ add_timer(&tp->timer);
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ return (0);
+}
+
+/*
+ * Timeout function while waiting for event
+ */
+static void sktr_timer_end_wait(unsigned long data)
+{
+ struct device *dev = (struct device*)data;
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ if(tp->Sleeping)
+ {
+ tp->Sleeping = 0;
+ wake_up_interruptible(&tp->wait_for_tok_int);
+ }
+
+ return;
+}
+
+/*
+ * Initialize the chipset
+ */
+static int sktr_chipset_init(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned char PosReg, Tmp;
+ int i, err;
+
+ sktr_init_ipb(tp);
+ sktr_init_opb(tp);
+ sktr_init_net_local(dev);
+
+ /* Set pos register: selects irq and dma channel.
+ * Only for ISA bus adapters.
+ */
+ if(dev->dma > 0)
+ {
+ PosReg = 0;
+ for(i = 0; sktr_irqlist[i] != 0; i++)
+ {
+ if(sktr_irqlist[i] == dev->irq)
+ break;
+ }
+
+ /* Choose default cycle time, 500 nsec */
+ PosReg |= CYCLE_TIME << 2;
+ PosReg |= i << 4;
+ i = dev->dma - 5;
+ PosReg |= i;
+
+ if(tp->DataRate == SPEED_4)
+ PosReg |= LINE_SPEED_BIT;
+ else
+ PosReg &= ~LINE_SPEED_BIT;
+
+ outb(PosReg, dev->base_addr + POSREG);
+ Tmp = inb(dev->base_addr + POSREG);
+ if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME))
+ printk(KERN_INFO "%s: POSREG error\n", dev->name);
+ }
+
+ err = sktr_reset_adapter(dev);
+ if(err < 0)
+ return (-1);
+
+ err = sktr_bringup_diags(dev);
+ if(err < 0)
+ return (-1);
+
+ err = sktr_init_adapter(dev);
+ if(err < 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Initializes the net_local structure.
+ */
+static void sktr_init_net_local(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ int i;
+
+ tp->scb.CMD = 0;
+ tp->scb.Parm[0] = 0;
+ tp->scb.Parm[1] = 0;
+
+ tp->ssb.STS = 0;
+ tp->ssb.Parm[0] = 0;
+ tp->ssb.Parm[1] = 0;
+ tp->ssb.Parm[2] = 0;
+
+ tp->CMDqueue = 0;
+
+ tp->AdapterOpenFlag = 0;
+ tp->AdapterVirtOpenFlag = 0;
+ tp->ScbInUse = 0;
+ tp->OpenCommandIssued = 0;
+ tp->ReOpenInProgress = 0;
+ tp->HaltInProgress = 0;
+ tp->TransmitHaltScheduled = 0;
+ tp->LobeWireFaultLogged = 0;
+ tp->LastOpenStatus = 0;
+ tp->MaxPacketSize = DEFAULT_PACKET_SIZE;
+
+ skb_queue_head_init(&tp->SendSkbQueue);
+ tp->QueueSkb = MAX_TX_QUEUE;
+
+ /* Create circular chain of transmit lists */
+ for (i = 0; i < TPL_NUM; i++)
+ {
+ tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM]));
+ tp->Tpl[i].Status = 0;
+ tp->Tpl[i].FrameSize = 0;
+ tp->Tpl[i].FragList[0].DataCount = 0;
+ tp->Tpl[i].FragList[0].DataAddr = 0;
+ tp->Tpl[i].NextTPLPtr = &tp->Tpl[(i+1) % TPL_NUM];
+ tp->Tpl[i].MData = NULL;
+ tp->Tpl[i].TPLIndex = i;
+ tp->Tpl[i].BusyFlag = 0;
+ }
+
+ tp->TplFree = tp->TplBusy = &tp->Tpl[0];
+
+ /* Create circular chain of receive lists */
+ for (i = 0; i < RPL_NUM; i++)
+ {
+ tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM]));
+ tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
+ tp->Rpl[i].FrameSize = 0;
+ tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize);
+
+ /* Alloc skb and point adapter to data area */
+ tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);
+
+ /* skb == NULL ? then use local buffer */
+ if(tp->Rpl[i].Skb == NULL)
+ {
+ tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;
+ tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+ tp->Rpl[i].MData = tp->LocalRxBuffers[i];
+ }
+ else /* SKB != NULL */
+ {
+ tp->Rpl[i].Skb->dev = dev;
+ skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
+
+ /* data unreachable for DMA ? then use local buffer */
+ if(virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS)
+ {
+ tp->Rpl[i].SkbStat = SKB_DATA_COPY;
+ tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+ tp->Rpl[i].MData = tp->LocalRxBuffers[i];
+ }
+ else /* DMA directly in skb->data */
+ {
+ tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;
+ tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data));
+ tp->Rpl[i].MData = tp->Rpl[i].Skb->data;
+ }
+ }
+
+ tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM];
+ tp->Rpl[i].RPLIndex = i;
+ }
+
+ tp->RplHead = &tp->Rpl[0];
+ tp->RplTail = &tp->Rpl[RPL_NUM-1];
+ tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
+
+ return;
+}
+
+/*
+ * Initializes the initialisation parameter block.
+ */
+static void sktr_init_ipb(struct net_local *tp)
+{
+ tp->ipb.Init_Options = BURST_MODE;
+ tp->ipb.CMD_Status_IV = 0;
+ tp->ipb.TX_IV = 0;
+ tp->ipb.RX_IV = 0;
+ tp->ipb.Ring_Status_IV = 0;
+ tp->ipb.SCB_Clear_IV = 0;
+ tp->ipb.Adapter_CHK_IV = 0;
+ tp->ipb.RX_Burst_Size = BURST_SIZE;
+ tp->ipb.TX_Burst_Size = BURST_SIZE;
+ tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES;
+ tp->ipb.SCB_Addr = 0;
+ tp->ipb.SSB_Addr = 0;
+
+ return;
+}
+
+/*
+ * Initializes the open parameter block.
+ */
+static void sktr_init_opb(struct net_local *tp)
+{
+ unsigned long Addr;
+ unsigned short RplSize = RPL_SIZE;
+ unsigned short TplSize = TPL_SIZE;
+ unsigned short BufferSize = BUFFER_SIZE;
+
+ tp->ocpl.OPENOptions = 0;
+ tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION;
+ tp->ocpl.OPENOptions |= PAD_ROUTING_FIELD;
+ tp->ocpl.FullDuplex = 0;
+ tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF;
+
+ /* Fixme: If mac address setable:
+ * for (i=0; i<LENGTH_OF_ADDRESS; i++)
+ * mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i];
+ */
+
+ tp->ocpl.GroupAddr = 0;
+ tp->ocpl.FunctAddr = 0;
+ tp->ocpl.RxListSize = SWAPB(RplSize);
+ tp->ocpl.TxListSize = SWAPB(TplSize);
+ tp->ocpl.BufSize = SWAPB(BufferSize);
+ tp->ocpl.Reserved = 0;
+ tp->ocpl.TXBufMin = TX_BUF_MIN;
+ tp->ocpl.TXBufMax = TX_BUF_MAX;
+
+ Addr = htonl(virt_to_bus(tp->ProductID));
+
+ tp->ocpl.ProdIDAddr[0] = LOWORD(Addr);
+ tp->ocpl.ProdIDAddr[1] = HIWORD(Addr);
+
+ return;
+}
+
+/*
+ * Send OPEN command to adapter
+ */
+static void sktr_open_adapter(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ if(tp->OpenCommandIssued)
+ return;
+
+ tp->OpenCommandIssued = 1;
+ sktr_exec_cmd(dev, OC_OPEN);
+
+ return;
+}
+
+/*
+ * Clear the adapter's interrupt flag. Clear system interrupt enable
+ * (SINTEN): disable adapter to system interrupts.
+ */
+static void sktr_disable_interrupts(struct device *dev)
+{
+ outb(0, dev->base_addr + SIFACL);
+
+ return;
+}
+
+/*
+ * Set the adapter's interrupt flag. Set system interrupt enable
+ * (SINTEN): enable adapter to system interrupts.
+ */
+static void sktr_enable_interrupts(struct device *dev)
+{
+ outb(ACL_SINTEN, dev->base_addr + SIFACL);
+
+ return;
+}
+
+/*
+ * Put command in command queue, try to execute it.
+ */
+static void sktr_exec_cmd(struct device *dev, unsigned short Command)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ tp->CMDqueue |= Command;
+ sktr_chk_outstanding_cmds(dev);
+
+ return;
+}
+
+/*
+ * Linux always gives 18 byte of source routing information in the frame header.
+ * But the length field can indicate shorter length. Then cut header
+ * appropriate.
+ */
+static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen)
+{
+ struct trh_hdr *trh = (struct trh_hdr *)buf;
+ int len;
+
+ if(buf[8] & TR_RII)
+ {
+ trh->rcf &= ~SWAPB((unsigned short) TR_RCF_LONGEST_FRAME_MASK);
+ trh->rcf |= SWAPB((unsigned short) TR_RCF_FRAME4K);
+ len = (SWAPB(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+ if(len < 18)
+ {
+ memcpy(&buf[18-len],buf,sizeof(struct trh_hdr)-18+len);
+ *FrameLen -= (18 - len);
+ }
+ return (&buf[18-len]);
+ }
+
+ return (buf);
+}
+
+/*
+ * Gets skb from system, queues it and checks if it can be sent
+ */
+static int sktr_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ if(dev->tbusy)
+ {
+ /*
+ * If we get here, some higher level has decided we are broken.
+ * There should really be a "kick me" function call instead.
+ *
+ * Resetting the token ring adapter takes a long time so just
+ * fake transmission time and go on trying. Our own timeout
+ * routine is in sktr_timer_chk()
+ */
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ return (1);
+ }
+
+ /*
+ * If some higher layer thinks we've missed an tx-done interrupt we
+ * are passed NULL.
+ */
+ if(skb == NULL)
+ return (0);
+
+ /*
+ * 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(test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+ {
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ return (1);
+ }
+
+ if(tp->QueueSkb == 0)
+ return (1); /* Return with tbusy set: queue full */
+
+ tp->QueueSkb--;
+ skb_queue_tail(&tp->SendSkbQueue, skb);
+ sktr_hardware_send_packet(dev, tp);
+ if(tp->QueueSkb > 0)
+ dev->tbusy = 0;
+
+ return (0);
+}
+
+/*
+ * Move frames from internal skb queue into adapter tx queue
+ */
+static void sktr_hardware_send_packet(struct device *dev, struct net_local* tp)
+{
+ TPL *tpl;
+ short length;
+ unsigned char *buf, *newbuf;
+ struct sk_buff *skb;
+ int i;
+
+ for(;;)
+ {
+ /* Try to get a free TPL from the chain.
+ *
+ * NOTE: We *must* always leave one unused TPL in the chain,
+ * because otherwise the adapter might send frames twice.
+ */
+ if(tp->TplFree->NextTPLPtr->BusyFlag) /* No free TPL */
+ {
+ printk(KERN_INFO "%s: No free TPL\n", dev->name);
+ return;
+ }
+
+ /* Send first buffer from queue */
+ skb = skb_dequeue(&tp->SendSkbQueue);
+ if(skb == NULL)
+ return;
+
+ tp->QueueSkb++;
+ /* Is buffer reachable for Busmaster-DMA? */
+ if(virt_to_bus((void*)(((long) skb->data) + skb->len))
+ > ISA_MAX_ADDRESS)
+ {
+ /* Copy frame to local buffer */
+ i = tp->TplFree->TPLIndex;
+ length = skb->len;
+ buf = tp->LocalTxBuffers[i];
+ memcpy(buf, skb->data, length);
+ newbuf = sktr_fix_srouting(buf, &length);
+ }
+ else
+ {
+ /* Send direct from skb->data */
+ length = skb->len;
+ newbuf = sktr_fix_srouting(skb->data, &length);
+ }
+
+ /* Source address in packet? */
+ sktr_chk_src_addr(newbuf, dev->dev_addr);
+
+ tp->LastSendTime = jiffies;
+ tpl = tp->TplFree; /* Get the "free" TPL */
+ tpl->BusyFlag = 1; /* Mark TPL as busy */
+ tp->TplFree = tpl->NextTPLPtr;
+
+ /* Save the skb for delayed return of skb to system */
+ tpl->Skb = skb;
+ tpl->FragList[0].DataCount = (unsigned short) SWAPB(length);
+ tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf));
+
+ /* Write the data length in the transmit list. */
+ tpl->FrameSize = (unsigned short) SWAPB(length);
+ tpl->MData = newbuf;
+
+ /* Transmit the frame and set the status values. */
+ sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME
+ | TX_END_FRAME | TX_PASS_SRC_ADDR
+ | TX_FRAME_IRQ);
+
+ /* Let adapter send the frame. */
+ sktr_exec_sifcmd(dev, CMD_TX_VALID);
+ }
+
+ return;
+}
+
+/*
+ * Write the given value to the 'Status' field of the specified TPL.
+ * NOTE: This function should be used whenever the status of any TPL must be
+ * modified by the driver, because the compiler may otherwise change the
+ * order of instructions such that writing the TPL status may be executed at
+ * an undesireable time. When this function is used, the status is always
+ * written when the function is called.
+ */
+static void sktr_write_tpl_status(TPL *tpl, unsigned int Status)
+{
+ tpl->Status = Status;
+}
+
+static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr)
+{
+ unsigned char SRBit;
+
+ if((((unsigned long)frame[8]) & ~0x80) != 0) /* Compare 4 bytes */
+ return;
+ if((unsigned short)frame[12] != 0) /* Compare 2 bytes */
+ return;
+
+ SRBit = frame[8] & 0x80;
+ memcpy(&frame[8], hw_addr, 6);
+ frame[8] |= SRBit;
+
+ return;
+}
+
+/*
+ * The timer routine: Check if adapter still open and working, reopen if not.
+ */
+static void sktr_timer_chk(unsigned long data)
+{
+ struct device *dev = (struct device*)data;
+ struct net_local *tp = (struct net_local*)dev->priv;
+
+ if(tp->HaltInProgress)
+ return;
+
+ sktr_chk_outstanding_cmds(dev);
+ if(tp->LastSendTime + SEND_TIMEOUT < jiffies
+ && (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy))
+ {
+ /* Anything to send, but stalled to long */
+ tp->LastSendTime = jiffies;
+ sktr_exec_cmd(dev, OC_CLOSE); /* Does reopen automatically */
+ }
+
+ tp->timer.expires = jiffies + 2*HZ;
+ add_timer(&tp->timer);
+
+ if(tp->AdapterOpenFlag || tp->ReOpenInProgress)
+ return;
+ tp->ReOpenInProgress = 1;
+ sktr_open_adapter(dev);
+
+ return;
+}
+
+/*
+ * The typical workload of the driver: Handle the network interface interrupts.
+ */
+static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = dev_id;
+ struct net_local *tp;
+ int ioaddr;
+ unsigned short irq_type;
+
+ if(dev == NULL)
+ {
+ printk("%s: irq %d for unknown device.\n", dev->name, irq);
+ return;
+ }
+
+ dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ tp = (struct net_local *)dev->priv;
+
+ irq_type = inw(ioaddr + SIFSTS);
+
+ while(irq_type & STS_SYSTEM_IRQ)
+ {
+ irq_type &= STS_IRQ_MASK;
+
+ if(!sktr_chk_ssb(tp, irq_type))
+ {
+ printk(KERN_INFO "%s: DATA LATE occured\n", dev->name);
+ break;
+ }
+
+ switch(irq_type)
+ {
+ case STS_IRQ_RECEIVE_STATUS:
+ sktr_reset_interrupt(dev);
+ sktr_rcv_status_irq(dev);
+ break;
+
+ case STS_IRQ_TRANSMIT_STATUS:
+ /* Check if TRANSMIT.HALT command is complete */
+ if(tp->ssb.Parm[0] & COMMAND_COMPLETE)
+ {
+ tp->TransmitCommandActive = 0;
+ tp->TransmitHaltScheduled = 0;
+
+ /* Issue a new transmit command. */
+ sktr_exec_cmd(dev, OC_TRANSMIT);
+ }
+
+ sktr_reset_interrupt(dev);
+ sktr_tx_status_irq(dev);
+ break;
+
+ case STS_IRQ_COMMAND_STATUS:
+ /* The SSB contains status of last command
+ * other than receive/transmit.
+ */
+ sktr_cmd_status_irq(dev);
+ break;
+
+ case STS_IRQ_SCB_CLEAR:
+ /* The SCB is free for another command. */
+ tp->ScbInUse = 0;
+ sktr_chk_outstanding_cmds(dev);
+ break;
+
+ case STS_IRQ_RING_STATUS:
+ sktr_ring_status_irq(dev);
+ break;
+
+ case STS_IRQ_ADAPTER_CHECK:
+ sktr_chk_irq(dev);
+ break;
+
+ default:
+ printk(KERN_INFO "Unknown Token Ring IRQ\n");
+ break;
+ }
+
+ /* Reset system interrupt if not already done. */
+ if(irq_type != STS_IRQ_TRANSMIT_STATUS
+ && irq_type != STS_IRQ_RECEIVE_STATUS)
+ {
+ sktr_reset_interrupt(dev);
+ }
+
+ irq_type = inw(ioaddr + SIFSTS);
+ }
+
+ dev->interrupt = 0;
+
+ return;
+}
+
+/*
+ * Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command.
+ */
+static void sktr_reset_interrupt(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ SSB *ssb = &tp->ssb;
+
+ /*
+ * [Workaround for "Data Late"]
+ * Set all fields of the SSB to well-defined values so we can
+ * check if the adapter has written the SSB.
+ */
+
+ ssb->STS = (unsigned short) -1;
+ ssb->Parm[0] = (unsigned short) -1;
+ ssb->Parm[1] = (unsigned short) -1;
+ ssb->Parm[2] = (unsigned short) -1;
+
+ /* Free SSB by issuing SSB_CLEAR command after reading IRQ code
+ * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts.
+ */
+ sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ);
+
+ return;
+}
+
+/*
+ * Check if the SSB has actually been written by the adapter.
+ */
+static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType)
+{
+ SSB *ssb = &tp->ssb; /* The address of the SSB. */
+
+ /* C 0 1 2 INTERRUPT CODE
+ * - - - - --------------
+ * 1 1 1 1 TRANSMIT STATUS
+ * 1 1 1 1 RECEIVE STATUS
+ * 1 ? ? 0 COMMAND STATUS
+ * 0 0 0 0 SCB CLEAR
+ * 1 1 0 0 RING STATUS
+ * 0 0 0 0 ADAPTER CHECK
+ *
+ * 0 = SSB field not affected by interrupt
+ * 1 = SSB field is affected by interrupt
+ *
+ * C = SSB ADDRESS +0: COMMAND
+ * 0 = SSB ADDRESS +2: STATUS 0
+ * 1 = SSB ADDRESS +4: STATUS 1
+ * 2 = SSB ADDRESS +6: STATUS 2
+ */
+
+ /* Check if this interrupt does use the SSB. */
+
+ if(IrqType != STS_IRQ_TRANSMIT_STATUS
+ && IrqType != STS_IRQ_RECEIVE_STATUS
+ && IrqType != STS_IRQ_COMMAND_STATUS
+ && IrqType != STS_IRQ_RING_STATUS)
+ {
+ return (1); /* SSB not involved. */
+ }
+
+ /* Note: All fields of the SSB have been set to all ones (-1) after it
+ * has last been used by the software (see DriverIsr()).
+ *
+ * Check if the affected SSB fields are still unchanged.
+ */
+
+ if(ssb->STS == (unsigned short) -1)
+ return (0); /* Command field not yet available. */
+ if(IrqType == STS_IRQ_COMMAND_STATUS)
+ return (1); /* Status fields not always affected. */
+ if(ssb->Parm[0] == (unsigned short) -1)
+ return (0); /* Status 1 field not yet available. */
+ if(IrqType == STS_IRQ_RING_STATUS)
+ return (1); /* Status 2 & 3 fields not affected. */
+
+ /* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */
+ if(ssb->Parm[1] == (unsigned short) -1)
+ return (0); /* Status 2 field not yet available. */
+ if(ssb->Parm[2] == (unsigned short) -1)
+ return (0); /* Status 3 field not yet available. */
+
+ return (1); /* All SSB fields have been written by the adapter. */
+}
+
+/*
+ * Evaluates the command results status in the SSB status field.
+ */
+static void sktr_cmd_status_irq(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned short ssb_cmd, ssb_parm_0;
+ unsigned short ssb_parm_1;
+ char *open_err = "Open error -";
+ char *code_err = "Open code -";
+
+ /* Copy the ssb values to local variables */
+ ssb_cmd = tp->ssb.STS;
+ ssb_parm_0 = tp->ssb.Parm[0];
+ ssb_parm_1 = tp->ssb.Parm[1];
+
+ if(ssb_cmd == OPEN)
+ {
+ tp->Sleeping = 0;
+ if(!tp->ReOpenInProgress)
+ wake_up_interruptible(&tp->wait_for_tok_int);
+
+ tp->OpenCommandIssued = 0;
+ tp->ScbInUse = 0;
+
+ if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION)
+ {
+ /* Success, the adapter is open. */
+ tp->LobeWireFaultLogged = 0;
+ tp->AdapterOpenFlag = 1;
+ tp->AdapterVirtOpenFlag = 1;
+ tp->TransmitCommandActive = 0;
+ sktr_exec_cmd(dev, OC_TRANSMIT);
+ sktr_exec_cmd(dev, OC_RECEIVE);
+
+ if(tp->ReOpenInProgress)
+ tp->ReOpenInProgress = 0;
+
+ return;
+ }
+ else /* The adapter did not open. */
+ {
+ if(ssb_parm_0 & NODE_ADDR_ERROR)
+ printk(KERN_INFO "%s: Node address error\n",
+ dev->name);
+ if(ssb_parm_0 & LIST_SIZE_ERROR)
+ printk(KERN_INFO "%s: List size error\n",
+ dev->name);
+ if(ssb_parm_0 & BUF_SIZE_ERROR)
+ printk(KERN_INFO "%s: Buffer size error\n",
+ dev->name);
+ if(ssb_parm_0 & TX_BUF_COUNT_ERROR)
+ printk(KERN_INFO "%s: Tx buffer count error\n",
+ dev->name);
+ if(ssb_parm_0 & INVALID_OPEN_OPTION)
+ printk(KERN_INFO "%s: Invalid open option\n",
+ dev->name);
+ if(ssb_parm_0 & OPEN_ERROR)
+ {
+ /* Show the open phase. */
+ switch(ssb_parm_0 & OPEN_PHASES_MASK)
+ {
+ case LOBE_MEDIA_TEST:
+ if(!tp->LobeWireFaultLogged)
+ {
+ tp->LobeWireFaultLogged = 1;
+ printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err);
+ }
+ tp->ReOpenInProgress = 1;
+ tp->AdapterOpenFlag = 0;
+ tp->AdapterVirtOpenFlag = 1;
+ sktr_open_adapter(dev);
+ return;
+
+ case PHYSICAL_INSERTION:
+ printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err);
+ break;
+
+ case ADDRESS_VERIFICATION:
+ printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err);
+ break;
+
+ case PARTICIPATION_IN_RING_POLL:
+ printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err);
+ break;
+
+ case REQUEST_INITIALISATION:
+ printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err);
+ break;
+
+ case FULLDUPLEX_CHECK:
+ printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err);
+ break;
+
+ default:
+ printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err);
+ break;
+ }
+
+ /* Show the open errors. */
+ switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK)
+ {
+ case OPEN_FUNCTION_FAILURE:
+ printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_FUNCTION_FAILURE;
+ break;
+
+ case OPEN_SIGNAL_LOSS:
+ printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_SIGNAL_LOSS;
+ break;
+
+ case OPEN_TIMEOUT:
+ printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_TIMEOUT;
+ break;
+
+ case OPEN_RING_FAILURE:
+ printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_RING_FAILURE;
+ break;
+
+ case OPEN_RING_BEACONING:
+ printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_RING_BEACONING;
+ break;
+
+ case OPEN_DUPLICATE_NODEADDR:
+ printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_DUPLICATE_NODEADDR;
+ break;
+
+ case OPEN_REQUEST_INIT:
+ printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_REQUEST_INIT;
+ break;
+
+ case OPEN_REMOVE_RECEIVED:
+ printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_REMOVE_RECEIVED;
+ break;
+
+ case OPEN_FULLDUPLEX_SET:
+ printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_FULLDUPLEX_SET;
+ break;
+
+ default:
+ printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err);
+ tp->LastOpenStatus =
+ OPEN_FUNCTION_FAILURE;
+ break;
+ }
+ }
+
+ tp->AdapterOpenFlag = 0;
+ tp->AdapterVirtOpenFlag = 0;
+
+ return;
+ }
+ }
+ else
+ {
+ if(ssb_cmd != READ_ERROR_LOG)
+ return;
+
+ /* Add values from the error log table to the MAC
+ * statistics counters and update the errorlogtable
+ * memory.
+ */
+ tp->MacStat.line_errors += tp->errorlogtable.Line_Error;
+ tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error;
+ tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error;
+ tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error;
+ tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error;
+ tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error;
+ tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error;
+ tp->MacStat.token_errors += tp->errorlogtable.Token_Error;
+ tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error;
+ tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error;
+ tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters;
+ tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error;
+ tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error;
+ }
+
+ return;
+}
+
+/*
+ * The inverse routine to sktr_open().
+ */
+static int sktr_close(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ del_timer(&tp->timer);
+
+ /* Flush the Tx and disable Rx here. */
+
+ tp->HaltInProgress = 1;
+ sktr_exec_cmd(dev, OC_CLOSE);
+ tp->timer.expires = jiffies + 1*HZ;
+ tp->timer.function = sktr_timer_end_wait;
+ tp->timer.data = (unsigned long)dev;
+ add_timer(&tp->timer);
+
+ sktr_enable_interrupts(dev);
+
+ tp->Sleeping = 1;
+ interruptible_sleep_on(&tp->wait_for_tok_int);
+ tp->TransmitCommandActive = 0;
+
+ del_timer(&tp->timer);
+ sktr_disable_interrupts(dev);
+
+ if(dev->dma > 0)
+ disable_dma(dev->dma);
+ outw(0xFF00, dev->base_addr + SIFCMD);
+ if(dev->dma > 0)
+ outb(0xff, dev->base_addr + POSREG);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
+ sktr_cancel_tx_queue(tp);
+
+ return (0);
+}
+
+/*
+ * Get the current statistics. This may be called with the card open
+ * or closed.
+ */
+static struct enet_statistics *sktr_get_stats(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ return ((struct enet_statistics *)&tp->MacStat);
+}
+
+/*
+ * Set or clear the multicast filter for this adapter.
+ */
+static void sktr_set_multicast_list(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned int OpenOptions;
+
+ OpenOptions = tp->ocpl.OPENOptions &
+ ~(PASS_ADAPTER_MAC_FRAMES
+ | PASS_ATTENTION_FRAMES
+ | PASS_BEACON_MAC_FRAMES
+ | COPY_ALL_MAC_FRAMES
+ | COPY_ALL_NON_MAC_FRAMES);
+
+ if(dev->flags & IFF_PROMISC)
+ /* Enable promiscuous mode */
+ OpenOptions |= COPY_ALL_NON_MAC_FRAMES | COPY_ALL_MAC_FRAMES;
+ else
+ {
+ if(dev->flags & IFF_ALLMULTI)
+ /* || dev->mc_count > HW_MAX_ADDRS) */
+ {
+ /* Disable promiscuous mode, use normal mode. */
+ }
+ else
+ {
+ if(dev->mc_count)
+ {
+ /* Walk the address list, and load the filter */
+ }
+ }
+ }
+
+ tp->ocpl.OPENOptions = OpenOptions;
+ sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS);
+
+ return;
+}
+
+/*
+ * Wait for some time (microseconds)
+ */
+static void sktr_wait(unsigned long time)
+{
+ long tmp;
+
+ tmp = jiffies + time/(1000000/HZ);
+ do {
+ current->timeout = tmp;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ } while(tmp > jiffies);
+
+ return;
+}
+
+/*
+ * Write a command value to the SIFCMD register
+ */
+static void sktr_exec_sifcmd(struct device *dev, unsigned int WriteValue)
+{
+ int ioaddr = dev->base_addr;
+ unsigned short cmd;
+ unsigned short SifStsValue;
+ unsigned long loop_counter;
+
+ WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER);
+ cmd = (unsigned short)WriteValue;
+ loop_counter = 0,5 * 800000;
+ do {
+ SifStsValue = inw(ioaddr + SIFSTS);
+ } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--);
+ outw(cmd, ioaddr + SIFCMD);
+
+ return;
+}
+
+/*
+ * Processes adapter hardware reset, halts adapter and downloads firmware,
+ * clears the halt bit.
+ */
+static int sktr_reset_adapter(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned short *fw_ptr = (unsigned short *)&sktr_code;
+ unsigned short count, c;
+ int ioaddr = dev->base_addr;
+
+ /* Hardware adapter reset */
+ outw(ACL_ARESET, ioaddr + SIFACL);
+ sktr_wait(40);
+
+ c = inw(ioaddr + SIFACL);
+ sktr_wait(20);
+
+ if(dev->dma == 0) /* For PCI adapters */
+ {
+ c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */
+ if(tp->DataRate == SPEED_4)
+ c |= ACL_SPEED4; /* Set 4Mbps */
+ else
+ c |= ACL_SPEED16; /* Set 16Mbps */
+ }
+
+ /* In case a comand is pending - forget it */
+ tp->ScbInUse = 0;
+
+ c &= ~ACL_ARESET; /* Clear adapter reset bit */
+ c |= ACL_CPHALT; /* Halt adapter CPU, allow download */
+ c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */
+ outw(c, ioaddr + SIFACL);
+ sktr_wait(40);
+
+ /* Download firmware via DIO interface: */
+ do {
+ /* Download first address part */
+ outw(*fw_ptr, ioaddr + SIFADX);
+ fw_ptr++;
+
+ /* Download second address part */
+ outw(*fw_ptr, ioaddr + SIFADD);
+ fw_ptr++;
+
+ if((count = *fw_ptr) != 0) /* Load loop counter */
+ {
+ fw_ptr++; /* Download block data */
+ for(; count > 0; count--)
+ {
+ outw(*fw_ptr, ioaddr + SIFINC);
+ fw_ptr++;
+ }
+ }
+ else /* Stop, if last block downloaded */
+ {
+ c = inw(ioaddr + SIFACL);
+ c &= (~ACL_CPHALT | ACL_SINTEN);
+
+ /* Clear CPHALT and start BUD */
+ outw(c, ioaddr + SIFACL);
+ return (1);
+ }
+ } while(count == 0);
+
+ return (-1);
+}
+
+/*
+ * Starts bring up diagnostics of token ring adapter and evaluates
+ * diagnostic results.
+ */
+static int sktr_bringup_diags(struct device *dev)
+{
+ int loop_cnt, retry_cnt;
+ unsigned short Status;
+ int ioaddr = dev->base_addr;
+
+ sktr_wait(HALF_SECOND);
+ sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
+ sktr_wait(HALF_SECOND);
+
+ retry_cnt = BUD_MAX_RETRIES; /* maximal number of retrys */
+
+ do {
+ retry_cnt--;
+ if(sktr_debug > 3)
+ printk(KERN_INFO "BUD-Status: \n");
+ loop_cnt = BUD_MAX_LOOPCNT; /* maximum: three seconds*/
+ do { /* Inspect BUD results */
+ loop_cnt--;
+ sktr_wait(HALF_SECOND);
+ Status = inw(ioaddr + SIFSTS);
+ Status &= STS_MASK;
+
+ if(sktr_debug > 3)
+ printk(KERN_INFO " %04X \n", Status);
+ /* BUD successfully completed */
+ if(Status == STS_INITIALIZE)
+ return (1);
+ /* Unrecoverable hardware error, BUD not completed? */
+ } while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST))
+ != (STS_ERROR | STS_TEST)));
+
+ /* Error preventing completion of BUD */
+ if(retry_cnt > 0)
+ {
+ printk(KERN_INFO "%s: Adapter Software Reset.\n",
+ dev->name);
+ sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
+ sktr_wait(HALF_SECOND);
+ }
+ } while(retry_cnt > 0);
+
+ Status = inw(ioaddr + SIFSTS);
+ Status &= STS_ERROR_MASK; /* Hardware error occured! */
+
+ printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n",
+ dev->name, Status);
+
+ return (-1);
+}
+
+/*
+ * Copy initialisation data to adapter memory, beginning at address
+ * 1:0A00; Starting DMA test and evaluating result bits.
+ */
+static int sktr_init_adapter(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B};
+ const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7,
+ 0xC5, 0xD9, 0xC3, 0xD4};
+ void *ptr = (void *)&tp->ipb;
+ unsigned short *ipb_ptr = (unsigned short *)ptr;
+ unsigned char *cb_ptr = (unsigned char *) &tp->scb;
+ unsigned char *sb_ptr = (unsigned char *) &tp->ssb;
+ unsigned short Status;
+ int i, loop_cnt, retry_cnt;
+ int ioaddr = dev->base_addr;
+
+ /* Normalize: byte order low/high, word order high/low! (only IPB!) */
+ tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb));
+ tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb));
+
+ /* Maximum: three initialization retries */
+ retry_cnt = INIT_MAX_RETRIES;
+
+ do {
+ retry_cnt--;
+
+ /* Transfer initialization block */
+ outw(0x0001, ioaddr + SIFADX);
+
+ /* To address 0001:0A00 of adapter RAM */
+ outw(0x0A00, ioaddr + SIFADD);
+
+ /* Write 11 words to adapter RAM */
+ for(i = 0; i < 11; i++)
+ outw(ipb_ptr[i], ioaddr + SIFINC);
+
+ /* Execute SCB adapter command */
+ sktr_exec_sifcmd(dev, CMD_EXECUTE);
+
+ loop_cnt = INIT_MAX_LOOPCNT; /* Maximum: 11 seconds */
+
+ /* While remaining retries, no error and not completed */
+ do {
+ Status = 0;
+ loop_cnt--;
+ sktr_wait(HALF_SECOND);
+
+ /* Mask interesting status bits */
+ Status = inw(ioaddr + SIFSTS);
+ Status &= STS_MASK;
+ } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0)
+ && ((Status & STS_ERROR) == 0) && (loop_cnt != 0));
+
+ if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0)
+ {
+ /* Initialization completed without error */
+ i = 0;
+ do { /* Test if contents of SCB is valid */
+ if(SCB_Test[i] != *(cb_ptr + i))
+ /* DMA data error: wrong data in SCB */
+ return (-1);
+ i++;
+ } while(i < 6);
+
+ i = 0;
+ do { /* Test if contents of SSB is valid */
+ if(SSB_Test[i] != *(sb_ptr + i))
+ /* DMA data error: wrong data in SSB */
+ return (-1);
+ i++;
+ } while (i < 8);
+
+ return (1); /* Adapter successfully initialized */
+ }
+ else
+ {
+ if((Status & STS_ERROR) != 0)
+ {
+ /* Initialization error occured */
+ Status = inw(ioaddr + SIFSTS);
+ Status &= STS_ERROR_MASK;
+ /* ShowInitialisationErrorCode(Status); */
+ return (-1); /* Unrecoverable error */
+ }
+ else
+ {
+ if(retry_cnt > 0)
+ {
+ /* Reset adapter and try init again */
+ sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
+ sktr_wait(HALF_SECOND);
+ }
+ }
+ }
+ } while(retry_cnt > 0);
+
+ return (-1);
+}
+
+/*
+ * Check for outstanding commands in command queue and tries to execute
+ * command immediately. Corresponding command flag in command queue is cleared.
+ */
+static void sktr_chk_outstanding_cmds(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned long Addr = 0;
+ unsigned char i = 0;
+
+ if(tp->CMDqueue == 0)
+ return; /* No command execution */
+
+ /* If SCB in use: no command */
+ if(tp->ScbInUse == 1)
+ return;
+
+ /* Check if adapter is opened, avoiding COMMAND_REJECT
+ * interrupt by the adapter!
+ */
+ if(tp->AdapterOpenFlag == 0)
+ {
+ if(tp->CMDqueue & OC_OPEN)
+ {
+ /* Execute OPEN command */
+ tp->CMDqueue ^= OC_OPEN;
+
+ /* Copy the 18 bytes of the product ID */
+ while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE))
+ {
+ tp->ProductID[i] = AdapterName[i];
+ i++;
+ }
+
+ Addr = htonl(virt_to_bus(&tp->ocpl));
+ tp->scb.Parm[0] = LOWORD(Addr);
+ tp->scb.Parm[1] = HIWORD(Addr);
+ tp->scb.CMD = OPEN;
+ }
+ else
+ /* No OPEN command queued, but adapter closed. Note:
+ * We'll try to re-open the adapter in DriverPoll()
+ */
+ return; /* No adapter command issued */
+ }
+ else
+ {
+ /* Adapter is open; evaluate command queue: try to execute
+ * outstanding commands (depending on priority!) CLOSE
+ * command queued
+ */
+ if(tp->CMDqueue & OC_CLOSE)
+ {
+ tp->CMDqueue ^= OC_CLOSE;
+ tp->AdapterOpenFlag = 0;
+ tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */
+ tp->scb.Parm[1] = 0; /* but should be set to zero! */
+ tp->scb.CMD = CLOSE;
+ if(!tp->HaltInProgress)
+ tp->CMDqueue |= OC_OPEN; /* re-open adapter */
+ else
+ tp->CMDqueue = 0; /* no more commands */
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_RECEIVE)
+ {
+ tp->CMDqueue ^= OC_RECEIVE;
+ Addr = htonl(virt_to_bus(tp->RplHead));
+ tp->scb.Parm[0] = LOWORD(Addr);
+ tp->scb.Parm[1] = HIWORD(Addr);
+ tp->scb.CMD = RECEIVE;
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_TRANSMIT_HALT)
+ {
+ /* NOTE: TRANSMIT.HALT must be checked
+ * before TRANSMIT.
+ */
+ tp->CMDqueue ^= OC_TRANSMIT_HALT;
+ tp->scb.CMD = TRANSMIT_HALT;
+
+ /* Parm[0] and Parm[1] are ignored
+ * but should be set to zero!
+ */
+ tp->scb.Parm[0] = 0;
+ tp->scb.Parm[1] = 0;
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_TRANSMIT)
+ {
+ /* NOTE: TRANSMIT must be
+ * checked after TRANSMIT.HALT
+ */
+ if(tp->TransmitCommandActive)
+ {
+ if(!tp->TransmitHaltScheduled)
+ {
+ tp->TransmitHaltScheduled = 1;
+ sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ;
+ }
+ tp->TransmitCommandActive = 0;
+ return;
+ }
+
+ tp->CMDqueue ^= OC_TRANSMIT;
+ sktr_cancel_tx_queue(tp);
+ Addr = htonl(virt_to_bus(tp->TplBusy));
+ tp->scb.Parm[0] = LOWORD(Addr);
+ tp->scb.Parm[1] = HIWORD(Addr);
+ tp->scb.CMD = TRANSMIT;
+ tp->TransmitCommandActive = 1;
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS)
+ {
+ tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS;
+ tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/
+ tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION;
+ tp->scb.Parm[1] = 0; /* is ignored but should be zero */
+ tp->scb.CMD = MODIFY_OPEN_PARMS;
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_SET_FUNCT_ADDR)
+ {
+ tp->CMDqueue ^= OC_SET_FUNCT_ADDR;
+ tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr);
+ tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr);
+ tp->scb.CMD = SET_FUNCT_ADDR;
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_SET_GROUP_ADDR)
+ {
+ tp->CMDqueue ^= OC_SET_GROUP_ADDR;
+ tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr);
+ tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr);
+ tp->scb.CMD = SET_GROUP_ADDR;
+ }
+ else
+ {
+ if(tp->CMDqueue & OC_READ_ERROR_LOG)
+ {
+ tp->CMDqueue ^= OC_READ_ERROR_LOG;
+ Addr = htonl(virt_to_bus(&tp->errorlogtable));
+ tp->scb.Parm[0] = LOWORD(Addr);
+ tp->scb.Parm[1] = HIWORD(Addr);
+ tp->scb.CMD = READ_ERROR_LOG;
+ }
+ else
+ {
+ printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n");
+ tp->CMDqueue = 0;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ tp->ScbInUse = 1; /* Set semaphore: SCB in use. */
+
+ /* Execute SCB and generate IRQ when done. */
+ sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST);
+
+ return;
+}
+
+/*
+ * IRQ conditions: signal loss on the ring, transmit or receive of beacon
+ * frames (disabled if bit 1 of OPEN option is set); report error MAC
+ * frame transmit (disabled if bit 2 of OPEN option is set); open or short
+ * cirquit fault on the lobe is detected; remove MAC frame received;
+ * error counter overflow (255); opened adapter is the only station in ring.
+ * After some of the IRQs the adapter is closed!
+ */
+static void sktr_ring_status_irq(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]);
+
+ /* First: fill up statistics */
+ if(tp->ssb.Parm[0] & SIGNAL_LOSS)
+ {
+ printk(KERN_INFO "%s: Signal Loss\n", dev->name);
+ tp->MacStat.line_errors++;
+ }
+
+ /* Adapter is closed, but initialized */
+ if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT)
+ {
+ printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n",
+ dev->name);
+ tp->MacStat.line_errors++;
+ }
+
+ if(tp->ssb.Parm[0] & RING_RECOVERY)
+ printk(KERN_INFO "%s: Ring Recovery\n", dev->name);
+
+ /* Counter overflow: read error log */
+ if(tp->ssb.Parm[0] & COUNTER_OVERFLOW)
+ {
+ printk(KERN_INFO "%s: Counter Overflow\n", dev->name);
+ sktr_exec_cmd(dev, OC_READ_ERROR_LOG);
+ }
+
+ /* Adapter is closed, but initialized */
+ if(tp->ssb.Parm[0] & REMOVE_RECEIVED)
+ printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n",
+ dev->name);
+
+ /* Adapter is closed, but initialized */
+ if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR)
+ printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n",
+ dev->name);
+
+ if(tp->ssb.Parm[0] & HARD_ERROR)
+ printk(KERN_INFO "%s: Hard Error\n", dev->name);
+
+ if(tp->ssb.Parm[0] & SOFT_ERROR)
+ printk(KERN_INFO "%s: Soft Error\n", dev->name);
+
+ if(tp->ssb.Parm[0] & TRANSMIT_BEACON)
+ printk(KERN_INFO "%s: Transmit Beacon\n", dev->name);
+
+ if(tp->ssb.Parm[0] & SINGLE_STATION)
+ printk(KERN_INFO "%s: Single Station\n", dev->name);
+
+ /* Check if adapter has been closed */
+ if(tp->ssb.Parm[0] & ADAPTER_CLOSED)
+ {
+ printk(KERN_INFO "%s: Adapter closed (Reopening),"
+ "QueueSkb %d, CurrentRingStat %x\n",
+ dev->name, tp->QueueSkb, tp->CurrentRingStatus);
+ tp->AdapterOpenFlag = 0;
+ sktr_open_adapter(dev);
+ }
+
+ return;
+}
+
+/*
+ * Issued if adapter has encountered an unrecoverable hardware
+ * or software error.
+ */
+static void sktr_chk_irq(struct device *dev)
+{
+ int i;
+ unsigned short AdapterCheckBlock[4];
+ unsigned short ioaddr = dev->base_addr;
+ struct net_local *tp = (struct net_local *)dev->priv;
+
+ tp->AdapterOpenFlag = 0; /* Adapter closed now */
+
+ /* Page number of adapter memory */
+ outw(0x0001, ioaddr + SIFADX);
+ /* Address offset */
+ outw(CHECKADDR, ioaddr + SIFADR);
+
+ /* Reading 8 byte adapter check block. */
+ for(i = 0; i < 4; i++)
+ AdapterCheckBlock[i] = inw(ioaddr + SIFINC);
+
+ if(sktr_debug > 3)
+ {
+ printk("%s: AdapterCheckBlock: ", dev->name);
+ for (i = 0; i < 4; i++)
+ printk("%04X", AdapterCheckBlock[i]);
+ printk("\n");
+ }
+
+ switch(AdapterCheckBlock[0])
+ {
+ case DIO_PARITY:
+ printk(KERN_INFO "%s: DIO parity error\n", dev->name);
+ break;
+
+ case DMA_READ_ABORT:
+ printk(KERN_INFO "%s DMA read operation aborted:\n",
+ dev->name);
+ switch (AdapterCheckBlock[1])
+ {
+ case 0:
+ printk(KERN_INFO "Timeout\n");
+ printk(KERN_INFO "Address: %04X %04X\n",
+ AdapterCheckBlock[2],
+ AdapterCheckBlock[3]);
+ break;
+
+ case 1:
+ printk(KERN_INFO "Parity error\n");
+ printk(KERN_INFO "Address: %04X %04X\n",
+ AdapterCheckBlock[2],
+ AdapterCheckBlock[3]);
+ break;
+
+ case 2:
+ printk(KERN_INFO "Bus error\n");
+ printk(KERN_INFO "Address: %04X %04X\n",
+ AdapterCheckBlock[2],
+ AdapterCheckBlock[3]);
+ break;
+
+ default:
+ printk(KERN_INFO "Unknown error.\n");
+ break;
+ }
+ break;
+
+ case DMA_WRITE_ABORT:
+ printk(KERN_INFO "%s: DMA write operation aborted: \n",
+ dev->name);
+ switch (AdapterCheckBlock[1])
+ {
+ case 0:
+ printk(KERN_INFO "Timeout\n");
+ printk(KERN_INFO "Address: %04X %04X\n",
+ AdapterCheckBlock[2],
+ AdapterCheckBlock[3]);
+ break;
+
+ case 1:
+ printk(KERN_INFO "Parity error\n");
+ printk(KERN_INFO "Address: %04X %04X\n",
+ AdapterCheckBlock[2],
+ AdapterCheckBlock[3]);
+ break;
+
+ case 2:
+ printk(KERN_INFO "Bus error\n");
+ printk(KERN_INFO "Address: %04X %04X\n",
+ AdapterCheckBlock[2],
+ AdapterCheckBlock[3]);
+ break;
+
+ default:
+ printk(KERN_INFO "Unknown error.\n");
+ break;
+ }
+ break;
+
+ case ILLEGAL_OP_CODE:
+ printk("%s: Illegal operation code in firmware\n",
+ dev->name);
+ /* Parm[0-3]: adapter internal register R13-R15 */
+ break;
+
+ case PARITY_ERRORS:
+ printk("%s: Adapter internal bus parity error\n",
+ dev->name);
+ /* Parm[0-3]: adapter internal register R13-R15 */
+ break;
+
+ case RAM_DATA_ERROR:
+ printk("%s: RAM data error\n", dev->name);
+ /* Parm[0-1]: MSW/LSW address of RAM location. */
+ break;
+
+ case RAM_PARITY_ERROR:
+ printk("%s: RAM parity error\n", dev->name);
+ /* Parm[0-1]: MSW/LSW address of RAM location. */
+ break;
+
+ case RING_UNDERRUN:
+ printk("%s: Internal DMA underrun detected\n",
+ dev->name);
+ break;
+
+ case INVALID_IRQ:
+ printk("%s: Unrecognized interrupt detected\n",
+ dev->name);
+ /* Parm[0-3]: adapter internal register R13-R15 */
+ break;
+
+ case INVALID_ERROR_IRQ:
+ printk("%s: Unrecognized error interrupt detected\n",
+ dev->name);
+ /* Parm[0-3]: adapter internal register R13-R15 */
+ break;
+
+ case INVALID_XOP:
+ printk("%s: Unrecognized XOP request detected\n",
+ dev->name);
+ /* Parm[0-3]: adapter internal register R13-R15 */
+ break;
+
+ default:
+ printk("%s: Unknown status", dev->name);
+ break;
+ }
+
+ if(sktr_chipset_init(dev) == 1)
+ {
+ /* Restart of firmware successful */
+ tp->AdapterOpenFlag = 1;
+ }
+
+ return;
+}
+
+/*
+ * Internal adapter pointer to RAM data are copied from adapter into
+ * host system.
+ */
+static void sktr_read_ptr(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned short adapterram;
+
+ sktr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr,
+ ADAPTER_INT_PTRS, 16);
+ sktr_read_ram(dev, (unsigned char *)&adapterram,
+ (unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2);
+
+ printk(KERN_INFO "%s: Adapter RAM size: %d K\n",
+ dev->name, SWAPB(adapterram));
+
+ return;
+}
+
+/*
+ * Reads a number of bytes from adapter to system memory.
+ */
+static void sktr_read_ram(struct device *dev, unsigned char *Data,
+ unsigned short Address, int Length)
+{
+ int i;
+ unsigned short old_sifadx, old_sifadr, InWord;
+ unsigned short ioaddr = dev->base_addr;
+
+ /* Save the current values */
+ old_sifadx = inw(ioaddr + SIFADX);
+ old_sifadr = inw(ioaddr + SIFADR);
+
+ /* Page number of adapter memory */
+ outw(0x0001, ioaddr + SIFADX);
+ /* Address offset in adapter RAM */
+ outw(Address, ioaddr + SIFADR);
+
+ /* Copy len byte from adapter memory to system data area. */
+ i = 0;
+ for(;;)
+ {
+ InWord = inw(ioaddr + SIFINC);
+
+ *(Data + i) = HIBYTE(InWord); /* Write first byte */
+ if(++i == Length) /* All is done break */
+ break;
+
+ *(Data + i) = LOBYTE(InWord); /* Write second byte */
+ if (++i == Length) /* All is done break */
+ break;
+ }
+
+ /* Restore original values */
+ outw(old_sifadx, ioaddr + SIFADX);
+ outw(old_sifadr, ioaddr + SIFADR);
+
+ return;
+}
+
+/*
+ * Reads MAC address from adapter ROM.
+ */
+static void sktr_read_addr(struct device *dev, unsigned char *Address)
+{
+ int i, In;
+ unsigned short ioaddr = dev->base_addr;
+
+ /* Address: 0000:0000 */
+ outw(0, ioaddr + SIFADX);
+ outw(0, ioaddr + SIFADR);
+
+ /* Read six byte MAC address data */
+ for(i = 0; i < 6; i++)
+ {
+ In = inw(ioaddr + SIFINC);
+ *(Address + i) = (unsigned char)(In >> 8);
+ }
+
+ return;
+}
+
+/*
+ * Cancel all queued packets in the transmission queue.
+ */
+static void sktr_cancel_tx_queue(struct net_local* tp)
+{
+ TPL *tpl;
+ struct sk_buff *skb;
+
+ /*
+ * NOTE: There must not be an active TRANSMIT command pending, when
+ * this function is called.
+ */
+ if(tp->TransmitCommandActive)
+ return;
+
+ for(;;)
+ {
+ tpl = tp->TplBusy;
+ if(!tpl->BusyFlag)
+ break;
+ /* "Remove" TPL from busy list. */
+ tp->TplBusy = tpl->NextTPLPtr;
+ sktr_write_tpl_status(tpl, 0); /* Clear VALID bit */
+ tpl->BusyFlag = 0; /* "free" TPL */
+
+ printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
+
+ dev_kfree_skb(tpl->Skb);
+ }
+
+ for(;;)
+ {
+ skb = skb_dequeue(&tp->SendSkbQueue);
+ if(skb == NULL)
+ break;
+ tp->QueueSkb++;
+ dev_kfree_skb(skb);
+ }
+
+ return;
+}
+
+/*
+ * This function is called whenever a transmit interrupt is generated by the
+ * adapter. For a command complete interrupt, it is checked if we have to
+ * issue a new transmit command or not.
+ */
+static void sktr_tx_status_irq(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned char HighByte, HighAc, LowAc;
+ TPL *tpl;
+
+ /* NOTE: At this point the SSB from TRANSMIT STATUS is no longer
+ * available, because the CLEAR SSB command has already been issued.
+ *
+ * Process all complete transmissions.
+ */
+
+ for(;;)
+ {
+ tpl = tp->TplBusy;
+ if(!tpl->BusyFlag || (tpl->Status
+ & (TX_VALID | TX_FRAME_COMPLETE))
+ != TX_FRAME_COMPLETE)
+ {
+ break;
+ }
+
+ /* "Remove" TPL from busy list. */
+ tp->TplBusy = tpl->NextTPLPtr ;
+
+ if(sktr_debug > 3)
+ sktr_dump(tpl->MData, SWAPB(tpl->FrameSize));
+
+ /* Check the transmit status field only for directed frames*/
+ if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0)
+ {
+ HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status);
+ HighAc = GET_FRAME_STATUS_HIGH_AC(HighByte);
+ LowAc = GET_FRAME_STATUS_LOW_AC(HighByte);
+
+ if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED))
+ {
+ printk(KERN_INFO "%s: (DA=%08lX not recognized)",
+ dev->name,
+ *(unsigned long *)&tpl->MData[2+2]);
+ }
+ else
+ {
+ if(sktr_debug > 3)
+ printk("%s: Directed frame tx'd\n",
+ dev->name);
+ }
+ }
+ else
+ {
+ if(!DIRECTED_FRAME(tpl))
+ {
+ if(sktr_debug > 3)
+ printk("%s: Broadcast frame tx'd\n",
+ dev->name);
+ }
+ }
+
+ tp->MacStat.tx_packets++;
+ dev_kfree_skb(tpl->Skb);
+ tpl->BusyFlag = 0; /* "free" TPL */
+ }
+
+ dev->tbusy = 0;
+ if(tp->QueueSkb < MAX_TX_QUEUE)
+ sktr_hardware_send_packet(dev, tp);
+
+ return;
+}
+
+/*
+ * Called if a frame receive interrupt is generated by the adapter.
+ * Check if the frame is valid and indicate it to system.
+ */
+static void sktr_rcv_status_irq(struct device *dev)
+{
+ struct net_local *tp = (struct net_local *)dev->priv;
+ unsigned char *ReceiveDataPtr;
+ struct sk_buff *skb;
+ unsigned int Length, Length2;
+ RPL *rpl;
+ RPL *SaveHead;
+
+ /* NOTE: At this point the SSB from RECEIVE STATUS is no longer
+ * available, because the CLEAR SSB command has already been issued.
+ *
+ * Process all complete receives.
+ */
+
+ for(;;)
+ {
+ rpl = tp->RplHead;
+ if(rpl->Status & RX_VALID)
+ break; /* RPL still in use by adapter */
+
+ /* Forward RPLHead pointer to next list. */
+ SaveHead = tp->RplHead;
+ tp->RplHead = rpl->NextRPLPtr;
+
+ /* Get the frame size (Byte swap for Intel).
+ * Do this early (see workaround comment below)
+ */
+ Length = (unsigned short)SWAPB(rpl->FrameSize);
+
+ /* Check if the Frame_Start, Frame_End and
+ * Frame_Complete bits are set.
+ */
+ if((rpl->Status & VALID_SINGLE_BUFFER_FRAME)
+ == VALID_SINGLE_BUFFER_FRAME)
+ {
+ ReceiveDataPtr = rpl->MData;
+
+ /* Workaround for delayed write of FrameSize on ISA
+ * (FrameSize is false but valid-bit is reset)
+ * Frame size is set to zero when the RPL is freed.
+ * Length2 is there because there have also been
+ * cases where the FrameSize was partially written
+ */
+ Length2 = (unsigned short)SWAPB(rpl->FrameSize);
+
+ if(Length == 0 || Length != Length2)
+ {
+ tp->RplHead = SaveHead;
+ break; /* Return to sktr_interrupt */
+ }
+
+ /* Drop frames sent by myself */
+ if(sktr_chk_frame(dev, rpl->MData))
+ {
+ printk(KERN_INFO "%s: Received my own frame\n",
+ dev->name);
+ if(rpl->Skb != NULL)
+ dev_kfree_skb(rpl->Skb);
+ }
+ else
+ {
+ sktr_update_rcv_stats(tp,ReceiveDataPtr,Length);
+
+ if(sktr_debug > 3)
+ printk("%s: Packet Length %04X (%d)\n",
+ dev->name, Length, Length);
+
+ /* Indicate the received frame to system the
+ * adapter does the Source-Routing padding for
+ * us. See: OpenOptions in sktr_init_opb()
+ */
+ skb = rpl->Skb;
+ if(rpl->SkbStat == SKB_UNAVAILABLE)
+ {
+ /* Try again to allocate skb */
+ skb = dev_alloc_skb(tp->MaxPacketSize);
+ if(skb == NULL)
+ {
+ /* Update Stats ?? */
+ }
+ else
+ {
+ skb->dev = dev;
+ skb_put(skb, tp->MaxPacketSize);
+ rpl->SkbStat = SKB_DATA_COPY;
+ ReceiveDataPtr = rpl->MData;
+ }
+ }
+
+ if(rpl->SkbStat == SKB_DATA_COPY
+ || rpl->SkbStat == SKB_DMA_DIRECT)
+ {
+ if(rpl->SkbStat == SKB_DATA_COPY)
+ {
+ memmove(skb->data, ReceiveDataPtr, Length);
+ }
+
+ /* Deliver frame to system */
+ rpl->Skb = NULL;
+ skb_trim(skb,Length);
+ skb->protocol = tr_type_trans(skb,dev);
+ netif_rx(skb);
+ }
+ }
+ }
+ else /* Invalid frame */
+ {
+ if(rpl->Skb != NULL)
+ dev_kfree_skb(rpl->Skb);
+
+ /* Skip list. */
+ if(rpl->Status & RX_START_FRAME)
+ /* Frame start bit is set -> overflow. */
+ tp->MacStat.rx_errors++;
+ }
+
+ /* Allocate new skb for rpl */
+ rpl->Skb = dev_alloc_skb(tp->MaxPacketSize);
+
+ /* skb == NULL ? then use local buffer */
+ if(rpl->Skb == NULL)
+ {
+ rpl->SkbStat = SKB_UNAVAILABLE;
+ rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+ rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
+ }
+ else /* skb != NULL */
+ {
+ rpl->Skb->dev = dev;
+ skb_put(rpl->Skb, tp->MaxPacketSize);
+
+ /* Data unreachable for DMA ? then use local buffer */
+ if(virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize
+ > ISA_MAX_ADDRESS)
+ {
+ rpl->SkbStat = SKB_DATA_COPY;
+ rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+ rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
+ }
+ else
+ {
+ /* DMA directly in skb->data */
+ rpl->SkbStat = SKB_DMA_DIRECT;
+ rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data));
+ rpl->MData = rpl->Skb->data;
+ }
+ }
+
+ rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize);
+ rpl->FrameSize = 0;
+
+ /* Pass the last RPL back to the adapter */
+ tp->RplTail->FrameSize = 0;
+
+ /* Reset the CSTAT field in the list. */
+ sktr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ);
+
+ /* Current RPL becomes last one in list. */
+ tp->RplTail = tp->RplTail->NextRPLPtr;
+
+ /* Inform adapter about RPL valid. */
+ sktr_exec_sifcmd(dev, CMD_RX_VALID);
+ }
+
+ return;
+}
+
+/*
+ * This function should be used whenever the status of any RPL must be
+ * modified by the driver, because the compiler may otherwise change the
+ * order of instructions such that writing the RPL status may be executed
+ * at an undesireable time. When this function is used, the status is
+ * always written when the function is called.
+ */
+static void sktr_write_rpl_status(RPL *rpl, unsigned int Status)
+{
+ rpl->Status = Status;
+
+ return;
+}
+
+/*
+ * The function updates the statistic counters in mac->MacStat.
+ * It differtiates between directed and broadcast/multicast ( ==functional)
+ * frames.
+ */
+static void sktr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[],
+ unsigned int Length)
+{
+ tp->MacStat.rx_packets++;
+
+ /* Test functional bit */
+ if(DataPtr[2] & GROUP_BIT)
+ tp->MacStat.multicast++;
+
+ return;
+}
+
+/*
+ * Check if it is a frame of myself. Compare source address with my current
+ * address in reverse direction, and mask out the TR_RII.
+ */
+static unsigned char sktr_chk_frame(struct device *dev, unsigned char *Addr)
+{
+ int i;
+
+ for(i = 5; i > 0; i--)
+ {
+ if(Addr[8 + i] != dev->dev_addr[i])
+ return (0);
+ }
+
+ /* Mask out RIF bit. */
+ if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0]))
+ return (0);
+
+ return (1); /* It is my frame. */
+}
+
+/*
+ * Dump Packet (data)
+ */
+static void sktr_dump(unsigned char *Data, int length)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < length / 8; i++, j += 8)
+ {
+ printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ Data[j+0],Data[j+1],Data[j+2],Data[j+3],
+ Data[j+4],Data[j+5],Data[j+6],Data[j+7]);
+ }
+
+ return;
+}
+
+#ifdef MODULE
+
+static struct device* dev_sktr[SKTR_MAX_ADAPTERS];
+static int io[SKTR_MAX_ADAPTERS] = { 0, 0 };
+static int irq[SKTR_MAX_ADAPTERS] = { 0, 0 };
+static int mem[SKTR_MAX_ADAPTERS] = { 0, 0 };
+
+MODULE_PARM(io, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
+MODULE_PARM(mem, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
+
+int init_module(void)
+{
+ int i;
+
+ for(i = 0; i < SKTR_MAX_ADAPTERS; i++)
+ {
+ irq[i] = 0;
+ mem[i] = 0;
+ dev_sktr[i] = NULL;
+ dev_sktr[i] = init_trdev(dev_sktr[i], 0);
+ if(dev_sktr[i] == NULL)
+ return (-ENOMEM);
+
+ dev_sktr[i]->base_addr = io[i];
+ dev_sktr[i]->irq = irq[i];
+ dev_sktr[i]->mem_start = mem[i];
+ dev_sktr[i]->init = &sktr_probe;
+
+ if(register_trdev(dev_sktr[i]) != 0)
+ {
+ kfree_s(dev_sktr[i], sizeof(struct device));
+ dev_sktr[i] = NULL;
+ if(i == 0)
+ {
+ printk("sktr: register_trdev() returned non-zero.\n");
+ return (-EIO);
+ }
+ else
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+void cleanup_module(void)
+{
+ int i;
+
+ for(i = 0; i < SKTR_MAX_ADAPTERS; i++)
+ {
+ if(dev_sktr[i])
+ {
+ unregister_trdev(dev_sktr[i]);
+ release_region(dev_sktr[i]->base_addr, SKTR_IO_EXTENT);
+ if(dev_sktr[i]->irq)
+ free_irq(dev_sktr[i]->irq, dev_sktr[i]);
+ if(dev_sktr[i]->dma > 0)
+ free_dma(dev_sktr[i]->dma);
+ if(dev_sktr[i]->priv)
+ kfree_s(dev_sktr[i]->priv, sizeof(struct net_local));
+ kfree_s(dev_sktr[i], sizeof(struct device));
+ dev_sktr[i] = NULL;
+ }
+ }
+}
+#endif /* MODULE */
diff --git a/drivers/net/sktr.h b/drivers/net/sktr.h
new file mode 100644
index 000000000..e0fe718e7
--- /dev/null
+++ b/drivers/net/sktr.h
@@ -0,0 +1,1098 @@
+/* sktr.h: SysKonnect TokenRing driver for Linux
+ *
+ * Authors:
+ * - Christoph Goos <cgoos@syskonnect.de>
+ */
+
+#ifndef __LINUX_SKTR_H
+#define __LINUX_SKTR_H
+
+#ifdef __KERNEL__
+
+#define SKTR_MAX_ADAPTERS 7
+
+#define SEND_TIMEOUT 10*HZ
+
+#define TR_RCF_LONGEST_FRAME_MASK 0x0070
+#define TR_RCF_FRAME4K 0x0030
+
+/*------------------------------------------------------------------*/
+/* Bit order for adapter communication with DMA */
+/* -------------------------------------------------------------- */
+/* Bit 8 | 9| 10| 11|| 12| 13| 14| 15|| 0| 1| 2| 3|| 4| 5| 6| 7| */
+/* -------------------------------------------------------------- */
+/* The bytes in a word must be byte swapped. Also, if a double */
+/* word is used for storage, then the words, as well as the bytes, */
+/* must be swapped. */
+/* Bit order for adapter communication with DIO */
+/* -------------------------------------------------------------- */
+/* Bit 0 | 1| 2| 3|| 4| 5| 6| 7|| 8| 9| 10| 11|| 12| 13| 14| 15| */
+/* -------------------------------------------------------------- */
+/*------------------------------------------------------------------*/
+
+/* Swap bytes of a word. */
+#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8)))
+
+/* Swap words of a long. */
+#define SWAPW(x) (((x) << 16) | ((x) >> 16))
+
+/* Get the low byte of a word. */
+#define LOBYTE(w) ((unsigned char)(w))
+
+/* Get the high byte of a word. */
+#define HIBYTE(w) ((unsigned char)((unsigned short)(w) >> 8))
+
+/* Get the low word of a long. */
+#define LOWORD(l) ((unsigned short)(l))
+
+/* Get the high word of a long. */
+#define HIWORD(l) ((unsigned short)((unsigned long)(l) >> 16))
+
+
+
+/* Token ring adapter I/O addresses for normal mode. */
+#define SIFDAT 0L /* SIF/DMA data. */
+#define SIFINC 2L /* IO Word data with auto increment. */
+#define SIFINH 3L /* IO Byte data with auto increment. */
+#define SIFADR 4L /* SIF/DMA Address. */
+#define SIFCMD 6L /* SIF Command. */
+#define SIFSTS 6L /* SIF Status. */
+#define SIFACL 8L /* SIF Adapter Control Register. */
+#define SIFADD 10L /* SIF/DMA Address. */
+#define SIFADX 12L
+#define DMALEN 14L /* SIF DMA length. */
+#define POSREG 16L /* Adapter Program Option Select (POS)
+ * Register: base IO address + 16 byte.
+ */
+#define POSREG_2 24L /* only for TR4/16+ adapter
+ * base IO address + 24 byte.
+ */
+
+
+/* SIFCMD command codes (high-low) */
+#define CMD_INTERRUPT_ADAPTER 0x8000 /* Cause internal adapter interrupt */
+#define CMD_ADAPTER_RESET 0x4000 /* Hardware reset of adapter */
+#define CMD_SSB_CLEAR 0x2000 /* Acknowledge to adapter to
+ * system interrupts.
+ */
+#define CMD_EXECUTE 0x1000 /* Execute SCB command */
+#define CMD_SCB_REQUEST 0x0800 /* Request adapter to interrupt
+ * system when SCB is available for
+ * another command.
+ */
+#define CMD_RX_CONTINUE 0x0400 /* Continue receive after odd pointer
+ * stop. (odd pointer receive method)
+ */
+#define CMD_RX_VALID 0x0200 /* Now actual RPL is valid. */
+#define CMD_TX_VALID 0x0100 /* Now actual TPL is valid. (valid
+ * bit receive/transmit method)
+ */
+#define CMD_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system
+ * interrupt is reset.
+ */
+#define CMD_CLEAR_SYSTEM_IRQ 0x0080 /* Clear SYSTEM_INTERRUPT bit.
+ * (write: 1=ignore, 0=reset)
+ */
+#define EXEC_SOFT_RESET 0xFF00 /* adapter soft reset. (restart
+ * adapter after hardware reset)
+ */
+
+
+/* ACL commands (high-low) */
+#define ACL_SWHLDA 0x0800 /* Software hold acknowledge. */
+#define ACL_SWDDIR 0x0400 /* Data transfer direction. */
+#define ACL_SWHRQ 0x0200 /* Pseudo DMA operation. */
+#define ACL_PSDMAEN 0x0100 /* Enable pseudo system DMA. */
+#define ACL_ARESET 0x0080 /* Adapter hardware reset command.
+ * (held in reset condition as
+ * long as bit is set)
+ */
+#define ACL_CPHALT 0x0040 /* Communication processor halt.
+ * (can only be set while ACL_ARESET
+ * bit is set; prevents adapter
+ * processor from executing code while
+ * downloading firmware)
+ */
+#define ACL_BOOT 0x0020
+#define ACL_SINTEN 0x0008 /* System interrupt enable/disable
+ * (1/0): can be written if ACL_ARESET
+ * is zero.
+ */
+#define ACL_SPEED4 0x0003
+#define ACL_SPEED16 0x0001
+#define PS_DMA_MASK (ACL_SWHRQ | ACL_PSDMAEN)
+
+
+/* SIFSTS register return codes (high-low) */
+#define STS_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system
+ * interrupt is valid.
+ */
+#define STS_INITIALIZE 0x0040 /* INITIALIZE status. (ready to
+ * initialize)
+ */
+#define STS_TEST 0x0020 /* TEST status. (BUD not completed) */
+#define STS_ERROR 0x0010 /* ERROR status. (unrecoverable
+ * HW error occurred)
+ */
+#define STS_MASK 0x00F0 /* Mask interesting status bits. */
+#define STS_ERROR_MASK 0x000F /* Get Error Code by masking the
+ * interrupt code bits.
+ */
+#define ADAPTER_INT_PTRS 0x0A00 /* Address offset of adapter internal
+ * pointers 01:0a00 (high-low) have to
+ * be read after init and before open.
+ */
+
+
+/* Interrupt Codes (only MAC IRQs) */
+#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or
+ * software error.
+ */
+#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */
+#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an
+ * SCB_REQUEST IRQ.
+ */
+#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command
+ * status.
+ */
+#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive
+ * status.
+ */
+#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit
+ * status
+ */
+#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */
+
+
+/* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */
+#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed
+ * (avoid this!) issue another transmit
+ * to send additional frames.
+ */
+#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted;
+ * INTERRUPT_FRAME bit was set in the
+ * CSTAT request; indication of possibly
+ * more than one frame transmissions!
+ * SSB.Parm[0-1]: 32 bit pointer to
+ * TPL of last frame.
+ */
+#define LIST_ERROR 0x0020 /* Error in one of the TPLs that
+ * compose the frame; TRANSMIT
+ * terminated; Parm[1-2]: 32 bit pointer
+ * to TPL which starts the error
+ * frame; error details in bits 8-13.
+ * (14?)
+ */
+#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of
+ * the valid DATA_COUNT fields;
+ * FRAME_SIZE less than header plus
+ * information field. (15 bytes +
+ * routing field) Or if FRAME_SIZE
+ * was specified as zero in one list.
+ */
+#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE
+ * - 9) * TX_BUF_MAX.
+ */
+#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is
+ * read on a list without END_FRAME
+ * indication.
+ */
+#define FRAME_ERROR 0x1000 /* START_FRAME bit is (not) anticipated,
+ * but (not) set.
+ */
+#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not
+ * been allowed.
+ */
+#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero
+ * or MAC frame PCF ATTN field is
+ * greater than one.
+ */
+#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */
+
+
+/*
+ * Since we need to support some functions even if the adapter is in a
+ * CLOSED state, we have a (pseudo-) command queue which holds commands
+ * that are outstandig to be executed.
+ *
+ * Each time a command completes, an interrupt occurs and the next
+ * command is executed. The command queue is actually a simple word with
+ * a bit for each outstandig command. Therefore the commands will not be
+ * executed in the order they have been queued.
+ *
+ * The following defines the command code bits and the command queue:
+ */
+#define OC_OPEN 0x0001 /* OPEN command */
+#define OC_TRANSMIT 0x0002 /* TRANSMIT command */
+#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */
+#define OC_RECEIVE 0x0008 /* RECEIVE command */
+#define OC_CLOSE 0x0010 /* CLOSE command */
+#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */
+#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */
+#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */
+#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */
+#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */
+#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */
+#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */
+#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */
+#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */
+
+#define OPEN 0x0300 /* C: open command. S: completion. */
+#define TRANSMIT 0x0400 /* C: transmit command. S: completion
+ * status. (reject: COMMAND_REJECT if
+ * adapter not opened, TRANSMIT already
+ * issued or address passed in the SCB
+ * not word aligned)
+ */
+#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no
+ * TRANSMIT command issued, the command
+ * is ignored. (completion with TRANSMIT
+ * status (0x0400)!)
+ */
+#define RECEIVE 0x0600 /* C: receive command. S: completion
+ * status. (reject: COMMAND_REJECT if
+ * adapter not opened, RECEIVE already
+ * issued or address passed in the SCB
+ * not word aligned)
+ */
+#define CLOSE 0x0700 /* C: close adapter. S: completion.
+ * (COMMAND_REJECT if adapter not open)
+ */
+#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after
+ * OPEN. S: completion. (COMMAND_REJECT
+ * if adapter not open)
+ */
+#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address
+ * after OPEN. S: completion.
+ * (COMMAND_REJECT if adapter not open)
+ */
+#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters.
+ * S: completion. (command ignored
+ * if adapter not open!)
+ */
+#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory.
+ * (important: after init and before
+ * open!) S: completion. (ADAPTER_CHECK
+ * interrupt if undefined storage area
+ * read)
+ */
+#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational
+ * parameters. (bit correspondend to
+ * WRAP_INTERFACE is ignored)
+ * S: completion. (reject:
+ * COMMAND_REJECT)
+ */
+#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational
+ * parameters. (bit correspondend
+ * to WRAP_INTERFACE is ignored)
+ * S: completion. (reject:
+ * COMMAND_REJECT)
+ */
+#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in
+ * adapter group address.
+ * S: completion. (reject:
+ * COMMAND_REJECT)
+ */
+#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the
+ * adapter hardware to use when frames
+ * are copied for forwarding.
+ * S: completion. (reject:
+ * COMMAND_REJECT)
+ */
+#define CONFIG_BRIDGE_PARMS 0x1100 /* C: ..
+ * S: completion. (reject:
+ * COMMAND_REJECT)
+ */
+
+#define SPEED_4 4
+#define SPEED_16 16 /* Default transmission speed */
+
+
+/* Initialization Parameter Block (IPB); word alignment necessary! */
+#define BURST_SIZE 0x0018 /* Default burst size */
+#define BURST_MODE 0x9F00 /* Burst mode enable */
+#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */
+
+#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns
+ * (later adapter version: fix cycle time!)
+ */
+#define LINE_SPEED_BIT 0x80
+
+/* Macro definition for the wait function. */
+#define ONE_SECOND_TICKS 1000000
+#define HALF_SECOND (ONE_SECOND_TICKS / 2)
+#define ONE_SECOND (ONE_SECOND_TICKS)
+#define TWO_SECONDS (ONE_SECOND_TICKS * 2)
+#define THREE_SECONDS (ONE_SECOND_TICKS * 3)
+#define FOUR_SECONDS (ONE_SECOND_TICKS * 4)
+#define FIVE_SECONDS (ONE_SECOND_TICKS * 5)
+
+#define BUFFER_SIZE 2048 /* Buffers on Adapter */
+
+#pragma pack(1)
+typedef struct {
+ unsigned short Init_Options; /* Initialize with burst mode;
+ * LLC disabled. (MAC only)
+ */
+
+ /* Interrupt vectors the adapter places on attached system bus. */
+ unsigned char CMD_Status_IV; /* Interrupt vector: command status. */
+ unsigned char TX_IV; /* Interrupt vector: transmit. */
+ unsigned char RX_IV; /* Interrupt vector: receive. */
+ unsigned char Ring_Status_IV; /* Interrupt vector: ring status. */
+ unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */
+ unsigned char Adapter_CHK_IV; /* Interrupt vector: adapter check. */
+
+ unsigned short RX_Burst_Size; /* Max. number of transfer cycles. */
+ unsigned short TX_Burst_Size; /* During DMA burst; even value! */
+ unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */
+
+ unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low. */
+ unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low. */
+} IPB, *IPB_Ptr;
+#pragma pack()
+
+/*
+ * OPEN Command Parameter List (OCPL) (can be reused, if the adapter has to
+ * be reopened)
+ */
+#define BUFFER_SIZE 2048 /* Buffers on Adapter. */
+#define TPL_SIZE 8+6*TX_FRAG_NUM /* Depending on fragments per TPL. */
+#define RPL_SIZE 14 /* (with TI firmware v2.26 handling
+ * up to nine fragments possible)
+ */
+#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */
+#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ???
+ */
+#define DISABLE_EARLY_TOKEN_RELEASE 0x1000
+
+/* OPEN Options (high-low) */
+#define WRAP_INTERFACE 0x0080 /* Inserting omitted for test
+ * purposes; transmit data appears
+ * as receive data. (usefull for
+ * testing; change: CLOSE necessary)
+ */
+#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON
+ * no RING.STATUS interrupt.
+ */
+#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS
+ * interrupt.
+ */
+#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames
+ * to system.
+ */
+#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are
+ * passed to the system.
+ */
+#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18
+ * bytes.
+ */
+#define FRAME_HOLD 0x0002 /* Adapter waits for entire frame before
+ * initiating DMA transfer; otherwise:
+ * DMA transfer initiation if internal
+ * buffer filled.
+ */
+#define CONTENDER 0x0001 /* Adapter participates in the monitor
+ * contention process.
+ */
+#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames
+ * to the system.
+ */
+#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation;
+ * 0 = ETR. (no effect in 4 Mbps
+ * operation)
+ */
+#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to
+ * the system. (after OPEN: duplicate
+ * address test (DAT) MAC frame is
+ * first received frame copied to the
+ * system)
+ */
+#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to
+ * the system.
+ */
+#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer
+ * of each received frame; FrameSize
+ * of RPLs must contain internal
+ * BUFFER_SIZE bits for promiscous mode.
+ */
+#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex
+ * settings with bits in byte 22 in
+ * ocpl. (new feature in firmware
+ * version 3.09)
+ */
+
+/* Full-duplex settings */
+#define OPEN_FULL_DUPLEX_OFF 0x0000
+#define OPEN_FULL_DUPLEX_ON 0x00c0
+#define OPEN_FULL_DUPLEX_AUTO 0x0080
+
+#define PROD_ID_SIZE 18 /* Length of product ID. */
+
+#define TX_FRAG_NUM 3 /* Number of fragments used in one TPL. */
+#define TX_MORE_FRAGMENTS 0x8000 /* Bit set in DataCount to indicate more
+ * fragments following.
+ */
+
+#define ISA_MAX_ADDRESS 0x00ffffff
+
+#pragma pack(1)
+typedef struct {
+ unsigned short OPENOptions;
+ unsigned char NodeAddr[6]; /* Adapter node address; use ROM
+ * address
+ */
+ unsigned long GroupAddr; /* Multicast: high order
+ * bytes = 0xC000
+ */
+ unsigned long FunctAddr; /* High order bytes = 0xC000 */
+ unsigned short RxListSize; /* RPL size: 0 (=26), 14, 20 or
+ * 26 bytes read by the adapter.
+ * (Depending on the number of
+ * fragments/list)
+ */
+ unsigned short TxListSize; /* TPL size */
+ unsigned short BufSize; /* Is automatically rounded up to the
+ * nearest nK boundary.
+ */
+ unsigned short FullDuplex;
+ unsigned short Reserved;
+ unsigned char TXBufMin; /* Number of adapter buffers reserved
+ * for transmission a minimum of 2
+ * buffers must be allocated.
+ */
+ unsigned char TXBufMax; /* Maximum number of adapter buffers
+ * for transmit; a minimum of 2 buffers
+ * must be available for receive.
+ * Default: 6
+ */
+ unsigned short ProdIDAddr[2]; /* Pointer to product ID. */
+} OPB, *OPB_Ptr;
+#pragma pack()
+
+/*
+ * SCB: adapter commands enabled by the host system started by writing
+ * CMD_INTERRUPT_ADAPTER | CMD_EXECUTE (|SCB_REQUEST) to the SIFCMD IO
+ * register. (special case: | CMD_SYSTEM_IRQ for initialization)
+ */
+#pragma pack(1)
+typedef struct {
+ unsigned short CMD; /* Command code */
+ unsigned short Parm[2]; /* Pointer to Command Parameter Block */
+} SCB; /* System Command Block (32 bit physical address; big endian)*/
+#pragma pack()
+
+/*
+ * SSB: adapter command return status can be evaluated after COMMAND_STATUS
+ * adapter to system interrupt after reading SSB, the availability of the SSB
+ * has to be told the adapter by writing CMD_INTERRUPT_ADAPTER | CMD_SSB_CLEAR
+ * in the SIFCMD IO register.
+ */
+#pragma pack(1)
+typedef struct {
+ unsigned short STS; /* Status code */
+ unsigned short Parm[3]; /* Parameter or pointer to Status Parameter
+ * Block.
+ */
+} SSB; /* System Status Block (big endian - physical address) */
+#pragma pack()
+
+typedef struct {
+ unsigned short BurnedInAddrPtr; /* Pointer to adapter burned in
+ * address. (BIA)
+ */
+ unsigned short SoftwareLevelPtr;/* Pointer to software level data. */
+ unsigned short AdapterAddrPtr; /* Pointer to adapter addresses. */
+ unsigned short AdapterParmsPtr; /* Pointer to adapter parameters. */
+ unsigned short MACBufferPtr; /* Pointer to MAC buffer. (internal) */
+ unsigned short LLCCountersPtr; /* Pointer to LLC counters. */
+ unsigned short SpeedFlagPtr; /* Pointer to data rate flag.
+ * (4/16 Mbps)
+ */
+ unsigned short AdapterRAMPtr; /* Pointer to adapter RAM found. (KB) */
+} INTPTRS; /* Adapter internal pointers */
+
+#pragma pack(1)
+typedef struct {
+ unsigned char Line_Error; /* Line error: code violation in
+ * frame or in a token, or FCS error.
+ */
+ unsigned char Internal_Error; /* IBM specific. (Reserved_1) */
+ unsigned char Burst_Error;
+ unsigned char ARI_FCI_Error; /* ARI/FCI bit zero in AMP or
+ * SMP MAC frame.
+ */
+ unsigned char AbortDelimeters; /* IBM specific. (Reserved_2) */
+ unsigned char Reserved_3;
+ unsigned char Lost_Frame_Error; /* Receive of end of transmitted
+ * frame failed.
+ */
+ unsigned char Rx_Congest_Error; /* Adapter in repeat mode has not
+ * enough buffer space to copy incoming
+ * frame.
+ */
+ unsigned char Frame_Copied_Error;/* ARI bit not zero in frame
+ * addressed to adapter.
+ */
+ unsigned char Frequency_Error; /* IBM specific. (Reserved_4) */
+ unsigned char Token_Error; /* (active only in monitor station) */
+ unsigned char Reserved_5;
+ unsigned char DMA_Bus_Error; /* DMA bus errors not exceeding the
+ * abort thresholds.
+ */
+ unsigned char DMA_Parity_Error; /* DMA parity errors not exceeding
+ * the abort thresholds.
+ */
+} ERRORTAB; /* Adapter error counters */
+#pragma pack()
+
+
+/*--------------------- Send and Receive definitions -------------------*/
+#pragma pack(1)
+typedef struct {
+ unsigned short DataCount; /* Value 0, even and odd values are
+ * permitted; value is unaltered most
+ * significant bit set: following
+ * fragments last fragment: most
+ * significant bit is not evaluated.
+ * (???)
+ */
+ unsigned long DataAddr; /* Pointer to frame data fragment;
+ * even or odd.
+ */
+} Fragment;
+#pragma pack()
+
+#define MAX_FRAG_NUMBERS 9 /* Maximal number of fragments possible to use
+ * in one RPL/TPL. (depending on TI firmware
+ * version)
+ */
+#define MAX_TX_QUEUE 10 /* Maximal number of skb's queued in driver. */
+
+/*
+ * AC (1), FC (1), Dst (6), Src (6), RIF (18), Data (4472) = 4504
+ * The packet size can be one of the follows: 548, 1502, 2084, 4504, 8176,
+ * 11439, 17832. Refer to TMS380 Second Generation Token Ring User's Guide
+ * Page 2-27.
+ */
+#define HEADER_SIZE (1 + 1 + 6 + 6)
+#define SRC_SIZE 18
+#define MIN_DATA_SIZE 516
+#define DEFAULT_DATA_SIZE 4472
+#define MAX_DATA_SIZE 17800
+
+#define DEFAULT_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + DEFAULT_DATA_SIZE)
+#define MIN_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MIN_DATA_SIZE)
+#define MAX_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MAX_DATA_SIZE)
+
+/*
+ * Macros to deal with the frame status field.
+ */
+#define AC_NOT_RECOGNIZED 0x00
+#define GROUP_BIT 0x80
+#define GET_TRANSMIT_STATUS_HIGH_BYTE(Ts) ((unsigned char)((Ts) >> 8))
+#define GET_FRAME_STATUS_HIGH_AC(Fs) ((unsigned char)(((Fs) & 0xC0) >> 6))
+#define GET_FRAME_STATUS_LOW_AC(Fs) ((unsigned char)(((Fs) & 0x0C) >> 2))
+#define DIRECTED_FRAME(Context) (!((Context)->MData[2] & GROUP_BIT))
+
+
+/*--------------------- Send Functions ---------------------------------*/
+/* define TX_CSTAT _REQUEST (R) and _COMPLETE (C) values (high-low) */
+
+#define TX_VALID 0x0080 /* R: set via TRANSMIT.VALID interrupt.
+ * C: always reset to zero!
+ */
+#define TX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero.
+ * C: set to one.
+ */
+#define TX_START_FRAME 0x0020 /* R: start of a frame: 1
+ * C: unchanged.
+ */
+#define TX_END_FRAME 0x0010 /* R: end of a frame: 1
+ * C: unchanged.
+ */
+#define TX_FRAME_IRQ 0x0008 /* R: request interrupt generation
+ * after transmission.
+ * C: unchanged.
+ */
+#define TX_ERROR 0x0004 /* R: reserved.
+ * C: set to one if Error occurred.
+ */
+#define TX_INTERFRAME_WAIT 0x0004
+#define TX_PASS_CRC 0x0002 /* R: set if CRC value is already
+ * calculated. (valid only in
+ * FRAME_START TPL)
+ * C: unchanged.
+ */
+#define TX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame
+ * source address and does not overwrite
+ * with the adapter node address.
+ * (valid only in FRAME_START TPL)
+ *
+ * C: unchanged.
+ */
+#define TX_STRIP_FS 0xFF00 /* R: reserved.
+ * C: if no Transmission Error,
+ * field contains copy of FS byte after
+ * stripping of frame.
+ */
+
+/*
+ * Structure of Transmit Parameter Lists (TPLs) (only one frame every TPL,
+ * but possibly multiple TPLs for one frame) the length of the TPLs has to be
+ * initialized in the OPL. (OPEN parameter list)
+ */
+#define TPL_NUM 3 /* Number of Transmit Parameter Lists.
+ * !! MUST BE >= 3 !!
+ */
+
+#pragma pack(1)
+typedef struct s_TPL TPL;
+
+struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */
+ unsigned long NextTPLAddr; /* Pointer to next TPL in chain; if
+ * pointer is odd: this is the last
+ * TPL. Pointing to itself can cause
+ * problems!
+ */
+ volatile unsigned short Status; /* Initialized by the adapter:
+ * CSTAT_REQUEST important: update least
+ * significant bit first! Set by the
+ * adapter: CSTAT_COMPLETE status.
+ */
+ unsigned short FrameSize; /* Number of bytes to be transmitted
+ * as a frame including AC/FC,
+ * Destination, Source, Routing field
+ * not including CRC, FS, End Delimiter
+ * (valid only if START_FRAME bit in
+ * CSTAT nonzero) must not be zero in
+ * any list; maximum value: (BUFFER_SIZE
+ * - 8) * TX_BUF_MAX sum of DataCount
+ * values in FragmentList must equal
+ * Frame_Size value in START_FRAME TPL!
+ * frame data fragment list.
+ */
+
+ /* TPL/RPL size in OPEN parameter list depending on maximal
+ * numbers of fragments used in one parameter list.
+ */
+ Fragment FragList[TX_FRAG_NUM]; /* Maximum: nine frame fragments in one
+ * TPL actual version of firmware: 9
+ * fragments possible.
+ */
+#pragma pack()
+
+ /* Special proprietary data and precalculations */
+
+ TPL *NextTPLPtr; /* Pointer to next TPL in chain. */
+ unsigned char *MData;
+ struct sk_buff *Skb;
+ unsigned char TPLIndex;
+ volatile unsigned char BusyFlag;/* Flag: TPL busy? */
+};
+
+/* ---------------------Receive Functions-------------------------------*
+ * define RECEIVE_CSTAT_REQUEST (R) and RECEIVE_CSTAT_COMPLETE (C) values.
+ * (high-low)
+ */
+#define RX_VALID 0x0080 /* R: set; tell adapter with
+ * RECEIVE.VALID interrupt.
+ * C: reset to zero.
+ */
+#define RX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero,
+ * C: set to one.
+ */
+#define RX_START_FRAME 0x0020 /* R: must be reset to zero.
+ * C: set to one on the list.
+ */
+#define RX_END_FRAME 0x0010 /* R: must be reset to zero.
+ * C: set to one on the list
+ * that ends the frame.
+ */
+#define RX_FRAME_IRQ 0x0008 /* R: request interrupt generation
+ * after receive.
+ * C: unchanged.
+ */
+#define RX_INTERFRAME_WAIT 0x0004 /* R: after receiving a frame:
+ * interrupt and wait for a
+ * RECEIVE.CONTINUE.
+ * C: unchanged.
+ */
+#define RX_PASS_CRC 0x0002 /* R: if set, the adapter includes
+ * the CRC in data passed. (last four
+ * bytes; valid only if FRAME_START is
+ * set)
+ * C: set, if CRC is included in
+ * received data.
+ */
+#define RX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame
+ * source address and does not
+ * overwrite with the adapter node
+ * address. (valid only if FRAME_START
+ * is set)
+ * C: unchanged.
+ */
+#define RX_RECEIVE_FS 0xFC00 /* R: reserved; must be reset to zero.
+ * C: on lists with START_FRAME, field
+ * contains frame status field from
+ * received frame; otherwise cleared.
+ */
+#define RX_ADDR_MATCH 0x0300 /* R: reserved; must be reset to zero.
+ * C: address match code mask.
+ */
+#define RX_STATUS_MASK 0x00FF /* Mask for receive status bits. */
+
+#define RX_INTERN_ADDR_MATCH 0x0100 /* C: internally address match. */
+#define RX_EXTERN_ADDR_MATCH 0x0200 /* C: externally matched via
+ * XMATCH/XFAIL interface.
+ */
+#define RX_INTEXT_ADDR_MATCH 0x0300 /* C: internally and externally
+ * matched.
+ */
+#define RX_READY (RX_VALID | RX_FRAME_IRQ) /* Ready for receive. */
+
+/* Constants for Command Status Interrupt.
+ * COMMAND_REJECT status field bit functions (SSB.Parm[0])
+ */
+#define ILLEGAL_COMMAND 0x0080 /* Set if an unknown command
+ * is issued to the adapter
+ */
+#define ADDRESS_ERROR 0x0040 /* Set if any address field in
+ * the SCB is odd. (not word aligned)
+ */
+#define ADAPTER_OPEN 0x0020 /* Command issued illegal with
+ * open adapter.
+ */
+#define ADAPTER_CLOSE 0x0010 /* Command issued illegal with
+ * closed adapter.
+ */
+#define SAME_COMMAND 0x0008 /* Command issued with same command
+ * already executing.
+ */
+
+/* OPEN_COMPLETION values (SSB.Parm[0], MSB) */
+#define NODE_ADDR_ERROR 0x0040 /* Wrong address or BIA read
+ * zero address.
+ */
+#define LIST_SIZE_ERROR 0x0020 /* If List_Size value not in 0,
+ * 14, 20, 26.
+ */
+#define BUF_SIZE_ERROR 0x0010 /* Not enough available memory for
+ * two buffers.
+ */
+#define TX_BUF_COUNT_ERROR 0x0004 /* Remaining receive buffers less than
+ * two.
+ */
+#define OPEN_ERROR 0x0002 /* Error during ring insertion; more
+ * information in bits 8-15.
+ */
+
+/* Standard return codes */
+#define GOOD_COMPLETION 0x0080 /* =OPEN_SUCCESSFULL */
+#define INVALID_OPEN_OPTION 0x0001 /* OPEN options are not supported by
+ * the adapter.
+ */
+
+/* OPEN phases; details of OPEN_ERROR (SSB.Parm[0], LSB) */
+#define OPEN_PHASES_MASK 0xF000 /* Check only the bits 8-11. */
+#define LOBE_MEDIA_TEST 0x1000
+#define PHYSICAL_INSERTION 0x2000
+#define ADDRESS_VERIFICATION 0x3000
+#define PARTICIPATION_IN_RING_POLL 0x4000
+#define REQUEST_INITIALISATION 0x5000
+#define FULLDUPLEX_CHECK 0x6000
+
+/* OPEN error codes; details of OPEN_ERROR (SSB.Parm[0], LSB) */
+#define OPEN_ERROR_CODES_MASK 0x0F00 /* Check only the bits 12-15. */
+#define OPEN_FUNCTION_FAILURE 0x0100 /* Unable to transmit to itself or
+ * frames received before insertion.
+ */
+#define OPEN_SIGNAL_LOSS 0x0200 /* Signal loss condition detected at
+ * receiver.
+ */
+#define OPEN_TIMEOUT 0x0500 /* Insertion timer expired before
+ * logical insertion.
+ */
+#define OPEN_RING_FAILURE 0x0600 /* Unable to receive own ring purge
+ * MAC frames.
+ */
+#define OPEN_RING_BEACONING 0x0700 /* Beacon MAC frame received after
+ * ring insertion.
+ */
+#define OPEN_DUPLICATE_NODEADDR 0x0800 /* Other station in ring found
+ * with the same address.
+ */
+#define OPEN_REQUEST_INIT 0x0900 /* RPS present but does not respond. */
+#define OPEN_REMOVE_RECEIVED 0x0A00 /* Adapter received a remove adapter
+ * MAC frame.
+ */
+#define OPEN_FULLDUPLEX_SET 0x0D00 /* Got this with full duplex on when
+ * trying to connect to a normal ring.
+ */
+
+/* SET_BRIDGE_PARMS return codes: */
+#define BRIDGE_INVALID_MAX_LEN 0x4000 /* MAX_ROUTING_FIELD_LENGTH odd,
+ * less than 6 or > 30.
+ */
+#define BRIDGE_INVALID_SRC_RING 0x2000 /* SOURCE_RING number zero, too large
+ * or = TARGET_RING.
+ */
+#define BRIDGE_INVALID_TRG_RING 0x1000 /* TARGET_RING number zero, too large
+ * or = SOURCE_RING.
+ */
+#define BRIDGE_INVALID_BRDGE_NO 0x0800 /* BRIDGE_NUMBER too large. */
+#define BRIDGE_INVALID_OPTIONS 0x0400 /* Invalid bridge options. */
+#define BRIDGE_DIAGS_FAILED 0x0200 /* Diagnostics of TMS380SRA failed. */
+#define BRIDGE_NO_SRA 0x0100 /* The TMS380SRA does not exist in HW
+ * configuration.
+ */
+
+/*
+ * Bring Up Diagnostics error codes.
+ */
+#define BUD_INITIAL_ERROR 0x0
+#define BUD_CHECKSUM_ERROR 0x1
+#define BUD_ADAPTER_RAM_ERROR 0x2
+#define BUD_INSTRUCTION_ERROR 0x3
+#define BUD_CONTEXT_ERROR 0x4
+#define BUD_PROTOCOL_ERROR 0x5
+#define BUD_INTERFACE_ERROR 0x6
+
+/* BUD constants */
+#define BUD_MAX_RETRIES 3
+#define BUD_MAX_LOOPCNT 6
+#define BUD_TIMEOUT 3000
+
+/* Initialization constants */
+#define INIT_MAX_RETRIES 3 /* Maximum three retries. */
+#define INIT_MAX_LOOPCNT 22 /* Maximum loop counts. */
+
+/* RING STATUS field values (high/low) */
+#define SIGNAL_LOSS 0x0080 /* Loss of signal on the ring
+ * detected.
+ */
+#define HARD_ERROR 0x0040 /* Transmitting or receiving beacon
+ * frames.
+ */
+#define SOFT_ERROR 0x0020 /* Report error MAC frame
+ * transmitted.
+ */
+#define TRANSMIT_BEACON 0x0010 /* Transmitting beacon frames on the
+ * ring.
+ */
+#define LOBE_WIRE_FAULT 0x0008 /* Open or short circuit in the
+ * cable to concentrator; adapter
+ * closed.
+ */
+#define AUTO_REMOVAL_ERROR 0x0004 /* Lobe wrap test failed, deinserted;
+ * adapter closed.
+ */
+#define REMOVE_RECEIVED 0x0001 /* Received a remove ring station MAC
+ * MAC frame request; adapter closed.
+ */
+#define COUNTER_OVERFLOW 0x8000 /* Overflow of one of the adapters
+ * error counters; READ.ERROR.LOG.
+ */
+#define SINGLE_STATION 0x4000 /* Adapter is the only station on the
+ * ring.
+ */
+#define RING_RECOVERY 0x2000 /* Claim token MAC frames on the ring;
+ * reset after ring purge frame.
+ */
+
+#define ADAPTER_CLOSED (LOBE_WIRE_FAULT | AUTO_REMOVAL_ERROR |\
+ REMOVE_RECEIVED)
+
+/* Adapter_check_block.Status field bit assignments: */
+#define DIO_PARITY 0x8000 /* Adapter detects bad parity
+ * through direct I/O access.
+ */
+#define DMA_READ_ABORT 0x4000 /* Aborting DMA read operation
+ * from system Parm[0]: 0=timeout,
+ * 1=parity error, 2=bus error;
+ * Parm[1]: 32 bit pointer to host
+ * system address at failure.
+ */
+#define DMA_WRITE_ABORT 0x2000 /* Aborting DMA write operation
+ * to system. (parameters analogous to
+ * DMA_READ_ABORT)
+ */
+#define ILLEGAL_OP_CODE 0x1000 /* Illegal operation code in the
+ * the adapters firmware Parm[0]-2:
+ * communications processor registers
+ * R13-R15.
+ */
+#define PARITY_ERRORS 0x0800 /* Adapter detects internal bus
+ * parity error.
+ */
+#define RAM_DATA_ERROR 0x0080 /* Valid only during RAM testing;
+ * RAM data error Parm[0-1]: 32 bit
+ * pointer to RAM location.
+ */
+#define RAM_PARITY_ERROR 0x0040 /* Valid only during RAM testing;
+ * RAM parity error Parm[0-1]: 32 bit
+ * pointer to RAM location.
+ */
+#define RING_UNDERRUN 0x0020 /* Internal DMA underrun when
+ * transmitting onto ring.
+ */
+#define INVALID_IRQ 0x0008 /* Unrecognized interrupt generated
+ * internal to adapter Parm[0-2]:
+ * adapter register R13-R15.
+ */
+#define INVALID_ERROR_IRQ 0x0004 /* Unrecognized error interrupt
+ * generated Parm[0-2]: adapter register
+ * R13-R15.
+ */
+#define INVALID_XOP 0x0002 /* Unrecognized XOP request in
+ * communication processor Parm[0-2]:
+ * adapter register R13-R15.
+ */
+#define CHECKADDR 0x05E0 /* Adapter check status information
+ * address offset.
+ */
+#define ROM_PAGE_0 0x0000 /* Adapter ROM page 0. */
+
+/*
+ * RECEIVE.STATUS interrupt result SSB values: (high-low)
+ * (RECEIVE_COMPLETE field bit definitions in SSB.Parm[0])
+ */
+#define RX_COMPLETE 0x0080 /* SSB.Parm[0]; SSB.Parm[1]: 32
+ * bit pointer to last RPL.
+ */
+#define RX_SUSPENDED 0x0040 /* SSB.Parm[0]; SSB.Parm[1]: 32
+ * bit pointer to RPL with odd
+ * forward pointer.
+ */
+
+/* Valid receive CSTAT: */
+#define RX_FRAME_CONTROL_BITS (RX_VALID | RX_START_FRAME | RX_END_FRAME | \
+ RX_FRAME_COMPLETE)
+#define VALID_SINGLE_BUFFER_FRAME (RX_START_FRAME | RX_END_FRAME | \
+ RX_FRAME_COMPLETE)
+
+typedef enum SKB_STAT SKB_STAT;
+enum SKB_STAT {
+ SKB_UNAVAILABLE,
+ SKB_DMA_DIRECT,
+ SKB_DATA_COPY
+};
+
+/* Receive Parameter List (RPL) The length of the RPLs has to be initialized
+ * in the OPL. (OPEN parameter list)
+ */
+#define RPL_NUM 3
+
+#define RX_FRAG_NUM 1 /* Maximal number of used fragments in one RPL.
+ * (up to firmware v2.24: 3, now: up to 9)
+ */
+
+#pragma pack(1)
+typedef struct s_RPL RPL;
+struct s_RPL { /* Receive Parameter List */
+ unsigned long NextRPLAddr; /* Pointer to next RPL in chain
+ * (normalized = physical 32 bit
+ * address) if pointer is odd: this
+ * is last RPL. Pointing to itself can
+ * cause problems!
+ */
+ volatile unsigned short Status; /* Set by creation of Receive Parameter
+ * List RECEIVE_CSTAT_COMPLETE set by
+ * adapter in lists that start or end
+ * a frame.
+ */
+ volatile unsigned short FrameSize; /* Number of bytes received as a
+ * frame including AC/FC, Destination,
+ * Source, Routing field not including
+ * CRC, FS (Frame Status), End Delimiter
+ * (valid only if START_FRAME bit in
+ * CSTAT nonzero) must not be zero in
+ * any list; maximum value: (BUFFER_SIZE
+ * - 8) * TX_BUF_MAX sum of DataCount
+ * values in FragmentList must equal
+ * Frame_Size value in START_FRAME TPL!
+ * frame data fragment list
+ */
+
+ /* TPL/RPL size in OPEN parameter list depending on maximal numbers
+ * of fragments used in one parameter list.
+ */
+ Fragment FragList[RX_FRAG_NUM]; /* Maximum: nine frame fragments in
+ * one TPL. Actual version of firmware:
+ * 9 fragments possible.
+ */
+#pragma pack()
+
+ /* Special proprietary data and precalculations. */
+ RPL *NextRPLPtr; /* Logical pointer to next RPL in chain. */
+ unsigned char *MData;
+ struct sk_buff *Skb;
+ SKB_STAT SkbStat;
+ int RPLIndex;
+};
+
+/* Information that need to be kept for each board. */
+typedef struct net_local {
+#pragma pack(1)
+ IPB ipb; /* Initialization Parameter Block. */
+ SCB scb; /* System Command Block: system to adapter
+ * communication.
+ */
+ SSB ssb; /* System Status Block: adapter to system
+ * communication.
+ */
+ OPB ocpl; /* Open Options Parameter Block. */
+
+ ERRORTAB errorlogtable; /* Adapter statistic error counters.
+ * (read from adapter memory)
+ */
+ unsigned char ProductID[PROD_ID_SIZE + 1]; /* Product ID */
+#pragma pack()
+
+ TPL Tpl[TPL_NUM];
+ TPL *TplFree;
+ TPL *TplBusy;
+ unsigned char LocalTxBuffers[TPL_NUM][DEFAULT_PACKET_SIZE];
+
+ RPL Rpl[RPL_NUM];
+ RPL *RplHead;
+ RPL *RplTail;
+ unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE];
+
+ int DataRate;
+ unsigned char ScbInUse;
+ unsigned short CMDqueue;
+
+ unsigned long AdapterOpenFlag:1;
+ unsigned long AdapterVirtOpenFlag:1;
+ unsigned long OpenCommandIssued:1;
+ unsigned long TransmitCommandActive:1;
+ unsigned long TransmitHaltScheduled:1;
+ unsigned long HaltInProgress:1;
+ unsigned long LobeWireFaultLogged:1;
+ unsigned long ReOpenInProgress:1;
+ unsigned long Sleeping:1;
+
+ unsigned long LastOpenStatus;
+ unsigned short CurrentRingStatus;
+ unsigned long MaxPacketSize;
+
+ unsigned long StartTime;
+ unsigned long LastSendTime;
+
+ struct sk_buff_head SendSkbQueue;
+ unsigned short QueueSkb;
+
+ struct tr_statistics MacStat; /* MAC statistics structure */
+
+ struct timer_list timer;
+
+ struct wait_queue *wait_for_tok_int;
+
+ INTPTRS intptrs; /* Internal adapter pointer. Must be read
+ * before OPEN command.
+ */
+} NET_LOCAL;
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_SKTR_H */
diff --git a/drivers/net/sktr_firmware.h b/drivers/net/sktr_firmware.h
new file mode 100644
index 000000000..bef17faa4
--- /dev/null
+++ b/drivers/net/sktr_firmware.h
@@ -0,0 +1,3616 @@
+/*
+ * The firmware this driver downloads into the tokenring card is a
+ * seperate program and is not GPL'd source code, even though the Linux
+ * side driver and the routine that loads this data into the card are.
+ *
+ * This firmware is licensed to you strictly for use in conjunction
+ * with the use of SysKonnect TokenRing adapters. There is no
+ * waranty expressed or implied about its fitness for any purpose.
+ */
+
+/* sktr_firmware.h: SysKonnect TokenRing driver firmware dump for Linux.
+ *
+ * Notes:
+ * - Loaded from sktr_reset_adapter upon adapter reset.
+ *
+ * Authors:
+ * - Christoph Goos <cgoos@syskonnect.de>
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_SKTR) || defined(CONFIG_SKTR_MODULE)
+
+unsigned char sktr_code[] = {
+ 0x00, 0x00, 0x00, 0xA0, 0x00, 0x20, 0x68, 0x54,
+ 0x73, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x20, 0x65,
+ 0x73, 0x69, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x65,
+ 0x65, 0x73, 0x20, 0x64, 0x6E, 0x75, 0x65, 0x64,
+ 0x20, 0x72, 0x69, 0x6C, 0x65, 0x63, 0x63, 0x6E,
+ 0x20, 0x65, 0x6E, 0x4F, 0x79, 0x6C, 0x20, 0x2C,
+ 0x6C, 0x41, 0x20, 0x6C, 0x69, 0x72, 0x68, 0x67,
+ 0x73, 0x74, 0x72, 0x20, 0x73, 0x65, 0x72, 0x65,
+ 0x65, 0x76, 0x2E, 0x64, 0x60, 0x01, 0x42, 0x01,
+ 0x00, 0x08, 0x08, 0x16, 0xB0, 0x03, 0xE0, 0x04,
+ 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF,
+ 0xFC, 0x13, 0x80, 0x03, 0xA0, 0x07, 0x42, 0x01,
+ 0x00, 0x08, 0x20, 0x07, 0x00, 0x00, 0xE0, 0x04,
+ 0x00, 0x01, 0x8B, 0x07, 0x00, 0x3D, 0x60, 0x01,
+ 0x42, 0x01, 0x80, 0x00, 0x09, 0x13, 0x8B, 0x07,
+ 0x00, 0x2D, 0x20, 0xC0, 0x4E, 0x01, 0x80, 0x02,
+ 0x41, 0x0F, 0x02, 0x11, 0x8B, 0x07, 0x00, 0x3D,
+ 0x0B, 0xC8, 0x4A, 0x01, 0x00, 0x02, 0x00, 0x90,
+ 0xA0, 0x09, 0x00, 0xC8, 0x66, 0x01, 0xE0, 0x02,
+ 0xA0, 0x00, 0xA0, 0x07, 0x04, 0x01, 0x20, 0x00,
+ 0xA0, 0x01, 0x40, 0x01, 0x00, 0xFE, 0x20, 0x48,
+ 0x2A, 0xE0, 0x42, 0x01, 0xE0, 0x04, 0x02, 0x01,
+ 0xE0, 0x04, 0x60, 0x09, 0xE0, 0x04, 0x82, 0x01,
+ 0x60, 0x01, 0x1C, 0x01, 0x04, 0x00, 0x03, 0x16,
+ 0xE0, 0x01, 0x40, 0x01, 0x00, 0x0C, 0xA0, 0x06,
+ 0xBC, 0xA1, 0xA0, 0x07, 0x04, 0x01, 0x2D, 0x00,
+ 0x20, 0xC2, 0x00, 0xE0, 0x88, 0x02, 0x11, 0xE3,
+ 0x14, 0x16, 0xA0, 0x07, 0x04, 0x01, 0x2E, 0x00,
+ 0x60, 0x01, 0x42, 0x01, 0x00, 0x03, 0x0D, 0x16,
+ 0xA0, 0x07, 0x04, 0x01, 0x21, 0x00, 0x88, 0x07,
+ 0x00, 0xA0, 0x89, 0x07, 0xFE, 0xFF, 0xA8, 0x09,
+ 0xA9, 0x09, 0x8A, 0x07, 0x02, 0xE0, 0xA0, 0x06,
+ 0x84, 0xEC, 0x56, 0x10, 0x88, 0x07, 0x00, 0x90,
+ 0x89, 0x07, 0xFE, 0x9F, 0xA8, 0x09, 0xA9, 0x09,
+ 0x8A, 0x07, 0x78, 0xE0, 0xA0, 0x06, 0x84, 0xEC,
+ 0x4B, 0x10, 0xA0, 0x05, 0x04, 0x01, 0x88, 0x07,
+ 0x08, 0x00, 0x89, 0x07, 0x7A, 0x00, 0x00, 0x03,
+ 0x01, 0x00, 0xA0, 0x06, 0xD2, 0xAC, 0x40, 0x10,
+ 0xA0, 0x06, 0xBC, 0xA1, 0xE0, 0x02, 0xF4, 0x03,
+ 0x88, 0x07, 0xA0, 0x00, 0x89, 0x07, 0xFE, 0x00,
+ 0xA0, 0x06, 0xD2, 0xAC, 0x35, 0x10, 0xE0, 0x02,
+ 0xA0, 0x00, 0xE0, 0x04, 0x7E, 0x01, 0xC8, 0x04,
+ 0x09, 0x02, 0xF2, 0x03, 0x48, 0x62, 0xE0, 0xC1,
+ 0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04,
+ 0x18, 0xCE, 0x09, 0x06, 0xFD, 0x16, 0xA0, 0x01,
+ 0x40, 0x01, 0x00, 0x40, 0x07, 0xC8, 0x40, 0x01,
+ 0x88, 0x07, 0xF4, 0x03, 0x89, 0x07, 0xFE, 0x3F,
+ 0xA0, 0x06, 0xD2, 0xAC, 0x19, 0x10, 0xE0, 0x02,
+ 0xA0, 0x00, 0xA0, 0x06, 0xFA, 0xAD, 0x14, 0x10,
+ 0x08, 0xC8, 0x44, 0x04, 0x09, 0xC8, 0x46, 0x04,
+ 0xA0, 0x06, 0x28, 0xAD, 0x0D, 0x10, 0x81, 0x07,
+ 0x7C, 0xE0, 0xB1, 0xC0, 0x26, 0x13, 0x01, 0xC8,
+ 0xE0, 0x00, 0xA0, 0x05, 0x04, 0x01, 0x92, 0x06,
+ 0x03, 0x10, 0x60, 0xC0, 0xE0, 0x00, 0xF5, 0x10,
+ 0xE0, 0x01, 0x04, 0x01, 0x10, 0x00, 0xB0, 0x03,
+ 0xFF, 0x10, 0xA0, 0x01, 0x04, 0x01, 0x00, 0x80,
+ 0x80, 0x03, 0x80, 0x07, 0xA0, 0x00, 0xC2, 0x04,
+ 0x80, 0xCC, 0x81, 0x07, 0xAA, 0xA1, 0x82, 0x02,
+ 0x1E, 0x00, 0x02, 0x16, 0x81, 0x07, 0xB4, 0xA1,
+ 0x81, 0xC4, 0x81, 0x8C, 0xE9, 0x16, 0x82, 0x02,
+ 0x7C, 0x00, 0xF2, 0x16, 0x00, 0x03, 0x0F, 0x00,
+ 0x5B, 0x04, 0x81, 0x07, 0x08, 0xE1, 0x82, 0x07,
+ 0x04, 0x00, 0xE0, 0x04, 0x80, 0x01, 0xE0, 0x04,
+ 0x82, 0x01, 0x91, 0xC4, 0xB1, 0x8C, 0xD8, 0x16,
+ 0x82, 0x02, 0x7C, 0x00, 0xFA, 0x16, 0x20, 0xC8,
+ 0x04, 0xE0, 0x82, 0x01, 0x20, 0xE8, 0x0C, 0xE0,
+ 0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0x80, 0x01,
+ 0x81, 0x07, 0x86, 0xE0, 0xB1, 0xC0, 0x07, 0x13,
+ 0xB1, 0xC4, 0xFC, 0x10, 0xA0, 0x07, 0x04, 0x01,
+ 0x2E, 0x00, 0x60, 0x04, 0xAA, 0xA1, 0x81, 0x07,
+ 0x34, 0xE0, 0x82, 0x07, 0xFC, 0x05, 0x83, 0x07,
+ 0x0A, 0x00, 0xB1, 0xCC, 0x43, 0x06, 0xFD, 0x16,
+ 0x02, 0x02, 0x00, 0x06, 0x60, 0xD0, 0x4E, 0x01,
+ 0xED, 0x13, 0x21, 0x02, 0x00, 0xF7, 0x21, 0x02,
+ 0x00, 0xC0, 0x81, 0xDC, 0x60, 0xD0, 0x4F, 0x01,
+ 0xC1, 0xC0, 0x41, 0x09, 0x21, 0x02, 0x00, 0xF0,
+ 0x81, 0xDC, 0x43, 0x02, 0x00, 0x0F, 0x23, 0x02,
+ 0x00, 0xF0, 0x83, 0xDC, 0x01, 0x02, 0x32, 0x0C,
+ 0xA0, 0xC0, 0x44, 0x04, 0xE0, 0xC0, 0x46, 0x04,
+ 0x03, 0xC1, 0x02, 0x61, 0x84, 0x05, 0x04, 0xC8,
+ 0x48, 0x04, 0x03, 0xC1, 0x84, 0x05, 0x04, 0xA1,
+ 0x01, 0xA1, 0x04, 0xC8, 0x30, 0x0C, 0x03, 0xC1,
+ 0x84, 0x05, 0xF1, 0x04, 0x04, 0x06, 0xFD, 0x16,
+ 0x08, 0x02, 0x00, 0xA0, 0xA8, 0x09, 0x60, 0xC2,
+ 0x30, 0x0C, 0x29, 0x02, 0xFF, 0x03, 0xA9, 0x09,
+ 0x29, 0x02, 0x40, 0x00, 0x80, 0x07, 0x00, 0x90,
+ 0xA0, 0x09, 0x8A, 0x07, 0xFE, 0x9F, 0x2A, 0x02,
+ 0xFF, 0x03, 0xAA, 0x09, 0x01, 0x02, 0x32, 0x0C,
+ 0x05, 0x02, 0x00, 0x00, 0x03, 0xC1, 0x84, 0x05,
+ 0x11, 0x07, 0xC1, 0x05, 0x85, 0x05, 0x04, 0x06,
+ 0x0B, 0x13, 0x85, 0x80, 0xF9, 0x1A, 0x05, 0x80,
+ 0xF8, 0x1A, 0x85, 0x82, 0xF5, 0x1A, 0x05, 0x82,
+ 0xF4, 0x1A, 0x45, 0x82, 0xF1, 0x1A, 0xF1, 0x10,
+ 0x20, 0x2D, 0x02, 0x00, 0x60, 0x01, 0x40, 0x01,
+ 0x00, 0x40, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x08,
+ 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 0x48, 0x10,
+ 0x60, 0x01, 0x42, 0x01, 0x00, 0x80, 0x06, 0x16,
+ 0x8A, 0x07, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01,
+ 0x00, 0x80, 0x3E, 0x10, 0x60, 0x01, 0x02, 0x01,
+ 0x00, 0x10, 0x0A, 0x16, 0x60, 0x01, 0x00, 0x01,
+ 0x00, 0x04, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x80,
+ 0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0x30, 0x10,
+ 0x60, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0A, 0x16,
+ 0x60, 0x01, 0x00, 0x01, 0x00, 0x04, 0x06, 0x16,
+ 0xA0, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0D, 0x02,
+ 0x01, 0x00, 0x0D, 0x10, 0x60, 0x01, 0x02, 0x01,
+ 0x00, 0x04, 0x16, 0x16, 0x60, 0x01, 0x00, 0x01,
+ 0x00, 0x08, 0x12, 0x16, 0xA0, 0x01, 0x02, 0x01,
+ 0x00, 0x04, 0x0D, 0x02, 0x02, 0x00, 0xA0, 0xC3,
+ 0x0E, 0x01, 0xE0, 0xC3, 0x10, 0x01, 0x8A, 0x07,
+ 0x00, 0x20, 0x60, 0x01, 0x00, 0x01, 0x00, 0x80,
+ 0x0B, 0x13, 0x8A, 0x07, 0x00, 0x40, 0x08, 0x10,
+ 0x8A, 0x07, 0x04, 0x00, 0x05, 0x10, 0x8A, 0x07,
+ 0x02, 0x00, 0x02, 0x10, 0x8A, 0x07, 0x08, 0x00,
+ 0x00, 0x03, 0x00, 0x00, 0xE0, 0x04, 0x82, 0x01,
+ 0x8B, 0x07, 0xE0, 0x05, 0xCA, 0xCE, 0xCD, 0xCE,
+ 0xCE, 0xCE, 0xCF, 0xC6, 0x20, 0xC3, 0x58, 0x07,
+ 0x20, 0x23, 0x04, 0xE0, 0x12, 0x13, 0x8B, 0x07,
+ 0x18, 0xFF, 0x8A, 0x02, 0x00, 0x80, 0x0A, 0x13,
+ 0x8B, 0x05, 0xCD, 0xA2, 0x8A, 0x02, 0x00, 0x40,
+ 0x05, 0x13, 0x8A, 0x02, 0x00, 0x20, 0x02, 0x13,
+ 0x8B, 0x07, 0x1D, 0xFF, 0x0B, 0xC8, 0x04, 0x01,
+ 0x0D, 0x10, 0x20, 0xD3, 0x05, 0x01, 0xFD, 0x11,
+ 0x20, 0xD8, 0xDF, 0x07, 0x17, 0x01, 0x8B, 0x07,
+ 0x80, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0x20, 0xE8,
+ 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x04, 0x01,
+ 0xE0, 0x22, 0x86, 0xE1, 0xFB, 0x16, 0xE0, 0x02,
+ 0xA0, 0x00, 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8,
+ 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01,
+ 0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0xA0, 0x01,
+ 0x40, 0x01, 0x00, 0xF6, 0x60, 0x04, 0x90, 0xA0,
+ 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, 0x02, 0x01,
+ 0xFF, 0xDF, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03,
+ 0x00, 0x03, 0x02, 0x00, 0x09, 0x07, 0xA0, 0xC2,
+ 0x04, 0x01, 0x8A, 0x01, 0x80, 0x00, 0x4A, 0x52,
+ 0x89, 0xD2, 0x0A, 0xC8, 0x04, 0x01, 0xA0, 0xD2,
+ 0x04, 0x01, 0xF9, 0x16, 0x49, 0x05, 0x89, 0x01,
+ 0x00, 0x80, 0x49, 0x01, 0x00, 0x40, 0x0E, 0x13,
+ 0x09, 0xF8, 0x3A, 0x07, 0x60, 0xC2, 0x36, 0x07,
+ 0x03, 0x16, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03,
+ 0xE0, 0x04, 0x36, 0x07, 0x54, 0x04, 0x90, 0x03,
+ 0xFF, 0xFF, 0x80, 0x03, 0x60, 0x22, 0x86, 0xE1,
+ 0xC2, 0x13, 0xE0, 0x04, 0x82, 0x01, 0x60, 0x04,
+ 0xE0, 0xA3, 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07,
+ 0x62, 0x09, 0xE8, 0x03, 0xC9, 0x04, 0xA0, 0xC1,
+ 0x34, 0x06, 0x04, 0x16, 0xA0, 0x06, 0x50, 0xB5,
+ 0xE0, 0x04, 0x20, 0x09, 0x86, 0x07, 0xE8, 0x05,
+ 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 0x20, 0xC2,
+ 0x84, 0x01, 0x20, 0x48, 0x08, 0xE0, 0x84, 0x01,
+ 0x20, 0x22, 0x08, 0xE0, 0x08, 0x13, 0x60, 0x01,
+ 0xAE, 0x01, 0x01, 0x00, 0x04, 0x16, 0xE0, 0x01,
+ 0x34, 0x06, 0x00, 0x80, 0x06, 0x10, 0x20, 0xC2,
+ 0x32, 0x09, 0x06, 0x13, 0xE0, 0x01, 0x34, 0x06,
+ 0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x09, 0x07,
+ 0xA0, 0x05, 0xEE, 0x05, 0x20, 0x06, 0xEC, 0x05,
+ 0x02, 0x16, 0x16, 0xC2, 0x03, 0x16, 0x49, 0xC2,
+ 0x12, 0x16, 0x80, 0x03, 0x98, 0xC5, 0xE8, 0xC1,
+ 0x02, 0x00, 0xE0, 0xE9, 0x14, 0xE0, 0x04, 0x00,
+ 0xD7, 0x04, 0x27, 0x02, 0x08, 0x00, 0xA0, 0x06,
+ 0xE6, 0xB4, 0x16, 0xC2, 0x04, 0x13, 0x28, 0xC8,
+ 0x08, 0x00, 0xEC, 0x05, 0xEF, 0x13, 0x54, 0x04,
+ 0x00, 0x03, 0x02, 0x00, 0xE0, 0xC1, 0x86, 0x01,
+ 0x47, 0x02, 0x0E, 0x00, 0xA7, 0xC2, 0x90, 0xE1,
+ 0x5A, 0x04, 0x8A, 0x07, 0x00, 0xA0, 0x0A, 0xC8,
+ 0x86, 0x01, 0xC7, 0xA1, 0x27, 0x02, 0x98, 0xE1,
+ 0x37, 0xE8, 0x34, 0x06, 0x17, 0xE8, 0xD2, 0x06,
+ 0xE0, 0x04, 0x30, 0x06, 0x60, 0x04, 0xF2, 0xA9,
+ 0x0A, 0xE8, 0xD2, 0x06, 0xE0, 0x01, 0x34, 0x06,
+ 0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x20, 0xE0,
+ 0x18, 0xE0, 0x5B, 0x04, 0xA0, 0x05, 0x20, 0x09,
+ 0x20, 0x88, 0x20, 0x09, 0x16, 0xE0, 0xE5, 0x1A,
+ 0xE0, 0x04, 0x20, 0x09, 0xA0, 0x06, 0xD0, 0xD5,
+ 0x80, 0x03, 0xA0, 0x05, 0x32, 0x09, 0x80, 0x03,
+ 0x01, 0xC3, 0xFB, 0x13, 0x60, 0x01, 0x6A, 0x09,
+ 0x01, 0x00, 0x78, 0x13, 0xA0, 0x05, 0x32, 0x09,
+ 0x75, 0x10, 0x41, 0xC0, 0x06, 0x13, 0x01, 0xC8,
+ 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x01, 0x11,
+ 0x7B, 0x10, 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00,
+ 0x79, 0x16, 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01,
+ 0x41, 0xC0, 0x04, 0x13, 0x01, 0xC8, 0x8A, 0x01,
+ 0x01, 0xC8, 0x18, 0x09, 0x86, 0x07, 0x43, 0x00,
+ 0x06, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x02, 0xFC,
+ 0x17, 0xC2, 0x60, 0x04, 0xFA, 0xA6, 0xE0, 0x04,
+ 0x18, 0x09, 0xC7, 0x61, 0x08, 0x07, 0x60, 0x01,
+ 0x06, 0xFC, 0x40, 0x00, 0x02, 0x13, 0x08, 0x02,
+ 0x01, 0x00, 0x09, 0x10, 0x4C, 0xC2, 0x20, 0xC3,
+ 0x00, 0xFC, 0x2A, 0x13, 0x0C, 0xC8, 0x6C, 0x01,
+ 0xE0, 0xC2, 0x02, 0xFC, 0x1B, 0x11, 0x4B, 0x01,
+ 0x00, 0x01, 0xF4, 0x16, 0xC8, 0x22, 0x12, 0x13,
+ 0xCB, 0x01, 0x00, 0x40, 0x0B, 0xC8, 0x02, 0xFC,
+ 0x0D, 0x10, 0xE0, 0xC1, 0x18, 0x09, 0x01, 0xC3,
+ 0x21, 0x13, 0x4C, 0xC2, 0x15, 0x13, 0x0C, 0xC8,
+ 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x06, 0x11,
+ 0xCC, 0x81, 0xD5, 0x13, 0x4C, 0xC2, 0x20, 0xC3,
+ 0x00, 0xFC, 0xF4, 0x10, 0x09, 0xC8, 0x6C, 0x01,
+ 0xE0, 0xC2, 0x02, 0xFC, 0x1E, 0x16, 0xA0, 0x07,
+ 0x02, 0xFC, 0x00, 0x80, 0x09, 0xC3, 0x19, 0x10,
+ 0x09, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC,
+ 0x05, 0x16, 0xA0, 0x07, 0x02, 0xFC, 0x00, 0x80,
+ 0x09, 0xC3, 0x0F, 0x10, 0xE0, 0xC2, 0x02, 0x0C,
+ 0x01, 0x11, 0x1E, 0x10, 0x20, 0xD8, 0x00, 0xE2,
+ 0x83, 0x01, 0x8B, 0x09, 0x8B, 0x09, 0x8B, 0x09,
+ 0x8B, 0x09, 0xA0, 0x07, 0x8A, 0x01, 0x43, 0x00,
+ 0x13, 0x10, 0x0C, 0xC8, 0x8A, 0x01, 0x0C, 0xC8,
+ 0x18, 0x09, 0x0E, 0x10, 0x00, 0x03, 0x02, 0x00,
+ 0xE0, 0xC0, 0x6C, 0x01, 0x20, 0xC3, 0x8A, 0x01,
+ 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x81, 0x13,
+ 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0xB9, 0x13,
+ 0x01, 0x83, 0x31, 0x16, 0x03, 0xC8, 0x6C, 0x01,
+ 0x40, 0x01, 0x10, 0x00, 0x14, 0x16, 0xE0, 0xC2,
+ 0x2E, 0x06, 0x11, 0x13, 0xE0, 0xC2, 0xF8, 0x05,
+ 0x0E, 0x13, 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80,
+ 0x80, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x36, 0x07,
+ 0x06, 0x13, 0xE0, 0x04, 0x36, 0x07, 0x80, 0x01,
+ 0x20, 0x00, 0x60, 0x04, 0xF2, 0xA9, 0x40, 0x01,
+ 0x20, 0x00, 0xF9, 0x13, 0x90, 0x03, 0xFF, 0x11,
+ 0x80, 0x03, 0x08, 0x01, 0x00, 0x04, 0x19, 0x16,
+ 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 0x15, 0x16,
+ 0x88, 0x01, 0x00, 0x1A, 0xC8, 0x01, 0x00, 0x01,
+ 0xC8, 0xC5, 0x0F, 0x10, 0xE0, 0x04, 0x18, 0x09,
+ 0xC0, 0x01, 0x04, 0x00, 0x15, 0x10, 0x81, 0xC1,
+ 0x01, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x00, 0xFC,
+ 0x77, 0xC0, 0x17, 0xC2, 0x48, 0x01, 0x00, 0x18,
+ 0xE4, 0x13, 0x40, 0x01, 0x40, 0x00, 0x15, 0x16,
+ 0x80, 0x01, 0x45, 0x00, 0x46, 0xC1, 0x20, 0xD0,
+ 0x07, 0xFC, 0x60, 0x81, 0x18, 0x09, 0xE6, 0x13,
+ 0xE0, 0xC2, 0x08, 0xFC, 0x08, 0x11, 0xE0, 0xC2,
+ 0x0E, 0xFC, 0x07, 0x15, 0x06, 0x13, 0xE0, 0xC2,
+ 0x14, 0xFC, 0x03, 0x15, 0x02, 0x13, 0xC0, 0x01,
+ 0x01, 0x00, 0x48, 0x01, 0x00, 0x01, 0x11, 0x13,
+ 0x40, 0x01, 0x80, 0x40, 0x69, 0x13, 0x60, 0x04,
+ 0x66, 0xA6, 0x48, 0x01, 0x01, 0x00, 0x03, 0x16,
+ 0x40, 0x01, 0x00, 0x40, 0x0B, 0x16, 0xC8, 0x01,
+ 0x00, 0x40, 0xA0, 0x05, 0x32, 0x09, 0xC8, 0xC5,
+ 0x05, 0x10, 0xC0, 0x01, 0x40, 0x00, 0x40, 0x01,
+ 0x04, 0x00, 0xEF, 0x13, 0xB7, 0x01, 0x20, 0x00,
+ 0xD7, 0xC2, 0xC4, 0x62, 0x0B, 0x05, 0x2B, 0x02,
+ 0xFC, 0xFF, 0xCB, 0xC5, 0x02, 0x15, 0x46, 0x81,
+ 0x6A, 0x13, 0x08, 0x01, 0x00, 0x5E, 0x67, 0x16,
+ 0x08, 0x01, 0x88, 0x00, 0x13, 0x16, 0x86, 0x02,
+ 0x43, 0x00, 0x25, 0x16, 0x40, 0x01, 0x00, 0x40,
+ 0x0B, 0x13, 0x08, 0x01, 0x03, 0x00, 0x08, 0x13,
+ 0x84, 0xC2, 0x2A, 0x02, 0xD8, 0xFF, 0x06, 0xC8,
+ 0x6C, 0x01, 0x0A, 0x68, 0x04, 0xFC, 0x73, 0x10,
+ 0x60, 0x04, 0xD2, 0xA8, 0x40, 0x01, 0x01, 0x00,
+ 0xEA, 0x13, 0x08, 0x01, 0x02, 0x00, 0xE7, 0x16,
+ 0x48, 0x01, 0x01, 0x00, 0xE4, 0x16, 0x40, 0x01,
+ 0x00, 0x40, 0x04, 0x16, 0x60, 0x01, 0xA8, 0x09,
+ 0x80, 0x00, 0xDD, 0x13, 0x8A, 0x07, 0x80, 0x00,
+ 0xA0, 0x06, 0x32, 0xA5, 0xD8, 0x10, 0x00, 0xC0,
+ 0xE7, 0x11, 0x60, 0xC2, 0x6A, 0x09, 0x40, 0x01,
+ 0x00, 0x40, 0x0A, 0x13, 0x48, 0x01, 0x01, 0x00,
+ 0x34, 0x13, 0x48, 0x01, 0x02, 0x00, 0x0A, 0x13,
+ 0x49, 0x01, 0x04, 0x00, 0xD9, 0x16, 0x06, 0x10,
+ 0x49, 0x01, 0x02, 0x00, 0x03, 0x13, 0x08, 0x01,
+ 0x03, 0x00, 0x6E, 0x13, 0x49, 0x01, 0x01, 0x00,
+ 0x12, 0x13, 0x40, 0x01, 0x80, 0x40, 0x01, 0x16,
+ 0x46, 0xC1, 0xE0, 0x04, 0x00, 0xFC, 0x87, 0x07,
+ 0xF8, 0x05, 0x17, 0xC2, 0x14, 0x13, 0xC7, 0x05,
+ 0x17, 0xC8, 0x6C, 0x01, 0x05, 0xC8, 0x00, 0xFC,
+ 0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x07, 0x02,
+ 0x02, 0xFC, 0xE0, 0xA1, 0x2C, 0x09, 0xE0, 0xCD,
+ 0xEE, 0x05, 0xE0, 0xC5, 0x04, 0xFC, 0x20, 0xC8,
+ 0x2C, 0x09, 0x04, 0xFC, 0xE2, 0x10, 0xC5, 0xCD,
+ 0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x60, 0x04,
+ 0xB6, 0xA8, 0x06, 0xC8, 0x6C, 0x01, 0x85, 0x81,
+ 0x1A, 0x13, 0xE0, 0xC2, 0x04, 0xFC, 0x17, 0x15,
+ 0x86, 0xC2, 0x8A, 0xA2, 0xAA, 0xC1, 0x32, 0x0C,
+ 0x06, 0xC8, 0x6C, 0x01, 0x0B, 0xA8, 0x04, 0xFC,
+ 0x1A, 0x09, 0x0A, 0xC8, 0x6C, 0x01, 0xE0, 0xC2,
+ 0x02, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 0x06, 0xC8,
+ 0x6C, 0x01, 0x0B, 0xC8, 0x02, 0xFC, 0xA0, 0x06,
+ 0x3E, 0xB4, 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04,
+ 0x00, 0xFC, 0xA0, 0x01, 0x02, 0xFC, 0x02, 0x00,
+ 0x87, 0x07, 0x30, 0x06, 0xE7, 0x01, 0x04, 0x00,
+ 0x40, 0x00, 0xD7, 0x04, 0x27, 0x02, 0x0C, 0x00,
+ 0x05, 0xC2, 0x60, 0x01, 0x6A, 0x09, 0x04, 0x00,
+ 0x03, 0x16, 0xE0, 0x01, 0x02, 0xFC, 0x20, 0x00,
+ 0xA0, 0x06, 0xFC, 0xB4, 0xC0, 0x01, 0x20, 0x00,
+ 0x60, 0x04, 0x66, 0xA6, 0x48, 0x01, 0x00, 0x18,
+ 0x03, 0x13, 0x48, 0x01, 0x00, 0x10, 0x02, 0x16,
+ 0xA0, 0x05, 0x32, 0x09, 0x86, 0x02, 0x43, 0x00,
+ 0x03, 0x13, 0x40, 0x01, 0x80, 0x40, 0x98, 0x13,
+ 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC,
+ 0x85, 0xC2, 0xA0, 0x06, 0x3E, 0xB4, 0x20, 0x06,
+ 0x62, 0x09, 0xE6, 0x16, 0xA0, 0x06, 0xD0, 0xD5,
+ 0xE3, 0x10, 0xA0, 0xC2, 0xF6, 0x05, 0x56, 0x16,
+ 0x19, 0xC8, 0xF0, 0x05, 0xA9, 0xC2, 0x0A, 0x00,
+ 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 0x0A, 0xD8,
+ 0x80, 0x01, 0x29, 0xC8, 0x06, 0x00, 0x8C, 0x01,
+ 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 0x09, 0xC8,
+ 0xF4, 0x05, 0x46, 0x10, 0x29, 0xC8, 0x06, 0x00,
+ 0x6C, 0x01, 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01,
+ 0x20, 0xC8, 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8,
+ 0x12, 0xFC, 0xB2, 0x01, 0xA0, 0xF2, 0x2E, 0x09,
+ 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x80, 0x01,
+ 0x00, 0xC4, 0xE1, 0x10, 0x47, 0x01, 0x08, 0x00,
+ 0x06, 0x16, 0xA8, 0xC2, 0x06, 0x00, 0xA0, 0x06,
+ 0x3E, 0xB4, 0xE8, 0x04, 0x06, 0x00, 0x07, 0x01,
+ 0x20, 0x00, 0x31, 0x13, 0xE8, 0x04, 0x02, 0x00,
+ 0x3B, 0x10, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x06,
+ 0x3E, 0xB4, 0x29, 0x10, 0x00, 0x03, 0x02, 0x00,
+ 0x20, 0xC2, 0x8C, 0x01, 0xE0, 0xC0, 0x6C, 0x01,
+ 0x20, 0xC2, 0xF4, 0x05, 0x28, 0xC8, 0x08, 0x00,
+ 0x6C, 0x01, 0xE8, 0xC1, 0x0A, 0x00, 0x20, 0xC3,
+ 0x02, 0xFC, 0x8C, 0x01, 0x20, 0x00, 0x0C, 0xC8,
+ 0x02, 0xFC, 0x0C, 0x01, 0x00, 0xFE, 0x3B, 0x16,
+ 0x47, 0x01, 0x40, 0x00, 0x50, 0x13, 0x60, 0xC2,
+ 0xF0, 0x05, 0xA7, 0x16, 0xE0, 0x04, 0xF4, 0x05,
+ 0x0C, 0xCA, 0x08, 0x00, 0x47, 0x01, 0x80, 0x00,
+ 0xC9, 0x16, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01,
+ 0xA0, 0xC2, 0x00, 0xFC, 0xD2, 0x16, 0xE8, 0xC1,
+ 0x02, 0x00, 0xD7, 0xC2, 0x0F, 0x16, 0x27, 0x02,
+ 0x10, 0x00, 0xD8, 0x04, 0x57, 0xC2, 0x0E, 0x13,
+ 0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5,
+ 0x03, 0xC8, 0x6C, 0x01, 0x0D, 0x11, 0x90, 0x03,
+ 0xFF, 0x11, 0x80, 0x03, 0xD7, 0x04, 0xC3, 0x01,
+ 0x00, 0x80, 0xED, 0x10, 0xE7, 0x01, 0xF4, 0xFF,
+ 0x20, 0x00, 0xC8, 0xCD, 0xC8, 0xC5, 0xF0, 0x10,
+ 0x90, 0x03, 0xF8, 0x11, 0xE0, 0x02, 0xC0, 0x00,
+ 0x60, 0xC3, 0xFA, 0x00, 0xA0, 0xC3, 0xFC, 0x00,
+ 0xE0, 0xC3, 0xFE, 0x00, 0x54, 0x04, 0xE8, 0xC2,
+ 0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x0C, 0xC3,
+ 0x33, 0x11, 0x20, 0x23, 0x0A, 0xE0, 0x45, 0x13,
+ 0x20, 0x23, 0x10, 0xE0, 0x46, 0x13, 0x20, 0x23,
+ 0x0E, 0xE0, 0x13, 0x13, 0xE0, 0x21, 0x16, 0xE0,
+ 0xB6, 0x16, 0x20, 0x23, 0x06, 0xE0, 0x03, 0x16,
+ 0x20, 0x27, 0xA8, 0xE4, 0x0A, 0x13, 0xE8, 0xC2,
+ 0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x4C, 0x01,
+ 0x88, 0x00, 0xA9, 0x16, 0x0C, 0x01, 0x44, 0x00,
+ 0xA6, 0x16, 0x20, 0x06, 0x16, 0x09, 0xA3, 0x13,
+ 0x0A, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x04, 0xE0,
+ 0x02, 0xFC, 0x0B, 0xC8, 0x6C, 0x01, 0xA0, 0x07,
+ 0x02, 0xFC, 0x00, 0x81, 0x20, 0xC3, 0x80, 0x01,
+ 0xA0, 0x01, 0x80, 0x01, 0x00, 0xC4, 0x0C, 0xC8,
+ 0x80, 0x01, 0x0A, 0xC8, 0x8C, 0x01, 0xAC, 0x10,
+ 0x0A, 0xC2, 0x0F, 0x13, 0x08, 0xC8, 0x6C, 0x01,
+ 0xA0, 0xC2, 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC,
+ 0x20, 0x23, 0x12, 0xE0, 0xF5, 0x16, 0x0B, 0xC8,
+ 0x6C, 0x01, 0x0C, 0xC8, 0x02, 0xFC, 0x60, 0x04,
+ 0x72, 0xA9, 0x8A, 0x07, 0x00, 0x04, 0x60, 0x04,
+ 0x8A, 0xA3, 0x8A, 0x07, 0x20, 0x00, 0x60, 0x04,
+ 0x8A, 0xA3, 0x8A, 0x07, 0x00, 0x02, 0x20, 0x27,
+ 0x0E, 0xE0, 0x04, 0x16, 0xA0, 0x06, 0x32, 0xA5,
+ 0xC3, 0x01, 0x00, 0x80, 0xA8, 0xC2, 0x06, 0x00,
+ 0x60, 0x04, 0x98, 0xA9, 0x00, 0x03, 0x02, 0x00,
+ 0xC0, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x2E, 0x06,
+ 0x08, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 0x05, 0x13,
+ 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 0x80, 0x01,
+ 0x10, 0x00, 0x90, 0x03, 0xFF, 0x7F, 0x80, 0x03,
+ 0x00, 0x03, 0x02, 0x00, 0x20, 0xC2, 0xF6, 0x05,
+ 0x20, 0xE2, 0xF4, 0x05, 0x0E, 0x16, 0x20, 0xD8,
+ 0x2E, 0x09, 0x80, 0x01, 0x2B, 0xC8, 0x06, 0x00,
+ 0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00,
+ 0x0B, 0xC8, 0xF4, 0x05, 0x90, 0x03, 0xFF, 0xFF,
+ 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 0xDB, 0x04,
+ 0x57, 0xC2, 0x05, 0x16, 0xCB, 0xCD, 0xCB, 0xC5,
+ 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0xC7, 0x05,
+ 0x57, 0xC2, 0x4B, 0xC6, 0xCB, 0xC5, 0x90, 0x03,
+ 0xFF, 0xFF, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00,
+ 0x0B, 0xC2, 0x20, 0xC3, 0xF4, 0x05, 0x0F, 0x13,
+ 0xA8, 0xC2, 0x0A, 0x00, 0x4A, 0x01, 0x10, 0x00,
+ 0x16, 0x16, 0xA0, 0x22, 0x04, 0xE0, 0x1A, 0x16,
+ 0x08, 0xC3, 0xA0, 0x06, 0x36, 0xAC, 0x0C, 0xC2,
+ 0x20, 0xC3, 0xF4, 0x05, 0x13, 0x16, 0x68, 0x01,
+ 0x0A, 0x00, 0x10, 0x00, 0x03, 0x13, 0xE0, 0xC2,
+ 0xF6, 0x05, 0x05, 0x16, 0xA0, 0x06, 0x78, 0xAC,
+ 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07,
+ 0xF0, 0x05, 0xA0, 0x06, 0xE6, 0xB4, 0x90, 0x03,
+ 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05,
+ 0xA0, 0x06, 0x2C, 0xB5, 0x80, 0x03, 0x00, 0x03,
+ 0x02, 0x00, 0x87, 0x07, 0xF0, 0x05, 0xCB, 0xC2,
+ 0x08, 0x16, 0xA0, 0x06, 0x36, 0xAC, 0x20, 0x07,
+ 0xF6, 0x05, 0x60, 0xCB, 0xF4, 0x05, 0x02, 0x00,
+ 0x80, 0x03, 0xE0, 0x04, 0xF6, 0x05, 0x20, 0xC2,
+ 0xF4, 0x05, 0x05, 0x16, 0x17, 0xC2, 0x03, 0x13,
+ 0xD8, 0xC5, 0xA0, 0x06, 0x78, 0xAC, 0x80, 0x03,
+ 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC3, 0xA0, 0x06,
+ 0x36, 0xAC, 0x8C, 0xC2, 0xCC, 0xC1, 0x27, 0x02,
+ 0x10, 0x00, 0x88, 0x07, 0xF0, 0x05, 0x88, 0xC1,
+ 0x18, 0xC2, 0x26, 0x13, 0xA8, 0x82, 0x02, 0x00,
+ 0xFA, 0x16, 0xE8, 0xC2, 0x0A, 0x00, 0xE0, 0x22,
+ 0x1E, 0xE0, 0xF5, 0x16, 0x98, 0xC5, 0xE0, 0x22,
+ 0x1C, 0xE0, 0x0B, 0x16, 0x28, 0xC8, 0x06, 0x00,
+ 0xF4, 0x00, 0xE0, 0x02, 0xE0, 0x00, 0xA0, 0x06,
+ 0x3E, 0xB4, 0xE0, 0x02, 0xC0, 0x00, 0xE8, 0x04,
+ 0x06, 0x00, 0xE0, 0x22, 0x18, 0xE0, 0xE4, 0x13,
+ 0x20, 0xEA, 0x22, 0xE0, 0x0A, 0x00, 0xA0, 0xEA,
+ 0x18, 0xE0, 0x04, 0x00, 0xDA, 0x04, 0xA0, 0x06,
+ 0xE6, 0xB4, 0x47, 0x06, 0x06, 0xC2, 0xD8, 0x10,
+ 0x06, 0xC8, 0xF2, 0x05, 0x60, 0xCB, 0xF4, 0x05,
+ 0x02, 0x00, 0x54, 0x04, 0x20, 0xC2, 0xF4, 0x05,
+ 0x13, 0x13, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40,
+ 0x8B, 0x0B, 0x8B, 0x0B, 0x60, 0x01, 0x9C, 0x01,
+ 0x00, 0x40, 0x0A, 0x16, 0x60, 0xC2, 0x6C, 0x01,
+ 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC2,
+ 0x02, 0xFC, 0x03, 0x11, 0x09, 0xC8, 0x6C, 0x01,
+ 0x5B, 0x04, 0x09, 0xC8, 0x6C, 0x01, 0x4B, 0xC2,
+ 0x87, 0x07, 0xF0, 0x05, 0xA0, 0x06, 0x2C, 0xB5,
+ 0xE0, 0x04, 0xF4, 0x05, 0x59, 0x04, 0xA8, 0xC2,
+ 0x0A, 0x00, 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09,
+ 0x0A, 0xD8, 0x80, 0x01, 0x28, 0xC8, 0x06, 0x00,
+ 0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00,
+ 0x08, 0xC8, 0xF4, 0x05, 0x5B, 0x04, 0x20, 0xC3,
+ 0x6C, 0x01, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01,
+ 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 0x20, 0xC8,
+ 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 0x12, 0xFC,
+ 0xB2, 0x01, 0x0C, 0xC8, 0x6C, 0x01, 0xA0, 0xF2,
+ 0x2E, 0x09, 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01,
+ 0x80, 0x01, 0x00, 0xC4, 0xDD, 0x10, 0x48, 0xC0,
+ 0x89, 0xC0, 0x81, 0x60, 0xC2, 0x05, 0x5B, 0x04,
+ 0x0B, 0xC3, 0xA0, 0x06, 0xC8, 0xAC, 0x41, 0xCC,
+ 0x42, 0x06, 0xFD, 0x16, 0xA0, 0x06, 0xC8, 0xAC,
+ 0x01, 0xC1, 0x44, 0x8C, 0x12, 0x16, 0xC4, 0x05,
+ 0x42, 0x06, 0xFB, 0x16, 0x04, 0x02, 0x0E, 0xAD,
+ 0x03, 0x02, 0x01, 0x01, 0x94, 0x06, 0x03, 0x02,
+ 0x5A, 0x5A, 0x94, 0x06, 0x43, 0x05, 0x94, 0x06,
+ 0x03, 0x07, 0x94, 0x06, 0xC3, 0x04, 0x94, 0x06,
+ 0xCC, 0x05, 0x5C, 0x04, 0xCB, 0xC1, 0xA0, 0x06,
+ 0xC8, 0xAC, 0x43, 0xCC, 0x42, 0x06, 0xFD, 0x16,
+ 0xA0, 0x06, 0xC8, 0xAC, 0x43, 0x8C, 0xF5, 0x16,
+ 0x42, 0x06, 0xFC, 0x16, 0x57, 0x04, 0x8B, 0xC2,
+ 0x08, 0xC0, 0x49, 0xC1, 0x85, 0x05, 0x80, 0x02,
+ 0x40, 0x00, 0x03, 0x11, 0x80, 0x02, 0x4F, 0x00,
+ 0x45, 0x12, 0x01, 0x02, 0xC8, 0xAC, 0xA1, 0x09,
+ 0x01, 0x80, 0x40, 0x13, 0x01, 0x02, 0xF8, 0xAD,
+ 0xA1, 0x09, 0x01, 0x80, 0x3B, 0x13, 0x60, 0xC0,
+ 0x06, 0x00, 0xA1, 0x09, 0x01, 0x80, 0x36, 0x13,
+ 0x81, 0x05, 0x01, 0x80, 0x33, 0x13, 0x4A, 0xC0,
+ 0xA1, 0x09, 0x01, 0x80, 0x2F, 0x13, 0x00, 0xC8,
+ 0x6A, 0x01, 0x80, 0x02, 0x80, 0x00, 0x17, 0x14,
+ 0x01, 0x02, 0x00, 0xF8, 0xA0, 0xC1, 0x40, 0x01,
+ 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 0x02, 0x02,
+ 0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0xB1, 0xCC,
+ 0x43, 0x06, 0xFD, 0x16, 0xA0, 0x01, 0x40, 0x01,
+ 0x00, 0x40, 0x08, 0x02, 0x10, 0xF8, 0x06, 0xC8,
+ 0x40, 0x01, 0x00, 0xC0, 0x02, 0x13, 0x08, 0x02,
+ 0x00, 0xF8, 0x09, 0x02, 0xFE, 0xFB, 0xA0, 0x06,
+ 0xD2, 0xAC, 0x25, 0x10, 0x80, 0x02, 0x80, 0x00,
+ 0x09, 0x14, 0x01, 0x02, 0x00, 0xF8, 0x02, 0x02,
+ 0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0x72, 0xCC,
+ 0x43, 0x06, 0xFD, 0x16, 0x80, 0x05, 0x80, 0x02,
+ 0x80, 0x00, 0x04, 0x12, 0x60, 0x01, 0x04, 0x01,
+ 0x20, 0x00, 0x05, 0x13, 0x40, 0x81, 0xAB, 0x16,
+ 0x80, 0x02, 0x80, 0x00, 0x0B, 0x14, 0xA0, 0x07,
+ 0x6A, 0x01, 0x7E, 0x00, 0x02, 0x02, 0x00, 0x10,
+ 0x03, 0x02, 0x00, 0x04, 0xC1, 0x04, 0x81, 0xCC,
+ 0x43, 0x06, 0xFD, 0x16, 0xCA, 0x05, 0x5A, 0x04,
+ 0x00, 0x02, 0xEA, 0xAD, 0x01, 0x02, 0x1A, 0xAF,
+ 0x40, 0x02, 0x00, 0xFC, 0x41, 0x02, 0x00, 0xFC,
+ 0x40, 0x80, 0x04, 0x13, 0xA0, 0x07, 0x04, 0x01,
+ 0x3C, 0x00, 0x5B, 0x04, 0xC0, 0x04, 0x01, 0x02,
+ 0x08, 0x00, 0x02, 0x02, 0x00, 0x12, 0xE0, 0xC1,
+ 0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04,
+ 0x03, 0x02, 0x00, 0x01, 0x00, 0xC8, 0x6A, 0x01,
+ 0xA0, 0xCC, 0x10, 0xF8, 0x80, 0x05, 0x03, 0x06,
+ 0xF9, 0x16, 0x22, 0x02, 0x00, 0x02, 0x01, 0x06,
+ 0xF3, 0x16, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40,
+ 0x07, 0xC8, 0x40, 0x01, 0x00, 0x02, 0x00, 0x08,
+ 0x40, 0xC0, 0x01, 0x06, 0x01, 0xC8, 0x6A, 0x01,
+ 0x61, 0x02, 0x00, 0x80, 0x01, 0xC8, 0x10, 0xF8,
+ 0x00, 0x06, 0xF6, 0x16, 0xC0, 0x04, 0xC8, 0x04,
+ 0xC9, 0x04, 0x03, 0x02, 0x00, 0x08, 0x00, 0xC8,
+ 0x6A, 0x01, 0x80, 0xC1, 0x66, 0x02, 0x00, 0x80,
+ 0x20, 0xC1, 0x10, 0xF8, 0x06, 0x81, 0x15, 0x16,
+ 0x08, 0xC2, 0x06, 0x13, 0x80, 0x05, 0x03, 0x06,
+ 0xF2, 0x16, 0x08, 0xC2, 0x0D, 0x13, 0x19, 0x10,
+ 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 0x20, 0xC1,
+ 0x10, 0xF8, 0x84, 0x02, 0x55, 0x55, 0x02, 0x16,
+ 0x06, 0xC2, 0xF0, 0x10, 0x06, 0x81, 0xEE, 0x13,
+ 0x5B, 0x04, 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55,
+ 0x60, 0xC1, 0x10, 0xF8, 0x05, 0x81, 0x03, 0x13,
+ 0x85, 0x02, 0x55, 0x55, 0xF5, 0x16, 0x08, 0xC2,
+ 0xE1, 0x13, 0x40, 0xC2, 0x09, 0x06, 0x48, 0x02,
+ 0xFF, 0x07, 0xC0, 0x04, 0x01, 0x02, 0x08, 0x00,
+ 0x02, 0x02, 0x00, 0x12, 0x03, 0x02, 0x00, 0x01,
+ 0x00, 0xC8, 0x6A, 0x01, 0x32, 0xC8, 0x10, 0xF8,
+ 0x80, 0x05, 0x03, 0x06, 0xF9, 0x16, 0x22, 0x02,
+ 0x00, 0x02, 0x01, 0x06, 0xF3, 0x16, 0x88, 0x02,
+ 0x40, 0x00, 0x13, 0x15, 0x89, 0x02, 0x4F, 0x00,
+ 0x10, 0x11, 0xC0, 0x04, 0x02, 0x02, 0x00, 0x12,
+ 0x01, 0x02, 0x08, 0x00, 0x03, 0x02, 0x00, 0x01,
+ 0x80, 0xCC, 0x03, 0x06, 0xFD, 0x16, 0x22, 0x02,
+ 0x00, 0x02, 0x01, 0x06, 0xF7, 0x16, 0xCB, 0x05,
+ 0x5B, 0x04, 0xA0, 0x07, 0x04, 0x01, 0x37, 0x00,
+ 0x5B, 0x04, 0x33, 0x07, 0x33, 0x07, 0x0C, 0x10,
+ 0x13, 0x07, 0x23, 0x07, 0x02, 0x00, 0xCB, 0xC8,
+ 0x06, 0x00, 0x23, 0x02, 0x18, 0x00, 0xE0, 0xCC,
+ 0x6C, 0x01, 0xCD, 0xCC, 0xCE, 0xCC, 0xCF, 0xCC,
+ 0x83, 0x07, 0x30, 0x06, 0xD3, 0xC1, 0x0A, 0x13,
+ 0x83, 0x07, 0x36, 0x07, 0xD3, 0xC1, 0x06, 0x13,
+ 0x83, 0x07, 0xA0, 0x00, 0x93, 0x00, 0x0C, 0xC8,
+ 0x6C, 0x01, 0x80, 0x03, 0x63, 0x07, 0x02, 0x00,
+ 0x2A, 0x15, 0x63, 0xC2, 0x04, 0x00, 0x63, 0x42,
+ 0x06, 0x00, 0xDB, 0x13, 0x63, 0xC3, 0x1A, 0x00,
+ 0x49, 0xD2, 0x0C, 0x13, 0xC9, 0x06, 0x49, 0x72,
+ 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 0x49, 0x72,
+ 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB,
+ 0x02, 0x00, 0x52, 0x04, 0x69, 0xC2, 0xC0, 0xE1,
+ 0x49, 0x72, 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2,
+ 0xE9, 0xA2, 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02,
+ 0x12, 0x00, 0x0F, 0x13, 0xDC, 0xC6, 0x03, 0x16,
+ 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB,
+ 0x02, 0x00, 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03,
+ 0xFF, 0x01, 0x93, 0x00, 0x0C, 0xC8, 0x6C, 0x01,
+ 0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6,
+ 0x00, 0xFC, 0xF1, 0x16, 0xE9, 0x48, 0x04, 0xE0,
+ 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 0x4C, 0xCB,
+ 0x04, 0x00, 0xED, 0x10, 0x00, 0x03, 0x02, 0x00,
+ 0xDB, 0xC2, 0x63, 0xC2, 0x04, 0x00, 0x4B, 0x42,
+ 0x9F, 0x13, 0x49, 0xD2, 0x0E, 0x13, 0xC9, 0x06,
+ 0x49, 0x72, 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06,
+ 0x49, 0x72, 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00,
+ 0x49, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF,
+ 0x80, 0x03, 0x69, 0xC2, 0xC0, 0xE1, 0x49, 0x72,
+ 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 0xE9, 0xA2,
+ 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 0x12, 0x00,
+ 0x0C, 0x13, 0xDC, 0xC6, 0x03, 0x16, 0xE9, 0x48,
+ 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00,
+ 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 0xFF, 0xFF,
+ 0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6,
+ 0x00, 0xFC, 0xF4, 0x16, 0xF0, 0x10, 0x00, 0x03,
+ 0x02, 0x00, 0xBB, 0xC2, 0xBB, 0xC1, 0x86, 0xD1,
+ 0x03, 0x13, 0x86, 0xEA, 0x04, 0x00, 0x13, 0x10,
+ 0xA6, 0xD1, 0xC0, 0xE1, 0xC6, 0x06, 0x86, 0x71,
+ 0xCA, 0xC1, 0xE6, 0xA1, 0xB8, 0xE1, 0xA6, 0xEA,
+ 0x14, 0xE0, 0x04, 0x00, 0x1B, 0xC2, 0x86, 0x02,
+ 0x02, 0x00, 0x03, 0x16, 0xA0, 0x06, 0x0C, 0xB5,
+ 0x02, 0x10, 0xA0, 0x06, 0xE6, 0xB4, 0xDA, 0x04,
+ 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xAB, 0xC2,
+ 0x06, 0x00, 0x8C, 0x07, 0xE8, 0x05, 0x5C, 0xC2,
+ 0x16, 0x13, 0xA0, 0xC1, 0xEC, 0x05, 0x8A, 0x81,
+ 0x1A, 0x1A, 0xC6, 0xC1, 0x09, 0xC2, 0x59, 0xC2,
+ 0x20, 0x13, 0xE9, 0xA1, 0x08, 0x00, 0x87, 0x82,
+ 0xF9, 0x12, 0xA9, 0xA2, 0x08, 0x00, 0x87, 0x62,
+ 0xCA, 0xCA, 0x08, 0x00, 0x4A, 0x6A, 0x08, 0x00,
+ 0xC9, 0xC6, 0x0B, 0xC6, 0x80, 0x03, 0xCA, 0xCA,
+ 0x08, 0x00, 0x0A, 0xC8, 0xEC, 0x05, 0xDB, 0x04,
+ 0x0B, 0xCF, 0x0B, 0xC7, 0x80, 0x03, 0x8A, 0x61,
+ 0x46, 0xCA, 0x08, 0x00, 0xCA, 0xCA, 0x08, 0x00,
+ 0x0A, 0xC8, 0xEC, 0x05, 0xC9, 0xC6, 0x0B, 0xC7,
+ 0x80, 0x03, 0x87, 0x62, 0xCA, 0xCA, 0x08, 0x00,
+ 0xDB, 0x04, 0x0B, 0xC6, 0x0B, 0xCB, 0x02, 0x00,
+ 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xBB, 0xC1,
+ 0xDB, 0xC2, 0x8C, 0x07, 0xE8, 0x05, 0x4C, 0xC2,
+ 0xED, 0x04, 0x02, 0x00, 0x09, 0xC2, 0x59, 0xC2,
+ 0x18, 0x13, 0xA9, 0x81, 0x02, 0x00, 0xFA, 0x16,
+ 0xE9, 0x82, 0x04, 0x00, 0xF7, 0x16, 0x49, 0xCB,
+ 0x04, 0x00, 0x99, 0xC2, 0x0A, 0xC6, 0x0A, 0x13,
+ 0x08, 0x83, 0x04, 0x13, 0xA9, 0xAA, 0x08, 0x00,
+ 0x08, 0x00, 0x80, 0x03, 0x2A, 0xA8, 0x08, 0x00,
+ 0xEC, 0x05, 0x80, 0x03, 0x08, 0xCB, 0x02, 0x00,
+ 0x80, 0x03, 0x2D, 0x07, 0x02, 0x00, 0x8C, 0x07,
+ 0x08, 0x00, 0x06, 0xA3, 0x4C, 0xC2, 0x09, 0xC2,
+ 0x59, 0xC2, 0x13, 0x13, 0xE9, 0x82, 0x04, 0x00,
+ 0xFA, 0x16, 0xAD, 0x07, 0x02, 0x00, 0x01, 0x00,
+ 0x49, 0xCB, 0x04, 0x00, 0x19, 0xC6, 0x01, 0x13,
+ 0x80, 0x03, 0x08, 0x83, 0x04, 0x16, 0xA0, 0x49,
+ 0x14, 0xE0, 0x04, 0x00, 0x80, 0x03, 0x08, 0xCB,
+ 0x02, 0x00, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00,
+ 0x0B, 0x06, 0x1F, 0x11, 0x4D, 0x13, 0x8B, 0x07,
+ 0x00, 0x4E, 0x60, 0x01, 0x42, 0x01, 0x80, 0x00,
+ 0x09, 0x13, 0x8B, 0x07, 0x00, 0x3A, 0x20, 0xC1,
+ 0x4E, 0x01, 0x84, 0x02, 0x41, 0x0F, 0x02, 0x11,
+ 0x8B, 0x07, 0x00, 0x4E, 0x0B, 0xC8, 0x44, 0x01,
+ 0xA0, 0x07, 0x62, 0x09, 0xE8, 0x03, 0xE0, 0x01,
+ 0x40, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x40, 0x01,
+ 0x00, 0x20, 0x84, 0x07, 0x34, 0xAF, 0x60, 0x04,
+ 0x42, 0xAF, 0x20, 0xC8, 0x16, 0xE0, 0xE0, 0x00,
+ 0xE0, 0xC2, 0x6A, 0x09, 0xE0, 0x22, 0x10, 0xE0,
+ 0x03, 0x13, 0x20, 0xE8, 0x14, 0xE0, 0xE0, 0x00,
+ 0x20, 0xC8, 0x04, 0xE0, 0x82, 0x01, 0x20, 0xC8,
+ 0xE2, 0x00, 0x8A, 0x01, 0xE0, 0x04, 0x18, 0x09,
+ 0xE0, 0x04, 0xF4, 0x05, 0xE0, 0x04, 0xF8, 0x05,
+ 0xE0, 0x04, 0xF0, 0x05, 0xE0, 0x04, 0x42, 0x07,
+ 0xA0, 0x07, 0x88, 0x01, 0x20, 0x00, 0xE0, 0xC2,
+ 0x30, 0x09, 0x09, 0x13, 0xA0, 0x07, 0x88, 0x01,
+ 0x80, 0x00, 0x20, 0xE8, 0x16, 0xE0, 0x80, 0x01,
+ 0xE0, 0x01, 0x82, 0x01, 0x00, 0x03, 0x8B, 0x07,
+ 0x00, 0xA0, 0x0B, 0xE8, 0x86, 0x01, 0x80, 0x03,
+ 0xE0, 0x04, 0x86, 0x01, 0xE0, 0x01, 0x9C, 0x01,
+ 0x40, 0x00, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40,
+ 0xCB, 0x04, 0xB0, 0x03, 0x0B, 0x06, 0x04, 0x13,
+ 0x60, 0x01, 0x9C, 0x01, 0x00, 0x40, 0xF9, 0x16,
+ 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, 0x08, 0xE0,
+ 0x6A, 0x09, 0x8B, 0x07, 0x00, 0x80, 0x0B, 0xC8,
+ 0x98, 0x07, 0x0B, 0xC8, 0x78, 0x07, 0x20, 0xC8,
+ 0x04, 0xE0, 0x82, 0x01, 0x8B, 0x07, 0x6F, 0x87,
+ 0x0B, 0x48, 0x3A, 0x07, 0xE0, 0xC2, 0x50, 0x07,
+ 0x8B, 0x02, 0x58, 0x07, 0x10, 0x13, 0x20, 0xE8,
+ 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01,
+ 0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0x8B, 0x07,
+ 0x58, 0x07, 0x0B, 0xC8, 0x50, 0x07, 0x8B, 0x07,
+ 0x0C, 0xB8, 0x0B, 0xC8, 0x52, 0x07, 0x80, 0x03,
+ 0x00, 0x03, 0x02, 0x00, 0xE0, 0xC2, 0x1A, 0x09,
+ 0x0C, 0x13, 0x20, 0x06, 0x1C, 0x09, 0x0B, 0xC8,
+ 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 0x1A, 0x09,
+ 0x4B, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF,
+ 0x80, 0x03, 0x41, 0xC0, 0x0F, 0x13, 0x81, 0x80,
+ 0x0D, 0x13, 0x82, 0xA0, 0xE2, 0xC2, 0x32, 0x0C,
+ 0x12, 0x09, 0x0B, 0xC8, 0x6C, 0x01, 0xE0, 0x04,
+ 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 0x07, 0x11,
+ 0x02, 0xC8, 0x00, 0xFC, 0xED, 0x04, 0x02, 0x00,
+ 0xE0, 0x04, 0x6C, 0x01, 0x80, 0x03, 0x42, 0xCB,
+ 0x02, 0x00, 0x02, 0xC8, 0x6C, 0x01, 0x8B, 0xC0,
+ 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x83, 0x07,
+ 0x00, 0x80, 0x60, 0xC2, 0x7E, 0x09, 0x09, 0xC1,
+ 0x24, 0x02, 0xF8, 0xFF, 0xA9, 0x08, 0x01, 0x02,
+ 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0B, 0x02,
+ 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x07, 0x02,
+ 0x00, 0x00, 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C,
+ 0x06, 0x13, 0x8B, 0x05, 0xCC, 0x05, 0x0B, 0x88,
+ 0x46, 0x04, 0x27, 0x1B, 0xF6, 0x10, 0x09, 0xC2,
+ 0x8B, 0xC2, 0x08, 0x06, 0x0A, 0x13, 0x8B, 0x05,
+ 0xCC, 0x05, 0x0B, 0x88, 0x46, 0x04, 0x1D, 0x1B,
+ 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 0xED, 0x16,
+ 0xF4, 0x10, 0x82, 0xC0, 0x14, 0x13, 0x02, 0xC8,
+ 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 0x0A, 0xC8,
+ 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x07,
+ 0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC,
+ 0x0A, 0xC2, 0x08, 0xA2, 0x02, 0xCA, 0x32, 0x0C,
+ 0x8A, 0xC0, 0x87, 0x05, 0xD6, 0x10, 0x4A, 0xC0,
+ 0xEE, 0x10, 0x47, 0xCB, 0x02, 0x00, 0xE0, 0x04,
+ 0x6C, 0x01, 0x8B, 0x07, 0x43, 0x00, 0xE0, 0x04,
+ 0x00, 0x0C, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8,
+ 0x6C, 0x01, 0x8B, 0x02, 0x43, 0x00, 0x04, 0x13,
+ 0x60, 0x01, 0x02, 0xFC, 0x20, 0x00, 0x06, 0x13,
+ 0x8B, 0xC2, 0xA0, 0x06, 0x42, 0xB4, 0x90, 0x03,
+ 0x7F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x02, 0xFC,
+ 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00,
+ 0x0B, 0x16, 0x0A, 0x02, 0x02, 0xFC, 0xA0, 0xA2,
+ 0x2C, 0x09, 0xA0, 0xCE, 0xEE, 0x05, 0xA0, 0xC6,
+ 0x04, 0xFC, 0x20, 0xC8, 0x2C, 0x09, 0x04, 0xFC,
+ 0x8A, 0x07, 0xF8, 0x05, 0x5A, 0xC2, 0x08, 0x13,
+ 0xCA, 0x05, 0x5A, 0xC2, 0x09, 0xC8, 0x6C, 0x01,
+ 0x0B, 0xC8, 0x00, 0xFC, 0x8B, 0xC6, 0x02, 0x10,
+ 0x8B, 0xCE, 0x8B, 0xC6, 0x20, 0x20, 0x1A, 0xE0,
+ 0x05, 0x16, 0x20, 0xE8, 0x04, 0xE0, 0x3A, 0x07,
+ 0xE0, 0x04, 0x36, 0x07, 0x90, 0x03, 0x7F, 0x00,
+ 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8,
+ 0x6C, 0x01, 0xCC, 0x04, 0xE0, 0x04, 0x00, 0xFC,
+ 0x8B, 0xC2, 0xA0, 0x06, 0x50, 0xB4, 0x90, 0x03,
+ 0x7F, 0x00, 0x80, 0x03, 0xA0, 0x07, 0x02, 0xFC,
+ 0x00, 0x80, 0x20, 0xC8, 0x8C, 0xE1, 0x04, 0xFC,
+ 0x41, 0xC0, 0x0F, 0x16, 0x20, 0xD8, 0x00, 0xE2,
+ 0x83, 0x01, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B,
+ 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B,
+ 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x0A, 0xC8,
+ 0x8A, 0x01, 0x5B, 0x04, 0x0A, 0xC8, 0x6C, 0x01,
+ 0x20, 0xC3, 0x00, 0xFC, 0xE0, 0x04, 0x00, 0xFC,
+ 0x8A, 0x02, 0x43, 0x00, 0xDF, 0x13, 0xA0, 0x07,
+ 0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC,
+ 0x20, 0x98, 0x84, 0x09, 0x1D, 0x09, 0x0A, 0x13,
+ 0x20, 0xC8, 0x1A, 0x09, 0x00, 0xFC, 0x0A, 0xC8,
+ 0x1A, 0x09, 0xA0, 0x05, 0x1C, 0x09, 0x8C, 0xC2,
+ 0xE5, 0x16, 0x5B, 0x04, 0x41, 0xC0, 0x10, 0x13,
+ 0x8A, 0xA2, 0x82, 0xCA, 0x32, 0x0C, 0x1A, 0x09,
+ 0x02, 0xC8, 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC,
+ 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2,
+ 0x09, 0x13, 0x8C, 0xC2, 0xD3, 0x16, 0x5B, 0x04,
+ 0x4A, 0xC0, 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01,
+ 0x00, 0xE2, 0x1B, 0x16, 0xE0, 0x01, 0x9C, 0x01,
+ 0x40, 0x00, 0xA0, 0x07, 0x64, 0x09, 0x00, 0x70,
+ 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0x07, 0x13,
+ 0x20, 0x06, 0x64, 0x09, 0xF9, 0x16, 0x0A, 0x02,
+ 0x00, 0x01, 0x60, 0x04, 0x8A, 0xA3, 0x60, 0x01,
+ 0x02, 0x0C, 0x00, 0x01, 0xE2, 0x13, 0x20, 0xD8,
+ 0x2F, 0x09, 0x83, 0x01, 0xA0, 0x07, 0x02, 0x0C,
+ 0x00, 0x80, 0x0A, 0xC8, 0x8A, 0x01, 0x0A, 0xC8,
+ 0x18, 0x09, 0xD7, 0x10, 0xD8, 0x04, 0x57, 0xC2,
+ 0x03, 0x16, 0xC8, 0xCD, 0xC8, 0xC5, 0x5B, 0x04,
+ 0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5,
+ 0x5B, 0x04, 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xA2,
+ 0x20, 0xCA, 0x00, 0xFC, 0x32, 0x0C, 0x18, 0x09,
+ 0x02, 0x10, 0x08, 0xC8, 0x6C, 0x01, 0xE0, 0x04,
+ 0x00, 0xFC, 0x57, 0xC2, 0x03, 0x16, 0xC8, 0xCD,
+ 0xC8, 0xC5, 0x5B, 0x04, 0xC7, 0x05, 0x17, 0xC8,
+ 0x6C, 0x01, 0x08, 0xC8, 0x00, 0xFC, 0xC8, 0xC5,
+ 0x5B, 0x04, 0x17, 0xC6, 0x02, 0x16, 0xC8, 0xC9,
+ 0x02, 0x00, 0xC8, 0xC5, 0x5B, 0x04, 0x17, 0xC2,
+ 0x08, 0xC8, 0x6C, 0x01, 0x07, 0x13, 0xE0, 0xC5,
+ 0x00, 0xFC, 0x08, 0xA2, 0x28, 0xC8, 0x32, 0x0C,
+ 0x00, 0xFC, 0x18, 0x09, 0x5B, 0x04, 0x60, 0x01,
+ 0x82, 0x01, 0x00, 0x20, 0x0A, 0x16, 0x60, 0xC2,
+ 0x84, 0x01, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x20,
+ 0xE0, 0x01, 0x82, 0x01, 0x00, 0x20, 0x09, 0xC8,
+ 0x84, 0x01, 0xC9, 0x04, 0x5B, 0x04, 0xA0, 0x06,
+ 0xBE, 0xB7, 0xD3, 0x04, 0xE0, 0x04, 0x02, 0x01,
+ 0x20, 0xE8, 0x14, 0xE0, 0x00, 0x01, 0x20, 0xC8,
+ 0x16, 0xE0, 0x04, 0x01, 0x05, 0x2C, 0x20, 0x48,
+ 0x14, 0xE0, 0x00, 0x01, 0x8C, 0x07, 0x00, 0x0A,
+ 0x8D, 0x07, 0xD8, 0x07, 0x8E, 0x07, 0x18, 0x00,
+ 0x7C, 0xCF, 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x02,
+ 0xD8, 0x07, 0x8F, 0x07, 0x11, 0xFF, 0x8B, 0x02,
+ 0x3B, 0x59, 0x21, 0x16, 0x8A, 0x02, 0x3B, 0x59,
+ 0x1E, 0x13, 0x8F, 0x05, 0x20, 0x20, 0x16, 0xE0,
+ 0x01, 0x16, 0x19, 0x10, 0x20, 0x20, 0x04, 0xE0,
+ 0x16, 0x16, 0x00, 0x01, 0xBF, 0x00, 0x13, 0x16,
+ 0x8B, 0x07, 0xC0, 0x40, 0x00, 0x01, 0x00, 0x60,
+ 0x10, 0x13, 0x40, 0x01, 0x00, 0x60, 0x0B, 0x16,
+ 0x8B, 0x07, 0xC4, 0x44, 0xA0, 0xC3, 0x02, 0x01,
+ 0x0E, 0x48, 0x02, 0x01, 0x4E, 0x01, 0x00, 0x10,
+ 0x04, 0x16, 0x8F, 0x07, 0x18, 0xFF, 0x60, 0x04,
+ 0x94, 0xB7, 0x0B, 0xC3, 0x4B, 0xC3, 0x20, 0x20,
+ 0x0A, 0xE0, 0x02, 0x16, 0x6B, 0x02, 0x20, 0x20,
+ 0x20, 0x20, 0x0C, 0xE0, 0x02, 0x16, 0x6C, 0x02,
+ 0x00, 0x20, 0x20, 0x20, 0x0E, 0xE0, 0x02, 0x16,
+ 0x6C, 0x02, 0x20, 0x00, 0x8F, 0x05, 0x20, 0x20,
+ 0x10, 0xE0, 0x07, 0x16, 0x6D, 0x02, 0x20, 0x00,
+ 0x20, 0x21, 0x22, 0xE0, 0xE4, 0x13, 0x04, 0xC1,
+ 0x02, 0x16, 0x84, 0x07, 0xFE, 0x7F, 0x8F, 0x05,
+ 0x20, 0x20, 0x12, 0xE0, 0x02, 0x16, 0x6D, 0x02,
+ 0x00, 0x20, 0x60, 0x21, 0x22, 0xE0, 0xD7, 0x13,
+ 0x45, 0xC1, 0x02, 0x16, 0x85, 0x07, 0xFE, 0x7F,
+ 0x8F, 0x05, 0x86, 0xD1, 0x0B, 0x13, 0xA0, 0x25,
+ 0x26, 0xE0, 0x08, 0x13, 0x8F, 0x05, 0x20, 0x26,
+ 0x22, 0xE0, 0x04, 0x16, 0x8F, 0x05, 0xA0, 0x26,
+ 0x22, 0xE0, 0x02, 0x13, 0x60, 0x04, 0x94, 0xB7,
+ 0x01, 0xD8, 0xEC, 0x08, 0x20, 0xD8, 0xDB, 0x07,
+ 0x00, 0x09, 0x02, 0xD8, 0xF6, 0x08, 0x20, 0xD8,
+ 0xDD, 0x07, 0xE2, 0x08, 0xE0, 0x02, 0x58, 0x07,
+ 0x20, 0xD8, 0xEF, 0x07, 0xF4, 0x07, 0x20, 0xD8,
+ 0xF1, 0x07, 0xF6, 0x07, 0x20, 0xD8, 0xF3, 0x07,
+ 0xF8, 0x07, 0x09, 0x02, 0x06, 0x00, 0xCB, 0x04,
+ 0x0F, 0x02, 0xEE, 0x07, 0x8F, 0x05, 0xCB, 0xDF,
+ 0x09, 0x06, 0xFC, 0x16, 0xA0, 0x06, 0xBE, 0xB7,
+ 0x89, 0x07, 0x5C, 0xE3, 0xE0, 0x04, 0x1A, 0x01,
+ 0x20, 0xC8, 0xE4, 0x07, 0x18, 0x01, 0x19, 0xC8,
+ 0x0C, 0x01, 0x39, 0xC8, 0x0A, 0x01, 0x39, 0xC8,
+ 0x12, 0x01, 0x09, 0x16, 0x79, 0xC3, 0x0F, 0x02,
+ 0x00, 0xE0, 0x4F, 0x63, 0x2D, 0x02, 0x00, 0x90,
+ 0x0D, 0xC8, 0x14, 0x01, 0x02, 0x10, 0x39, 0xC8,
+ 0x14, 0x01, 0xF9, 0xC3, 0x3F, 0xC8, 0x0E, 0x01,
+ 0x1F, 0xC8, 0x10, 0x01, 0xE0, 0x04, 0x14, 0x09,
+ 0xB9, 0xC2, 0x1A, 0xC8, 0x00, 0x01, 0x96, 0x06,
+ 0x89, 0x02, 0x84, 0xE3, 0xE0, 0x16, 0x8F, 0x07,
+ 0x1C, 0xFF, 0x8C, 0x07, 0x00, 0x0A, 0x8D, 0x07,
+ 0x84, 0xE3, 0x8E, 0x07, 0x10, 0x00, 0x7C, 0x8F,
+ 0x44, 0x16, 0x4E, 0x06, 0xFC, 0x16, 0xA0, 0xC3,
+ 0xE2, 0x07, 0xE0, 0xC3, 0xE0, 0x07, 0xCE, 0x83,
+ 0x01, 0x14, 0xCE, 0xC3, 0x0F, 0xC8, 0x1A, 0x01,
+ 0x8C, 0x07, 0x94, 0xE3, 0x8D, 0x07, 0x00, 0x0A,
+ 0x8E, 0x07, 0xA4, 0xE3, 0x8C, 0x63, 0x7C, 0xCF,
+ 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x04, 0x30, 0x09,
+ 0x20, 0x01, 0x42, 0x01, 0x00, 0x04, 0x02, 0x16,
+ 0x20, 0x07, 0x30, 0x09, 0x60, 0xC2, 0x62, 0x01,
+ 0xE0, 0x04, 0x62, 0x01, 0x8E, 0x07, 0x00, 0x80,
+ 0x8C, 0x07, 0x34, 0x09, 0x8D, 0x07, 0x06, 0x00,
+ 0x3E, 0xDF, 0x8E, 0x05, 0x0D, 0x06, 0xFC, 0x16,
+ 0xFE, 0xD3, 0xCF, 0x06, 0x8E, 0x05, 0xFE, 0xD3,
+ 0xCF, 0x06, 0x8C, 0x07, 0x34, 0x09, 0x09, 0xC8,
+ 0x62, 0x01, 0xC9, 0x04, 0x5C, 0xA3, 0x7C, 0xE2,
+ 0x5C, 0xA3, 0x7C, 0xE2, 0x5C, 0xA3, 0x7C, 0xE2,
+ 0x02, 0x13, 0xCD, 0x83, 0x09, 0x13, 0x20, 0x07,
+ 0x34, 0x09, 0x06, 0x10, 0x8F, 0x07, 0x19, 0xFF,
+ 0xCD, 0xA3, 0x0F, 0xC8, 0x04, 0x01, 0xFF, 0x10,
+ 0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0xE0, 0xC3,
+ 0xEE, 0x07, 0xE0, 0x43, 0x06, 0xE0, 0x0F, 0xC8,
+ 0x00, 0x01, 0x20, 0xC0, 0x04, 0xE0, 0xE0, 0x04,
+ 0xFE, 0x06, 0xD3, 0x04, 0xE0, 0x04, 0x04, 0x01,
+ 0x60, 0x04, 0x0C, 0xB8, 0x8C, 0x07, 0x00, 0x0A,
+ 0x8D, 0x07, 0x18, 0x00, 0x8E, 0x07, 0x3B, 0x59,
+ 0x0E, 0xCF, 0x4D, 0x06, 0xFD, 0x16, 0x5B, 0x04,
+ 0x93, 0x01, 0x00, 0x80, 0x20, 0x04, 0xC0, 0xE2,
+ 0x60, 0xD0, 0x98, 0x07, 0x1C, 0x13, 0x00, 0x03,
+ 0x02, 0x00, 0xA0, 0xC0, 0x46, 0x07, 0x12, 0xC8,
+ 0x46, 0x07, 0x02, 0x16, 0x93, 0x01, 0x20, 0x00,
+ 0x00, 0x03, 0x0F, 0x00, 0x20, 0x04, 0xE8, 0xE2,
+ 0x93, 0x01, 0x00, 0x20, 0x80, 0x01, 0x00, 0x40,
+ 0x00, 0x01, 0xFE, 0x00, 0x49, 0x16, 0xC4, 0xC3,
+ 0x25, 0x16, 0xD3, 0xC3, 0xC5, 0x43, 0x0C, 0x16,
+ 0xE0, 0xC3, 0x98, 0x07, 0x03, 0x11, 0xE0, 0x02,
+ 0x98, 0x07, 0x51, 0x04, 0xE0, 0xC3, 0x78, 0x07,
+ 0x0A, 0x11, 0xE0, 0x02, 0x78, 0x07, 0x51, 0x04,
+ 0xD3, 0x11, 0x4F, 0x01, 0x00, 0x20, 0xE4, 0x13,
+ 0x4F, 0x01, 0x20, 0x00, 0xD1, 0x13, 0x05, 0x2C,
+ 0x41, 0xA0, 0x21, 0x04, 0xC0, 0xE2, 0x8B, 0x07,
+ 0x0C, 0xB8, 0x00, 0x01, 0x00, 0x40, 0x0F, 0x13,
+ 0xDD, 0xC3, 0x4F, 0x02, 0x0F, 0x00, 0x2F, 0xE1,
+ 0x14, 0xE0, 0x5B, 0x04, 0xE4, 0xC3, 0xC0, 0xE1,
+ 0xCF, 0x73, 0x2F, 0x41, 0x14, 0xE0, 0x6F, 0xC3,
+ 0xEC, 0xEA, 0x8B, 0x07, 0x0C, 0xB8, 0x4B, 0xC2,
+ 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 0x08, 0x00,
+ 0xBD, 0xC0, 0xA0, 0xC3, 0xEA, 0x07, 0xE0, 0xC3,
+ 0xEC, 0x07, 0xA0, 0x06, 0x00, 0xBA, 0xC0, 0x01,
+ 0x00, 0x40, 0x02, 0xD8, 0x17, 0x01, 0x62, 0x02,
+ 0x80, 0xFF, 0xA0, 0x06, 0x54, 0xBA, 0x02, 0xC8,
+ 0x04, 0x01, 0x90, 0x03, 0x3F, 0x60, 0x59, 0x04,
+ 0xC0, 0xC3, 0xCF, 0x73, 0xEF, 0xC3, 0xC0, 0xE1,
+ 0xCF, 0x73, 0xAF, 0xC3, 0xDE, 0xEA, 0x9E, 0xC3,
+ 0x4E, 0x02, 0x0F, 0x00, 0x2E, 0x21, 0x14, 0xE0,
+ 0x08, 0x13, 0x2F, 0x40, 0x14, 0xE0, 0xCF, 0xA3,
+ 0x2F, 0x04, 0xF0, 0xE2, 0x40, 0x01, 0x00, 0x40,
+ 0xA4, 0x13, 0xC4, 0xC3, 0xC7, 0x16, 0x00, 0x01,
+ 0xFE, 0x00, 0xE6, 0x16, 0x9E, 0x10, 0x40, 0x01,
+ 0x00, 0x40, 0x05, 0x16, 0x20, 0xE0, 0x14, 0xE0,
+ 0x65, 0x02, 0x00, 0x58, 0x96, 0x10, 0x20, 0xD8,
+ 0xDE, 0x07, 0x17, 0x01, 0x8F, 0x07, 0x86, 0xFF,
+ 0x0F, 0xC8, 0x04, 0x01, 0xC0, 0x01, 0x00, 0x40,
+ 0x45, 0x02, 0xFF, 0xA7, 0x8A, 0x10, 0x20, 0xC3,
+ 0xFE, 0x06, 0x20, 0x27, 0x38, 0xE3, 0x07, 0x13,
+ 0x20, 0x23, 0x22, 0xE0, 0x1A, 0x13, 0x65, 0x02,
+ 0xFF, 0xDF, 0x20, 0x40, 0x14, 0xE0, 0x20, 0xE0,
+ 0x16, 0xE0, 0x0C, 0xC8, 0xE6, 0x08, 0x8D, 0x07,
+ 0xE2, 0x08, 0x58, 0x04, 0x20, 0x48, 0x08, 0xE0,
+ 0xFE, 0x06, 0x20, 0xC3, 0xE6, 0x08, 0x20, 0x27,
+ 0x38, 0xE3, 0x19, 0x16, 0x80, 0x03, 0x02, 0xC3,
+ 0x6C, 0xC2, 0x0A, 0x00, 0x99, 0x06, 0x60, 0x04,
+ 0x0C, 0xB8, 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07,
+ 0x01, 0x00, 0x8D, 0x07, 0x06, 0x06, 0xCE, 0x04,
+ 0xE0, 0xC3, 0x08, 0x06, 0x01, 0x13, 0x97, 0x06,
+ 0x20, 0xD8, 0x07, 0x06, 0x17, 0x01, 0x8B, 0x07,
+ 0x82, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0xA0, 0x06,
+ 0xB4, 0xBE, 0x60, 0x04, 0x0C, 0xB8, 0xA0, 0xC2,
+ 0xEE, 0x07, 0x8C, 0x07, 0x06, 0x00, 0x8D, 0x07,
+ 0xEE, 0x08, 0xA0, 0xC3, 0xE6, 0x07, 0xE0, 0xC3,
+ 0xE8, 0x07, 0x97, 0x06, 0xA0, 0xC2, 0xF4, 0x07,
+ 0x8D, 0x07, 0xF4, 0x08, 0xDD, 0x04, 0x8C, 0x07,
+ 0x02, 0x00, 0x97, 0x06, 0x8D, 0x07, 0x00, 0x80,
+ 0xA0, 0xC2, 0xEE, 0x08, 0x0A, 0x88, 0x0C, 0x06,
+ 0x14, 0x1B, 0x82, 0x07, 0xD0, 0xB9, 0xA0, 0xC3,
+ 0xF0, 0x08, 0xE0, 0xC3, 0xF2, 0x08, 0x8B, 0x07,
+ 0x0C, 0xE3, 0x8A, 0x02, 0x14, 0x00, 0x04, 0x1A,
+ 0x8B, 0x07, 0xBA, 0xEA, 0x2A, 0x02, 0xEC, 0xFF,
+ 0x8A, 0xA2, 0xCA, 0xA2, 0xDB, 0xC2, 0x01, 0x13,
+ 0x9B, 0x06, 0x20, 0xC8, 0xEE, 0x08, 0xF2, 0x08,
+ 0x20, 0xC8, 0x20, 0xE0, 0xEE, 0x08, 0x0D, 0xC8,
+ 0xF0, 0x08, 0x8D, 0x07, 0xEC, 0x08, 0x20, 0xE0,
+ 0x18, 0xE0, 0x65, 0x02, 0x00, 0x58, 0x58, 0x04,
+ 0x45, 0x02, 0xFF, 0xA7, 0x80, 0x03, 0x60, 0xC0,
+ 0xEE, 0x05, 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01,
+ 0x02, 0x01, 0x06, 0x00, 0x07, 0x16, 0x01, 0x88,
+ 0xEE, 0x05, 0xF9, 0x16, 0x39, 0x10, 0x60, 0xD0,
+ 0x03, 0x01, 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01,
+ 0x4C, 0xCC, 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC,
+ 0xB1, 0x07, 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8,
+ 0x00, 0x01, 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05,
+ 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01,
+ 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 0xEE, 0x05,
+ 0xF9, 0x16, 0x1E, 0x10, 0x60, 0xD0, 0x03, 0x01,
+ 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 0x4C, 0xCC,
+ 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 0xB1, 0x07,
+ 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 0x00, 0x01,
+ 0xA0, 0x03, 0x60, 0xD0, 0x03, 0x01, 0x01, 0x13,
+ 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 0x21, 0x02,
+ 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 0x06, 0x00,
+ 0xF7, 0x16, 0x01, 0x88, 0xEE, 0x05, 0xF9, 0x16,
+ 0xCD, 0x04, 0x8A, 0x07, 0x00, 0x40, 0x20, 0xC3,
+ 0x00, 0x01, 0x0C, 0x01, 0x00, 0x80, 0x02, 0x13,
+ 0x8A, 0x07, 0x00, 0x20, 0xA0, 0xC3, 0x0E, 0x01,
+ 0xE0, 0xC3, 0x10, 0x01, 0xB0, 0x03, 0x20, 0xC3,
+ 0x58, 0x07, 0x20, 0x23, 0x04, 0xE0, 0x02, 0x13,
+ 0x60, 0x04, 0x8E, 0xB7, 0x60, 0x04, 0x8A, 0xA3,
+ 0x8D, 0x07, 0x00, 0x20, 0x20, 0x20, 0x0A, 0xE0,
+ 0x01, 0x16, 0x5B, 0x04, 0x0D, 0x02, 0x32, 0x0C,
+ 0x5D, 0xC2, 0x01, 0x11, 0xDD, 0x04, 0xCD, 0x05,
+ 0x0D, 0x88, 0x30, 0x0C, 0xF9, 0x16, 0x60, 0xC2,
+ 0x0A, 0x06, 0x8D, 0x07, 0x6A, 0x09, 0xA0, 0x06,
+ 0xF4, 0xBE, 0x09, 0x02, 0x48, 0x00, 0xE0, 0xC3,
+ 0x30, 0x09, 0x03, 0x16, 0xE0, 0x01, 0x6A, 0x09,
+ 0x10, 0x00, 0xE0, 0xC2, 0x6A, 0x09, 0x0F, 0x02,
+ 0x00, 0x01, 0xC9, 0x26, 0x02, 0x13, 0x60, 0x04,
+ 0x86, 0xBD, 0x09, 0x02, 0x00, 0x12, 0x4B, 0x01,
+ 0x10, 0x00, 0x02, 0x13, 0x09, 0x02, 0x00, 0x13,
+ 0x09, 0xD8, 0x2E, 0x09, 0x8F, 0x07, 0x00, 0x40,
+ 0x89, 0x07, 0x6C, 0x09, 0xCB, 0x04, 0xF9, 0xE2,
+ 0xF9, 0xE2, 0xF9, 0xE2, 0x07, 0x16, 0x8B, 0x07,
+ 0x34, 0x09, 0x8C, 0x07, 0x6C, 0x09, 0x3B, 0xCF,
+ 0x3B, 0xCF, 0x1B, 0xC7, 0x20, 0xC3, 0x6C, 0x09,
+ 0x19, 0x11, 0x8F, 0x07, 0x00, 0x20, 0x89, 0x07,
+ 0x7A, 0x09, 0xA0, 0x06, 0x3A, 0xBB, 0xA0, 0x06,
+ 0x3A, 0xBB, 0x12, 0x10, 0x4C, 0xCE, 0x5B, 0x04,
+ 0x19, 0xC3, 0x02, 0x16, 0x8C, 0x07, 0x1A, 0x00,
+ 0x4C, 0xC3, 0x2D, 0x02, 0xF8, 0xFF, 0x0A, 0x02,
+ 0x09, 0x00, 0x2D, 0x02, 0xFA, 0xFF, 0xF2, 0x13,
+ 0x0A, 0x06, 0xFB, 0x16, 0x60, 0x04, 0x86, 0xBD,
+ 0x8F, 0x07, 0x00, 0x10, 0xD9, 0xC2, 0xFA, 0x11,
+ 0x02, 0x16, 0x8B, 0x07, 0x00, 0x04, 0x4B, 0xC3,
+ 0x8D, 0x02, 0x20, 0x00, 0x02, 0x14, 0x0D, 0x02,
+ 0x20, 0x00, 0x8D, 0x02, 0x00, 0x04, 0x02, 0x12,
+ 0x0D, 0x02, 0x00, 0x04, 0x2D, 0x02, 0xF8, 0xFF,
+ 0x0D, 0xC8, 0x2C, 0x09, 0x2B, 0x02, 0xFF, 0x03,
+ 0x8B, 0x01, 0xFF, 0x03, 0x4B, 0xCE, 0x60, 0xC3,
+ 0x6A, 0x09, 0x60, 0x23, 0x18, 0xE0, 0x0C, 0x16,
+ 0x49, 0xC3, 0xDD, 0xC2, 0x0F, 0x02, 0x01, 0x01,
+ 0x8B, 0x01, 0x80, 0xC0, 0xD7, 0x16, 0x8F, 0x05,
+ 0xED, 0xC2, 0x02, 0x00, 0xD3, 0x16, 0x02, 0x10,
+ 0x8D, 0x07, 0xBA, 0xEA, 0x3D, 0xC8, 0xA8, 0x09,
+ 0x1D, 0xC8, 0xAA, 0x09, 0xCB, 0x04, 0xE0, 0x04,
+ 0xF8, 0x05, 0xE0, 0x04, 0x66, 0x09, 0x20, 0xC8,
+ 0x30, 0x0C, 0x80, 0x09, 0xA0, 0x07, 0x82, 0x09,
+ 0xFE, 0xDF, 0x8D, 0x07, 0xFE, 0xDF, 0xE0, 0xC3,
+ 0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x24, 0x16,
+ 0xE0, 0xC3, 0x30, 0x0C, 0x4F, 0x63, 0xFF, 0x04,
+ 0xFF, 0x04, 0x4D, 0x06, 0xFD, 0x16, 0x8D, 0x07,
+ 0xFE, 0xDF, 0x20, 0x04, 0xA2, 0xEA, 0xA0, 0xC3,
+ 0xA2, 0xEA, 0xEE, 0xC3, 0x12, 0x00, 0xAA, 0x16,
+ 0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x8C, 0x07,
+ 0x00, 0xE0, 0xAC, 0x09, 0x0D, 0x63, 0x0C, 0x13,
+ 0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x2D, 0x02,
+ 0x40, 0x00, 0x1D, 0x0A, 0x2D, 0x02, 0x32, 0x0C,
+ 0xBD, 0x07, 0xFF, 0x7F, 0x0C, 0x06, 0xFC, 0x16,
+ 0x20, 0xC3, 0x46, 0x04, 0x8C, 0x02, 0x80, 0x00,
+ 0x13, 0x1A, 0xAC, 0x02, 0x0C, 0xC8, 0x9A, 0x00,
+ 0xE0, 0x02, 0x80, 0x00, 0x88, 0x07, 0x80, 0x00,
+ 0x60, 0xC2, 0x46, 0x04, 0xA0, 0x06, 0x28, 0xAD,
+ 0x02, 0x10, 0x9D, 0x00, 0x05, 0x10, 0x9D, 0x00,
+ 0x8F, 0x07, 0x00, 0x08, 0x60, 0x04, 0x86, 0xBD,
+ 0x4B, 0x2D, 0x81, 0xC3, 0xC9, 0x05, 0x8F, 0x07,
+ 0x00, 0x10, 0x8E, 0x02, 0x02, 0x00, 0xF6, 0x11,
+ 0x8F, 0x07, 0x00, 0x04, 0xC9, 0x05, 0xD9, 0xC2,
+ 0xE0, 0x26, 0x26, 0xE0, 0x02, 0x16, 0x2B, 0x02,
+ 0x06, 0x00, 0x4B, 0xC6, 0x4B, 0xC3, 0xCB, 0x72,
+ 0x2E, 0x02, 0xFE, 0xFF, 0x8B, 0x83, 0xE6, 0x1B,
+ 0xCD, 0x06, 0x4D, 0x73, 0xCD, 0x82, 0xE2, 0x1B,
+ 0xE0, 0x04, 0x1A, 0x09, 0xE0, 0x04, 0x1C, 0x09,
+ 0x4D, 0xC3, 0x02, 0x13, 0x60, 0x66, 0x12, 0xE0,
+ 0xC9, 0x05, 0xCF, 0x04, 0x81, 0x2D, 0x01, 0xC8,
+ 0x6C, 0x01, 0xD4, 0x13, 0x0F, 0xC8, 0x00, 0xFC,
+ 0xC1, 0xC3, 0x0D, 0x06, 0xF7, 0x15, 0x0D, 0x02,
+ 0x36, 0x07, 0x0E, 0x02, 0x98, 0x08, 0x0C, 0x02,
+ 0x03, 0x00, 0x8D, 0xCB, 0x02, 0x00, 0x81, 0x2D,
+ 0x81, 0xCB, 0x06, 0x00, 0xC3, 0x13, 0xEE, 0x04,
+ 0x0C, 0x00, 0x2E, 0x02, 0x18, 0x00, 0x0C, 0x06,
+ 0xF4, 0x16, 0xE0, 0x04, 0x96, 0x08, 0x1F, 0x2E,
+ 0xB9, 0xC3, 0xD9, 0xC3, 0x89, 0x07, 0x12, 0x00,
+ 0x8D, 0x07, 0x3A, 0x09, 0xA0, 0x06, 0xF4, 0xBE,
+ 0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0,
+ 0x09, 0x16, 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09,
+ 0x20, 0xE8, 0x18, 0xE0, 0x98, 0x07, 0x20, 0xE8,
+ 0x12, 0xE0, 0x78, 0x07, 0x60, 0xC3, 0x6A, 0x09,
+ 0x60, 0x23, 0x1E, 0xE0, 0x03, 0x16, 0x20, 0x48,
+ 0xA4, 0xE3, 0x6A, 0x09, 0x60, 0x23, 0x22, 0xE0,
+ 0x06, 0x13, 0x60, 0x27, 0xA6, 0xE3, 0x03, 0x13,
+ 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 0x20, 0x2D,
+ 0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, 0xA0, 0x06,
+ 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 0xA0, 0xC0,
+ 0x04, 0x08, 0xEF, 0xC3, 0x06, 0x00, 0x1B, 0x16,
+ 0xA0, 0xC3, 0x72, 0x09, 0xE0, 0xC3, 0x74, 0x09,
+ 0xA0, 0x06, 0xC2, 0xBD, 0xA0, 0xC3, 0x76, 0x09,
+ 0xE0, 0xC3, 0x78, 0x09, 0xA0, 0x06, 0xE0, 0xBD,
+ 0x20, 0xE0, 0x0A, 0xE0, 0x60, 0xC3, 0xD8, 0x07,
+ 0x60, 0x23, 0x16, 0xE0, 0x05, 0x16, 0xE0, 0x04,
+ 0x2E, 0x06, 0x60, 0x41, 0x04, 0xE0, 0x4D, 0x2E,
+ 0x8D, 0x07, 0x00, 0x80, 0x52, 0x04, 0xCF, 0x73,
+ 0x2F, 0x02, 0x00, 0x02, 0x4F, 0xC3, 0x52, 0x04,
+ 0x20, 0x20, 0x0A, 0xE0, 0x03, 0x13, 0x8D, 0x07,
+ 0x00, 0x10, 0x5B, 0x04, 0x20, 0x40, 0x0A, 0xE0,
+ 0x40, 0x02, 0xFF, 0xF0, 0x8E, 0x07, 0x02, 0x00,
+ 0xA0, 0x06, 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C,
+ 0xA0, 0xC0, 0x04, 0x08, 0xA0, 0x06, 0xB4, 0xBE,
+ 0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0,
+ 0x66, 0x16, 0x20, 0x04, 0xB6, 0xEA, 0x63, 0x10,
+ 0x6E, 0x02, 0x00, 0x80, 0x8D, 0x07, 0x00, 0xC0,
+ 0x0D, 0xC8, 0xA6, 0x01, 0x0E, 0xC8, 0x72, 0x09,
+ 0x0F, 0xC8, 0x74, 0x09, 0x0E, 0xC8, 0xA8, 0x01,
+ 0x0F, 0xC8, 0xAA, 0x01, 0x12, 0x10, 0x8F, 0x01,
+ 0x01, 0x00, 0x8A, 0x07, 0x76, 0x09, 0xA0, 0xE3,
+ 0x4E, 0x09, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF,
+ 0xE0, 0xE3, 0x50, 0x09, 0x8F, 0xE6, 0x8A, 0x07,
+ 0xAC, 0x01, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF,
+ 0x8F, 0xE6, 0x20, 0x20, 0x0A, 0xE0, 0x3F, 0x13,
+ 0x8D, 0x07, 0x00, 0x10, 0x5B, 0x04, 0x20, 0x20,
+ 0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10,
+ 0x5B, 0x04, 0x8E, 0xC3, 0x04, 0x13, 0xE0, 0x01,
+ 0x50, 0x09, 0x00, 0x01, 0x06, 0x10, 0xA0, 0x01,
+ 0x50, 0x09, 0x00, 0x01, 0xA0, 0x01, 0x78, 0x09,
+ 0x00, 0x01, 0xA0, 0xC3, 0x76, 0x09, 0xE0, 0xC3,
+ 0x78, 0x09, 0xA0, 0xE3, 0x4E, 0x09, 0xE0, 0xE3,
+ 0x50, 0x09, 0x0E, 0xC8, 0xAC, 0x01, 0x0F, 0xC8,
+ 0xAE, 0x01, 0x0E, 0xC8, 0x76, 0x09, 0x0F, 0xC8,
+ 0x78, 0x09, 0x19, 0x10, 0x6E, 0x02, 0x00, 0x80,
+ 0x0E, 0xC8, 0xA6, 0x01, 0x20, 0x20, 0x0A, 0xE0,
+ 0x12, 0x13, 0x0D, 0x02, 0x00, 0x10, 0x5B, 0x04,
+ 0x8D, 0x07, 0x28, 0x07, 0x89, 0x07, 0x0E, 0x00,
+ 0xA0, 0x06, 0xFA, 0xBE, 0x8D, 0x07, 0x28, 0x07,
+ 0xFD, 0x04, 0x8D, 0x02, 0x36, 0x07, 0xFC, 0x16,
+ 0x20, 0x48, 0x14, 0xE0, 0xFE, 0x06, 0x8D, 0x07,
+ 0x00, 0x80, 0x52, 0x04, 0xA0, 0xC2, 0xEE, 0x07,
+ 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 0xF0, 0x08,
+ 0x97, 0x06, 0x7D, 0xC2, 0x5D, 0xC3, 0x60, 0x43,
+ 0x22, 0xE0, 0xA0, 0x06, 0xFA, 0xBE, 0xEF, 0x10,
+ 0x0E, 0xC8, 0x06, 0x06, 0x0F, 0xC8, 0x08, 0x06,
+ 0xEA, 0x10, 0xB0, 0x03, 0xA0, 0x01, 0x60, 0x07,
+ 0x26, 0x00, 0x40, 0x02, 0x00, 0xC0, 0xE0, 0x04,
+ 0x06, 0x06, 0x8C, 0x07, 0x10, 0x40, 0xCC, 0x44,
+ 0xE0, 0x04, 0xFE, 0x06, 0x85, 0x07, 0x40, 0x80,
+ 0x5B, 0x04, 0x02, 0xC8, 0x04, 0x08, 0x8F, 0x07,
+ 0xFA, 0x07, 0xCE, 0xCB, 0x02, 0x00, 0x8E, 0x07,
+ 0x36, 0x07, 0xCE, 0xCB, 0x04, 0x00, 0x8D, 0x07,
+ 0x30, 0x06, 0x8E, 0x07, 0x10, 0x00, 0x4D, 0x2C,
+ 0x5B, 0x04, 0xA0, 0xC2, 0xF2, 0x07, 0x02, 0x10,
+ 0xA0, 0xC2, 0xF8, 0x07, 0x0B, 0xC8, 0xEA, 0x08,
+ 0x09, 0xC3, 0x0A, 0x13, 0xA0, 0x06, 0x36, 0xBA,
+ 0xA0, 0xC2, 0x00, 0x01, 0xA0, 0xE2, 0x06, 0xE0,
+ 0x4C, 0xA3, 0xCC, 0xA3, 0x01, 0x17, 0x8E, 0x05,
+ 0x4C, 0x62, 0xE0, 0xC2, 0xEA, 0x08, 0x5B, 0x04,
+ 0x8D, 0x07, 0x00, 0x10, 0x20, 0x20, 0x0A, 0xE0,
+ 0x01, 0x13, 0x5B, 0x04, 0x0D, 0x02, 0x48, 0x00,
+ 0xE0, 0xC3, 0x30, 0x09, 0x02, 0x16, 0xCE, 0x01,
+ 0x10, 0x00, 0x8D, 0x27, 0x03, 0x13, 0x0D, 0x02,
+ 0x00, 0x01, 0x52, 0x04, 0x00, 0x03, 0x02, 0x00,
+ 0x60, 0xC3, 0x6A, 0x09, 0x4D, 0x02, 0x08, 0x80,
+ 0x4E, 0x02, 0xF7, 0x7F, 0x8D, 0xE3, 0xE0, 0xC3,
+ 0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x04, 0x13,
+ 0x8D, 0x07, 0x06, 0x00, 0x8D, 0x27, 0x02, 0x13,
+ 0xA0, 0xE3, 0x10, 0xE0, 0x0E, 0xC8, 0x6A, 0x09,
+ 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x09, 0x13,
+ 0x0D, 0x02, 0x00, 0x12, 0x4E, 0x01, 0x10, 0x00,
+ 0x02, 0x13, 0x0D, 0x02, 0x00, 0x13, 0x0D, 0xD8,
+ 0x2E, 0x09, 0x60, 0xC3, 0x80, 0x01, 0x4E, 0x02,
+ 0x01, 0x00, 0x4D, 0x02, 0xFE, 0xFF, 0x4E, 0xE3,
+ 0x0D, 0xC8, 0x80, 0x01, 0x20, 0xD8, 0x40, 0xE2,
+ 0x2F, 0x09, 0x20, 0x01, 0x6A, 0x09, 0x06, 0x00,
+ 0x03, 0x13, 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09,
+ 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x03, 0x13,
+ 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, 0x00, 0x03,
+ 0x0F, 0x00, 0x60, 0x04, 0x88, 0xBE, 0x20, 0x20,
+ 0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10,
+ 0x5B, 0x04, 0x09, 0x02, 0x08, 0x00, 0x0D, 0x02,
+ 0x58, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 0xA0, 0x07,
+ 0x02, 0x02, 0x00, 0x00, 0x0D, 0x02, 0x00, 0x04,
+ 0xE0, 0xC3, 0x58, 0x09, 0x0F, 0x01, 0x00, 0x7C,
+ 0x01, 0x13, 0x52, 0x04, 0x8F, 0xC3, 0x4E, 0x02,
+ 0x0F, 0x00, 0xFB, 0x13, 0x8E, 0x02, 0x0F, 0x00,
+ 0xF8, 0x13, 0x0D, 0x02, 0x00, 0x40, 0x4F, 0xC2,
+ 0x49, 0x09, 0x49, 0x02, 0x3F, 0x00, 0x09, 0x01,
+ 0x01, 0x00, 0xEF, 0x16, 0x89, 0x02, 0x06, 0x00,
+ 0xEC, 0x1A, 0x89, 0x02, 0x20, 0x00, 0xE9, 0x14,
+ 0xC9, 0x06, 0x1F, 0x09, 0x4F, 0x02, 0x00, 0x40,
+ 0x4F, 0xE2, 0x69, 0x02, 0x00, 0x80, 0x09, 0xC8,
+ 0x58, 0x09, 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2,
+ 0x1F, 0x09, 0x09, 0x06, 0xFD, 0x16, 0x4F, 0x05,
+ 0x0D, 0x02, 0x00, 0x20, 0x60, 0xC2, 0x5A, 0x09,
+ 0xD4, 0x13, 0x4F, 0x26, 0xD2, 0x16, 0x0D, 0x02,
+ 0x00, 0x10, 0x60, 0xC2, 0x5C, 0x09, 0xCD, 0x13,
+ 0x4F, 0x26, 0xCB, 0x16, 0x0D, 0x02, 0x00, 0x30,
+ 0x20, 0x88, 0x5A, 0x09, 0x5C, 0x09, 0xC5, 0x13,
+ 0xE0, 0xC3, 0x5A, 0x09, 0x4E, 0xC2, 0x1F, 0x0A,
+ 0x09, 0x06, 0xFD, 0x16, 0xE0, 0xE3, 0x5E, 0x09,
+ 0x0F, 0xC8, 0x5A, 0x09, 0xE0, 0xC3, 0x5C, 0x09,
+ 0x4E, 0xC2, 0x1F, 0x0A, 0x09, 0x06, 0xFD, 0x16,
+ 0xE0, 0xE3, 0x5E, 0x09, 0x0F, 0xC8, 0x5C, 0x09,
+ 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 0x1F, 0x0A,
+ 0x09, 0x06, 0xFD, 0x16, 0x0D, 0x02, 0x00, 0x08,
+ 0x60, 0xC2, 0x5E, 0x09, 0x4F, 0x26, 0xA5, 0x16,
+ 0x4F, 0x05, 0x0F, 0xC8, 0x5E, 0x09, 0x0F, 0x02,
+ 0x02, 0x02, 0x0E, 0x02, 0x03, 0x00, 0x60, 0xC3,
+ 0x40, 0x01, 0x0C, 0x02, 0xFE, 0xC0, 0xA0, 0x01,
+ 0x40, 0x01, 0x00, 0x04, 0xCF, 0x05, 0x09, 0x02,
+ 0x55, 0x55, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06,
+ 0x09, 0x07, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06,
+ 0x0E, 0x06, 0xF4, 0x16, 0xA0, 0x01, 0x40, 0x01,
+ 0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x09, 0x02,
+ 0x08, 0x00, 0x0E, 0x02, 0x58, 0x09, 0x0F, 0x02,
+ 0x02, 0x02, 0xFE, 0xCF, 0x49, 0x06, 0xFD, 0x16,
+ 0x60, 0x04, 0x88, 0xBE, 0xC9, 0xC7, 0x5F, 0x82,
+ 0x01, 0x16, 0x5B, 0x04, 0xA0, 0x01, 0x40, 0x01,
+ 0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x0D, 0x02,
+ 0x00, 0x01, 0x52, 0x04, 0x8D, 0x07, 0x00, 0x10,
+ 0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07,
+ 0x00, 0x08, 0x20, 0x20, 0x10, 0xE0, 0x05, 0x13,
+ 0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00,
+ 0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x10, 0xE0,
+ 0x20, 0x07, 0x9C, 0x08, 0x20, 0x07, 0xB4, 0x08,
+ 0x20, 0x07, 0xCC, 0x08, 0xA0, 0x07, 0xA2, 0x08,
+ 0x84, 0x02, 0xA0, 0x07, 0xBA, 0x08, 0x84, 0x02,
+ 0xA0, 0x07, 0xD2, 0x08, 0x84, 0x02, 0xA0, 0x07,
+ 0x04, 0x09, 0x00, 0x40, 0xE0, 0x04, 0x06, 0x09,
+ 0xE0, 0x04, 0x08, 0x09, 0x0E, 0xC8, 0x4C, 0x08,
+ 0x0F, 0xC8, 0x4E, 0x08, 0x0E, 0xC8, 0x8E, 0x08,
+ 0x0F, 0xC8, 0x90, 0x08, 0xE0, 0x04, 0x5A, 0x08,
+ 0xE0, 0x04, 0x60, 0x08, 0xE0, 0x02, 0x78, 0x07,
+ 0xE0, 0x04, 0x94, 0x08, 0x20, 0x40, 0x40, 0xE3,
+ 0x20, 0xE0, 0x0C, 0xE0, 0x60, 0x04, 0xBC, 0xC6,
+ 0x80, 0x01, 0x00, 0xF0, 0xC0, 0x01, 0x00, 0x40,
+ 0x10, 0x10, 0x80, 0x01, 0x00, 0xF0, 0x0D, 0x10,
+ 0xC0, 0x01, 0x00, 0xF0, 0x20, 0x40, 0x06, 0xE0,
+ 0x08, 0x10, 0xC0, 0x01, 0x00, 0xF0, 0x80, 0x01,
+ 0x00, 0x20, 0xE0, 0xC3, 0x94, 0x08, 0x01, 0x16,
+ 0x5B, 0x04, 0x4B, 0xC0, 0x20, 0x04, 0xDA, 0xEA,
+ 0x40, 0x01, 0x00, 0x20, 0xFB, 0x16, 0x51, 0x04,
+ 0xA0, 0xC2, 0xD8, 0x07, 0x4A, 0x01, 0x40, 0x00,
+ 0x01, 0x16, 0x5B, 0x04, 0xE0, 0x02, 0x78, 0x07,
+ 0x20, 0x20, 0x0C, 0xE0, 0xEF, 0x16, 0x43, 0xC2,
+ 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 0x20, 0x2F,
+ 0x36, 0x07, 0x20, 0x40, 0x0C, 0xE0, 0xA0, 0x06,
+ 0xAC, 0xC1, 0xA0, 0xC3, 0x94, 0x08, 0xFB, 0x16,
+ 0xA0, 0x06, 0x3A, 0xC2, 0x8E, 0x07, 0x04, 0x09,
+ 0x9E, 0x07, 0x00, 0x80, 0x20, 0x20, 0x10, 0xE0,
+ 0x05, 0x16, 0x8F, 0x07, 0x4C, 0x08, 0xBF, 0xCF,
+ 0xBF, 0xCF, 0x9F, 0xC7, 0xA0, 0x06, 0x5A, 0xC2,
+ 0x20, 0xE8, 0x3C, 0xE3, 0x62, 0x07, 0xA0, 0x06,
+ 0x3A, 0xC2, 0x20, 0x48, 0x3C, 0xE3, 0x62, 0x07,
+ 0x20, 0x40, 0x40, 0xE3, 0x20, 0xE0, 0x04, 0xE0,
+ 0x20, 0x48, 0x10, 0xE0, 0x58, 0x07, 0x5B, 0x04,
+ 0x80, 0x01, 0x00, 0xF0, 0x20, 0xE0, 0x04, 0xE0,
+ 0x60, 0x01, 0x60, 0x07, 0x02, 0x00, 0x02, 0x13,
+ 0x9B, 0x06, 0xB8, 0x10, 0x20, 0xE8, 0x1E, 0xE0,
+ 0x58, 0x07, 0xB4, 0x10, 0x9B, 0x06, 0x80, 0x03,
+ 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 0x00, 0x40,
+ 0x07, 0x16, 0x8D, 0x07, 0x00, 0x09, 0xA0, 0x06,
+ 0x68, 0xB8, 0xE0, 0x02, 0x78, 0x07, 0x5B, 0x04,
+ 0xC4, 0x01, 0x02, 0x00, 0xE0, 0x02, 0x78, 0x07,
+ 0x5B, 0x04, 0x0E, 0x68, 0x96, 0x08, 0xE9, 0x04,
+ 0x0C, 0x00, 0x11, 0x10, 0x0E, 0x02, 0x00, 0x23,
+ 0x4E, 0xDB, 0x01, 0x00, 0xCC, 0x01, 0x00, 0x04,
+ 0x4C, 0xD7, 0x1C, 0x10, 0x60, 0xC2, 0x5C, 0x07,
+ 0x20, 0x06, 0x94, 0x08, 0xA9, 0xC2, 0x08, 0x00,
+ 0xA9, 0xC3, 0x0C, 0x00, 0xEA, 0x16, 0x29, 0x07,
+ 0x04, 0x00, 0x69, 0x01, 0x0A, 0x00, 0x01, 0x00,
+ 0x2D, 0x13, 0x49, 0xC3, 0x2D, 0x02, 0x0E, 0x00,
+ 0x0A, 0xC3, 0x1D, 0xD3, 0x8C, 0x01, 0x00, 0x84,
+ 0xCC, 0x01, 0x00, 0x40, 0x0A, 0x01, 0x00, 0x5E,
+ 0xDD, 0x16, 0x4C, 0xC7, 0xA9, 0xC3, 0x10, 0x00,
+ 0xE9, 0xC3, 0x12, 0x00, 0x41, 0xCA, 0x10, 0x00,
+ 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 0x8E, 0x05,
+ 0x8C, 0x07, 0x02, 0x00, 0xA0, 0xC2, 0xF6, 0x07,
+ 0xA0, 0x06, 0x00, 0xBA, 0x69, 0xC0, 0x10, 0x00,
+ 0x29, 0xC8, 0x14, 0x00, 0x06, 0x09, 0x29, 0xC8,
+ 0x16, 0x00, 0x08, 0x09, 0x69, 0x01, 0x0E, 0x00,
+ 0x00, 0x08, 0x04, 0x16, 0x90, 0x03, 0x7F, 0x00,
+ 0xA0, 0x06, 0x5A, 0xC2, 0x40, 0x01, 0x00, 0x40,
+ 0x01, 0x16, 0x51, 0x04, 0x60, 0x04, 0xBE, 0xC1,
+ 0xA9, 0xC3, 0x0C, 0x00, 0x0B, 0x13, 0x0E, 0x68,
+ 0x96, 0x08, 0xE9, 0x04, 0x0C, 0x00, 0x29, 0xC8,
+ 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC3, 0x00, 0xFC,
+ 0x01, 0x13, 0x1E, 0x2E, 0x29, 0x07, 0x04, 0x00,
+ 0x5B, 0x04, 0x81, 0x07, 0x20, 0x20, 0x89, 0x07,
+ 0x4C, 0x08, 0x41, 0xCE, 0x63, 0xCE, 0x10, 0x00,
+ 0x63, 0xC6, 0x12, 0x00, 0xA0, 0x06, 0x54, 0xBA,
+ 0x43, 0xC2, 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3,
+ 0x20, 0xE0, 0x10, 0xE0, 0x60, 0x04, 0xEC, 0xC1,
+ 0x40, 0x01, 0x00, 0x04, 0xEA, 0x16, 0xA0, 0x06,
+ 0xAC, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 0x8C, 0x07,
+ 0x04, 0x00, 0x8D, 0x07, 0x4C, 0x08, 0xA0, 0xC3,
+ 0x8E, 0x08, 0xE0, 0xC3, 0x90, 0x08, 0xA0, 0x06,
+ 0x36, 0xBA, 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01,
+ 0x01, 0x00, 0x13, 0x16, 0xE0, 0xC2, 0x94, 0x08,
+ 0xEA, 0x16, 0x60, 0x04, 0xEC, 0xC1, 0xE0, 0xC3,
+ 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 0x09, 0x16,
+ 0x60, 0x04, 0xEC, 0xC1, 0xA0, 0x06, 0x54, 0xBA,
+ 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00,
+ 0xD7, 0x13, 0xA0, 0xC2, 0xF0, 0x07, 0x20, 0xC3,
+ 0x7C, 0x09, 0x8D, 0x07, 0x4C, 0x08, 0x9D, 0xC3,
+ 0xA0, 0x06, 0x36, 0xBA, 0xC0, 0x06, 0x20, 0xD0,
+ 0x50, 0x08, 0xC0, 0x06, 0x40, 0x01, 0x00, 0x04,
+ 0x0A, 0x16, 0x40, 0x01, 0x80, 0x00, 0x07, 0x13,
+ 0x0E, 0xC8, 0x4C, 0x08, 0x0F, 0xC8, 0x4E, 0x08,
+ 0xA0, 0x06, 0xA2, 0xC1, 0xD8, 0x10, 0x0E, 0xC8,
+ 0x8E, 0x08, 0x0F, 0xC8, 0x90, 0x08, 0x40, 0x01,
+ 0x00, 0x04, 0x0C, 0x13, 0x40, 0x01, 0x20, 0x00,
+ 0x58, 0x16, 0x81, 0x07, 0x10, 0x20, 0x9F, 0x10,
+ 0xA0, 0x06, 0xAC, 0xC1, 0xA0, 0xC3, 0x8E, 0x08,
+ 0xE0, 0xC3, 0x90, 0x08, 0x83, 0x07, 0x98, 0x08,
+ 0x63, 0x07, 0x04, 0x00, 0x2D, 0x11, 0x83, 0x07,
+ 0xB0, 0x08, 0x63, 0x07, 0x04, 0x00, 0x28, 0x11,
+ 0x83, 0x07, 0xC8, 0x08, 0x63, 0x07, 0x04, 0x00,
+ 0x23, 0x11, 0xC3, 0x60, 0x60, 0xC2, 0x46, 0x07,
+ 0xE7, 0x13, 0x69, 0x01, 0x0E, 0x00, 0x00, 0x08,
+ 0xE3, 0x13, 0x00, 0x03, 0x02, 0x00, 0x19, 0xC8,
+ 0x46, 0x07, 0x03, 0x16, 0xA0, 0x01, 0x3A, 0x07,
+ 0x20, 0x00, 0x00, 0x03, 0x0F, 0x00, 0xC0, 0x01,
+ 0x00, 0xF0, 0x80, 0x01, 0x00, 0x20, 0x01, 0x02,
+ 0x06, 0xC4, 0x60, 0x04, 0x9A, 0xC2, 0x81, 0x07,
+ 0x80, 0x20, 0xE0, 0xC8, 0x8E, 0x08, 0x14, 0x00,
+ 0xE0, 0xC8, 0x90, 0x08, 0x16, 0x00, 0xC7, 0x10,
+ 0xE0, 0xC8, 0x50, 0x08, 0x0E, 0x00, 0xCE, 0xC8,
+ 0x10, 0x00, 0xCF, 0xC8, 0x12, 0x00, 0x40, 0x01,
+ 0x20, 0x00, 0xBB, 0x16, 0xE3, 0xC1, 0x06, 0x00,
+ 0xC7, 0xC8, 0x08, 0x00, 0x07, 0xC8, 0x6C, 0x01,
+ 0x07, 0xC8, 0xE0, 0x08, 0x08, 0x02, 0x02, 0xFC,
+ 0xB8, 0x07, 0x00, 0x81, 0xE0, 0xC1, 0xE8, 0x00,
+ 0x07, 0xCE, 0x20, 0xC8, 0x52, 0x08, 0x92, 0x08,
+ 0xDA, 0x13, 0xCE, 0xC8, 0x14, 0x00, 0xCF, 0xC8,
+ 0x16, 0x00, 0x80, 0x01, 0x00, 0x04, 0x82, 0x07,
+ 0x54, 0x08, 0x32, 0xC1, 0x08, 0x11, 0x72, 0xC1,
+ 0x92, 0xC1, 0x82, 0x07, 0x8A, 0x08, 0x04, 0xC1,
+ 0x07, 0x16, 0x60, 0x04, 0x8E, 0xC5, 0x72, 0xC1,
+ 0xB2, 0xC1, 0x84, 0x01, 0x00, 0x80, 0xF9, 0x13,
+ 0x04, 0x68, 0x92, 0x08, 0xC7, 0xC1, 0x37, 0x16,
+ 0x20, 0x98, 0x97, 0x08, 0x85, 0x09, 0x16, 0x16,
+ 0x81, 0x07, 0x40, 0x20, 0xE0, 0xC1, 0x94, 0x08,
+ 0x57, 0x13, 0xA0, 0x06, 0xAC, 0xC1, 0xF4, 0x10,
+ 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 0x62, 0x07,
+ 0xE0, 0x26, 0x3A, 0xE3, 0x02, 0x13, 0xA0, 0x06,
+ 0x92, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 0x22, 0x10,
+ 0xA0, 0x06, 0x9C, 0xC1, 0x81, 0x2D, 0x01, 0xC2,
+ 0xFB, 0x13, 0xA0, 0x05, 0x96, 0x08, 0x23, 0xC8,
+ 0x08, 0x00, 0x6C, 0x01, 0xA0, 0x07, 0x02, 0xFC,
+ 0x00, 0x80, 0xC3, 0xC1, 0x27, 0x02, 0x06, 0x00,
+ 0xA0, 0x06, 0x0C, 0xB5, 0xA3, 0x05, 0x0C, 0x00,
+ 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xC8, 0xE0, 0x08,
+ 0x08, 0x02, 0x02, 0xFC, 0xB8, 0x07, 0x00, 0x81,
+ 0xF8, 0xC1, 0x04, 0xC1, 0x37, 0x13, 0xE0, 0xD2,
+ 0x03, 0x01, 0xD2, 0x13, 0x0B, 0x02, 0x0A, 0x01,
+ 0xC4, 0xCE, 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE,
+ 0xFB, 0x04, 0x09, 0x02, 0x00, 0x04, 0x48, 0xA2,
+ 0xC9, 0xC6, 0x20, 0xA8, 0xE0, 0x08, 0x12, 0x01,
+ 0x20, 0xC8, 0xF2, 0x07, 0x00, 0x01, 0x47, 0xC2,
+ 0xC4, 0x81, 0x01, 0x14, 0x44, 0xC2, 0xC9, 0x61,
+ 0x09, 0xA2, 0x89, 0xA1, 0x01, 0x17, 0x85, 0x05,
+ 0x09, 0x61, 0xA8, 0x16, 0x82, 0x02, 0x8A, 0x08,
+ 0x05, 0x16, 0x40, 0x01, 0x10, 0x00, 0x12, 0x13,
+ 0x60, 0x04, 0xA6, 0xC3, 0x60, 0x04, 0xBC, 0xC4,
+ 0x60, 0x04, 0x40, 0xC3, 0x81, 0x07, 0x80, 0x20,
+ 0xFB, 0x10, 0x81, 0x07, 0x80, 0x20, 0xF8, 0x10,
+ 0x81, 0x07, 0x02, 0x20, 0xF5, 0x10, 0x81, 0x07,
+ 0x04, 0x20, 0xF2, 0x10, 0x23, 0xC8, 0x08, 0x00,
+ 0x6C, 0x01, 0x07, 0x05, 0xE0, 0xA1, 0xE8, 0x00,
+ 0x0C, 0x02, 0x04, 0xFC, 0x07, 0xCF, 0xE0, 0xC2,
+ 0x92, 0x08, 0xE8, 0x16, 0xE0, 0xD2, 0x03, 0x01,
+ 0x10, 0x16, 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42,
+ 0x62, 0x07, 0xE0, 0x26, 0x3A, 0xE3, 0x07, 0x13,
+ 0x90, 0x03, 0xC8, 0x2F, 0xA0, 0x06, 0x92, 0xC1,
+ 0xE0, 0xD2, 0x03, 0x01, 0x02, 0x16, 0xA0, 0x06,
+ 0x54, 0xBA, 0x23, 0xC8, 0x06, 0x00, 0x6C, 0x01,
+ 0xA3, 0xC2, 0x0E, 0x00, 0x4A, 0x01, 0x00, 0x01,
+ 0x0B, 0x13, 0x0C, 0x02, 0x0E, 0xFC, 0x5C, 0xC2,
+ 0x49, 0x02, 0x00, 0x80, 0x0D, 0x02, 0x6C, 0x09,
+ 0x7D, 0xE2, 0x09, 0xCF, 0x3D, 0xCF, 0x3D, 0xCF,
+ 0x0C, 0x02, 0x00, 0xFC, 0x6C, 0xC3, 0x06, 0x00,
+ 0x4D, 0x02, 0xFF, 0xE0, 0x4A, 0x02, 0x00, 0x02,
+ 0x8A, 0xA2, 0x8A, 0xA2, 0x4A, 0xE3, 0x60, 0xE3,
+ 0x9E, 0x09, 0x0D, 0xCB, 0x06, 0x00, 0xCD, 0x06,
+ 0x0B, 0x02, 0x0F, 0x00, 0xEC, 0x82, 0x04, 0x00,
+ 0xAD, 0x11, 0xEC, 0xC3, 0x0E, 0x00, 0x11, 0x15,
+ 0x10, 0x13, 0x6C, 0xC2, 0x14, 0x00, 0x49, 0x02,
+ 0x00, 0x1F, 0xA7, 0x13, 0xC9, 0x06, 0x89, 0x02,
+ 0x12, 0x00, 0xA3, 0x1B, 0x49, 0x01, 0x01, 0x00,
+ 0xA0, 0x13, 0xC9, 0xA2, 0xEC, 0x82, 0x04, 0x00,
+ 0x9C, 0x11, 0x4D, 0xA3, 0x9D, 0x18, 0x14, 0x11,
+ 0x60, 0x01, 0x6A, 0x09, 0x00, 0x80, 0x18, 0x13,
+ 0x1D, 0x09, 0xCC, 0xA2, 0xEB, 0xC2, 0x08, 0x00,
+ 0x7B, 0x09, 0x4B, 0x02, 0x1E, 0x00, 0xA0, 0xC3,
+ 0xF0, 0x06, 0xAB, 0x23, 0x04, 0xE0, 0x8F, 0x16,
+ 0x60, 0x27, 0x3E, 0xE3, 0x8C, 0x16, 0x4D, 0xA3,
+ 0x4D, 0xA3, 0x4D, 0xA3, 0xCD, 0x06, 0x4D, 0x02,
+ 0x07, 0x00, 0x0D, 0x88, 0xEE, 0x06, 0x0A, 0x15,
+ 0x90, 0x03, 0xFF, 0x6F, 0x53, 0x2F, 0xA0, 0x05,
+ 0x94, 0x08, 0xC3, 0x04, 0xC0, 0x01, 0x00, 0x04,
+ 0x60, 0x04, 0xAA, 0xC3, 0x60, 0x01, 0x6A, 0x09,
+ 0x00, 0x80, 0xF2, 0x13, 0x01, 0x02, 0x08, 0x20,
+ 0x60, 0x04, 0xA2, 0xC5, 0x8D, 0x07, 0x00, 0x10,
+ 0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07,
+ 0x00, 0x08, 0x20, 0x20, 0x0E, 0xE0, 0x05, 0x13,
+ 0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00,
+ 0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x0E, 0xE0,
+ 0xA0, 0x07, 0xFA, 0x08, 0x00, 0x80, 0x0E, 0xC8,
+ 0xFA, 0x07, 0x0F, 0xC8, 0xFC, 0x07, 0x0E, 0xC8,
+ 0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xE0, 0x04,
+ 0x08, 0x08, 0xE0, 0x04, 0x0E, 0x08, 0xE0, 0x02,
+ 0x98, 0x07, 0x20, 0x40, 0x4C, 0xE3, 0x20, 0x07,
+ 0x2E, 0x06, 0x60, 0x04, 0x12, 0xCA, 0x00, 0x70,
+ 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 0x0B, 0x10,
+ 0x20, 0xF0, 0x4B, 0xE3, 0x02, 0x10, 0x20, 0xF0,
+ 0x4A, 0xE3, 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06,
+ 0xE0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x20, 0xE8,
+ 0x46, 0xE3, 0x62, 0x07, 0x20, 0x04, 0xDA, 0xEA,
+ 0x40, 0x01, 0x00, 0x20, 0x04, 0x13, 0xFA, 0x10,
+ 0x40, 0x01, 0x00, 0x40, 0xF7, 0x16, 0x20, 0x07,
+ 0x2E, 0x06, 0x20, 0x50, 0x50, 0xE3, 0x51, 0x04,
+ 0xF1, 0x10, 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01,
+ 0x00, 0x40, 0x07, 0x16, 0x8D, 0x07, 0xF6, 0x08,
+ 0xA0, 0x06, 0x68, 0xB8, 0xE0, 0x02, 0x98, 0x07,
+ 0x5B, 0x04, 0xC4, 0x01, 0x04, 0x00, 0xE0, 0x02,
+ 0x98, 0x07, 0x5B, 0x04, 0x60, 0x01, 0x60, 0x07,
+ 0x04, 0x00, 0x06, 0x16, 0x20, 0xE8, 0x1C, 0xE0,
+ 0x58, 0x07, 0x80, 0x03, 0xE0, 0x02, 0x98, 0x07,
+ 0x20, 0xD8, 0xDC, 0x07, 0x17, 0x01, 0x8F, 0x07,
+ 0x8E, 0xFF, 0x0F, 0xC8, 0x04, 0x01, 0x20, 0xE8,
+ 0x06, 0xE0, 0x58, 0x07, 0x80, 0x01, 0x00, 0x80,
+ 0x5B, 0x04, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82,
+ 0x03, 0x13, 0xDB, 0x2D, 0x03, 0xC8, 0x4A, 0x08,
+ 0x49, 0x01, 0x00, 0x01, 0x02, 0x16, 0x60, 0x04,
+ 0x52, 0xC9, 0xE0, 0xC0, 0xF8, 0x05, 0xFD, 0x13,
+ 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC,
+ 0xF8, 0x05, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2,
+ 0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x49, 0x01,
+ 0x00, 0x01, 0x4D, 0x16, 0x09, 0x01, 0x00, 0x5E,
+ 0x29, 0x16, 0x49, 0x01, 0x02, 0x00, 0x0B, 0x16,
+ 0x60, 0x01, 0x46, 0x08, 0x00, 0x02, 0x0A, 0x16,
+ 0x27, 0x02, 0x04, 0x00, 0x07, 0x88, 0x7E, 0x09,
+ 0x05, 0x12, 0x27, 0x02, 0xFC, 0xFF, 0xA0, 0x01,
+ 0x46, 0x08, 0x00, 0x02, 0xC7, 0xC1, 0x37, 0x15,
+ 0xD3, 0x2D, 0xE0, 0xC0, 0x4A, 0x08, 0x07, 0xA8,
+ 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 0x0C, 0x15,
+ 0x20, 0xC8, 0x3C, 0x08, 0xFA, 0x07, 0x20, 0xC8,
+ 0x3E, 0x08, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08,
+ 0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08,
+ 0x60, 0x04, 0x52, 0xC9, 0xA0, 0x06, 0x54, 0xBA,
+ 0xD3, 0x2D, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82,
+ 0x01, 0x13, 0xDB, 0x2D, 0x20, 0x88, 0x3E, 0x08,
+ 0x3A, 0x08, 0x0D, 0x16, 0x20, 0x88, 0x3C, 0x08,
+ 0x38, 0x08, 0x09, 0x16, 0xE0, 0x04, 0x44, 0x08,
+ 0x82, 0x07, 0x02, 0x08, 0x04, 0x61, 0xE0, 0x04,
+ 0x48, 0x08, 0x60, 0x04, 0x1E, 0xCA, 0x20, 0xC8,
+ 0x38, 0x08, 0xFA, 0x07, 0x20, 0xC8, 0x3A, 0x08,
+ 0xFC, 0x07, 0x60, 0x04, 0x12, 0xCA, 0x07, 0xA8,
+ 0x48, 0x08, 0x04, 0xC1, 0x1B, 0x16, 0x82, 0x02,
+ 0x38, 0x08, 0x0A, 0x16, 0x60, 0x01, 0xFC, 0x07,
+ 0x01, 0x00, 0x02, 0x16, 0xA0, 0x06, 0x6E, 0xCB,
+ 0xA0, 0x06, 0xFC, 0xCA, 0x80, 0x01, 0x10, 0x00,
+ 0x32, 0xC1, 0x07, 0x11, 0x72, 0xC1, 0x92, 0xC1,
+ 0x82, 0x07, 0x38, 0x08, 0x04, 0xC1, 0x06, 0x16,
+ 0xEA, 0x10, 0x72, 0xC1, 0xB2, 0xC1, 0x84, 0x01,
+ 0x00, 0x80, 0xE5, 0x13, 0xE0, 0xD2, 0x03, 0x01,
+ 0x34, 0x13, 0x0B, 0x02, 0x0A, 0x01, 0xC4, 0xCE,
+ 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 0xFB, 0x04,
+ 0xC8, 0xC6, 0x03, 0xA8, 0x12, 0x01, 0x20, 0xC8,
+ 0xF8, 0x07, 0x00, 0x01, 0xC7, 0xC2, 0xC4, 0x81,
+ 0x01, 0x14, 0xC4, 0xC2, 0x0B, 0xA8, 0x44, 0x08,
+ 0x0B, 0x61, 0x0B, 0xA2, 0x8B, 0xA1, 0x01, 0x17,
+ 0x85, 0x05, 0xCB, 0x61, 0xC6, 0x16, 0x40, 0x01,
+ 0x40, 0x00, 0x15, 0x16, 0x87, 0x07, 0x20, 0x00,
+ 0xE0, 0x61, 0x44, 0x08, 0xC4, 0x81, 0x08, 0x1A,
+ 0x07, 0xA8, 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08,
+ 0x07, 0x61, 0x87, 0xA1, 0x01, 0x17, 0x85, 0x05,
+ 0x80, 0x01, 0x40, 0x00, 0x03, 0xC8, 0x6C, 0x01,
+ 0xE0, 0xC1, 0x04, 0xFC, 0xAC, 0x10, 0x60, 0x04,
+ 0xBC, 0xC7, 0x20, 0x01, 0x3A, 0x07, 0x00, 0x70,
+ 0x04, 0x13, 0xA0, 0x06, 0x28, 0xC7, 0x20, 0x07,
+ 0x2E, 0x06, 0xA0, 0x06, 0x54, 0xBA, 0xC1, 0x10,
+ 0xE0, 0xD2, 0x03, 0x01, 0x0A, 0x16, 0x20, 0x01,
+ 0x3A, 0x07, 0x00, 0x70, 0x04, 0x13, 0xA0, 0x06,
+ 0x28, 0xC7, 0x20, 0x07, 0x2E, 0x06, 0xA0, 0x06,
+ 0x54, 0xBA, 0x90, 0x03, 0xBF, 0x4F, 0xD3, 0x2D,
+ 0x60, 0x01, 0xFC, 0x07, 0x01, 0x00, 0x02, 0x16,
+ 0xA0, 0x06, 0x6E, 0xCB, 0x60, 0xD2, 0x46, 0x08,
+ 0x89, 0x01, 0x00, 0xF1, 0xC9, 0x01, 0x00, 0x70,
+ 0x40, 0x01, 0x10, 0x00, 0x1C, 0x13, 0x20, 0x88,
+ 0x3E, 0x08, 0x3A, 0x08, 0x04, 0x16, 0x20, 0x88,
+ 0x3C, 0x08, 0x38, 0x08, 0x14, 0x13, 0x89, 0x01,
+ 0x00, 0x10, 0x8D, 0x07, 0x44, 0x08, 0x9D, 0x07,
+ 0x00, 0x50, 0xA0, 0xC2, 0xF6, 0x07, 0x8C, 0x07,
+ 0x02, 0x00, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3,
+ 0x3E, 0x08, 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17,
+ 0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x8D, 0x07,
+ 0x46, 0x08, 0x49, 0xC7, 0xA0, 0xC2, 0xF6, 0x07,
+ 0x8C, 0x07, 0x04, 0x00, 0xA0, 0xC3, 0x38, 0x08,
+ 0xE0, 0xC3, 0x3A, 0x08, 0xCC, 0xA3, 0x01, 0x17,
+ 0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x20, 0xC8,
+ 0x3C, 0x08, 0xFC, 0x08, 0x20, 0xC8, 0x3E, 0x08,
+ 0xFE, 0x08, 0x09, 0x01, 0x00, 0x0C, 0x0C, 0x13,
+ 0x49, 0x01, 0x00, 0x04, 0x05, 0x16, 0xA0, 0x06,
+ 0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0x04, 0x10,
+ 0x90, 0x03, 0x7F, 0x40, 0xA0, 0x06, 0x6C, 0xC7,
+ 0xC0, 0x01, 0x90, 0x00, 0xA0, 0x06, 0xFC, 0xCA,
+ 0x0B, 0xC8, 0x46, 0x08, 0xE0, 0xC2, 0x42, 0x07,
+ 0x2D, 0x13, 0xE0, 0xC2, 0x2E, 0x06, 0x2A, 0x13,
+ 0xE0, 0x02, 0x58, 0x07, 0x8F, 0x07, 0xBF, 0xFF,
+ 0x0F, 0x2C, 0xE0, 0x02, 0x98, 0x07, 0xE0, 0xC0,
+ 0x5C, 0x07, 0x03, 0xC8, 0x4A, 0x08, 0x03, 0xC8,
+ 0x6C, 0x01, 0xC3, 0xC2, 0xCB, 0xA2, 0xEB, 0xC2,
+ 0x32, 0x0C, 0x32, 0x13, 0x0B, 0xC8, 0x00, 0xFC,
+ 0x0B, 0xC3, 0x4B, 0xC3, 0x0B, 0xC8, 0x6C, 0x01,
+ 0xE0, 0xC2, 0x00, 0xFC, 0xFA, 0x16, 0x00, 0x03,
+ 0x02, 0x00, 0x20, 0xC8, 0xF8, 0x05, 0x00, 0xFC,
+ 0x02, 0x16, 0x0D, 0xC8, 0xFA, 0x05, 0x0C, 0xC8,
+ 0xF8, 0x05, 0x00, 0x03, 0x0F, 0x00, 0x03, 0xC8,
+ 0x6C, 0x01, 0x1A, 0x10, 0xA0, 0xC3, 0x2E, 0x06,
+ 0x03, 0x13, 0xE0, 0xC0, 0xF8, 0x05, 0x0D, 0x16,
+ 0x4F, 0x2E, 0xC0, 0x01, 0x00, 0x80, 0xA0, 0x01,
+ 0x62, 0x07, 0x00, 0x80, 0x8E, 0xC3, 0x03, 0x13,
+ 0xA0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x60, 0x04,
+ 0x4E, 0xC7, 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8,
+ 0x00, 0xFC, 0xF8, 0x05, 0x03, 0xC8, 0x4A, 0x08,
+ 0x60, 0x01, 0x6A, 0x09, 0x00, 0x04, 0x02, 0x13,
+ 0x60, 0x04, 0xE4, 0xC7, 0x8C, 0x07, 0x0E, 0x00,
+ 0x20, 0xC2, 0x0E, 0xFC, 0x0A, 0x15, 0x09, 0x13,
+ 0x20, 0xC2, 0x14, 0xFC, 0x48, 0x02, 0x00, 0x1F,
+ 0xC8, 0x06, 0x88, 0x02, 0x12, 0x00, 0xF0, 0x1B,
+ 0x08, 0xA3, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2,
+ 0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x07, 0x83,
+ 0xE7, 0x1A, 0xCC, 0x61, 0x07, 0xC8, 0x04, 0xFC,
+ 0xCC, 0xC1, 0xC0, 0x01, 0x40, 0x00, 0x60, 0x04,
+ 0xF0, 0xC7, 0x4B, 0xC1, 0xA0, 0xC2, 0xF0, 0x07,
+ 0x20, 0xC3, 0x7A, 0x09, 0x8D, 0x07, 0xFA, 0x07,
+ 0x9D, 0xC3, 0xE0, 0xC3, 0xFC, 0x07, 0xA0, 0x06,
+ 0x00, 0xBA, 0x20, 0xC8, 0x3C, 0x08, 0x40, 0x08,
+ 0x20, 0xC8, 0x3E, 0x08, 0x42, 0x08, 0x0E, 0xC8,
+ 0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xC4, 0x04,
+ 0x82, 0x07, 0x02, 0x08, 0xE0, 0x04, 0x44, 0x08,
+ 0x40, 0x01, 0x80, 0x00, 0x06, 0x16, 0x0E, 0xC8,
+ 0x38, 0x08, 0x0F, 0xC8, 0x3A, 0x08, 0xE0, 0x04,
+ 0x48, 0x08, 0xA0, 0x06, 0x54, 0xBA, 0xE0, 0xC2,
+ 0xFE, 0x07, 0x0D, 0x11, 0x0E, 0xC8, 0xFA, 0x07,
+ 0x0F, 0xC8, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08,
+ 0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08,
+ 0xA0, 0x06, 0x32, 0xC7, 0xCB, 0x10, 0x80, 0x01,
+ 0x80, 0x00, 0x55, 0x04, 0x8B, 0xC0, 0xA0, 0xC2,
+ 0xF0, 0x07, 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07,
+ 0xFA, 0x07, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3,
+ 0x3E, 0x08, 0xA0, 0x06, 0x36, 0xBA, 0x60, 0x01,
+ 0xFC, 0x07, 0x01, 0x00, 0x04, 0x13, 0xA0, 0x07,
+ 0xFA, 0x08, 0x00, 0x80, 0x52, 0x04, 0x60, 0x01,
+ 0x60, 0x07, 0x04, 0x00, 0x07, 0x16, 0x20, 0xD0,
+ 0x04, 0xE0, 0x20, 0xE8, 0x1A, 0xE0, 0x58, 0x07,
+ 0x60, 0x04, 0x3E, 0xC7, 0xA0, 0x07, 0xFA, 0x08,
+ 0x00, 0x40, 0x20, 0xC8, 0x3C, 0x08, 0xFC, 0x08,
+ 0x20, 0xC8, 0x3E, 0x08, 0xFE, 0x08, 0xA0, 0x06,
+ 0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0xD3, 0x10,
+ 0xAD, 0xC2, 0x02, 0x00, 0x6D, 0xC2, 0x00, 0x00,
+ 0x05, 0x16, 0xAA, 0x07, 0x02, 0x00, 0x36, 0x07,
+ 0x9A, 0x2C, 0x80, 0x03, 0xEA, 0x2C, 0x02, 0x00,
+ 0x41, 0xCB, 0x00, 0x00, 0x80, 0x03, 0x2D, 0xC3,
+ 0x18, 0x00, 0xAC, 0x07, 0x02, 0x00, 0x36, 0x07,
+ 0x20, 0x4B, 0x06, 0xEB, 0x0A, 0x00, 0x20, 0xEB,
+ 0x00, 0xEB, 0x0A, 0x00, 0x9C, 0x2E, 0x80, 0x03,
+ 0xA0, 0xC2, 0x22, 0xE0, 0x60, 0x04, 0x8A, 0xA3,
+ 0xED, 0xC0, 0x18, 0x00, 0xA0, 0x06, 0x3A, 0xCC,
+ 0x80, 0x03, 0x44, 0xC2, 0xC3, 0xC0, 0x02, 0x13,
+ 0xA0, 0x06, 0x3A, 0xCC, 0x19, 0xC3, 0x09, 0xCB,
+ 0x18, 0x00, 0xC9, 0x05, 0x19, 0xCB, 0x16, 0x00,
+ 0x4C, 0xC2, 0x2C, 0x02, 0x1A, 0x00, 0x0D, 0xCF,
+ 0x0E, 0xCF, 0x0F, 0xC7, 0x99, 0x00, 0x5B, 0x04,
+ 0x8C, 0x07, 0x0A, 0x09, 0x9C, 0xC2, 0xA0, 0x22,
+ 0x14, 0xE0, 0x06, 0x13, 0xA0, 0xC2, 0x58, 0x07,
+ 0xA0, 0x22, 0x20, 0xE0, 0x01, 0x16, 0x80, 0x03,
+ 0x03, 0xC1, 0xC3, 0x04, 0x8A, 0x07, 0x04, 0x00,
+ 0x84, 0xA2, 0x3A, 0xCF, 0x3A, 0xCF, 0x3A, 0xCF,
+ 0x3A, 0xCF, 0x3A, 0xCF, 0xE0, 0x02, 0x58, 0x07,
+ 0x8D, 0x07, 0x0A, 0x09, 0x0B, 0xC8, 0xC2, 0x07,
+ 0xA0, 0x06, 0x44, 0xB8, 0xE0, 0xC2, 0xC2, 0x07,
+ 0x20, 0xE0, 0x20, 0xE0, 0xE0, 0x02, 0xB8, 0x07,
+ 0x5B, 0x04, 0x2D, 0xC3, 0x18, 0x00, 0x8C, 0xC2,
+ 0x60, 0xC2, 0x6C, 0x01, 0x0A, 0xC8, 0x6C, 0x01,
+ 0xE0, 0xC2, 0x00, 0xFC, 0x02, 0x13, 0x8B, 0xC2,
+ 0xF9, 0x10, 0x09, 0xC8, 0x6C, 0x01, 0x8B, 0x07,
+ 0xF8, 0x05, 0x5B, 0xC2, 0x0C, 0x13, 0xCB, 0x05,
+ 0x5B, 0xC2, 0xCA, 0xC6, 0xE0, 0xC2, 0x6C, 0x01,
+ 0x09, 0xC8, 0x6C, 0x01, 0x0C, 0xC8, 0x00, 0xFC,
+ 0x0B, 0xC8, 0x6C, 0x01, 0x02, 0x10, 0xCC, 0xCE,
+ 0xCA, 0xC6, 0xA0, 0xC2, 0xE0, 0x00, 0xA0, 0x22,
+ 0x1A, 0xE0, 0x06, 0x16, 0x20, 0xE8, 0x04, 0xE0,
+ 0x3A, 0x07, 0x20, 0x48, 0x1A, 0xE0, 0xE0, 0x00,
+ 0x80, 0x03, 0xE0, 0xD3, 0xAB, 0xE3, 0xE0, 0x04,
+ 0x8E, 0x09, 0xE0, 0xC1, 0xA8, 0x06, 0x05, 0x16,
+ 0x07, 0x02, 0xA2, 0x06, 0xA0, 0x06, 0x38, 0xB5,
+ 0x0B, 0x16, 0xE0, 0xC1, 0xBA, 0x06, 0x23, 0x16,
+ 0x07, 0x02, 0xB4, 0x06, 0xA0, 0x06, 0x38, 0xB5,
+ 0x1E, 0x13, 0x07, 0x02, 0xB8, 0x06, 0x02, 0x10,
+ 0x07, 0x02, 0xA6, 0x06, 0x60, 0xC1, 0x02, 0xFC,
+ 0x25, 0xC8, 0x0C, 0x00, 0x02, 0xFC, 0xC5, 0xC9,
+ 0x0C, 0x00, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCD,
+ 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xC5, 0xB7, 0x01,
+ 0x28, 0x00, 0x27, 0x02, 0xF4, 0xFF, 0xA7, 0x07,
+ 0x04, 0x00, 0x52, 0xCE, 0x20, 0xE8, 0x9E, 0x09,
+ 0x06, 0xFC, 0x97, 0x2E, 0xD2, 0x10, 0x00, 0x03,
+ 0x02, 0x00, 0xA0, 0x06, 0x50, 0xB5, 0x00, 0x03,
+ 0x0F, 0x00, 0x20, 0x2C, 0xF0, 0xED, 0xE0, 0x93,
+ 0xAB, 0xE3, 0x03, 0x16, 0x81, 0x02, 0x16, 0x00,
+ 0xC4, 0x16, 0x21, 0xC1, 0x10, 0xEB, 0x54, 0x04,
+ 0xE0, 0x93, 0x10, 0xE0, 0x03, 0x16, 0xA0, 0xD2,
+ 0xA8, 0xE3, 0x0B, 0x10, 0xCF, 0xD3, 0x09, 0x16,
+ 0xA0, 0x23, 0x08, 0xE0, 0x06, 0x16, 0x84, 0x07,
+ 0x20, 0x00, 0x04, 0xE8, 0xD2, 0x06, 0xA0, 0xD2,
+ 0x0C, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0x04,
+ 0x70, 0xD1, 0x22, 0xC1, 0x04, 0x00, 0xE2, 0x04,
+ 0x02, 0x00, 0x54, 0x04, 0x02, 0xC8, 0x6C, 0x01,
+ 0x82, 0xA0, 0x22, 0xC8, 0x32, 0x0C, 0x00, 0xFC,
+ 0x02, 0x02, 0x00, 0xFC, 0xE0, 0x93, 0xAA, 0xE3,
+ 0x13, 0x16, 0xB0, 0x03, 0x20, 0x98, 0xAA, 0xE3,
+ 0x65, 0x06, 0x0D, 0x16, 0x8B, 0x07, 0x17, 0xFC,
+ 0xDB, 0xD2, 0x8B, 0x09, 0x8B, 0x02, 0x15, 0x00,
+ 0x7B, 0x1B, 0xEB, 0xD2, 0xC4, 0xEA, 0x06, 0x13,
+ 0x77, 0x15, 0x20, 0x07, 0xA0, 0x09, 0x74, 0x10,
+ 0xA0, 0x06, 0x02, 0xD0, 0xA0, 0x48, 0x04, 0xE0,
+ 0x0E, 0x00, 0x85, 0x02, 0x07, 0x00, 0x0E, 0x13,
+ 0x0E, 0x01, 0x03, 0x00, 0x0B, 0x13, 0xA0, 0x23,
+ 0x22, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 0x0E, 0xE0,
+ 0x02, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 0x8E, 0x01,
+ 0x03, 0x00, 0x5E, 0x10, 0x05, 0xC8, 0xFC, 0x06,
+ 0xC3, 0xC0, 0x57, 0x16, 0xA0, 0x43, 0x10, 0xE0,
+ 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 0x0A, 0x16,
+ 0x22, 0x88, 0x10, 0x00, 0x6E, 0x09, 0x06, 0x16,
+ 0x22, 0x88, 0x12, 0x00, 0x70, 0x09, 0x02, 0x16,
+ 0xA0, 0xE3, 0x10, 0xE0, 0x85, 0x02, 0x09, 0x00,
+ 0x02, 0x13, 0xA0, 0x06, 0xB8, 0xD7, 0x45, 0xA1,
+ 0x65, 0xC1, 0xAC, 0xE3, 0x55, 0x04, 0x62, 0xC0,
+ 0x04, 0x00, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01,
+ 0x82, 0x02, 0x48, 0x04, 0x02, 0x1B, 0xA0, 0x43,
+ 0x0C, 0xE0, 0x22, 0xC1, 0x0E, 0x00, 0x51, 0x04,
+ 0x42, 0xC0, 0xE1, 0x04, 0x02, 0x00, 0xA2, 0xC0,
+ 0x0C, 0x00, 0x22, 0xC1, 0x0A, 0x00, 0x20, 0x21,
+ 0x18, 0xE0, 0x07, 0x13, 0xA1, 0xC8, 0x0A, 0x00,
+ 0x0A, 0x00, 0xA1, 0xC8, 0x08, 0x00, 0x08, 0x00,
+ 0xE2, 0x10, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01,
+ 0xA0, 0x06, 0x66, 0xD6, 0x60, 0x04, 0xB0, 0xCE,
+ 0x02, 0xC8, 0xD4, 0x06, 0x62, 0xC1, 0x02, 0x00,
+ 0x65, 0xC1, 0xD8, 0xE3, 0x55, 0x04, 0x0F, 0x10,
+ 0x0E, 0x10, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04,
+ 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 0xA2, 0xD8,
+ 0xA0, 0xE3, 0x0C, 0xE0, 0x20, 0xE8, 0x9E, 0x09,
+ 0x06, 0x04, 0xA0, 0x2E, 0xF4, 0x03, 0x60, 0x04,
+ 0xE4, 0xCC, 0xA0, 0x06, 0x26, 0xD5, 0x0C, 0x10,
+ 0xA0, 0x06, 0x66, 0xD6, 0x09, 0x10, 0xA0, 0x06,
+ 0x2A, 0xD8, 0x06, 0x10, 0xA0, 0x06, 0x66, 0xD6,
+ 0x03, 0xC8, 0x2A, 0x09, 0xA0, 0xD2, 0xAA, 0xE3,
+ 0xA0, 0x06, 0x6E, 0xCF, 0xA0, 0x92, 0x26, 0xE0,
+ 0x0C, 0x16, 0xE0, 0xD3, 0x26, 0xE0, 0xE0, 0x23,
+ 0x14, 0xE0, 0x0A, 0x13, 0x0A, 0xC1, 0xC4, 0x83,
+ 0x07, 0x13, 0xC4, 0xC3, 0x24, 0xC1, 0xDC, 0xE3,
+ 0x54, 0x04, 0xCA, 0x93, 0xDC, 0x13, 0xCA, 0xD3,
+ 0xB0, 0x03, 0x0F, 0xD8, 0x59, 0x06, 0x04, 0x71,
+ 0x24, 0xC1, 0xEC, 0xE3, 0x54, 0x04, 0xA0, 0x23,
+ 0x0C, 0xE0, 0xD1, 0x13, 0x4D, 0xC3, 0xCF, 0x13,
+ 0x4D, 0x01, 0x00, 0x04, 0x0B, 0x13, 0x86, 0x07,
+ 0x02, 0x00, 0x84, 0x07, 0x26, 0x00, 0x46, 0x23,
+ 0x03, 0x13, 0x44, 0x06, 0x86, 0xA1, 0xFB, 0x10,
+ 0x46, 0x43, 0xB3, 0x10, 0x84, 0x07, 0x18, 0x00,
+ 0x8D, 0x01, 0x00, 0x04, 0x85, 0x07, 0xF4, 0x03,
+ 0xF5, 0x04, 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06,
+ 0xA2, 0xD8, 0x20, 0xE8, 0x9C, 0x09, 0xFE, 0x03,
+ 0x20, 0xE8, 0x9E, 0x09, 0x06, 0x04, 0xA8, 0x10,
+ 0x85, 0x07, 0x1C, 0x07, 0x86, 0x07, 0x1A, 0x04,
+ 0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0xC6, 0x05,
+ 0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0x83, 0x07,
+ 0x00, 0x90, 0xA9, 0x10, 0x0B, 0xC3, 0x86, 0x07,
+ 0x00, 0x01, 0x85, 0x07, 0x00, 0x80, 0x20, 0xC1,
+ 0xD2, 0x06, 0x37, 0x13, 0xC4, 0x04, 0x60, 0xC0,
+ 0xD2, 0x06, 0x45, 0x20, 0x04, 0x13, 0x84, 0x05,
+ 0x15, 0x09, 0xF9, 0x16, 0x2E, 0x10, 0xCF, 0xD3,
+ 0x06, 0x16, 0xE0, 0x23, 0x14, 0xE0, 0x03, 0x16,
+ 0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0xE0, 0x04,
+ 0xD2, 0x06, 0x23, 0x10, 0x64, 0xD0, 0x1C, 0x07,
+ 0x46, 0xB0, 0x10, 0x18, 0x01, 0xD9, 0x1C, 0x07,
+ 0x60, 0x23, 0x20, 0xE0, 0x0B, 0x13, 0x81, 0x07,
+ 0x18, 0x00, 0x61, 0xC0, 0xFC, 0xE3, 0x11, 0x88,
+ 0xCE, 0xED, 0x04, 0x13, 0x08, 0x02, 0x18, 0x80,
+ 0xA0, 0x06, 0xDA, 0xD4, 0x64, 0xD0, 0x28, 0x07,
+ 0x46, 0xB0, 0x08, 0x18, 0x01, 0xD9, 0x28, 0x07,
+ 0x46, 0xB0, 0x04, 0x17, 0x83, 0x07, 0x40, 0x80,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x05, 0x48, 0xD2, 0x06,
+ 0xCA, 0x16, 0x20, 0xC1, 0x32, 0x09, 0x01, 0x16,
+ 0x5C, 0x04, 0x04, 0x02, 0x07, 0x00, 0x20, 0x06,
+ 0x32, 0x09, 0x05, 0x02, 0x00, 0x01, 0xC7, 0x10,
+ 0x0B, 0xC3, 0xC5, 0x04, 0x42, 0xC0, 0xC7, 0x04,
+ 0x20, 0xC2, 0x6C, 0x01, 0xE1, 0xA1, 0x04, 0x00,
+ 0x11, 0xC8, 0x6C, 0x01, 0xFB, 0x16, 0x08, 0xC8,
+ 0x6C, 0x01, 0xC8, 0x04, 0xA0, 0x43, 0x1A, 0xE0,
+ 0x22, 0xC1, 0x0E, 0x00, 0x0D, 0x15, 0x0C, 0x13,
+ 0xA0, 0xE3, 0x1A, 0xE0, 0xA0, 0x06, 0x14, 0xD8,
+ 0x08, 0xC2, 0x48, 0x13, 0x88, 0x02, 0x12, 0x00,
+ 0x45, 0x1B, 0x20, 0x22, 0x22, 0xE0, 0x42, 0x13,
+ 0x02, 0xC1, 0x08, 0xA1, 0x08, 0x05, 0x28, 0x02,
+ 0xF2, 0xFF, 0x07, 0xA2, 0x83, 0x07, 0x01, 0x80,
+ 0x88, 0x02, 0x04, 0x00, 0x6E, 0x11, 0x64, 0xC2,
+ 0x16, 0x00, 0x49, 0xD2, 0x02, 0x16, 0x02, 0x81,
+ 0x31, 0x16, 0x09, 0x01, 0x00, 0xF0, 0x28, 0x16,
+ 0x49, 0xC1, 0x45, 0x71, 0xC3, 0x04, 0x85, 0x02,
+ 0x09, 0x00, 0x7C, 0x13, 0x83, 0x07, 0x02, 0x80,
+ 0xA4, 0xC1, 0x14, 0x00, 0x88, 0x81, 0x76, 0x16,
+ 0x83, 0x05, 0x85, 0x02, 0x15, 0x00, 0x13, 0x1B,
+ 0x83, 0x05, 0x49, 0x99, 0x30, 0xEB, 0x0A, 0x13,
+ 0x09, 0x98, 0x0E, 0xE0, 0x6B, 0x16, 0x25, 0x98,
+ 0x30, 0xEB, 0x0C, 0xE0, 0x67, 0x16, 0xE0, 0xC1,
+ 0xEC, 0x06, 0x64, 0x16, 0xC3, 0x04, 0x52, 0xC2,
+ 0x0F, 0x13, 0x83, 0x07, 0x09, 0x80, 0xE0, 0xC1,
+ 0x6A, 0x09, 0x47, 0x01, 0x00, 0x10, 0x5A, 0x16,
+ 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0x06, 0xBE, 0xD6,
+ 0x60, 0x04, 0xB0, 0xCE, 0x60, 0x04, 0xBA, 0xCE,
+ 0x89, 0x07, 0x0E, 0x07, 0xC7, 0x04, 0xE5, 0xD1,
+ 0x46, 0xEB, 0x05, 0x13, 0xC7, 0x06, 0x27, 0x02,
+ 0x5C, 0xEB, 0x77, 0xCE, 0xFE, 0x15, 0x44, 0xC0,
+ 0x21, 0x02, 0x18, 0x00, 0x28, 0x02, 0xFC, 0xFF,
+ 0x36, 0x13, 0x91, 0xC1, 0x86, 0xD1, 0x1F, 0x13,
+ 0xC6, 0x06, 0x87, 0x07, 0x0E, 0x07, 0xF7, 0xC0,
+ 0x46, 0x02, 0xFF, 0xBF, 0x43, 0x02, 0xFF, 0x3F,
+ 0xA0, 0x91, 0xF5, 0xED, 0x09, 0x16, 0xB0, 0x03,
+ 0x20, 0x98, 0x0E, 0xE0, 0x5D, 0x06, 0x0F, 0x16,
+ 0x21, 0xC8, 0x02, 0x00, 0x0C, 0x07, 0x17, 0x10,
+ 0x47, 0x82, 0x0C, 0x1B, 0xC6, 0x90, 0xEB, 0x16,
+ 0x47, 0x06, 0xF7, 0x04, 0xB0, 0x03, 0x20, 0x98,
+ 0x5D, 0x06, 0x57, 0x06, 0x0C, 0x13, 0x83, 0x07,
+ 0x05, 0x80, 0x1C, 0x10, 0xD1, 0xC0, 0xE0, 0x20,
+ 0x16, 0xE0, 0x03, 0x16, 0x83, 0x07, 0x08, 0x80,
+ 0x15, 0x10, 0x60, 0x44, 0x26, 0xE0, 0x86, 0x71,
+ 0x46, 0xA0, 0x06, 0x62, 0x83, 0x07, 0x05, 0x80,
+ 0x08, 0xC2, 0xCB, 0x15, 0x0B, 0x16, 0xC3, 0x04,
+ 0x87, 0x07, 0x0E, 0x07, 0x77, 0xC0, 0x47, 0x82,
+ 0x05, 0x1B, 0x60, 0x20, 0x06, 0xE0, 0xFA, 0x16,
+ 0x83, 0x07, 0x07, 0x80, 0x5C, 0x04, 0xA0, 0x92,
+ 0x0E, 0xE0, 0x11, 0x16, 0x20, 0xC8, 0x20, 0xE0,
+ 0x08, 0x07, 0xE0, 0x04, 0x84, 0x01, 0x60, 0x05,
+ 0x02, 0x07, 0x4B, 0x13, 0x20, 0x48, 0x06, 0xE0,
+ 0x82, 0x01, 0xA0, 0x06, 0xD0, 0xD4, 0x83, 0x07,
+ 0x00, 0xC0, 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8,
+ 0x1E, 0xE0, 0x02, 0x07, 0xA0, 0xE3, 0x04, 0xE0,
+ 0x08, 0x02, 0x24, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x42, 0x10, 0x20, 0xC1, 0x84, 0x01, 0x44, 0x02,
+ 0x00, 0x88, 0x2A, 0x13, 0x04, 0x48, 0x84, 0x01,
+ 0x20, 0x06, 0x02, 0x07, 0xF1, 0x16, 0x60, 0x01,
+ 0x8E, 0x09, 0x00, 0x80, 0x15, 0x13, 0xA0, 0x23,
+ 0x22, 0xE0, 0x05, 0x16, 0xA0, 0x43, 0x22, 0xE0,
+ 0xA0, 0xD2, 0x0E, 0xE0, 0xCF, 0x10, 0xE0, 0x23,
+ 0x14, 0xE0, 0x04, 0x13, 0x20, 0x98, 0xA9, 0xE3,
+ 0x65, 0x06, 0x0C, 0x16, 0xA0, 0x92, 0x0E, 0xE0,
+ 0xC5, 0x13, 0xA0, 0xD2, 0xA8, 0xE3, 0xD3, 0x10,
+ 0x20, 0xC8, 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07,
+ 0x00, 0xC0, 0x04, 0x10, 0x83, 0x07, 0x02, 0x00,
+ 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x04, 0xC0, 0xCE,
+ 0x20, 0xE8, 0x06, 0xE0, 0x82, 0x01, 0xA0, 0x06,
+ 0xD0, 0xD4, 0x20, 0x07, 0x02, 0x07, 0xA0, 0x43,
+ 0x04, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01,
+ 0x20, 0x88, 0x20, 0xE0, 0x08, 0x07, 0x03, 0x16,
+ 0x20, 0xC8, 0x78, 0xEB, 0x08, 0x07, 0x60, 0x04,
+ 0xD2, 0xCE, 0x0E, 0x01, 0x03, 0x00, 0x16, 0x13,
+ 0xCF, 0xD3, 0x08, 0x16, 0xA0, 0x23, 0x20, 0xE0,
+ 0x03, 0x16, 0xA0, 0xD2, 0xA8, 0xE3, 0x02, 0x10,
+ 0xA0, 0xD2, 0x0E, 0xE0, 0x8E, 0x01, 0x03, 0x00,
+ 0x09, 0x10, 0x60, 0xC1, 0x84, 0x01, 0x60, 0x21,
+ 0x0A, 0xE0, 0x04, 0x16, 0x83, 0x07, 0x00, 0x84,
+ 0x60, 0x04, 0xCA, 0xCE, 0x20, 0xC8, 0x2E, 0xE0,
+ 0x84, 0x01, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0xE3,
+ 0x20, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x93,
+ 0x26, 0xE0, 0x10, 0x16, 0xA0, 0x23, 0x08, 0xE0,
+ 0x0D, 0x16, 0xA0, 0x23, 0x06, 0xE0, 0x02, 0x13,
+ 0x60, 0xE3, 0x1C, 0xE0, 0x60, 0xE3, 0x18, 0xE0,
+ 0xA0, 0x43, 0x06, 0xE0, 0x08, 0x02, 0x3C, 0x80,
+ 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE,
+ 0xA0, 0x92, 0xA8, 0xE3, 0x03, 0x13, 0xA0, 0x92,
+ 0xA9, 0xE3, 0x1E, 0x16, 0xE0, 0x23, 0x14, 0xE0,
+ 0x08, 0x13, 0x20, 0x98, 0xA9, 0xE3, 0x65, 0x06,
+ 0x04, 0x13, 0x83, 0x07, 0x07, 0x00, 0x60, 0x04,
+ 0xCA, 0xCE, 0xA0, 0xD2, 0x0E, 0xE0, 0x20, 0xC8,
+ 0x20, 0xE0, 0x08, 0x07, 0xA0, 0x27, 0x04, 0xE0,
+ 0x0B, 0x16, 0x20, 0xC8, 0x1E, 0xE0, 0x08, 0x07,
+ 0xE0, 0x93, 0xA8, 0xE3, 0x05, 0x16, 0xA0, 0x23,
+ 0x12, 0xE0, 0x02, 0x13, 0x20, 0x06, 0x08, 0x07,
+ 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0,
+ 0x3E, 0x13, 0xB0, 0x03, 0x20, 0x98, 0x0E, 0xE0,
+ 0x6F, 0x06, 0x0F, 0x16, 0xCF, 0xD3, 0x37, 0x16,
+ 0xA0, 0xD2, 0xA8, 0xE3, 0x60, 0x04, 0xD2, 0xCE,
+ 0xA0, 0x92, 0x0C, 0xE0, 0x30, 0x16, 0xE0, 0x23,
+ 0x14, 0xE0, 0xF6, 0x13, 0x83, 0x07, 0x06, 0x00,
+ 0x07, 0x10, 0x83, 0x07, 0x05, 0x00, 0xE0, 0x93,
+ 0x0E, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x07, 0x00,
+ 0x60, 0x04, 0xCA, 0xCE, 0x60, 0xE3, 0x12, 0xE0,
+ 0xE0, 0x23, 0x14, 0xE0, 0x11, 0x13, 0x20, 0x98,
+ 0x0C, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8,
+ 0xA9, 0xE3, 0x65, 0x06, 0x14, 0x10, 0x60, 0x01,
+ 0x8E, 0x09, 0x00, 0x80, 0x10, 0x13, 0x20, 0xC1,
+ 0x84, 0x01, 0x20, 0x21, 0x06, 0xE0, 0xD2, 0x16,
+ 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x07, 0x13,
+ 0x20, 0x48, 0x06, 0xE0, 0x84, 0x01, 0x08, 0x02,
+ 0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04,
+ 0xD2, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x20,
+ 0xFA, 0x16, 0x08, 0x02, 0x78, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x20, 0xC2, 0xA2, 0x09, 0x03, 0x13,
+ 0x20, 0x06, 0xA2, 0x09, 0x21, 0x13, 0x20, 0xC2,
+ 0xA4, 0x09, 0xED, 0x13, 0x20, 0x06, 0xA4, 0x09,
+ 0xEA, 0x16, 0xA0, 0x07, 0xA4, 0x09, 0x05, 0x00,
+ 0xCD, 0x01, 0x00, 0x04, 0xE4, 0x10, 0x60, 0x01,
+ 0x8E, 0x09, 0x80, 0x00, 0x3E, 0x13, 0x60, 0x01,
+ 0x8E, 0x09, 0x00, 0x10, 0x02, 0x16, 0xA0, 0x06,
+ 0xE6, 0xD5, 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x10,
+ 0xE0, 0x01, 0x8E, 0x09, 0x80, 0x00, 0x83, 0x07,
+ 0x00, 0xA8, 0xA0, 0x06, 0x2A, 0xD8, 0x16, 0x10,
+ 0x60, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x21, 0x13,
+ 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x10, 0xA0, 0x07,
+ 0x08, 0x07, 0x05, 0x00, 0x83, 0x07, 0x08, 0xA8,
+ 0xA0, 0x23, 0x04, 0xE0, 0x05, 0x16, 0x20, 0xC8,
+ 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 0x08, 0xE8,
+ 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x01, 0x8E, 0x09,
+ 0x00, 0x20, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x01,
+ 0xE0, 0x01, 0x82, 0x01, 0x00, 0x08, 0xA0, 0xD2,
+ 0x0E, 0xE0, 0x83, 0x07, 0x10, 0x80, 0x60, 0x04,
+ 0xC0, 0xCE, 0x08, 0x02, 0x78, 0x00, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x83, 0x07, 0x00, 0x82, 0x60, 0x04,
+ 0xCA, 0xCE, 0x60, 0x04, 0xD2, 0xCE, 0x20, 0x06,
+ 0x90, 0x09, 0x07, 0x15, 0xA0, 0xD2, 0x10, 0xE0,
+ 0xCA, 0x06, 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04,
+ 0xF4, 0x10, 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x20, 0xC2, 0x90, 0x09, 0x88, 0x02,
+ 0x96, 0x00, 0x0D, 0x1B, 0xEA, 0x16, 0x20, 0x48,
+ 0x08, 0xE0, 0x82, 0x01, 0xA0, 0x01, 0x8E, 0x09,
+ 0x00, 0x10, 0xA0, 0x06, 0xE6, 0xD5, 0x83, 0x07,
+ 0x00, 0x28, 0x60, 0x04, 0xC0, 0xCE, 0x60, 0x01,
+ 0x8E, 0x09, 0x00, 0x10, 0xDA, 0x16, 0x84, 0x07,
+ 0x04, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04,
+ 0xB5, 0x07, 0x30, 0x06, 0xA0, 0x06, 0xA2, 0xD8,
+ 0xA0, 0x07, 0xF8, 0x03, 0x34, 0xD4, 0x60, 0x04,
+ 0xC0, 0xDB, 0xA0, 0x07, 0x90, 0x09, 0xF4, 0x01,
+ 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x08, 0x02, 0x36, 0x00, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x23,
+ 0x18, 0xE0, 0x06, 0x13, 0xA0, 0xE3, 0x18, 0xE0,
+ 0xE0, 0x2E, 0x00, 0x00, 0x41, 0xC0, 0xFA, 0x16,
+ 0xA0, 0x06, 0xE6, 0xD5, 0xB2, 0x10, 0x04, 0x02,
+ 0x64, 0x00, 0x04, 0x06, 0xFE, 0x16, 0x5B, 0x04,
+ 0xA0, 0xE3, 0x0A, 0xE0, 0x08, 0xC2, 0x02, 0x11,
+ 0xA0, 0x43, 0x0A, 0xE0, 0x20, 0x42, 0x04, 0xE0,
+ 0x28, 0x02, 0xFC, 0xE3, 0x58, 0xC0, 0x02, 0xC0,
+ 0x11, 0x88, 0xCE, 0xED, 0x03, 0x16, 0xD1, 0x2C,
+ 0x58, 0xC0, 0xD1, 0x04, 0x80, 0xC0, 0x0E, 0x01,
+ 0x00, 0x10, 0x0F, 0x13, 0x60, 0xCC, 0xCE, 0xED,
+ 0xC8, 0x05, 0x78, 0xCC, 0x03, 0x16, 0x41, 0x06,
+ 0x60, 0xCC, 0xD6, 0x06, 0x58, 0xC4, 0x02, 0x16,
+ 0x60, 0xC4, 0x00, 0x07, 0x21, 0x02, 0xFA, 0xFF,
+ 0x91, 0x2C, 0x5B, 0x04, 0x0B, 0xC3, 0xA0, 0x06,
+ 0xC2, 0xD5, 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2,
+ 0x05, 0x16, 0x62, 0xC2, 0x02, 0x00, 0x60, 0x26,
+ 0xA8, 0xE4, 0x0D, 0x16, 0x42, 0xC2, 0xC9, 0x05,
+ 0x60, 0xCE, 0xF2, 0xED, 0x60, 0xC6, 0x7C, 0xEB,
+ 0xA0, 0x06, 0x10, 0xD6, 0x18, 0xCA, 0x0A, 0x00,
+ 0x20, 0x46, 0x26, 0xE0, 0x04, 0x16, 0xA0, 0xC0,
+ 0x6C, 0x01, 0x12, 0x2E, 0x1D, 0x10, 0x12, 0xC1,
+ 0x05, 0x13, 0x60, 0xC1, 0x6C, 0x01, 0x14, 0x2E,
+ 0x05, 0xC8, 0x6C, 0x01, 0xD2, 0x04, 0x48, 0x06,
+ 0x84, 0x07, 0x02, 0x00, 0x48, 0xC1, 0xA0, 0xC0,
+ 0x6C, 0x01, 0x02, 0xC0, 0xA0, 0x06, 0xA2, 0xD8,
+ 0x60, 0xC5, 0x02, 0xFC, 0x07, 0x02, 0xA2, 0x06,
+ 0x25, 0x02, 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC,
+ 0x20, 0xC2, 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4,
+ 0x5C, 0x04, 0x42, 0xC2, 0x29, 0x02, 0x08, 0x00,
+ 0x39, 0xC2, 0x48, 0x02, 0x00, 0xC0, 0x88, 0x02,
+ 0x00, 0xC0, 0x08, 0x16, 0x60, 0x8E, 0x2E, 0xE0,
+ 0x05, 0x16, 0x60, 0x86, 0x2E, 0xE0, 0x02, 0x16,
+ 0xC8, 0x04, 0x5B, 0x04, 0x08, 0x07, 0x5B, 0x04,
+ 0x20, 0x88, 0x8E, 0xE1, 0x6C, 0x01, 0x02, 0x16,
+ 0x60, 0x04, 0xBA, 0xCE, 0x5B, 0x04, 0x88, 0x07,
+ 0xAE, 0x01, 0x20, 0xE8, 0x0E, 0xE0, 0x80, 0x01,
+ 0x08, 0x06, 0xFE, 0x16, 0x20, 0x48, 0x0E, 0xE0,
+ 0x80, 0x01, 0x5B, 0x04, 0xC2, 0x04, 0xA0, 0x23,
+ 0x0C, 0xE0, 0x10, 0x16, 0x20, 0x2F, 0x30, 0x06,
+ 0x82, 0x07, 0xDF, 0xFF, 0x02, 0x2C, 0x82, 0x02,
+ 0xF4, 0x03, 0x06, 0x13, 0xE2, 0x04, 0x02, 0x00,
+ 0xA2, 0xC0, 0x06, 0x00, 0x12, 0x2E, 0xF4, 0x10,
+ 0xA0, 0x43, 0x0C, 0xE0, 0x5B, 0x04, 0x42, 0xC2,
+ 0x88, 0x07, 0x0E, 0x00, 0x09, 0xA2, 0x29, 0x02,
+ 0x08, 0x00, 0x78, 0xCE, 0x78, 0xCE, 0x78, 0xCE,
+ 0x60, 0xCE, 0x6C, 0x09, 0x60, 0xCE, 0x6E, 0x09,
+ 0x60, 0xCE, 0x70, 0x09, 0xA0, 0x23, 0x1A, 0xE0,
+ 0x0F, 0x16, 0x58, 0xC2, 0x49, 0x02, 0x80, 0x1F,
+ 0x60, 0x2A, 0x14, 0xE0, 0xA0, 0xE8, 0x04, 0xE0,
+ 0x0E, 0x00, 0x09, 0xC6, 0x49, 0x02, 0x00, 0x1F,
+ 0xC9, 0x06, 0x09, 0xA2, 0x89, 0xA8, 0x04, 0x00,
+ 0x28, 0x02, 0x02, 0x00, 0x58, 0xC2, 0x49, 0x0A,
+ 0x49, 0x02, 0x00, 0xF0, 0x09, 0xD6, 0xE2, 0x04,
+ 0x06, 0x00, 0x5B, 0x04, 0x00, 0x07, 0x82, 0xC0,
+ 0x53, 0x13, 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0xC1,
+ 0x06, 0xFC, 0x46, 0x02, 0x0F, 0x00, 0x86, 0x02,
+ 0x01, 0x00, 0x3D, 0x12, 0x06, 0x88, 0xF2, 0x06,
+ 0x12, 0x16, 0x01, 0x02, 0x0E, 0xFC, 0x31, 0x88,
+ 0xF4, 0x06, 0x0D, 0x16, 0x31, 0x88, 0xF6, 0x06,
+ 0x0A, 0x16, 0x31, 0x88, 0xF8, 0x06, 0x07, 0x16,
+ 0x86, 0x02, 0x02, 0x00, 0x2C, 0x16, 0x20, 0x88,
+ 0x0A, 0x07, 0xFA, 0x06, 0x28, 0x13, 0x20, 0xC1,
+ 0x6A, 0x09, 0x44, 0x01, 0x00, 0x08, 0x06, 0x13,
+ 0x86, 0x02, 0x02, 0x00, 0x20, 0x16, 0x44, 0x01,
+ 0x80, 0x00, 0x1D, 0x16, 0x00, 0x07, 0xE0, 0x23,
+ 0x14, 0xE0, 0x19, 0x16, 0x82, 0x02, 0x43, 0x00,
+ 0x16, 0x13, 0x00, 0x02, 0x02, 0xFC, 0x40, 0xC0,
+ 0xB0, 0x01, 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09,
+ 0x01, 0x00, 0x07, 0x16, 0x60, 0xA0, 0x2C, 0x09,
+ 0x60, 0xCC, 0xEE, 0x05, 0x50, 0xC4, 0x20, 0xC4,
+ 0x2C, 0x09, 0x80, 0x07, 0x36, 0x07, 0x81, 0x07,
+ 0x40, 0x00, 0x40, 0x2C, 0xC0, 0x04, 0x84, 0x07,
+ 0xF2, 0x06, 0x06, 0xCD, 0x01, 0x02, 0x0E, 0xFC,
+ 0x31, 0xCD, 0x31, 0xCD, 0x31, 0xCD, 0x20, 0xC5,
+ 0x0A, 0x07, 0x00, 0xC0, 0x01, 0x13, 0x12, 0x2E,
+ 0xE0, 0x04, 0x6C, 0x01, 0x5B, 0x04, 0x60, 0x01,
+ 0x8A, 0x09, 0x00, 0x80, 0x12, 0x13, 0x0B, 0xC8,
+ 0x22, 0x09, 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02,
+ 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x08, 0x02,
+ 0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xC2,
+ 0x22, 0x09, 0x5B, 0x04, 0x20, 0x48, 0xAC, 0xE4,
+ 0x80, 0x01, 0x20, 0x48, 0x7E, 0xEB, 0x82, 0x01,
+ 0x20, 0x48, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0x48,
+ 0x22, 0xE0, 0x78, 0x09, 0x60, 0x43, 0x18, 0xE0,
+ 0xA0, 0x43, 0x08, 0xE0, 0x60, 0x01, 0x8A, 0x09,
+ 0x00, 0x80, 0xEB, 0x13, 0x0B, 0xC3, 0x08, 0x02,
+ 0x42, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 0x5C, 0x04,
+ 0x0B, 0xC3, 0x20, 0xE8, 0x0E, 0xE0, 0x82, 0x01,
+ 0x20, 0xE8, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0xE8,
+ 0x22, 0xE0, 0x78, 0x09, 0xA0, 0xE3, 0x08, 0xE0,
+ 0x60, 0xE3, 0x18, 0xE0, 0xA0, 0x43, 0x06, 0xE0,
+ 0x08, 0x02, 0x3C, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x5C, 0x04, 0x0B, 0xC3, 0x83, 0x07, 0x00, 0x68,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x83, 0x07, 0x10, 0x80,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x5C, 0x04, 0x0B, 0xC3,
+ 0xA0, 0x06, 0x14, 0xD8, 0x02, 0xA2, 0x68, 0xC2,
+ 0x14, 0x00, 0x29, 0x02, 0xFC, 0xFF, 0x24, 0x13,
+ 0x28, 0x02, 0x18, 0x00, 0x87, 0x07, 0x0E, 0x00,
+ 0x81, 0x07, 0x0E, 0x07, 0xF1, 0x04, 0x47, 0x06,
+ 0xFD, 0x15, 0x58, 0xC0, 0xB0, 0x03, 0x01, 0x78,
+ 0x63, 0x06, 0x41, 0x02, 0x3F, 0x00, 0x0E, 0x13,
+ 0x81, 0x02, 0x1F, 0x00, 0x0B, 0x1B, 0x41, 0xA0,
+ 0x61, 0xC0, 0x86, 0xE4, 0xF8, 0xC1, 0xC7, 0x06,
+ 0xC7, 0x71, 0x47, 0x06, 0x78, 0xCC, 0x47, 0x06,
+ 0xFD, 0x15, 0x04, 0x10, 0x58, 0xC0, 0xC1, 0x06,
+ 0x41, 0x70, 0x01, 0xA2, 0x49, 0xC2, 0xE5, 0x15,
+ 0x5C, 0x04, 0xA0, 0x23, 0x1A, 0xE0, 0x02, 0x13,
+ 0xC8, 0x04, 0x5B, 0x04, 0x22, 0xC2, 0x14, 0x00,
+ 0x48, 0x02, 0x00, 0x1F, 0xC8, 0x06, 0x5B, 0x04,
+ 0x83, 0x02, 0x0F, 0x00, 0x17, 0x1B, 0xA0, 0xC1,
+ 0xD4, 0x06, 0x35, 0x13, 0x26, 0x02, 0x04, 0x00,
+ 0xA0, 0xCD, 0xCE, 0xED, 0x83, 0xC5, 0x04, 0x13,
+ 0x4A, 0xC2, 0x39, 0x0A, 0xC9, 0xE0, 0x83, 0xC5,
+ 0x86, 0x07, 0x36, 0x07, 0x87, 0x07, 0x10, 0x00,
+ 0x20, 0xC2, 0xD4, 0x06, 0xE0, 0x04, 0xD4, 0x06,
+ 0x46, 0x2C, 0x5B, 0x04, 0x60, 0xC0, 0xFE, 0x06,
+ 0x20, 0xC2, 0x6A, 0x09, 0x48, 0x02, 0x00, 0x60,
+ 0x20, 0x22, 0x06, 0xE0, 0x04, 0x16, 0x20, 0xE2,
+ 0x0A, 0xE0, 0x20, 0xE2, 0x18, 0xE0, 0x13, 0x0A,
+ 0x04, 0x18, 0x41, 0x05, 0x03, 0x48, 0xFE, 0x06,
+ 0x06, 0x10, 0x83, 0x02, 0x02, 0x00, 0x01, 0x16,
+ 0x13, 0x09, 0x03, 0xE8, 0xFE, 0x06, 0xC8, 0x40,
+ 0xC1, 0x40, 0x05, 0x13, 0x88, 0x07, 0x36, 0x07,
+ 0x89, 0x07, 0x00, 0x40, 0x48, 0x2C, 0x5B, 0x04,
+ 0xC9, 0x04, 0x24, 0xC1, 0x94, 0xEB, 0x84, 0xC1,
+ 0x86, 0x71, 0x86, 0xA1, 0x26, 0x02, 0x56, 0xEC,
+ 0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xC2, 0xEB,
+ 0x14, 0xD2, 0xC8, 0x09, 0x08, 0xA2, 0xB0, 0x03,
+ 0x34, 0xD8, 0x5F, 0x06, 0x47, 0x02, 0x0F, 0x00,
+ 0xC7, 0xA1, 0x28, 0xC2, 0x82, 0xEB, 0x58, 0x04,
+ 0x76, 0xCD, 0x47, 0x06, 0xFD, 0x16, 0x32, 0x10,
+ 0x36, 0xC2, 0x26, 0x10, 0x17, 0x09, 0x47, 0xA1,
+ 0x2D, 0x10, 0x17, 0x09, 0x47, 0x61, 0x2A, 0x10,
+ 0xA0, 0x43, 0x16, 0xE0, 0x5B, 0x04, 0xA0, 0x43,
+ 0x16, 0xE0, 0x49, 0xC2, 0x03, 0x16, 0x44, 0xC2,
+ 0x06, 0xC8, 0x22, 0x09, 0x27, 0xC1, 0x8E, 0xED,
+ 0x84, 0xC1, 0x86, 0x71, 0x26, 0x02, 0xC4, 0xED,
+ 0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xAA, 0xED,
+ 0xD3, 0x10, 0x09, 0xC1, 0xA0, 0xC1, 0x22, 0x09,
+ 0xC9, 0x04, 0x10, 0x10, 0x36, 0xC2, 0x78, 0xD5,
+ 0x60, 0x41, 0x22, 0xE0, 0xC5, 0x05, 0x0A, 0x10,
+ 0x78, 0xCD, 0x47, 0x06, 0xFD, 0x15, 0x06, 0x10,
+ 0xA0, 0x23, 0x16, 0xE0, 0xCD, 0x16, 0x49, 0xC2,
+ 0xEC, 0x16, 0xD6, 0x10, 0xA0, 0xE3, 0x16, 0xE0,
+ 0xBB, 0x10, 0x08, 0x02, 0x5A, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x44, 0x10, 0xA0, 0x92, 0x0C, 0xE0,
+ 0x15, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x14, 0x16,
+ 0x20, 0x48, 0xAC, 0xE4, 0x80, 0x01, 0xA0, 0x06,
+ 0x72, 0xD7, 0x20, 0xC8, 0x9E, 0x01, 0x9E, 0x01,
+ 0xE0, 0x2E, 0x01, 0x00, 0xA0, 0x43, 0x18, 0xE0,
+ 0xA0, 0xD2, 0x26, 0xE0, 0x83, 0x07, 0x10, 0x00,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xD2, 0xCE,
+ 0x84, 0x07, 0x08, 0x00, 0x60, 0x04, 0x94, 0xCE,
+ 0x85, 0x07, 0x03, 0x02, 0x05, 0xC8, 0xCE, 0x06,
+ 0xA0, 0x43, 0x12, 0xE0, 0xE0, 0x04, 0xFA, 0x06,
+ 0xA0, 0x06, 0xA4, 0xD7, 0x08, 0x02, 0x48, 0x80,
+ 0xA0, 0x06, 0xDA, 0xD4, 0x17, 0x10, 0x60, 0x01,
+ 0x8E, 0x09, 0x00, 0x80, 0x02, 0x16, 0x60, 0x04,
+ 0x9C, 0xD4, 0xA0, 0x27, 0x2C, 0xE0, 0x04, 0x16,
+ 0x08, 0x02, 0x54, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x83, 0x07, 0x00, 0xA8, 0x20, 0x88, 0x08, 0x07,
+ 0x20, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x00, 0xE8,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x08, 0x02, 0x36, 0x00,
+ 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 0x0C, 0xE0,
+ 0x82, 0x01, 0xA0, 0x23, 0x18, 0xE0, 0x06, 0x13,
+ 0xA0, 0xE3, 0x18, 0xE0, 0xE0, 0x2E, 0x00, 0x00,
+ 0x41, 0xC0, 0xFA, 0x16, 0xA0, 0x06, 0xE6, 0xD5,
+ 0x82, 0xC0, 0x02, 0x13, 0x4F, 0x02, 0x80, 0xFF,
+ 0xC4, 0x04, 0x0F, 0xD1, 0xC4, 0x06, 0x60, 0x04,
+ 0x94, 0xCE, 0xA0, 0x06, 0x32, 0xDA, 0x08, 0x02,
+ 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 0x20, 0xDA,
+ 0xA0, 0x06, 0xDA, 0xD4, 0x10, 0x10, 0xA0, 0x06,
+ 0x32, 0xDA, 0x20, 0xD1, 0xCE, 0x06, 0xE6, 0x13,
+ 0x20, 0x78, 0x12, 0xE0, 0xCE, 0x06, 0xE2, 0x10,
+ 0x20, 0xC1, 0x16, 0x04, 0x14, 0x0A, 0xC4, 0x06,
+ 0x0A, 0x91, 0x01, 0x16, 0x5B, 0x04, 0x60, 0x04,
+ 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 0xAB, 0xE3,
+ 0x65, 0x06, 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE,
+ 0x60, 0xC1, 0x94, 0x09, 0x02, 0x13, 0x60, 0x04,
+ 0x22, 0xDE, 0x60, 0xD1, 0x0E, 0xE0, 0x3D, 0x10,
+ 0x85, 0x07, 0xBE, 0xEA, 0x35, 0xC8, 0x8A, 0x09,
+ 0x15, 0xC8, 0x8C, 0x09, 0x0B, 0x10, 0xE0, 0x04,
+ 0xA0, 0x09, 0x20, 0xD8, 0x2E, 0x09, 0xA6, 0x09,
+ 0x20, 0xC8, 0xA8, 0x09, 0x8A, 0x09, 0x20, 0xC8,
+ 0xAA, 0x09, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09,
+ 0xCA, 0x04, 0xCD, 0x04, 0xCE, 0x04, 0xCF, 0x04,
+ 0xE0, 0x04, 0xA8, 0x06, 0xE0, 0x04, 0xBA, 0x06,
+ 0x84, 0x07, 0xA0, 0x01, 0x85, 0x07, 0x10, 0x00,
+ 0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07,
+ 0xD8, 0x06, 0x85, 0x07, 0x34, 0x07, 0x44, 0x61,
+ 0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07,
+ 0xC8, 0x00, 0x04, 0xC8, 0x00, 0x07, 0x84, 0x07,
+ 0xFF, 0x7F, 0x04, 0xC8, 0xF0, 0x06, 0x84, 0x07,
+ 0x06, 0x00, 0x04, 0xC8, 0xEE, 0x06, 0x85, 0x07,
+ 0x02, 0x0C, 0x20, 0xC1, 0x8A, 0x09, 0x01, 0x11,
+ 0xC5, 0x06, 0xB0, 0x03, 0x05, 0xD8, 0x65, 0x06,
+ 0x60, 0x04, 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98,
+ 0xAA, 0xE3, 0x65, 0x06, 0x79, 0x16, 0x60, 0xD1,
+ 0x10, 0xE0, 0xF3, 0x10, 0x60, 0xD1, 0xAB, 0xE3,
+ 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0xE0, 0x01,
+ 0x80, 0x01, 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2,
+ 0x80, 0x01, 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8,
+ 0x2E, 0x09, 0xE3, 0x10, 0x20, 0xF8, 0x19, 0xEE,
+ 0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0xC6, 0x06,
+ 0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x20, 0xC8,
+ 0xC2, 0xEA, 0x90, 0x09, 0xE0, 0x2E, 0x00, 0x00,
+ 0xA0, 0x06, 0xE6, 0xD5, 0x20, 0xC8, 0x6C, 0x09,
+ 0xA0, 0x01, 0x20, 0xC8, 0x6E, 0x09, 0xA2, 0x01,
+ 0x20, 0xC8, 0x70, 0x09, 0xA4, 0x01, 0x20, 0xC8,
+ 0x6E, 0x09, 0xB0, 0x01, 0x20, 0xC8, 0x70, 0x09,
+ 0xB2, 0x01, 0x20, 0xC8, 0x70, 0x09, 0xCC, 0x06,
+ 0x20, 0xF8, 0x18, 0xEE, 0x80, 0x01, 0xB0, 0x03,
+ 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0x20, 0x98,
+ 0xAA, 0xE3, 0x65, 0x06, 0x3A, 0x13, 0xE0, 0x01,
+ 0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x56, 0xDF,
+ 0xE0, 0xC2, 0x8A, 0x09, 0x05, 0x11, 0xA0, 0x01,
+ 0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x9A, 0xDF,
+ 0x98, 0x06, 0x08, 0x02, 0x12, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x84, 0x07, 0x0A, 0x00, 0x85, 0x07,
+ 0xF4, 0x03, 0x20, 0x88, 0xC6, 0x06, 0x20, 0xE0,
+ 0x08, 0x1B, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80,
+ 0xA5, 0x13, 0x84, 0x07, 0x1C, 0x00, 0x85, 0x07,
+ 0xF8, 0x03, 0xA0, 0x06, 0xA2, 0xD8, 0x85, 0x07,
+ 0x42, 0xDC, 0x05, 0xC8, 0xF8, 0x03, 0x20, 0xC8,
+ 0xA0, 0x09, 0xA0, 0x09, 0x6C, 0x16, 0x20, 0xE8,
+ 0x9C, 0x09, 0xFE, 0x03, 0x20, 0xE8, 0x9E, 0x09,
+ 0x06, 0x04, 0xA0, 0x23, 0x0C, 0xE0, 0x32, 0x13,
+ 0xA0, 0xE3, 0x0C, 0xE0, 0xA0, 0x2E, 0xF4, 0x03,
+ 0x2D, 0x10, 0xA0, 0x06, 0x56, 0xDF, 0x60, 0x01,
+ 0x8E, 0x09, 0x00, 0x40, 0x08, 0x13, 0x08, 0x02,
+ 0x6C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x22, 0x10,
+ 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x40, 0x08, 0x02,
+ 0x60, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x84, 0x07,
+ 0x2A, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xA0, 0x06,
+ 0xA2, 0xD8, 0xD5, 0x10, 0xB0, 0x03, 0x20, 0x98,
+ 0xAA, 0xE3, 0x65, 0x06, 0x0F, 0x16, 0x20, 0x06,
+ 0x90, 0x09, 0x9A, 0x16, 0x60, 0x01, 0x8A, 0x09,
+ 0x00, 0x40, 0x39, 0x13, 0xE0, 0x04, 0x8A, 0x09,
+ 0xE0, 0x04, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09,
+ 0x60, 0x04, 0x62, 0xDA, 0x60, 0x04, 0xB0, 0xCE,
+ 0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06,
+ 0xF9, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x04, 0x16,
+ 0x20, 0x06, 0xC6, 0x06, 0x9A, 0x16, 0x0A, 0x10,
+ 0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06,
+ 0xED, 0x16, 0x20, 0x06, 0xC8, 0x06, 0x02, 0x13,
+ 0x60, 0x04, 0x5A, 0xDB, 0x60, 0x01, 0x8E, 0x09,
+ 0x00, 0x01, 0x02, 0x16, 0xCE, 0x01, 0x03, 0x00,
+ 0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0x83, 0x07,
+ 0x00, 0x82, 0x07, 0x10, 0x83, 0x07, 0x01, 0x00,
+ 0xE0, 0x04, 0x8E, 0x09, 0x20, 0xE8, 0x0C, 0xE0,
+ 0x82, 0x01, 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x01,
+ 0x8A, 0x09, 0x00, 0x40, 0xC7, 0x16, 0x83, 0x07,
+ 0x0D, 0x00, 0xF2, 0x10, 0xB0, 0x03, 0x20, 0x98,
+ 0xAA, 0xE3, 0x65, 0x06, 0xC7, 0x16, 0x20, 0x88,
+ 0x98, 0x09, 0x20, 0xE0, 0xF0, 0x16, 0x22, 0xC8,
+ 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 0x10, 0x00,
+ 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, 0xE0, 0x06,
+ 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x08, 0x02,
+ 0x66, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB2, 0x10,
+ 0xA0, 0x07, 0x9A, 0x09, 0x5A, 0x00, 0xA0, 0x07,
+ 0xA2, 0x09, 0x19, 0x00, 0xA0, 0x07, 0xA4, 0x09,
+ 0x05, 0x00, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x20,
+ 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x08, 0x02,
+ 0x78, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB0, 0x03,
+ 0x20, 0x98, 0xAB, 0xE3, 0x65, 0x06, 0x9A, 0x16,
+ 0x08, 0x02, 0x72, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x06,
+ 0xD0, 0xD5, 0x20, 0x06, 0x9A, 0x09, 0xBF, 0x13,
+ 0x84, 0x07, 0x2C, 0x00, 0x85, 0x07, 0xF4, 0x03,
+ 0xA0, 0x06, 0xA2, 0xD8, 0x60, 0x04, 0xC0, 0xDB,
+ 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 0x82, 0x10,
+ 0x0E, 0x01, 0x03, 0x00, 0x0A, 0x13, 0x08, 0x02,
+ 0x0C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xE3,
+ 0x14, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01,
+ 0x26, 0x10, 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01,
+ 0xE0, 0x2E, 0x01, 0x00, 0x60, 0xC1, 0x1E, 0x09,
+ 0x35, 0x0A, 0x05, 0xE8, 0x82, 0x01, 0x20, 0xC1,
+ 0x6A, 0x09, 0x04, 0x01, 0x06, 0x00, 0x06, 0x13,
+ 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 0x20, 0xD8,
+ 0xD0, 0xE1, 0x83, 0x01, 0x20, 0x21, 0x22, 0xE0,
+ 0x03, 0x16, 0x20, 0xE8, 0x22, 0xE0, 0x80, 0x01,
+ 0x20, 0x21, 0x04, 0xE0, 0x04, 0x16, 0xA0, 0xE3,
+ 0x14, 0xE0, 0x60, 0x04, 0x0A, 0xD3, 0x08, 0x02,
+ 0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8,
+ 0x08, 0xE0, 0x82, 0x01, 0xE0, 0xC2, 0x8A, 0x09,
+ 0x02, 0x11, 0x60, 0x04, 0xB0, 0xCE, 0xA0, 0x01,
+ 0x8E, 0x09, 0x00, 0x04, 0x6B, 0x10, 0x20, 0xC8,
+ 0xAE, 0xE4, 0x86, 0x01, 0x08, 0x02, 0x00, 0x80,
+ 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC2, 0x1E, 0x09,
+ 0x08, 0xA2, 0x08, 0x05, 0x28, 0xC8, 0x22, 0xE0,
+ 0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xC6, 0x06,
+ 0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x60, 0xE3,
+ 0x16, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x44, 0xC1,
+ 0x44, 0x02, 0x00, 0x5E, 0xF8, 0x16, 0x60, 0x25,
+ 0xA8, 0xE4, 0x0F, 0x16, 0x20, 0x06, 0xC6, 0x06,
+ 0xF2, 0x16, 0x20, 0x06, 0xCA, 0x06, 0x03, 0x13,
+ 0xA0, 0x05, 0xCC, 0x06, 0xE6, 0x10, 0xB0, 0x03,
+ 0x20, 0xD8, 0x0C, 0xE0, 0x65, 0x06, 0x60, 0x04,
+ 0xD2, 0xCE, 0x20, 0x06, 0xC8, 0x06, 0xE3, 0x16,
+ 0x20, 0x88, 0x70, 0x09, 0xCC, 0x06, 0x03, 0x16,
+ 0x83, 0x07, 0x08, 0x00, 0x02, 0x10, 0x83, 0x07,
+ 0x0C, 0x00, 0x60, 0x04, 0x8A, 0xDC, 0x60, 0x04,
+ 0xD2, 0xCE, 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x13,
+ 0x60, 0x23, 0x12, 0xE0, 0x06, 0x16, 0xB0, 0x03,
+ 0x20, 0xD8, 0xA9, 0xE3, 0x65, 0x06, 0x60, 0x04,
+ 0xD2, 0xCE, 0x08, 0x02, 0x00, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x60, 0x04, 0xB0, 0xCE, 0x08, 0x02,
+ 0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC8,
+ 0x1E, 0xE0, 0xC6, 0x06, 0x20, 0xC8, 0x1E, 0xE0,
+ 0xC8, 0x06, 0x60, 0xE3, 0x10, 0xE0, 0x60, 0x04,
+ 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 0x30, 0x13,
+ 0x44, 0xC1, 0x44, 0x02, 0x00, 0x1E, 0xF5, 0x16,
+ 0x60, 0x25, 0xA8, 0xE4, 0x1D, 0x16, 0x20, 0x06,
+ 0xC8, 0x06, 0xEF, 0x16, 0x60, 0x01, 0x8E, 0x09,
+ 0x00, 0x80, 0x13, 0x16, 0x60, 0x01, 0x8E, 0x09,
+ 0x00, 0x01, 0x0C, 0x16, 0xA0, 0x01, 0x8E, 0x09,
+ 0x00, 0x01, 0xA0, 0x01, 0x8E, 0x09, 0x80, 0x00,
+ 0xA0, 0x43, 0x04, 0xE0, 0x83, 0x07, 0x18, 0x68,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 0xAE, 0xE4,
+ 0x86, 0x01, 0xC2, 0x04, 0x60, 0x04, 0x2C, 0xE4,
+ 0x08, 0x02, 0x1E, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x07, 0x10, 0x20, 0x06, 0xC6, 0x06, 0xCD, 0x16,
+ 0x83, 0x07, 0x09, 0x00, 0xA0, 0x06, 0x8A, 0xDC,
+ 0x60, 0x04, 0xB0, 0xCE, 0xCE, 0x04, 0xE0, 0x04,
+ 0x2A, 0x09, 0xE0, 0xD3, 0xAA, 0xE3, 0x8F, 0xC2,
+ 0x20, 0xC8, 0xB0, 0xE4, 0x86, 0x01, 0x20, 0x48,
+ 0x08, 0xE0, 0x82, 0x01, 0x86, 0x07, 0x05, 0x00,
+ 0x84, 0x07, 0x72, 0x06, 0x54, 0xC1, 0x01, 0x13,
+ 0xD4, 0x2C, 0x24, 0x02, 0x0A, 0x00, 0x06, 0x06,
+ 0xF9, 0x16, 0x08, 0x02, 0x2A, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x20, 0x2C, 0x1A, 0xE0, 0x60, 0x04,
+ 0x50, 0xCD, 0xA0, 0x06, 0x3E, 0xD7, 0xCD, 0x04,
+ 0xA0, 0x23, 0x1C, 0xE0, 0x0D, 0x13, 0x0E, 0x01,
+ 0x03, 0x00, 0x0A, 0x13, 0xA0, 0xE3, 0x1C, 0xE0,
+ 0xB0, 0x03, 0x20, 0xD8, 0x10, 0xE0, 0x65, 0x06,
+ 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 0x08, 0x10,
+ 0x20, 0x2D, 0x01, 0x00, 0xE0, 0xC0, 0x2A, 0x09,
+ 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0xD2, 0xAB, 0xE3,
+ 0x60, 0x04, 0xD2, 0xCE, 0xA0, 0x01, 0x80, 0x01,
+ 0x00, 0x01, 0xE0, 0x01, 0x80, 0x01, 0x00, 0xAC,
+ 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 0xE0, 0x01,
+ 0x82, 0x01, 0x00, 0x08, 0x88, 0x07, 0xAE, 0x01,
+ 0x08, 0x06, 0xFE, 0x16, 0x60, 0x01, 0x8E, 0x09,
+ 0x00, 0x02, 0x03, 0x16, 0xA0, 0x01, 0x80, 0x01,
+ 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 0x80, 0x01,
+ 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 0x2E, 0x09,
+ 0xA0, 0x07, 0x9E, 0x09, 0x00, 0x10, 0x5B, 0x04,
+ 0x20, 0xD8, 0xA6, 0x09, 0x2E, 0x09, 0xE0, 0x01,
+ 0x80, 0x01, 0x00, 0x04, 0xE0, 0x01, 0x82, 0x01,
+ 0x00, 0x08, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03,
+ 0x20, 0xC2, 0x30, 0x09, 0x03, 0x13, 0xE0, 0x01,
+ 0x82, 0x01, 0x00, 0x03, 0xA0, 0x01, 0x80, 0x01,
+ 0x00, 0xA1, 0x20, 0xF8, 0x2E, 0x09, 0x80, 0x01,
+ 0x88, 0x07, 0xAE, 0x01, 0x08, 0x06, 0xFE, 0x16,
+ 0xA0, 0x01, 0x80, 0x01, 0x00, 0x0C, 0xE0, 0x04,
+ 0x9E, 0x01, 0xE0, 0x04, 0x9C, 0x09, 0xE0, 0x04,
+ 0x9E, 0x09, 0x5B, 0x04, 0x20, 0x01, 0xA8, 0x09,
+ 0x00, 0x80, 0x11, 0x13, 0xE0, 0x93, 0x26, 0xE0,
+ 0x0E, 0x16, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80,
+ 0x0A, 0x13, 0x08, 0x02, 0x84, 0x80, 0x00, 0x00,
+ 0x00, 0xE0, 0xDC, 0x0F, 0xA0, 0x06, 0xDA, 0xD4,
+ 0x20, 0x48, 0x08, 0xE0, 0x82, 0x01, 0x02, 0x10,
+ 0x60, 0x04, 0x70, 0xDA, 0x60, 0x04, 0xBA, 0xCE,
+ 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x19, 0x13,
+ 0x83, 0x07, 0x80, 0x80, 0xE0, 0x23, 0x14, 0xE0,
+ 0x02, 0x13, 0x83, 0x07, 0x0A, 0x00, 0x60, 0x04,
+ 0xC6, 0xCE, 0x20, 0xC1, 0x06, 0x06, 0x0D, 0x13,
+ 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x09, 0x13,
+ 0x83, 0x07, 0x0B, 0x00, 0xE0, 0x23, 0x14, 0xE0,
+ 0x02, 0x16, 0x83, 0x07, 0x01, 0x80, 0x60, 0x04,
+ 0xC6, 0xCE, 0x83, 0x07, 0x0A, 0x80, 0x60, 0x04,
+ 0xB4, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80,
+ 0x06, 0x16, 0xA0, 0x06, 0xA8, 0xE5, 0x47, 0x10,
+ 0xD0, 0x03, 0x60, 0x04, 0xB0, 0xD3, 0xE0, 0x93,
+ 0x0E, 0xE0, 0x5E, 0x13, 0xE0, 0x93, 0x10, 0xE0,
+ 0x17, 0x13, 0xE0, 0x23, 0x14, 0xE0, 0x04, 0x13,
+ 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 0xC6, 0xCE,
+ 0x83, 0x07, 0x00, 0xA0, 0xA0, 0x06, 0x2A, 0xD8,
+ 0x83, 0x07, 0x00, 0x48, 0xA0, 0x06, 0x2A, 0xD8,
+ 0xA0, 0xD2, 0x10, 0xE0, 0x20, 0xC8, 0x1C, 0xE0,
+ 0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06,
+ 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 0x4E, 0x80,
+ 0xA0, 0x06, 0xDA, 0xD4, 0xA0, 0x23, 0x1C, 0xE0,
+ 0x20, 0x13, 0x20, 0x88, 0x6C, 0x09, 0x0E, 0x07,
+ 0x1C, 0x16, 0x20, 0x88, 0x6E, 0x09, 0x10, 0x07,
+ 0x18, 0x16, 0x20, 0x88, 0x70, 0x09, 0x12, 0x07,
+ 0x14, 0x16, 0x20, 0x88, 0x0A, 0x07, 0x22, 0xE0,
+ 0x10, 0x13, 0x20, 0x06, 0xCA, 0x06, 0x38, 0x16,
+ 0xA0, 0xE3, 0x20, 0xE0, 0x06, 0x10, 0xE0, 0x23,
+ 0x14, 0xE0, 0xCA, 0x16, 0xA0, 0xE3, 0x22, 0xE0,
+ 0xC2, 0x04, 0xA0, 0xD2, 0xAA, 0xE3, 0x60, 0x04,
+ 0xBA, 0xCE, 0x20, 0xC8, 0x1C, 0xE0, 0xCA, 0x06,
+ 0xA0, 0x88, 0xDC, 0x06, 0x0E, 0x00, 0x10, 0x16,
+ 0xA0, 0x88, 0xDE, 0x06, 0x10, 0x00, 0x0C, 0x16,
+ 0xA0, 0x88, 0xE0, 0x06, 0x12, 0x00, 0x08, 0x16,
+ 0x20, 0x06, 0xCC, 0x06, 0x19, 0x16, 0x20, 0xE8,
+ 0x0E, 0xE0, 0x82, 0x01, 0xA0, 0xE3, 0x1E, 0xE0,
+ 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 0x10, 0x10,
+ 0xA0, 0x23, 0x10, 0xE0, 0x08, 0x16, 0x64, 0xC1,
+ 0x06, 0x00, 0x60, 0x21, 0x0C, 0xE0, 0x08, 0x13,
+ 0xA0, 0xD2, 0xA8, 0xE3, 0x05, 0x10, 0x20, 0x88,
+ 0x0A, 0x07, 0x08, 0x07, 0x96, 0x12, 0x00, 0x10,
+ 0x60, 0x04, 0xBA, 0xCE, 0x60, 0x01, 0x8E, 0x09,
+ 0x00, 0x80, 0x06, 0x16, 0x83, 0x07, 0x00, 0x82,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE,
+ 0xE0, 0x93, 0x0E, 0xE0, 0x50, 0x13, 0xE0, 0x93,
+ 0xA9, 0xE3, 0x4D, 0x13, 0xE0, 0x93, 0xA8, 0xE3,
+ 0x1C, 0x13, 0xA0, 0x06, 0xA4, 0xD7, 0xA0, 0x23,
+ 0x10, 0xE0, 0x45, 0x13, 0xA0, 0x23, 0x08, 0xE0,
+ 0x06, 0x16, 0x60, 0xE3, 0x1E, 0xE0, 0x20, 0xC8,
+ 0x22, 0xE0, 0x06, 0x07, 0x34, 0x10, 0xE0, 0x23,
+ 0x14, 0xE0, 0x31, 0x16, 0x60, 0xC1, 0x6A, 0x09,
+ 0x60, 0x21, 0x12, 0xE0, 0x2C, 0x16, 0xA0, 0x06,
+ 0x0E, 0xE2, 0x31, 0x10, 0xA0, 0xD2, 0xA8, 0xE3,
+ 0x2E, 0x10, 0xA0, 0xE3, 0x12, 0xE0, 0xA0, 0x06,
+ 0x0E, 0xE2, 0x64, 0xC1, 0x06, 0x00, 0x60, 0x21,
+ 0x0C, 0xE0, 0x25, 0x13, 0x20, 0x88, 0x0E, 0x07,
+ 0xDC, 0x06, 0x14, 0x16, 0x20, 0x88, 0x10, 0x07,
+ 0xDE, 0x06, 0x10, 0x16, 0x20, 0x88, 0x12, 0x07,
+ 0xE0, 0x06, 0x0C, 0x16, 0x20, 0x98, 0xCE, 0x06,
+ 0xCF, 0x06, 0x15, 0x13, 0x20, 0x06, 0xCE, 0x06,
+ 0x12, 0x16, 0x60, 0xE3, 0x1A, 0xE0, 0xA0, 0xD2,
+ 0x0C, 0xE0, 0x0D, 0x10, 0x60, 0xE3, 0x1E, 0xE0,
+ 0x20, 0xC8, 0x32, 0xE0, 0x06, 0x07, 0xA0, 0x06,
+ 0x3E, 0xD7, 0x08, 0x02, 0x48, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0xA0, 0xD2, 0xA9, 0xE3, 0x60, 0x04,
+ 0xBA, 0xCE, 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09,
+ 0xC9, 0x1A, 0x0B, 0x1B, 0x22, 0x88, 0x10, 0x00,
+ 0x6E, 0x09, 0xC4, 0x1A, 0x06, 0x1B, 0x22, 0x88,
+ 0x12, 0x00, 0x70, 0x09, 0xBF, 0x1A, 0x01, 0x1B,
+ 0x5B, 0x04, 0x60, 0xC1, 0x6C, 0x01, 0x85, 0x02,
+ 0x43, 0x00, 0xE1, 0x13, 0xE0, 0x93, 0xA8, 0xE3,
+ 0xDE, 0x16, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00,
+ 0x84, 0x07, 0x0E, 0x00, 0x42, 0xC1, 0xA0, 0xC0,
+ 0x6C, 0x01, 0x02, 0xC0, 0x25, 0x02, 0x48, 0x00,
+ 0x81, 0x07, 0x60, 0xE2, 0x83, 0x07, 0x14, 0xAE,
+ 0x60, 0x04, 0x9E, 0xE5, 0x02, 0x02, 0x00, 0xFC,
+ 0xCA, 0x10, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80,
+ 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 0xA0, 0x06,
+ 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 0x20, 0x98,
+ 0x0E, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8,
+ 0xA8, 0xE3, 0x65, 0x06, 0xE0, 0x93, 0xA9, 0xE3,
+ 0x0D, 0x13, 0xA0, 0x23, 0x08, 0xE0, 0x19, 0x16,
+ 0xA0, 0x23, 0x10, 0xE0, 0x16, 0x13, 0x60, 0xE3,
+ 0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07,
+ 0xA0, 0x06, 0x3E, 0xD7, 0xA0, 0x43, 0x18, 0xE0,
+ 0xE0, 0x2E, 0x01, 0x00, 0xA0, 0xD2, 0x26, 0xE0,
+ 0x83, 0x07, 0x10, 0x00, 0xA0, 0x06, 0x2A, 0xD8,
+ 0xE0, 0x23, 0x14, 0xE0, 0x02, 0x16, 0xA0, 0x06,
+ 0x18, 0xD7, 0xA0, 0x43, 0x2C, 0xE0, 0x20, 0xC8,
+ 0x20, 0xE0, 0x24, 0x09, 0x60, 0x04, 0xBA, 0xCE,
+ 0xA0, 0x06, 0xA8, 0xE5, 0x01, 0x10, 0x03, 0x10,
+ 0x20, 0x07, 0xA0, 0x09, 0x03, 0x10, 0xA0, 0x07,
+ 0xA2, 0x09, 0x19, 0x00, 0x60, 0x04, 0xBA, 0xCE,
+ 0xA0, 0x43, 0x0E, 0xE0, 0xA0, 0xC1, 0x24, 0x09,
+ 0x02, 0x13, 0x20, 0x06, 0x24, 0x09, 0xE0, 0x23,
+ 0x14, 0xE0, 0x03, 0x13, 0xA0, 0x23, 0x08, 0xE0,
+ 0x29, 0x16, 0x20, 0xC2, 0x8A, 0x09, 0xE4, 0x11,
+ 0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4,
+ 0xA0, 0x23, 0x08, 0xE0, 0x1F, 0x16, 0xA0, 0x23,
+ 0x10, 0xE0, 0x0A, 0x16, 0x22, 0xC1, 0x02, 0x00,
+ 0x20, 0x25, 0xA8, 0xE4, 0x23, 0x16, 0x83, 0x07,
+ 0x20, 0x80, 0xA0, 0x06, 0x2A, 0xD8, 0x12, 0x10,
+ 0xA0, 0x06, 0x3E, 0xD7, 0xE0, 0x23, 0x14, 0xE0,
+ 0x02, 0x16, 0xA0, 0x06, 0x18, 0xD7, 0x60, 0xE3,
+ 0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07,
+ 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x16, 0xA0, 0x23,
+ 0x06, 0xE0, 0x51, 0x13, 0x20, 0x98, 0x0E, 0xE0,
+ 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 0xA8, 0xE3,
+ 0x65, 0x06, 0x22, 0xC1, 0x02, 0x00, 0x20, 0x25,
+ 0xA8, 0xE4, 0x0E, 0x13, 0x83, 0x07, 0x20, 0x00,
+ 0xA0, 0x06, 0x2A, 0xD8, 0x22, 0xC8, 0x0E, 0x00,
+ 0xE6, 0x06, 0x22, 0xC8, 0x10, 0x00, 0xE8, 0x06,
+ 0x22, 0xC8, 0x12, 0x00, 0xEA, 0x06, 0x37, 0x10,
+ 0x22, 0x88, 0x0E, 0x00, 0xDC, 0x06, 0x08, 0x16,
+ 0x22, 0x88, 0x10, 0x00, 0xDE, 0x06, 0x04, 0x16,
+ 0x22, 0x88, 0x12, 0x00, 0xE0, 0x06, 0x0B, 0x13,
+ 0x22, 0xC8, 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8,
+ 0x10, 0x00, 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00,
+ 0xE0, 0x06, 0x60, 0xE3, 0x14, 0xE0, 0xA0, 0x23,
+ 0x0E, 0xE0, 0x08, 0x16, 0xA0, 0xC1, 0x24, 0x09,
+ 0x1A, 0x16, 0x86, 0x07, 0x00, 0x10, 0x06, 0xE8,
+ 0xD2, 0x06, 0x15, 0x10, 0xA0, 0xE3, 0x0E, 0xE0,
+ 0xA0, 0x23, 0x08, 0xE0, 0x09, 0x16, 0xA0, 0xE3,
+ 0x06, 0xE0, 0xE0, 0x04, 0xE6, 0x06, 0xE0, 0x04,
+ 0xE8, 0x06, 0xE0, 0x04, 0xEA, 0x06, 0x07, 0x10,
+ 0x08, 0x02, 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06,
+ 0x36, 0xD3, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04,
+ 0xBA, 0xCE, 0x20, 0x98, 0x65, 0x06, 0x10, 0xE0,
+ 0x03, 0x16, 0x20, 0xD8, 0x0E, 0xE0, 0x65, 0x06,
+ 0x60, 0x04, 0xBA, 0xCE, 0xE0, 0x23, 0x14, 0xE0,
+ 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 0x2E, 0x10,
+ 0xB0, 0x03, 0x20, 0x98, 0xA9, 0xE3, 0x6F, 0x06,
+ 0x19, 0x16, 0x24, 0xC2, 0x08, 0x00, 0x16, 0x11,
+ 0xE0, 0xE3, 0x14, 0xE0, 0x83, 0x07, 0x00, 0x00,
+ 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x23, 0x14, 0xE0,
+ 0x04, 0x13, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06,
+ 0xDA, 0xD4, 0x08, 0x02, 0x1E, 0x00, 0xA0, 0x06,
+ 0xDA, 0xD4, 0xA0, 0x23, 0x08, 0xE0, 0x02, 0x13,
+ 0xA0, 0x06, 0x18, 0xD7, 0x82, 0xC0, 0x02, 0x16,
+ 0x60, 0x04, 0xD2, 0xCE, 0x20, 0xE8, 0x1C, 0xEE,
+ 0xF0, 0x06, 0x20, 0x99, 0x0E, 0xE0, 0x16, 0x00,
+ 0x05, 0x16, 0xE0, 0x04, 0xEC, 0x06, 0x20, 0x48,
+ 0x14, 0xE0, 0xF0, 0x06, 0x83, 0x07, 0x01, 0x00,
+ 0x60, 0x04, 0xB4, 0xCE, 0x64, 0xC2, 0x14, 0x00,
+ 0x24, 0x02, 0x18, 0x00, 0xC4, 0xC1, 0xC2, 0x61,
+ 0x27, 0x02, 0xFC, 0xFF, 0x74, 0xC1, 0x85, 0xC1,
+ 0x45, 0x71, 0x85, 0x02, 0x27, 0x00, 0x46, 0x16,
+ 0x54, 0xC1, 0x45, 0x02, 0xCF, 0xFF, 0x42, 0x16,
+ 0xC8, 0x04, 0x64, 0xC1, 0x08, 0x00, 0x06, 0x15,
+ 0x05, 0x13, 0x24, 0xC2, 0x0E, 0x00, 0x48, 0x02,
+ 0x00, 0x1F, 0xC8, 0x06, 0x28, 0x02, 0x11, 0x00,
+ 0x04, 0xA2, 0x18, 0x98, 0x21, 0xEE, 0x32, 0x16,
+ 0x42, 0xC1, 0x25, 0x02, 0x04, 0x00, 0x47, 0x65,
+ 0x35, 0xC2, 0x74, 0xCD, 0x48, 0x06, 0xFD, 0x15,
+ 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC1, 0x04, 0xC8,
+ 0x6C, 0x01, 0xA0, 0xC1, 0x00, 0xFC, 0x05, 0x13,
+ 0x20, 0xC8, 0x80, 0xEB, 0x02, 0xFC, 0x06, 0xC1,
+ 0xF6, 0x10, 0x20, 0xC8, 0x00, 0xEE, 0x02, 0xFC,
+ 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x07, 0x08, 0xE5,
+ 0x04, 0xC0, 0x83, 0x07, 0x10, 0x02, 0x84, 0x07,
+ 0x0E, 0x00, 0x3B, 0x10, 0x84, 0x07, 0x0C, 0x00,
+ 0xE2, 0xC0, 0x08, 0x00, 0x05, 0x02, 0x00, 0xFC,
+ 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x95, 0xC1,
+ 0x30, 0x13, 0xD5, 0x04, 0x16, 0x2E, 0x02, 0xC8,
+ 0x6C, 0x01, 0x2B, 0x10, 0xA0, 0xC8, 0x22, 0xEE,
+ 0x0E, 0x00, 0xA0, 0xC8, 0x24, 0xEE, 0x10, 0x00,
+ 0xA0, 0xC8, 0x26, 0xEE, 0x12, 0x00, 0x83, 0x07,
+ 0x06, 0x80, 0x60, 0x04, 0xB4, 0xCE, 0x60, 0x04,
+ 0xD2, 0xCE, 0x84, 0x07, 0x10, 0x00, 0x85, 0x07,
+ 0x34, 0x00, 0x09, 0x10, 0x84, 0x07, 0x12, 0x00,
+ 0x85, 0x07, 0x32, 0x00, 0x04, 0x10, 0x84, 0x07,
+ 0x14, 0x00, 0x85, 0x07, 0x38, 0x00, 0xA0, 0x06,
+ 0xC2, 0xD5, 0x85, 0xC8, 0x04, 0x00, 0xA0, 0x06,
+ 0x10, 0xD6, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00,
+ 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x48, 0x06,
+ 0x48, 0xC1, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02,
+ 0xA2, 0x06, 0x60, 0xC5, 0x02, 0xFC, 0x25, 0x02,
+ 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 0x20, 0xC2,
+ 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 0x60, 0x04,
+ 0xB0, 0xCE, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02,
+ 0xB4, 0x06, 0xEF, 0x10, 0x22, 0x88, 0x12, 0x00,
+ 0x70, 0x09, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00,
+ 0x6E, 0x09, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00,
+ 0x6C, 0x09, 0x0E, 0x13, 0x22, 0x88, 0x12, 0x00,
+ 0xE0, 0x06, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00,
+ 0xDE, 0x06, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00,
+ 0xDC, 0x06, 0x01, 0x13, 0xCB, 0x05, 0xCB, 0x05,
+ 0x5B, 0x04, 0x0B, 0xC3, 0x00, 0x03, 0x02, 0x00,
+ 0x82, 0x07, 0xC0, 0x00, 0x20, 0xC8, 0x0C, 0x00,
+ 0xC0, 0x00, 0x20, 0xC8, 0x0E, 0x00, 0xC2, 0x00,
+ 0x20, 0xC8, 0x10, 0x00, 0xC4, 0x00, 0x20, 0xC8,
+ 0x12, 0x00, 0xC6, 0x00, 0x20, 0xC8, 0x14, 0x00,
+ 0xC8, 0x00, 0x20, 0xC8, 0x16, 0x00, 0xCA, 0x00,
+ 0x20, 0xC8, 0x04, 0x00, 0xCC, 0x00, 0x20, 0xC8,
+ 0x06, 0x00, 0xCE, 0x00, 0x02, 0xC8, 0x0C, 0x00,
+ 0xA0, 0x07, 0x0E, 0x00, 0x7E, 0xE6, 0x02, 0xC8,
+ 0x10, 0x00, 0xA0, 0x07, 0x12, 0x00, 0x88, 0xE6,
+ 0x02, 0xC8, 0x14, 0x00, 0xA0, 0x07, 0x16, 0x00,
+ 0xB8, 0xE6, 0x02, 0xC8, 0x04, 0x00, 0xA0, 0x07,
+ 0x06, 0x00, 0xCE, 0xE6, 0x60, 0x01, 0x1C, 0x01,
+ 0x04, 0x00, 0x09, 0x16, 0xE0, 0x01, 0x40, 0x01,
+ 0x00, 0x08, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40,
+ 0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xA0, 0x06,
+ 0x8E, 0xE9, 0x05, 0x02, 0x00, 0x80, 0x05, 0xD8,
+ 0x80, 0x04, 0xC7, 0x04, 0x00, 0x03, 0x0F, 0x00,
+ 0x88, 0x07, 0x00, 0x10, 0x09, 0x02, 0x00, 0x20,
+ 0x8A, 0x07, 0xE6, 0xE6, 0x03, 0x02, 0x3E, 0xE6,
+ 0x5A, 0x04, 0x00, 0x03, 0x00, 0x00, 0x20, 0xD2,
+ 0x87, 0x01, 0x06, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x20, 0xC2, 0x8A, 0x01, 0x08, 0x02, 0x00, 0x1A,
+ 0x60, 0xC2, 0xAE, 0x00, 0x48, 0xDA, 0x80, 0x04,
+ 0x89, 0x05, 0x89, 0x02, 0x06, 0x00, 0x07, 0x15,
+ 0x88, 0x07, 0x00, 0x80, 0x48, 0xDA, 0x80, 0x04,
+ 0x09, 0xC8, 0xAE, 0x00, 0x80, 0x03, 0xE0, 0x02,
+ 0xA0, 0x00, 0x5C, 0x04, 0x00, 0x03, 0x00, 0x00,
+ 0x60, 0x01, 0x9C, 0x01, 0x20, 0x00, 0xE2, 0x13,
+ 0x20, 0xC2, 0x8C, 0x01, 0x08, 0x02, 0x00, 0x1C,
+ 0xE3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x60, 0x01,
+ 0x40, 0x01, 0x00, 0x40, 0xEC, 0x16, 0xA0, 0x01,
+ 0x40, 0x01, 0x00, 0x40, 0x08, 0x02, 0x00, 0x02,
+ 0xD7, 0x10, 0xB3, 0xC0, 0x92, 0x06, 0xFD, 0x10,
+ 0xB3, 0xC0, 0x48, 0xC0, 0x72, 0xCC, 0x72, 0xCC,
+ 0x32, 0xC1, 0x44, 0xCC, 0x72, 0xDC, 0x04, 0x06,
+ 0xFD, 0x16, 0x5B, 0x04, 0x48, 0xC0, 0x02, 0x02,
+ 0xD0, 0xE9, 0x84, 0x07, 0x06, 0x00, 0xF6, 0x10,
+ 0x02, 0x02, 0x1E, 0xE6, 0x49, 0xC0, 0x84, 0x07,
+ 0x06, 0x00, 0xF0, 0x10, 0xB3, 0xC0, 0x32, 0xC1,
+ 0x01, 0x02, 0x01, 0x00, 0x44, 0xD0, 0xC1, 0x06,
+ 0x44, 0x02, 0xFF, 0x00, 0xE7, 0x10, 0x33, 0xC1,
+ 0x73, 0xC0, 0x44, 0xD1, 0x44, 0x02, 0xFF, 0x00,
+ 0x45, 0xDC, 0x04, 0x06, 0xFD, 0x16, 0x5A, 0x04,
+ 0xA0, 0x06, 0x0E, 0xE9, 0x33, 0xC8, 0x9E, 0x01,
+ 0x5A, 0x04, 0xA0, 0x06, 0x0C, 0xE7, 0x89, 0xC1,
+ 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8,
+ 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 0x66, 0x02,
+ 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 0xC2, 0x04,
+ 0xC7, 0xC1, 0x03, 0x16, 0x02, 0x06, 0xFC, 0x16,
+ 0x4D, 0x10, 0x5A, 0x04, 0xA0, 0x06, 0x58, 0xE8,
+ 0x89, 0xC1, 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00,
+ 0x06, 0xC8, 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09,
+ 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01,
+ 0x33, 0xC8, 0x9E, 0x01, 0xE8, 0x10, 0x33, 0x8A,
+ 0x02, 0x00, 0x38, 0x16, 0x73, 0x8A, 0x02, 0x00,
+ 0x35, 0x16, 0x5A, 0x04, 0x20, 0x8A, 0xCA, 0xE9,
+ 0x02, 0x00, 0x30, 0x16, 0x60, 0x8A, 0xCE, 0xE9,
+ 0x02, 0x00, 0x2C, 0x16, 0x82, 0x07, 0x74, 0xEA,
+ 0x01, 0x10, 0xB3, 0xC0, 0x04, 0x02, 0x80, 0x04,
+ 0x52, 0xD1, 0x03, 0x13, 0x32, 0x9D, 0x22, 0x16,
+ 0xFB, 0x10, 0x85, 0x07, 0x00, 0x80, 0x05, 0xD8,
+ 0x80, 0x04, 0xC7, 0x04, 0x5A, 0x04, 0x20, 0xC8,
+ 0xC0, 0x00, 0x0C, 0x00, 0x20, 0xC8, 0xC2, 0x00,
+ 0x0E, 0x00, 0x20, 0xC8, 0xC4, 0x00, 0x10, 0x00,
+ 0x20, 0xC8, 0xC6, 0x00, 0x12, 0x00, 0x20, 0xC8,
+ 0xC8, 0x00, 0x14, 0x00, 0x20, 0xC8, 0xCA, 0x00,
+ 0x16, 0x00, 0x20, 0xC8, 0xCC, 0x00, 0x04, 0x00,
+ 0x20, 0xC8, 0xCE, 0x00, 0x06, 0x00, 0x00, 0x03,
+ 0x0F, 0x00, 0xCC, 0x05, 0x5C, 0x04, 0xE0, 0x04,
+ 0x82, 0x01, 0x02, 0x02, 0x18, 0xE6, 0x32, 0xC8,
+ 0x82, 0x01, 0x32, 0xC8, 0x80, 0x01, 0xA0, 0x06,
+ 0x24, 0xE8, 0x12, 0xC8, 0x82, 0x01, 0xCA, 0xC2,
+ 0x84, 0x07, 0xD0, 0x07, 0xE0, 0x04, 0x84, 0x01,
+ 0x04, 0x06, 0xFC, 0x16, 0x20, 0xC1, 0x84, 0x01,
+ 0xE9, 0x16, 0x04, 0x02, 0x32, 0x00, 0x85, 0x07,
+ 0x00, 0x80, 0x05, 0xD8, 0x80, 0x04, 0xC7, 0x04,
+ 0x60, 0xC1, 0x86, 0x01, 0x04, 0x06, 0xFC, 0x16,
+ 0x20, 0xC1, 0x84, 0x01, 0x5B, 0x04, 0xB3, 0xC0,
+ 0xB3, 0xC4, 0x5B, 0x04, 0x48, 0xC0, 0xB3, 0xC0,
+ 0x73, 0xA0, 0x42, 0xC4, 0x5B, 0x04, 0x33, 0x88,
+ 0x84, 0x01, 0xE6, 0x16, 0x5A, 0x04, 0x89, 0xC1,
+ 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8,
+ 0x8A, 0x01, 0x5B, 0x04, 0xC5, 0x04, 0xA0, 0x07,
+ 0x9C, 0x01, 0x40, 0x00, 0x60, 0x01, 0x9C, 0x01,
+ 0x40, 0x00, 0x03, 0x13, 0x05, 0x06, 0xF7, 0x16,
+ 0x5C, 0x04, 0x5B, 0x04, 0xA0, 0x06, 0xAC, 0xE8,
+ 0x60, 0xC0, 0x40, 0x01, 0x05, 0xC8, 0x40, 0x01,
+ 0x02, 0xC5, 0x01, 0xC8, 0x40, 0x01, 0x5A, 0x04,
+ 0xA0, 0x06, 0xAC, 0xE8, 0x08, 0xA1, 0xF4, 0x10,
+ 0xB3, 0xC0, 0x33, 0xC1, 0x60, 0xC1, 0x40, 0x01,
+ 0x85, 0x01, 0x00, 0x04, 0xC5, 0x01, 0x00, 0x10,
+ 0x5B, 0x04, 0x08, 0xC1, 0x09, 0xC2, 0x44, 0xC2,
+ 0x5B, 0x04, 0x05, 0x02, 0xC8, 0x00, 0x05, 0x06,
+ 0xFE, 0x16, 0x5B, 0x04, 0x33, 0xC1, 0x03, 0xC0,
+ 0xC4, 0xC0, 0x5B, 0x04, 0xC0, 0xC0, 0x5B, 0x04,
+ 0xE0, 0x94, 0x9E, 0x01, 0xC2, 0x16, 0xC3, 0x05,
+ 0x5B, 0x04, 0x73, 0xC0, 0xA0, 0x06, 0x26, 0xE9,
+ 0x2D, 0x02, 0x08, 0x00, 0x85, 0x07, 0x08, 0x00,
+ 0x71, 0x9F, 0xB7, 0x16, 0x05, 0x06, 0xFC, 0x16,
+ 0x5A, 0x04, 0x02, 0x02, 0x24, 0xE6, 0x60, 0x04,
+ 0x10, 0xE7, 0xE9, 0x8C, 0x04, 0x00, 0xAD, 0x16,
+ 0x5B, 0x04, 0x20, 0xC1, 0x80, 0x01, 0x85, 0x07,
+ 0xD0, 0x07, 0xE0, 0x01, 0x80, 0x01, 0x00, 0x04,
+ 0x45, 0x06, 0xFE, 0x16, 0x04, 0xC8, 0x80, 0x01,
+ 0x5B, 0x04, 0x33, 0xC1, 0x48, 0xC3, 0x04, 0xC1,
+ 0x04, 0x13, 0x2D, 0x02, 0x00, 0x04, 0x04, 0x06,
+ 0xFC, 0x16, 0x5B, 0x04, 0x8D, 0xC3, 0xA0, 0x06,
+ 0x26, 0xE9, 0x8D, 0xC1, 0xA6, 0x09, 0x66, 0x02,
+ 0x40, 0x00, 0x86, 0xC7, 0x5A, 0x04, 0x8D, 0xC1,
+ 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8,
+ 0x8A, 0x01, 0x5B, 0x04, 0x8D, 0xC1, 0xA6, 0x09,
+ 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01,
+ 0x5B, 0x04, 0x4D, 0xC0, 0x04, 0x02, 0x28, 0x00,
+ 0x85, 0x07, 0x00, 0x55, 0x60, 0x04, 0x34, 0xE7,
+ 0x4D, 0xC0, 0xB3, 0xC0, 0x32, 0xC1, 0x60, 0x04,
+ 0xF8, 0xE6, 0x33, 0xC1, 0x60, 0x01, 0x1C, 0x01,
+ 0x04, 0x00, 0x01, 0x16, 0x5B, 0x04, 0xC4, 0xC0,
+ 0x5B, 0x04, 0x89, 0x07, 0x66, 0xE5, 0x39, 0xC2,
+ 0x07, 0x13, 0x39, 0xC6, 0x39, 0x86, 0x25, 0x16,
+ 0x39, 0xC6, 0x39, 0x86, 0x22, 0x16, 0xF7, 0x10,
+ 0x02, 0x02, 0xAC, 0xE9, 0xC4, 0x04, 0xC5, 0x04,
+ 0x39, 0xC2, 0x02, 0x13, 0x60, 0x04, 0xE8, 0xE9,
+ 0x02, 0x02, 0xBA, 0xE9, 0xC4, 0x04, 0x39, 0xC2,
+ 0x03, 0x13, 0x79, 0xC1, 0x60, 0x04, 0xE8, 0xE9,
+ 0x02, 0x02, 0xCA, 0xE9, 0xC5, 0x04, 0x39, 0xC2,
+ 0x03, 0x13, 0x39, 0xC1, 0x60, 0x04, 0xE8, 0xE9,
+ 0x79, 0xC0, 0xB9, 0xC0, 0x81, 0x60, 0xC2, 0x05,
+ 0x12, 0x09, 0xF1, 0x04, 0x02, 0x06, 0xFD, 0x16,
+ 0x5B, 0x04, 0x5C, 0x04, 0x01, 0x02, 0xAA, 0xAA,
+ 0x01, 0xC6, 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80,
+ 0xF8, 0x16, 0x01, 0x02, 0x14, 0x00, 0x01, 0x06,
+ 0xFE, 0x16, 0x01, 0x02, 0x55, 0x55, 0x01, 0xC6,
+ 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 0xED, 0x16,
+ 0x52, 0x04, 0xE0, 0x02, 0xA0, 0x00, 0x88, 0x07,
+ 0xC0, 0x00, 0x09, 0x02, 0x62, 0xEA, 0x84, 0x07,
+ 0x2A, 0xE6, 0x05, 0x02, 0x01, 0x00, 0x8B, 0xC2,
+ 0xCC, 0x04, 0xA0, 0x06, 0x6C, 0xEA, 0x60, 0x2C,
+ 0x01, 0x00, 0x99, 0x06, 0xA0, 0x2C, 0x02, 0x00,
+ 0x99, 0x06, 0x20, 0x2D, 0x04, 0x00, 0x99, 0x06,
+ 0x20, 0x2E, 0x08, 0x00, 0x99, 0x06, 0xA0, 0x2F,
+ 0x10, 0x00, 0x8C, 0x05, 0x09, 0x16, 0x80, 0xCC,
+ 0x81, 0xC4, 0x83, 0x07, 0xB0, 0xEA, 0x88, 0xC0,
+ 0x02, 0x04, 0x8C, 0x05, 0x01, 0x16, 0x33, 0x10,
+ 0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x8C, 0x05,
+ 0xFB, 0x16, 0x80, 0xCC, 0x81, 0xC4, 0x15, 0x0A,
+ 0xB4, 0xC0, 0x12, 0xC0, 0x88, 0xCC, 0x52, 0xC0,
+ 0xB4, 0xC4, 0x42, 0x06, 0x5B, 0x04, 0x2D, 0x07,
+ 0x18, 0x00, 0x41, 0x8B, 0x0A, 0x00, 0xEC, 0x16,
+ 0xC1, 0x82, 0xEA, 0x16, 0xC2, 0x02, 0x42, 0x02,
+ 0x00, 0x02, 0xE6, 0x16, 0x80, 0x03, 0x81, 0x07,
+ 0x01, 0x00, 0xF1, 0x10, 0x01, 0x02, 0x02, 0x00,
+ 0xEE, 0x10, 0x01, 0x02, 0x04, 0x00, 0xEB, 0x10,
+ 0x01, 0x02, 0x08, 0x00, 0xE8, 0x10, 0x01, 0x02,
+ 0x10, 0x00, 0xE5, 0x10, 0xA1, 0x02, 0x41, 0x8B,
+ 0x10, 0x00, 0x02, 0x13, 0x60, 0x04, 0x5C, 0xEA,
+ 0x2D, 0x07, 0x18, 0x00, 0x80, 0x03, 0x09, 0x02,
+ 0x00, 0x08, 0x03, 0x02, 0x04, 0x00, 0xC7, 0x04,
+ 0xA0, 0x06, 0xDC, 0xEB, 0x60, 0x01, 0x1C, 0x01,
+ 0x04, 0x00, 0x1C, 0x16, 0xA0, 0x01, 0x40, 0x01,
+ 0x00, 0x08, 0xE0, 0x01, 0x40, 0x01, 0x00, 0x10,
+ 0x04, 0x02, 0x01, 0x00, 0x44, 0xCE, 0xC4, 0x06,
+ 0x44, 0xC6, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x10,
+ 0x49, 0x06, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40,
+ 0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xE0, 0x01,
+ 0x40, 0x01, 0x00, 0x08, 0xA0, 0x06, 0x7A, 0xEC,
+ 0xA0, 0x06, 0x7A, 0xEC, 0xC7, 0x05, 0x04, 0x02,
+ 0xE4, 0xE4, 0xE0, 0x04, 0xD0, 0x03, 0x74, 0xC1,
+ 0xB4, 0xC1, 0x86, 0x05, 0x1C, 0x13, 0xE0, 0x02,
+ 0xC0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xC0,
+ 0x80, 0xC0, 0xC0, 0xC0, 0x00, 0xC1, 0x40, 0xC1,
+ 0x80, 0xC1, 0xC0, 0xC1, 0x00, 0xC2, 0x40, 0xC2,
+ 0x80, 0xC2, 0xC0, 0xC2, 0x00, 0xC3, 0x40, 0xC3,
+ 0x80, 0xC3, 0xC0, 0xC3, 0xA0, 0x04, 0xAA, 0x00,
+ 0xD0, 0x03, 0xD0, 0x03, 0x3F, 0x10, 0x85, 0x05,
+ 0x85, 0x81, 0xE1, 0x13, 0xE4, 0x10, 0xC7, 0x05,
+ 0x05, 0x02, 0xFF, 0x7F, 0x45, 0xA1, 0xD0, 0x03,
+ 0xD0, 0x03, 0x34, 0x10, 0xC0, 0xCC, 0xC1, 0xC4,
+ 0x03, 0x02, 0x28, 0x00, 0xA0, 0x06, 0xDC, 0xEB,
+ 0xE0, 0x01, 0x42, 0x01, 0x00, 0x10, 0xC7, 0x05,
+ 0xD0, 0x03, 0xD0, 0x03, 0x27, 0x10, 0xC7, 0x05,
+ 0xA0, 0xC1, 0x4A, 0x01, 0xA0, 0x07, 0x4A, 0x01,
+ 0x00, 0x0E, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x02,
+ 0x20, 0x07, 0x44, 0x01, 0x60, 0xC1, 0x44, 0x01,
+ 0x85, 0x02, 0x00, 0xFF, 0x17, 0x16, 0xE0, 0x01,
+ 0x40, 0x01, 0x00, 0x22, 0x05, 0x02, 0xC0, 0x00,
+ 0x05, 0x06, 0xD0, 0x03, 0xFD, 0x16, 0x60, 0xC1,
+ 0x46, 0x01, 0x85, 0x02, 0x00, 0xFF, 0x0A, 0x13,
+ 0x05, 0x02, 0x93, 0x33, 0x05, 0x06, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
+ 0xD0, 0x03, 0xF8, 0x16, 0x51, 0x10, 0x06, 0xC8,
+ 0x4A, 0x01, 0xC0, 0xCC, 0xC1, 0xC4, 0x4B, 0x10,
+ 0x13, 0xC0, 0xC8, 0xCC, 0x53, 0xC0, 0x02, 0x02,
+ 0xEC, 0xEB, 0xC2, 0xC4, 0x43, 0x06, 0x5B, 0x04,
+ 0x60, 0xC0, 0xAE, 0x00, 0xC4, 0x02, 0x44, 0x02,
+ 0x0F, 0x00, 0x44, 0x88, 0xCA, 0xE4, 0x3C, 0x16,
+ 0x81, 0x02, 0x08, 0x00, 0x27, 0x13, 0x21, 0xC1,
+ 0xDC, 0xE4, 0x14, 0xC1, 0x21, 0x21, 0xBA, 0xE4,
+ 0x33, 0x16, 0x21, 0xC1, 0xC2, 0xE4, 0x81, 0x02,
+ 0x00, 0x00, 0x0B, 0x13, 0x0D, 0x02, 0xA0, 0x00,
+ 0x84, 0x83, 0x09, 0x13, 0xC4, 0x05, 0x84, 0x83,
+ 0x06, 0x13, 0xC4, 0x05, 0x84, 0x83, 0x03, 0x13,
+ 0x23, 0x10, 0x0E, 0x81, 0x21, 0x16, 0x21, 0xC1,
+ 0xDC, 0xE4, 0x21, 0x45, 0xBA, 0xE4, 0xE0, 0x01,
+ 0x42, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01,
+ 0x00, 0x10, 0xA1, 0xC3, 0xD4, 0xE4, 0x0F, 0x02,
+ 0x2F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x40, 0x01,
+ 0x00, 0x02, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80,
+ 0x6D, 0xC0, 0x0A, 0x00, 0x09, 0x13, 0x81, 0x02,
+ 0x5C, 0x12, 0x06, 0x1B, 0x0E, 0x02, 0xD2, 0xEB,
+ 0x0F, 0x02, 0x0F, 0x00, 0x80, 0x03, 0xCA, 0x05,
+ 0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x59, 0xCE,
+ 0x20, 0x88, 0xE4, 0xE4, 0xE4, 0xE4, 0xF8, 0x10,
+ 0xC1, 0x04, 0x48, 0x62, 0x89, 0x05, 0xA0, 0xC0,
+ 0x6C, 0x01, 0x08, 0xC8, 0x6C, 0x01, 0x03, 0x02,
+ 0x00, 0xFC, 0x04, 0x02, 0x00, 0x02, 0x73, 0xA0,
+ 0x04, 0x06, 0xFD, 0x16, 0x88, 0x05, 0x09, 0x06,
+ 0xF4, 0x16, 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x86,
+ 0x02, 0x16, 0xD0, 0x03, 0xCB, 0x05, 0x5B, 0x04,
+ 0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33,
+ 0x38, 0x38, 0x42, 0x20, 0x20, 0x59, 0x49, 0x54,
+ 0x4B, 0xC2, 0xA8, 0x02, 0x98, 0x00, 0x83, 0x07,
+ 0x02, 0x00, 0x28, 0x02, 0x08, 0x00, 0x23, 0xC6,
+ 0x36, 0xE5, 0x48, 0x06, 0xC4, 0xC0, 0x73, 0x0A,
+ 0x65, 0x17, 0xA0, 0x06, 0xAA, 0xED, 0xC8, 0xC1,
+ 0xC7, 0x05, 0x03, 0x02, 0xA5, 0x00, 0xB0, 0x03,
+ 0xF8, 0xCD, 0xF8, 0xCD, 0xA6, 0x02, 0x06, 0x62,
+ 0x88, 0x02, 0x0A, 0x00, 0x57, 0x16, 0x03, 0x29,
+ 0x55, 0x16, 0x05, 0x29, 0xC4, 0x80, 0x52, 0x16,
+ 0x15, 0x09, 0x50, 0x17, 0x15, 0x09, 0x4E, 0x18,
+ 0x85, 0x02, 0x29, 0x00, 0x4B, 0x16, 0xC6, 0x05,
+ 0x96, 0x00, 0x03, 0x07, 0xC4, 0x04, 0x45, 0x06,
+ 0x95, 0x00, 0x44, 0x05, 0x43, 0x16, 0x44, 0x81,
+ 0x41, 0x16, 0x00, 0x03, 0x05, 0x00, 0xC4, 0x02,
+ 0x00, 0x03, 0x0A, 0x00, 0x44, 0x02, 0x0F, 0x00,
+ 0x84, 0x02, 0x05, 0x00, 0x37, 0x16, 0xC4, 0x02,
+ 0x00, 0x03, 0x0F, 0x00, 0x44, 0x02, 0x0F, 0x00,
+ 0x84, 0x02, 0x0A, 0x00, 0x2F, 0x16, 0x04, 0x02,
+ 0xFE, 0xFF, 0x2C, 0x13, 0x2B, 0x15, 0x2A, 0x1A,
+ 0x84, 0x05, 0x28, 0x12, 0x27, 0x15, 0x26, 0x1A,
+ 0x25, 0x18, 0x84, 0x05, 0x23, 0x16, 0x22, 0x1B,
+ 0x21, 0x17, 0x84, 0x05, 0x1F, 0x13, 0x1E, 0x1A,
+ 0x1D, 0x11, 0x04, 0x06, 0x1B, 0x16, 0xA5, 0x02,
+ 0xC5, 0xC1, 0x25, 0x02, 0x06, 0x00, 0x03, 0x02,
+ 0xA5, 0xA5, 0x83, 0xC1, 0x95, 0x00, 0x03, 0x38,
+ 0x94, 0x00, 0x83, 0x02, 0x2E, 0x6B, 0x0E, 0x16,
+ 0x84, 0x02, 0x59, 0x1C, 0x0B, 0x16, 0x24, 0x02,
+ 0x69, 0x00, 0x95, 0x00, 0x03, 0x3C, 0x94, 0x00,
+ 0x83, 0x81, 0x04, 0x16, 0x84, 0x02, 0x69, 0x00,
+ 0x01, 0x16, 0xC9, 0x05, 0x59, 0x04, 0xC3, 0xD0,
+ 0xFD, 0x13, 0x01, 0x1C, 0xFB, 0x10, 0xE0, 0x90,
+ 0x3D, 0xE5, 0xF8, 0x16, 0xC3, 0x06, 0xC3, 0xD0,
+ 0xF5, 0x1C, 0xF4, 0x16, 0xE0, 0x90, 0x3A, 0xE5,
+ 0xF1, 0x16, 0x5B, 0x04, 0x0B, 0xC3, 0x09, 0x02,
+ 0x3E, 0xE5, 0xA0, 0x06, 0x92, 0xE9, 0xCC, 0x05,
+ 0x5C, 0x04, 0x88, 0x07, 0x00, 0xA0, 0x89, 0x07,
+ 0xFE, 0xFF, 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07,
+ 0x02, 0xE0, 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00,
+ 0x88, 0x07, 0x00, 0x90, 0x89, 0x07, 0xFE, 0x9F,
+ 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 0x78, 0xE0,
+ 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 0xA0, 0x06,
+ 0xC4, 0xEC, 0x00, 0x00, 0xE6, 0x10, 0xE5, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90,
+ 0x00, 0x08, 0x11, 0xE3, 0x6C, 0xCC, 0x00, 0x80,
+ 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08,
+ 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00,
+ 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xFF,
+ 0xFF, 0x00, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0x00,
+ 0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0x00, 0x00, 0x00,
+ 0xC3, 0x00, 0xE7, 0xE7, 0xF3, 0xE7, 0xF1, 0xF1,
+ 0x43, 0x28, 0x20, 0x29, 0x4F, 0x43, 0x59, 0x50,
+ 0x49, 0x52, 0x48, 0x47, 0x20, 0x54, 0x42, 0x49,
+ 0x20, 0x4D, 0x39, 0x31, 0x33, 0x38, 0x34, 0x2C,
+ 0x35, 0x2C, 0x36, 0x2C, 0x43, 0x28, 0x20, 0x29,
+ 0x4F, 0x43, 0x59, 0x50, 0x49, 0x52, 0x48, 0x47,
+ 0x20, 0x54, 0x49, 0x54, 0x31, 0x20, 0x38, 0x39,
+ 0x2D, 0x33, 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30,
+ 0x38, 0x39, 0x00, 0x00, 0x61, 0x9B, 0xC4, 0xEC,
+ 0x0E, 0xEA, 0xDE, 0xE5, 0xC8, 0xED, 0x00, 0x00,
+ 0xC4, 0x00, 0xB8, 0xAF, 0x4A, 0x06, 0x50, 0x06,
+ 0x4C, 0x06, 0xDC, 0xCC, 0x4E, 0x06, 0x0F, 0x00,
+ 0x32, 0x06, 0x01, 0x00, 0x50, 0x07, 0x58, 0x07,
+ 0x52, 0x07, 0x70, 0xB5, 0x54, 0x07, 0x0F, 0x00,
+ 0x38, 0x07, 0x01, 0x00, 0xBA, 0x00, 0xA0, 0x00,
+ 0xBC, 0x00, 0xD6, 0xED, 0xBE, 0x00, 0x0F, 0x00,
+ 0x5E, 0x07, 0x3A, 0x07, 0x62, 0x07, 0x40, 0x80,
+ 0x64, 0x07, 0x54, 0xBA, 0x66, 0x07, 0x36, 0xBA,
+ 0x68, 0x07, 0x40, 0xB8, 0x98, 0x07, 0x00, 0x80,
+ 0x78, 0x07, 0x00, 0x80, 0xE2, 0x08, 0x04, 0x00,
+ 0xE4, 0x08, 0x01, 0x00, 0xEC, 0x08, 0x08, 0x00,
+ 0xF6, 0x08, 0x0A, 0x00, 0xF8, 0x08, 0x06, 0x00,
+ 0x00, 0x09, 0x0C, 0x00, 0x02, 0x09, 0x04, 0x00,
+ 0xAE, 0x01, 0x00, 0x00, 0x1E, 0x09, 0x00, 0x00,
+ 0x66, 0x09, 0x00, 0x00, 0x0C, 0x06, 0x13, 0x00,
+ 0x0A, 0x06, 0x20, 0x00, 0x00, 0x00, 0xE0, 0x00,
+ 0x86, 0xA3, 0xE0, 0x00, 0xE6, 0xA2, 0xE0, 0x00,
+ 0x86, 0xA3, 0xE0, 0x00, 0x02, 0xA5, 0xE0, 0x00,
+ 0x5E, 0xA6, 0xE0, 0x00, 0x66, 0xA9, 0xE0, 0x00,
+ 0x12, 0xA4, 0xC0, 0x00, 0x22, 0xA4, 0xE0, 0x00,
+ 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00,
+ 0x74, 0xA4, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00,
+ 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00,
+ 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00,
+ 0xDE, 0xAF, 0xC0, 0x00, 0x48, 0xB0, 0xC0, 0x00,
+ 0x84, 0xB0, 0xC0, 0x00, 0xF4, 0xB0, 0xC0, 0x00,
+ 0x76, 0xB1, 0xE0, 0x00, 0xE4, 0xB2, 0xE0, 0x00,
+ 0x8A, 0xB2, 0xE0, 0x00, 0xF4, 0xB3, 0xE0, 0x00,
+ 0x7C, 0xB3, 0xE0, 0x00, 0xC6, 0xAA, 0xC0, 0x00,
+ 0x36, 0xAB, 0xC0, 0x00, 0x90, 0xAB, 0xC0, 0x00,
+ 0xC2, 0xAB, 0xC0, 0x00, 0xEA, 0xAA, 0xC0, 0x00,
+ 0x80, 0xA3, 0xC0, 0x00, 0x80, 0xA3, 0x00, 0x3F,
+ 0x00, 0x7F, 0x00, 0x5E, 0x30, 0x00, 0x28, 0x00,
+ 0x43, 0x00, 0xB6, 0xA6, 0xB6, 0xA6, 0x1C, 0xA5,
+ 0x14, 0xA5, 0x46, 0xA5, 0x46, 0xA5, 0x62, 0xA5,
+ 0xB6, 0xA6, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08,
+ 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, 0x10,
+ 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00,
+ 0x14, 0x00, 0x0E, 0x10, 0x0C, 0x0C, 0x0A, 0x0A,
+ 0x0A, 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x98, 0x07, 0x7E, 0xCA, 0x58, 0x07,
+ 0xF8, 0xB8, 0x58, 0x07, 0xFE, 0xB7, 0x58, 0x07,
+ 0x68, 0xB9, 0x58, 0x07, 0xD0, 0xB8, 0x98, 0x07,
+ 0x5A, 0xC7, 0x98, 0x07, 0x52, 0xC7, 0x78, 0x07,
+ 0xC2, 0xC1, 0x58, 0x07, 0x30, 0xB9, 0x98, 0x07,
+ 0x38, 0xCA, 0x78, 0x07, 0x96, 0xC2, 0x58, 0x07,
+ 0x6A, 0xC7, 0x58, 0x07, 0xE0, 0xB8, 0x58, 0x07,
+ 0x1E, 0xB9, 0x58, 0x07, 0xE2, 0xB9, 0x98, 0x07,
+ 0xAE, 0xCB, 0x98, 0x07, 0x8E, 0xC7, 0x78, 0x07,
+ 0x56, 0xC2, 0xB8, 0x07, 0x14, 0xCC, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xA2, 0xBA, 0x16, 0xC1,
+ 0xCA, 0xC1, 0xD6, 0xC6, 0x8A, 0xBD, 0xC2, 0xBD,
+ 0xE0, 0xBD, 0x6A, 0xBE, 0x8E, 0xBE, 0xAA, 0xBE,
+ 0x22, 0xBF, 0x22, 0xBF, 0x56, 0xBE, 0xC8, 0xBF,
+ 0x10, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C,
+ 0x00, 0x0C, 0x01, 0x0F, 0xFF, 0xFE, 0x00, 0x58,
+ 0x00, 0x0E, 0xFF, 0xFE, 0x0E, 0x00, 0x00, 0x70,
+ 0x40, 0x80, 0x00, 0x5E, 0xA0, 0xC0, 0xDF, 0xFF,
+ 0x00, 0x18, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x50,
+ 0x00, 0x60, 0x00, 0x70, 0x00, 0x0C, 0x06, 0x00,
+ 0x00, 0x00, 0x84, 0xE3, 0xE6, 0x07, 0xF4, 0x07,
+ 0x08, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0xEA, 0x07,
+ 0xF4, 0x07, 0x06, 0x00, 0x40, 0x00, 0x00, 0x0A,
+ 0xE6, 0x07, 0xEE, 0x07, 0x08, 0x00, 0x40, 0x00,
+ 0x06, 0x0A, 0xEA, 0x07, 0xEE, 0x07, 0x00, 0x00,
+ 0xE2, 0xC1, 0x8B, 0xD4, 0xFF, 0xFF, 0xD7, 0xD1,
+ 0xD9, 0xC5, 0xD4, 0xC3, 0x3B, 0x59, 0x34, 0x09,
+ 0xFC, 0x05, 0x6C, 0x09, 0xD8, 0x06, 0x06, 0x04,
+ 0xBA, 0xEA, 0x30, 0x09, 0x48, 0x04, 0x80, 0x08,
+ 0x06, 0x00, 0x0A, 0x06, 0x0E, 0x0C, 0xBA, 0xCE,
+ 0x2E, 0xE0, 0x56, 0xE0, 0x50, 0xE1, 0x66, 0xE2,
+ 0xEC, 0xE2, 0x4C, 0xE3, 0xFE, 0xE3, 0xBA, 0xCE,
+ 0x80, 0xE4, 0x10, 0xE4, 0x14, 0xE0, 0x1C, 0xE4,
+ 0x1C, 0xE4, 0x46, 0xE5, 0x50, 0xE5, 0x5A, 0xE5,
+ 0xBA, 0xCE, 0xA6, 0xDC, 0xBA, 0xCE, 0x44, 0xDA,
+ 0xE6, 0xDF, 0x70, 0xDA, 0xDE, 0xDE, 0xB0, 0xCE,
+ 0x16, 0xDB, 0x3A, 0xDD, 0xB8, 0xDD, 0x34, 0xDE,
+ 0x58, 0xDE, 0x16, 0xDB, 0xDA, 0xDC, 0x08, 0xCF,
+ 0xB0, 0xCE, 0xA8, 0xD9, 0x8A, 0xD9, 0x44, 0xD9,
+ 0xB0, 0xCE, 0xEA, 0xDE, 0xB0, 0xCE, 0x72, 0x06,
+ 0xF6, 0xD2, 0x08, 0x07, 0x72, 0x06, 0x54, 0xD2,
+ 0xF4, 0x01, 0x72, 0x06, 0x34, 0xD2, 0x08, 0x07,
+ 0x7C, 0x06, 0x5A, 0xDC, 0x04, 0x00, 0x7C, 0x06,
+ 0x78, 0xD2, 0x00, 0x00, 0x7C, 0x06, 0xCC, 0xDE,
+ 0xFA, 0x00, 0x86, 0x06, 0xAC, 0xD1, 0x05, 0x00,
+ 0x90, 0x06, 0x1C, 0xDF, 0x28, 0x00, 0x90, 0x06,
+ 0x50, 0xD3, 0x04, 0x01, 0x90, 0x06, 0x00, 0x00,
+ 0x02, 0x00, 0x90, 0x06, 0x80, 0xD2, 0xBC, 0x02,
+ 0x9A, 0x06, 0x06, 0xD3, 0xDC, 0x05, 0x9A, 0x06,
+ 0xAA, 0xD2, 0x64, 0x00, 0x9A, 0x06, 0x0A, 0xD3,
+ 0x14, 0x00, 0x9A, 0x06, 0xE2, 0xE0, 0x40, 0x06,
+ 0x9A, 0x06, 0x12, 0xD3, 0x64, 0x00, 0x7C, 0x06,
+ 0x16, 0xDC, 0x04, 0x00, 0x7C, 0x06, 0xE6, 0xDA,
+ 0x16, 0x00, 0x7C, 0x06, 0xFA, 0xDB, 0x05, 0x00,
+ 0x7C, 0x06, 0x00, 0xDD, 0x14, 0x00, 0x9A, 0x06,
+ 0x7C, 0xD3, 0x14, 0x00, 0x9A, 0x06, 0x38, 0xD4,
+ 0x02, 0x00, 0x7C, 0x06, 0x0C, 0xE0, 0x19, 0x00,
+ 0x00, 0x00, 0x0A, 0x07, 0x0E, 0x07, 0x04, 0x07,
+ 0xD8, 0x06, 0x00, 0x07, 0xF0, 0x06, 0xEE, 0x06,
+ 0xEC, 0x06, 0x0C, 0x07, 0xE6, 0x06, 0x18, 0x07,
+ 0x92, 0x09, 0x94, 0x09, 0x96, 0x09, 0x98, 0x09,
+ 0x00, 0x50, 0xCC, 0x00, 0x03, 0x00, 0x00, 0x84,
+ 0x00, 0xA8, 0x00, 0xA0, 0x00, 0x20, 0x00, 0x80,
+ 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x80,
+ 0x00, 0x40, 0x00, 0x10, 0x82, 0xEC, 0x48, 0xEB,
+ 0x62, 0xEB, 0x7C, 0xEB, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0xEA, 0xEB,
+ 0x52, 0xEB, 0x68, 0xEB, 0x82, 0xEB, 0x40, 0x01,
+ 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x00, 0x00,
+ 0x7F, 0x00, 0xA0, 0x00, 0xFF, 0x00, 0x10, 0x02,
+ 0x1F, 0x02, 0x30, 0x02, 0x3F, 0x02, 0x50, 0x02,
+ 0x5F, 0x02, 0x70, 0x02, 0x7F, 0x02, 0x90, 0x02,
+ 0x9F, 0x02, 0xB0, 0x02, 0xBF, 0x02, 0xD0, 0x02,
+ 0xDF, 0x02, 0xE1, 0x02, 0xFF, 0x02, 0x01, 0x03,
+ 0x7F, 0x03, 0x81, 0x03, 0x8F, 0x03, 0x91, 0x03,
+ 0x9F, 0x03, 0xA1, 0x03, 0xAF, 0x03, 0xB1, 0x03,
+ 0xBF, 0x03, 0xC1, 0x03, 0xCF, 0x03, 0xE1, 0x03,
+ 0xFF, 0x03, 0xC0, 0x07, 0xFF, 0x07, 0x00, 0x0C,
+ 0xFF, 0x0F, 0x00, 0x30, 0xFF, 0x37, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xBC, 0xFE, 0x07, 0x00, 0x5E, 0x02,
+ 0x00, 0x01, 0xFF, 0xBA, 0x80, 0xBA, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x0A, 0x01,
+ 0x0E, 0x01, 0x10, 0x01, 0x14, 0x01, 0x00, 0x00,
+ 0x12, 0x01, 0x00, 0xF8, 0x16, 0x01, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x1C, 0x01,
+ 0x82, 0x01, 0x66, 0x96, 0x66, 0x96, 0x55, 0x55,
+ 0x00, 0x00, 0x82, 0x01, 0x2A, 0x8A, 0x2A, 0x8A,
+ 0x18, 0xC9, 0x18, 0xC9, 0x86, 0x01, 0xAA, 0xA2,
+ 0x1E, 0xA0, 0x55, 0x55, 0x1E, 0x54, 0x8A, 0x01,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00,
+ 0x8C, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8,
+ 0x00, 0x00, 0x8E, 0x01, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0xA8, 0x00, 0x00, 0x90, 0x01, 0x00, 0x50,
+ 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x92, 0x01,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00,
+ 0x94, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8,
+ 0x00, 0x00, 0x96, 0x01, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0xA8, 0x00, 0x00, 0x98, 0x01, 0x00, 0x50,
+ 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x9A, 0x01,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00,
+ 0x9C, 0x01, 0x55, 0x55, 0xC0, 0x7F, 0xAA, 0xAA,
+ 0xC0, 0x7F, 0x00, 0x00, 0xA2, 0x01, 0xA4, 0x01,
+ 0xA8, 0x01, 0xAA, 0x01, 0xAE, 0x01, 0xB0, 0x01,
+ 0xB2, 0x01, 0x80, 0x01, 0x00, 0x00, 0x88, 0x01,
+ 0x00, 0xFF, 0x9E, 0x01, 0xFF, 0x00, 0xA0, 0x01,
+ 0x00, 0x80, 0xAC, 0x01, 0x00, 0x80, 0x00, 0x00,
+ 0xA6, 0x01, 0x00, 0x80, 0x00, 0x00, 0x80, 0x01,
+ 0xBC, 0x01, 0x00, 0x88, 0x00, 0x06, 0x00, 0xC8,
+ 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0x44, 0x00, 0x92, 0xEA,
+ 0x48, 0x00, 0x98, 0xEA, 0x50, 0x00, 0x9E, 0xEA,
+ 0x60, 0x00, 0xA4, 0xEA, 0x78, 0x00, 0xAA, 0xEA,
+ 0x0A, 0xE8, 0x18, 0xE7, 0x3C, 0xEA, 0x2A, 0xE7,
+ 0x14, 0x55, 0xA0, 0x01, 0xEC, 0xE6, 0xD0, 0xE9,
+ 0x46, 0xE7, 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8,
+ 0x00, 0x00, 0x1E, 0x00, 0x46, 0xE7, 0x92, 0xE7,
+ 0x00, 0x41, 0x01, 0x41, 0xB6, 0xE7, 0x73, 0xEA,
+ 0x18, 0xE7, 0x48, 0xEA, 0xEC, 0xE6, 0x04, 0xEA,
+ 0x56, 0xE7, 0x62, 0xE7, 0xB6, 0xE7, 0x6E, 0xEA,
+ 0x62, 0xE8, 0x00, 0x00, 0x36, 0xE8, 0xEC, 0xE6,
+ 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 0x36, 0xE8,
+ 0x62, 0xE8, 0x00, 0x00, 0xEC, 0xE6, 0xF0, 0xE9,
+ 0x0C, 0xE7, 0x4A, 0xE7, 0x62, 0xE7, 0x36, 0xE8,
+ 0xEC, 0xE6, 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7,
+ 0x36, 0xE8, 0x62, 0xE8, 0x00, 0x20, 0x2A, 0xE7,
+ 0x14, 0x55, 0xA0, 0x01, 0x18, 0xE7, 0x50, 0xEA,
+ 0xEC, 0xE6, 0xD0, 0xE9, 0x58, 0xE8, 0x50, 0x55,
+ 0x0C, 0x00, 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01,
+ 0x00, 0x00, 0xB6, 0xE7, 0x75, 0xEA, 0x00, 0xE7,
+ 0x58, 0xE8, 0x55, 0x55, 0x0C, 0x00, 0x56, 0xE7,
+ 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 0xFF, 0xFF,
+ 0x08, 0x00, 0x58, 0xE8, 0x02, 0x10, 0x06, 0x00,
+ 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01,
+ 0xB6, 0xE7, 0x80, 0xEA, 0x00, 0xE7, 0x58, 0xE8,
+ 0x00, 0xC0, 0x08, 0x00, 0x58, 0xE8, 0xFF, 0xFF,
+ 0x0A, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 0x0C, 0x00,
+ 0x58, 0xE8, 0x0D, 0x10, 0x06, 0x00, 0x46, 0xE7,
+ 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 0xB6, 0xE7,
+ 0x74, 0xEA, 0x62, 0xE8, 0x08, 0x20, 0x00, 0xE7,
+ 0x52, 0xE8, 0x82, 0x01, 0x02, 0xC9, 0x46, 0xE7,
+ 0xB6, 0xE7, 0x80, 0xEA, 0x62, 0xE8, 0x34, 0x20,
+ 0x00, 0xE7, 0x58, 0xE8, 0x00, 0x10, 0x06, 0x00,
+ 0x46, 0xE7, 0xC6, 0xE8, 0xB6, 0xE7, 0x78, 0xEA,
+ 0x52, 0xE8, 0x9C, 0x01, 0x40, 0x00, 0x18, 0xE7,
+ 0x50, 0xEA, 0x2A, 0xE7, 0xFF, 0x00, 0x80, 0x07,
+ 0x26, 0xE9, 0x03, 0x00, 0x66, 0xE9, 0x74, 0xE9,
+ 0x12, 0xEA, 0x38, 0xE9, 0x00, 0x00, 0x74, 0xE9,
+ 0x1C, 0xEA, 0x38, 0xE9, 0x04, 0x00, 0x74, 0xE9,
+ 0x24, 0xEA, 0x38, 0xE9, 0x07, 0x00, 0x74, 0xE9,
+ 0x2C, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x74, 0xE9,
+ 0x34, 0xEA, 0x38, 0xE9, 0x02, 0x00, 0x74, 0xE9,
+ 0x34, 0xEA, 0x38, 0xE9, 0x06, 0x00, 0x74, 0xE9,
+ 0x34, 0xEA, 0x38, 0xE9, 0x05, 0x00, 0x74, 0xE9,
+ 0x34, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x4A, 0xE9,
+ 0x26, 0xE9, 0x03, 0x00, 0x58, 0xE9, 0x62, 0xE7,
+ 0xE6, 0xE8, 0xD8, 0xE9, 0x01, 0x00, 0xE6, 0xE8,
+ 0x25, 0xEA, 0x02, 0x00, 0xE6, 0xE8, 0x2F, 0xEA,
+ 0x06, 0x00, 0xE6, 0xE8, 0x3A, 0xEA, 0x05, 0x00,
+ 0xB6, 0xE7, 0x74, 0xEA, 0x36, 0xE8, 0xEC, 0xE6,
+ 0xD0, 0xE9, 0x56, 0xE7, 0xC6, 0xE8, 0x0C, 0xE7,
+ 0x92, 0xE7, 0x00, 0x01, 0x00, 0x80, 0xB6, 0xE7,
+ 0x78, 0xEA, 0x00, 0xE7, 0xFE, 0xE8, 0x52, 0xE8,
+ 0x80, 0x01, 0x41, 0x8E, 0x4A, 0xE7, 0x92, 0xE7,
+ 0x00, 0x01, 0x01, 0x1B, 0x06, 0xE9, 0xE4, 0xFF,
+ 0xB6, 0xE7, 0x7C, 0xEA, 0xBE, 0xE8, 0x18, 0xE7,
+ 0x56, 0xEA, 0x0C, 0xE7, 0x6A, 0xE8, 0x3C, 0xE7,
+ 0x00, 0xE0, 0xC6, 0xE8, 0xB6, 0xE7, 0x86, 0xEA,
+ 0x3C, 0xE7, 0x00, 0xE8, 0x62, 0xE7, 0xB6, 0xE7,
+ 0x85, 0xEA, 0x3C, 0xE7, 0x00, 0x08, 0xC6, 0xE8,
+ 0xB6, 0xE7, 0x86, 0xEA, 0x3C, 0xE7, 0x00, 0xF8,
+ 0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8,
+ 0x80, 0x01, 0x00, 0x02, 0x3C, 0xE7, 0x00, 0xE0,
+ 0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8,
+ 0x84, 0x01, 0x00, 0x00, 0x62, 0xE8, 0x34, 0x00,
+ 0x3C, 0xE7, 0x00, 0x00, 0xC6, 0xE8, 0x62, 0xE8,
+ 0x34, 0x60, 0x0E, 0xE9, 0x52, 0xE8, 0x84, 0x01,
+ 0x00, 0x00, 0xB6, 0xE7, 0x86, 0xEA, 0x52, 0xE8,
+ 0x82, 0x01, 0x00, 0xC8, 0x3C, 0xE7, 0x00, 0xE0,
+ 0xC6, 0xE8, 0x3C, 0xE7, 0x00, 0x10, 0xC6, 0xE8,
+ 0x62, 0xE8, 0x34, 0x60, 0x52, 0xE8, 0x80, 0x01,
+ 0x00, 0x06, 0x3C, 0xE7, 0x10, 0x00, 0x78, 0xE8,
+ 0x36, 0xE8, 0x52, 0xE8, 0x84, 0x01, 0x00, 0x00,
+ 0x62, 0xE8, 0x34, 0x00, 0xEC, 0xE6, 0xD0, 0xE9,
+ 0x18, 0xE7, 0x5C, 0xEA, 0xD0, 0xE8, 0x92, 0xE9,
+ 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xF0,
+ 0x06, 0x00, 0x00, 0xC7, 0xA0, 0xE7, 0xDC, 0xE8,
+ 0x00, 0xE0, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7,
+ 0x40, 0xD0, 0x06, 0x00, 0x00, 0xE0, 0xA0, 0xE7,
+ 0xDC, 0xE8, 0x00, 0xC0, 0x00, 0xE7, 0x0C, 0xE7,
+ 0x70, 0xE7, 0x40, 0x90, 0x06, 0x00, 0x00, 0xA0,
+ 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x80, 0x00, 0xE7,
+ 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x50, 0x06, 0x00,
+ 0x00, 0x60, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x40,
+ 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x10,
+ 0x06, 0x00, 0x00, 0x20, 0xA0, 0xE7, 0xDC, 0xE8,
+ 0x00, 0x00, 0xD0, 0xE8, 0x92, 0xE9, 0x00, 0xE7,
+ 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xD0, 0x06, 0x00,
+ 0x00, 0xA6, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0xC0,
+ 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x90,
+ 0x06, 0x00, 0x00, 0xC0, 0xA0, 0xE7, 0xDC, 0xE8,
+ 0x00, 0x80, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7,
+ 0x40, 0x50, 0x06, 0x00, 0x00, 0x40, 0xA0, 0xE7,
+ 0xDC, 0xE8, 0x00, 0x40, 0x00, 0xE7, 0x0C, 0xE7,
+ 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 0x00, 0x60,
+ 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 0x7E, 0xE9,
+ 0x90, 0xE9, 0x18, 0xE7, 0x62, 0xEA, 0xEC, 0xE6,
+ 0xD0, 0xE9, 0xA4, 0xE8, 0x55, 0x55, 0x16, 0x00,
+ 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x00, 0x00, 0x00,
+ 0xB6, 0xE7, 0x8B, 0xEA, 0x0A, 0xE8, 0x18, 0xE7,
+ 0x62, 0xEA, 0x58, 0xE8, 0x55, 0x55, 0x16, 0x00,
+ 0x00, 0xE7, 0x46, 0xE7, 0xA0, 0xE7, 0x2A, 0xE7,
+ 0xFF, 0x00, 0x00, 0x08, 0x2A, 0xE7, 0xFF, 0x00,
+ 0x00, 0x0C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x10,
+ 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x14, 0x2A, 0xE7,
+ 0xFF, 0x00, 0x00, 0x18, 0x2A, 0xE7, 0xFF, 0x00,
+ 0x00, 0x1C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x20,
+ 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x24, 0x2A, 0xE7,
+ 0xFF, 0x00, 0x00, 0x28, 0x2A, 0xE7, 0xFF, 0x00,
+ 0x00, 0x2C, 0xD2, 0xE7, 0x00, 0xE7, 0x0C, 0xE7,
+ 0x70, 0xE7, 0x40, 0x30, 0x06, 0x00, 0x00, 0x01,
+ 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x20, 0x00, 0xE7,
+ 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00,
+ 0x00, 0x43, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60,
+ 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xB0,
+ 0x06, 0x00, 0x00, 0x85, 0xA0, 0xE7, 0xDC, 0xE8,
+ 0x00, 0xA0, 0xD8, 0xE8, 0x00, 0x01, 0x03, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x81, 0x1A, 0x00,
+ 0x40, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x72, 0x82,
+ 0x4A, 0xA9, 0xA5, 0x5A, 0xDA, 0xE7, 0x03, 0x09,
+ 0x11, 0x9D, 0x00, 0x00, 0x00, 0x81, 0x04, 0x00,
+ 0xD8, 0x90, 0x00, 0x10, 0x00, 0x00, 0x00, 0x81,
+ 0x04, 0x00, 0xD8, 0x90, 0xD8, 0xB4, 0x00, 0x00,
+ 0x00, 0x81, 0x08, 0x00, 0xD8, 0x90, 0x46, 0x16,
+ 0x00, 0x40, 0xD8, 0xB4, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x13, 0x00, 0x40, 0x10, 0x16, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x81, 0x0F, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x12, 0x00, 0x0A, 0x80,
+ 0x40, 0x9E, 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80,
+ 0x0F, 0x00, 0x06, 0x80, 0x40, 0xFE, 0x00, 0xCC,
+ 0x00, 0x00, 0x04, 0x80, 0x40, 0x8E, 0x00, 0xC9,
+ 0x04, 0x80, 0x00, 0x06, 0x00, 0xCC, 0x04, 0x80,
+ 0x40, 0x0A, 0x00, 0xC8, 0x0A, 0x80, 0x40, 0x8A,
+ 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 0x0F, 0x00,
+ 0x0A, 0x08, 0x80, 0x1C, 0x0A, 0x00, 0x1C, 0x1A,
+ 0x00, 0x80, 0x1C, 0x0C, 0x00, 0x80, 0x1C, 0x1A,
+ 0x00, 0x80, 0x1A, 0x0E, 0x80, 0x1C, 0x04, 0x00,
+ 0x00, 0x80, 0x80, 0x02, 0x02, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x58, 0x07, 0x0C, 0xB8,
+ 0x16, 0xE0, 0xE2, 0x08, 0xEC, 0x08, 0xF6, 0x08,
+ 0x16, 0xE0, 0x00, 0x09, 0x0A, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0xE2, 0x08, 0x00, 0x00, 0xEC, 0x08,
+ 0xF6, 0x08, 0x00, 0x09, 0x00, 0x00, 0xB8, 0x07,
+ 0xCA, 0xCB, 0x80, 0x02, 0xB8, 0x07, 0xE8, 0xCB,
+ 0x84, 0xFF, 0xB8, 0x07, 0x0A, 0xCC, 0xB8, 0x07,
+ 0x84, 0xCC, 0x6E, 0xCD, 0x62, 0xCD, 0x88, 0xCD,
+ 0x90, 0xCE, 0x84, 0xCD, 0x92, 0xCE, 0x92, 0xCE,
+ 0x92, 0xCE, 0x8C, 0xCD, 0x96, 0xCD, 0x38, 0xCE,
+ 0x82, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 0x92, 0xCE,
+ 0x92, 0xCE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x08, 0x01, 0x05, 0x08,
+ 0x08, 0x08, 0x03, 0x08, 0x03, 0x03, 0x03, 0x03,
+ 0x00, 0x00, 0x04, 0x02, 0x04, 0x04, 0x00, 0x04,
+ 0x0A, 0x08, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x00,
+ 0x04, 0x41, 0x06, 0x0B, 0x08, 0xC2, 0x00, 0xE6,
+ 0x00, 0xE7, 0x04, 0x06, 0x04, 0x07, 0x04, 0x03,
+ 0x06, 0x04, 0x04, 0x05, 0x04, 0x88, 0x04, 0xCF,
+ 0x04, 0xCD, 0x03, 0x00, 0x05, 0x00, 0x1C, 0x00,
+ 0x00, 0x0C, 0x00, 0x80, 0xD2, 0xD8, 0xDA, 0xD8,
+ 0x1E, 0xD9, 0xDE, 0xD8, 0xEA, 0xD8, 0xF0, 0xD8,
+ 0x14, 0xD9, 0xE4, 0xD8, 0x32, 0xD9, 0x00, 0x06,
+ 0x00, 0x00, 0x03, 0x07, 0x0A, 0x0E, 0x0F, 0x14,
+ 0x26, 0x2A, 0x52, 0x42, 0x50, 0x48, 0x5D, 0x4D,
+ 0x62, 0x62, 0x6D, 0x57, 0x46, 0x39, 0x1A, 0x1D,
+ 0x7C, 0x76, 0x1F, 0x23, 0x15, 0x1D, 0x74, 0x6F,
+ 0x84, 0x7C, 0x8B, 0x82, 0x92, 0x89, 0x00, 0x00,
+ 0x32, 0x2F, 0x3F, 0x34, 0x32, 0x01, 0x01, 0x57,
+ 0x32, 0x11, 0x81, 0x51, 0x02, 0x56, 0x03, 0x55,
+ 0x54, 0x11, 0x56, 0x81, 0x55, 0x02, 0x54, 0x02,
+ 0x56, 0x81, 0x01, 0x76, 0x02, 0x34, 0x02, 0x55,
+ 0x81, 0x54, 0x02, 0x58, 0x02, 0x55, 0x81, 0x54,
+ 0x02, 0x58, 0x11, 0x12, 0x02, 0x52, 0x58, 0x83,
+ 0x52, 0x05, 0x83, 0x04, 0x02, 0x58, 0x08, 0x55,
+ 0x58, 0x83, 0x55, 0x02, 0x81, 0x02, 0x05, 0x58,
+ 0x03, 0x52, 0x5C, 0x15, 0x53, 0x5B, 0x52, 0x87,
+ 0x11, 0x03, 0x41, 0x51, 0x78, 0x51, 0x34, 0x11,
+ 0x81, 0x11, 0x20, 0x31, 0x54, 0x57, 0x01, 0x53,
+ 0x5A, 0x12, 0x81, 0x51, 0x20, 0x31, 0x5B, 0x57,
+ 0x01, 0x5A, 0x01, 0x11, 0x51, 0x11, 0x31, 0x81,
+ 0x57, 0x20, 0x15, 0x01, 0x13, 0x01, 0x11, 0x01,
+ 0x11, 0x11, 0x81, 0x51, 0x05, 0x58, 0x02, 0x52,
+ 0x5B, 0x54, 0x5D, 0x81, 0x52, 0x05, 0x54, 0x02,
+ 0x58, 0x81, 0x50, 0x02, 0x13, 0x03, 0x58, 0x81,
+ 0x50, 0x02, 0x11, 0x03, 0x81, 0x54, 0x72, 0x5D,
+ 0x50, 0x03, 0x13, 0x03, 0x13, 0x01, 0x40, 0x54,
+ 0x0E, 0x00, 0x20, 0x06, 0x56, 0x06, 0x0C, 0xDA,
+ 0x24, 0x00, 0x02, 0x10, 0x16, 0x00, 0x02, 0x00,
+ 0x01, 0x04, 0x08, 0x07, 0x0C, 0xDA, 0x20, 0x00,
+ 0x03, 0x10, 0x12, 0x00, 0x03, 0x00, 0x4E, 0xD9,
+ 0x14, 0x8E, 0x20, 0x00, 0x04, 0x10, 0x12, 0x00,
+ 0x04, 0x00, 0xD2, 0xCE, 0x20, 0x00, 0x05, 0xE0,
+ 0x12, 0x00, 0x05, 0x00, 0xD2, 0xCE, 0x20, 0x00,
+ 0x06, 0xE0, 0x12, 0x00, 0x06, 0x00, 0xE8, 0xDD,
+ 0x12, 0x00, 0x01, 0xE0, 0x6C, 0x09, 0xCC, 0x06,
+ 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x06,
+ 0x42, 0xDC, 0xF0, 0x05, 0x00, 0xE0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xE2, 0x05, 0x08, 0x00,
+ 0x26, 0xFF, 0xDC, 0x05, 0x00, 0x00, 0x30, 0x06,
+ 0xF8, 0xDB, 0x1E, 0x00, 0x01, 0xE0, 0x10, 0x00,
+ 0x11, 0x30, 0x0C, 0x04, 0x01, 0x00, 0x0E, 0x04,
+ 0x02, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x06, 0x32, 0xDD, 0x12, 0x00, 0x01, 0xE0,
+ 0x04, 0x00, 0x13, 0x30, 0x74, 0xDE, 0x3E, 0x00,
+ 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x02, 0x00,
+ 0x30, 0x00, 0x20, 0x50, 0x23, 0x0C, 0xFC, 0x05,
+ 0x52, 0x06, 0x56, 0x06, 0x00, 0x00, 0x00, 0x81,
+ 0x16, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00,
+ 0x10, 0x00, 0x08, 0x00, 0x2A, 0x40, 0x2A, 0x04,
+ 0x56, 0x06, 0x26, 0x00, 0x19, 0xED, 0x2B, 0x06,
+ 0x72, 0x09, 0x22, 0x00, 0x24, 0x00, 0x2F, 0xED,
+ 0x23, 0x0C, 0xFC, 0x05, 0x28, 0x08, 0x34, 0x09,
+ 0x29, 0x08, 0x58, 0x07, 0x78, 0x07, 0x98, 0x07,
+ 0x23, 0x00, 0x2A, 0x00, 0x3D, 0xED, 0x06, 0x04,
+ 0xF0, 0x06, 0x07, 0x04, 0xEE, 0x06, 0x24, 0x00,
+ 0xD2, 0xCE, 0x34, 0x00, 0x00, 0xE0, 0x00, 0xC0,
+ 0x00, 0x00, 0x10, 0x00, 0x26, 0x00, 0x25, 0x40,
+ 0xD2, 0xCE, 0x20, 0x00, 0x00, 0xE0, 0x00, 0xC0,
+ 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x26, 0x40,
+ 0xD2, 0xCE, 0x1A, 0x00, 0x00, 0xE0, 0x0C, 0x00,
+ 0x27, 0x60, 0x0A, 0x08, 0xE6, 0x06, 0xD2, 0xCE,
+ 0x24, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x28, 0x60,
+ 0x30, 0x04, 0x06, 0x07, 0x52, 0xCF, 0x00, 0x81,
+ 0x30, 0x00, 0x00, 0xE0, 0x22, 0x00, 0x29, 0x60,
+ 0x2D, 0x08, 0x1C, 0x07, 0x2E, 0x08, 0x22, 0x07,
+ 0x00, 0x00, 0x08, 0x02, 0x06, 0x01, 0x14, 0x06,
+ 0x18, 0x08, 0x20, 0x0C, 0x26, 0x0E, 0x30, 0x0F,
+ 0x34, 0x11, 0x3E, 0x12, 0x42, 0x14, 0x46, 0x16,
+ 0x1C, 0x0A, 0x4A, 0x18, 0x13, 0x03, 0x11, 0x83,
+ 0x01, 0x11, 0x11, 0x81, 0x12, 0x81, 0x13, 0x01,
+ 0x52, 0x83, 0x81, 0x85, 0x85, 0x11, 0x12, 0x81,
+ 0x12, 0x81, 0x19, 0x81, 0x60, 0x85, 0x00, 0xC0,
+ 0x00, 0x00, 0x08, 0x00, 0x6C, 0x09, 0x00, 0x00,
+ 0x30, 0x06, 0x08, 0xE5, 0x54, 0x06, 0x50, 0x06,
+ 0x38, 0x02, 0x21, 0x04, 0x1E, 0x09, 0x0B, 0x06,
+ 0xD8, 0x06, 0x02, 0x08, 0xDC, 0x06, 0x00, 0xC0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x00, 0x41, 0x00,
+ 0x14, 0xAE, 0x00, 0x00, 0x00, 0x81, 0x09, 0x04,
+ 0x0C, 0x07, 0x41, 0x00, 0x41, 0x00, 0x14, 0x02,
+ 0x00, 0x00, 0x00, 0x81, 0x0B, 0x06, 0xD8, 0x06,
+ 0x2C, 0x06, 0x76, 0x09, 0x22, 0x14, 0x3A, 0x09,
+ 0x41, 0x00, 0x41, 0x00, 0x54, 0x02, 0x00, 0x00,
+ 0x00, 0x81, 0xD8, 0x06, 0x00, 0x84, 0x00, 0x48,
+ 0xFC, 0xFF, 0x09, 0x00, 0x00, 0xC0, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xB8, 0xFF, 0x20, 0x00,
+ 0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33,
+ 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 0x38, 0x39,
+ 0x54, 0x20, 0x78, 0x65, 0x73, 0x61, 0x49, 0x20,
+ 0x73, 0x6E, 0x72, 0x74, 0x6D, 0x75, 0x6E, 0x65,
+ 0x73, 0x74, 0x28, 0x0A, 0x29, 0x43, 0x39, 0x31,
+ 0x33, 0x38, 0x34, 0x2C, 0x35, 0x2C, 0x36, 0x2C,
+ 0x49, 0x20, 0x4D, 0x42, 0x43, 0x20, 0x72, 0x6F,
+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x34, 0x90,
+ 0x00, 0x00, 0xFA, 0xFF, 0x01, 0x00, 0xB8, 0xFF,
+ 0x00, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x80, 0x00,
+ 0x3E, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#endif /* CONFIG_SKTR */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 489f0a39e..7187a3d8f 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -912,7 +912,7 @@ err_exit:
shutdown,
Seems, now it is clean. The solution is to consider netdevice and
- line discipline sides as two independant threads.
+ line discipline sides as two independent threads.
By-product (not desired): sl? does not feel hangups and remains open.
It is supposed, that user level program (dip, diald, slattach...)
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 152beacbc..cd10798a2 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -54,7 +54,7 @@ static void ultramca_block_input(struct device *dev, int count,
int ring_offset);
static void ultramca_block_output(struct device *dev, int count,
const unsigned char *buf,
- const start_page);
+ const int start_page);
static int ultramca_close_card(struct device *dev);
#define START_PG 0x00 /* First page of TX buffer */
@@ -118,6 +118,9 @@ __initfunc(int ultramca_probe(struct device *dev))
reg4 = inb(ioaddr + 4) & 0x7f;
outb(reg4, ioaddr + 4);
+ if (load_8390_module("wd.c"))
+ return -ENOSYS;
+
printk("%s: SMC Ultra MCA at %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
@@ -347,12 +350,15 @@ int init_module(void)
if (register_netdev(dev) != 0)
{
printk(KERN_WARNING "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0)
- return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
+ lock_8390_module();
return 0;
}
@@ -365,14 +371,16 @@ void cleanup_module(void)
struct device *dev = &dev_ultra[this_dev];
if (dev->priv != NULL)
{
+ void *priv = dev->priv;
/* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
release_region(ioaddr, ULTRA_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index e1073e2ef..f51ced5ad 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -152,6 +152,9 @@ __initfunc(int ultra_probe1(struct device *dev, int ioaddr))
if ((checksum & 0xff) != 0xFF)
return ENODEV;
+ if (load_8390_module("smc-ultra.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("smc-ultra.c: Passed a NULL device.\n");
@@ -456,12 +459,15 @@ init_module(void)
}
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -473,14 +479,16 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
struct device *dev = &dev_ultra[this_dev];
if (dev->priv != NULL) {
- /* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
+ /* NB: ultra_close_card() does free_irq */
release_region(ioaddr, ULTRA_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index a3d3abebf..64772c48c 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -69,7 +69,8 @@ static void ultra32_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
static void ultra32_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void ultra32_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf,
+ const int start_page);
static int ultra32_close(struct device *dev);
#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */
@@ -147,6 +148,9 @@ __initfunc(int ultra32_probe1(struct device *dev, int ioaddr))
if ((checksum & 0xff) != 0xff)
return ENODEV;
+ if (load_8390_module("smc-ultra32.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("smc-ultra32.c: Passed a NULL device.\n");
@@ -385,13 +389,16 @@ int init_module(void)
dev->name = namelist+(NAMELEN*this_dev);
dev->init = ultra32_probe;
if (register_netdev(dev) != 0) {
- if (found > 0) return 0; /* Got at least one. */
+ if (found > 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -402,13 +409,15 @@ void cleanup_module(void)
for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
struct device *dev = &dev_ultra[this_dev];
if (dev->priv != NULL) {
- /* NB: ultra32_close_card() does free_irq + irq2dev */
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
- kfree(dev->priv);
- dev->priv = NULL;
+ void *priv = dev->priv;
+ /* NB: ultra32_close_card() does free_irq */
release_region(ioaddr, ULTRA32_IO_EXTENT);
+ dev->priv = NULL;
unregister_netdev(dev);
+ kfree(priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index ebe502604..53bafee55 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -58,6 +58,70 @@ static struct happy_meal *root_happy_dev = NULL;
#undef SXDEBUG
#undef RXDEBUG
#undef TXDEBUG
+#undef TXLOGGING
+
+#ifdef TXLOGGING
+struct hme_tx_logent {
+ unsigned int tstamp;
+ int tx_new, tx_old;
+ unsigned int action;
+#define TXLOG_ACTION_IRQ 0x01
+#define TXLOG_ACTION_TXMIT 0x02
+#define TXLOG_ACTION_TBUSY 0x04
+#define TXLOG_ACTION_NBUFS 0x08
+ unsigned int status;
+};
+#define TX_LOG_LEN 128
+static struct hme_tx_logent tx_log[TX_LOG_LEN];
+static int txlog_cur_entry = 0;
+static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s)
+{
+ struct hme_tx_logent *tlp;
+ unsigned long flags;
+
+ save_and_cli(flags);
+ tlp = &tx_log[txlog_cur_entry];
+ tlp->tstamp = (unsigned int)jiffies;
+ tlp->tx_new = hp->tx_new;
+ tlp->tx_old = hp->tx_old;
+ tlp->action = a;
+ tlp->status = s;
+ txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1);
+ restore_flags(flags);
+}
+static __inline__ void tx_dump_log(void)
+{
+ int i, this;
+
+ this = txlog_cur_entry;
+ for(i = 0; i < TX_LOG_LEN; i++) {
+ printk("TXLOG[%d]: j[%08x] tx[N(%d)O(%d)] action[%08x] stat[%08x]\n", i,
+ tx_log[this].tstamp,
+ tx_log[this].tx_new, tx_log[this].tx_old,
+ tx_log[this].action, tx_log[this].status);
+ this = (this + 1) & (TX_LOG_LEN - 1);
+ }
+}
+static __inline__ void tx_dump_ring(struct happy_meal *hp)
+{
+ struct hmeal_init_block *hb = hp->happy_block;
+ struct happy_meal_txd *tp = &hb->happy_meal_txd[0];
+ int i;
+
+ for(i = 0; i < TX_RING_SIZE; i+=4) {
+ printk("TXD[%d..%d]: [%08x:%08x] [%08x:%08x] [%08x:%08x] [%08x:%08x]\n",
+ i, i + 4,
+ le32_to_cpu(tp[i].tx_flags), le32_to_cpu(tp[i].tx_addr),
+ le32_to_cpu(tp[i + 1].tx_flags), le32_to_cpu(tp[i + 1].tx_addr),
+ le32_to_cpu(tp[i + 2].tx_flags), le32_to_cpu(tp[i + 2].tx_addr),
+ le32_to_cpu(tp[i + 3].tx_flags), le32_to_cpu(tp[i + 3].tx_addr));
+ }
+}
+#else
+#define tx_add_log(hp, a, s) do { } while(0)
+#define tx_dump_log() do { } while(0)
+#define tx_dump_ring(hp) do { } while(0)
+#endif
#ifdef HMEDEBUG
#define HMD(x) printk x
@@ -73,7 +137,7 @@ static struct happy_meal *root_happy_dev = NULL;
#define ASD(x)
#endif
-#define DEFAULT_IPG0 32 /* For lance-mode only */
+#define DEFAULT_IPG0 16 /* For lance-mode only */
#define DEFAULT_IPG1 8 /* For all modes */
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
@@ -376,18 +440,33 @@ static int set_happy_link_modes(struct happy_meal *hp, struct hmeal_tcvregs *tre
full = 0;
}
- /* XXX This may not be enough, we may need to reinit the entire
- * XXX Happy Meal front end for this to work every time.
+ /* Before changing other bits in the tx_cfg register, and in
+ * general any of other the TX config registers too, you
+ * must:
+ * 1) Clear Enable
+ * 2) Poll with reads until that bit reads back as zero
+ * 3) Make TX configuration changes
+ * 4) Set Enable once more
*/
- if(full)
+ hme_write32(hp, &hp->bigmacregs->tx_cfg,
+ hme_read32(hp, &hp->bigmacregs->tx_cfg) &
+ ~(BIGMAC_TXCFG_ENABLE));
+ while(hme_read32(hp, &hp->bigmacregs->tx_cfg) & BIGMAC_TXCFG_ENABLE)
+ barrier();
+ if(full) {
+ hp->happy_flags |= HFLAG_FULL;
hme_write32(hp, &hp->bigmacregs->tx_cfg,
hme_read32(hp, &hp->bigmacregs->tx_cfg) |
BIGMAC_TXCFG_FULLDPLX);
- else
+ } else {
+ hp->happy_flags &= ~(HFLAG_FULL);
hme_write32(hp, &hp->bigmacregs->tx_cfg,
hme_read32(hp, &hp->bigmacregs->tx_cfg) &
~(BIGMAC_TXCFG_FULLDPLX));
-
+ }
+ hme_write32(hp, &hp->bigmacregs->tx_cfg,
+ hme_read32(hp, &hp->bigmacregs->tx_cfg) |
+ BIGMAC_TXCFG_ENABLE);
return 0;
no_response:
return 1;
@@ -1220,8 +1299,8 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Load up the MAC address and random seed. */
HMD(("rseed/macaddr, "));
- /* XXX use something less deterministic... */
- hme_write32(hp, &bregs->rand_seed, 0xbd);
+ /* The docs recommend to use the 10LSB of our MAC here. */
+ hme_write32(hp, &bregs->rand_seed, ((e[5] | e[4]<<8)&0x3ff));
hme_write32(hp, &bregs->mac_addr2, ((e[4] << 8) | e[5]));
hme_write32(hp, &bregs->mac_addr1, ((e[2] << 8) | e[3]));
@@ -2013,12 +2092,13 @@ static void pci_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs
hp->dev->tbusy = 0;
mark_bh(NET_BH);
}
-
+ tx_add_log(hp, TXLOG_ACTION_IRQ, happy_status);
dev->interrupt = 0;
HMD(("done\n"));
}
#endif
+#ifndef __sparc_v9__
static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *) dev_id;
@@ -2062,6 +2142,7 @@ static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *re
dev->interrupt = 0;
HMD(("done\n"));
}
+#endif
static int happy_meal_open(struct device *dev)
{
@@ -2069,6 +2150,7 @@ static int happy_meal_open(struct device *dev)
int res;
HMD(("happy_meal_open: "));
+#ifndef __sparc_v9__
if(sparc_cpu_model == sun4c) {
if(request_irq(dev->irq, &sun4c_happy_meal_interrupt,
SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
@@ -2076,47 +2158,26 @@ static int happy_meal_open(struct device *dev)
printk("happy meal: Can't order irq %d to go.\n", dev->irq);
return -EAGAIN;
}
- }
-#ifdef __sparc_v9__
- else if(sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
+ } else
+#else
#ifdef CONFIG_PCI
- if(hp->happy_flags & HFLAG_PCI) {
- if(request_irq(dev->irq, &pci_happy_meal_interrupt,
- SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
- HMD(("EAGAIN\n"));
- printk("happy_meal(PCI: Can't order irq %d to go.\n",
- dev->irq);
- return -EAGAIN;
- }
- goto v9_done;
- }
-#endif
- dcookie.real_dev_id = dev;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = hp->happy_sbus_dev->my_bus;
- if(request_irq(dev->irq, &happy_meal_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- "HAPPY MEAL", &dcookie)) {
- HMD(("EAGAIN\n"));
- printk("happy_meal(SBUS): Can't order irq %d to go.\n",
- dev->irq);
+ if(hp->happy_flags & HFLAG_PCI) {
+ if(request_irq(dev->irq, &pci_happy_meal_interrupt,
+ SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
+ HMD(("EAGAIN\n"));
+ printk("happy_meal(PCI: Can't order irq %s to go.\n",
+ __irq_itoa(dev->irq));
return -EAGAIN;
}
-#ifdef CONFIG_PCI
- v9_done:
+ } else
#endif
- }
#endif
- else {
- if(request_irq(dev->irq, &happy_meal_interrupt,
- SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
- HMD(("EAGAIN\n"));
- printk("happy meal: Can't order irq %d to go.\n", dev->irq);
- return -EAGAIN;
- }
+ if(request_irq(dev->irq, &happy_meal_interrupt,
+ SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
+ HMD(("EAGAIN\n"));
+ printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+ __irq_itoa(dev->irq));
+ return -EAGAIN;
}
HMD(("Init happy timer\n"));
init_timer(&hp->happy_timer);
@@ -2154,29 +2215,29 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
struct happy_meal *hp = (struct happy_meal *) dev->priv;
int len, entry;
- if(dev->tbusy) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 40) {
- return 1;
- } else {
+ if (tickssofar >= 40) {
printk ("%s: transmit timed out, resetting\n", dev->name);
hp->net_stats.tx_errors++;
+ tx_dump_log();
+ printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+ hme_read32(hp, &hp->gregs->stat),
+ hme_read32(hp, &hp->etxregs->cfg),
+ hme_read32(hp, &hp->bigmacregs->tx_cfg));
happy_meal_init(hp, 0);
dev->tbusy = 0;
dev->trans_start = jiffies;
- return 0;
- }
- }
-
- if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
- printk("happy meal: Transmitter access conflict.\n");
+ } else
+ tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0);
return 1;
}
- if(!TX_BUFFS_AVAIL(hp))
+ if(!TX_BUFFS_AVAIL(hp)) {
+ tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0);
return 1;
-
+ }
len = skb->len;
entry = hp->tx_new;
@@ -2194,6 +2255,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
if(TX_BUFFS_AVAIL(hp))
dev->tbusy = 0;
+ tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
return 0;
}
@@ -2203,29 +2265,32 @@ static int pci_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
struct happy_meal *hp = (struct happy_meal *) dev->priv;
int len, entry;
- if(dev->tbusy) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 40) {
- return 1;
- } else {
+ if (tickssofar >= 40) {
+ unsigned long flags;
+
printk ("%s: transmit timed out, resetting\n", dev->name);
+
+ save_and_cli(flags);
+ tx_dump_log();
+ tx_dump_ring(hp);
+ restore_flags(flags);
+
hp->net_stats.tx_errors++;
happy_meal_init(hp, 0);
dev->tbusy = 0;
dev->trans_start = jiffies;
- return 0;
- }
- }
-
- if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
- printk("happy meal: Transmitter access conflict.\n");
+ } else
+ tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0);
return 1;
}
- if(!TX_BUFFS_AVAIL(hp))
+ if(!TX_BUFFS_AVAIL(hp)) {
+ tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0);
return 1;
-
+ }
len = skb->len;
entry = hp->tx_new;
@@ -2243,6 +2308,7 @@ static int pci_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
if(TX_BUFFS_AVAIL(hp))
dev->tbusy = 0;
+ tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
return 0;
}
#endif
@@ -2510,7 +2576,7 @@ static inline int happy_meal_ether_init(struct device *dev, struct linux_sbus_de
dev->get_stats = &happy_meal_get_stats;
dev->set_multicast_list = &happy_meal_set_multicast;
- dev->irq = sdev->irqs[0].pri;
+ dev->irq = sdev->irqs[0];
dev->dma = 0;
ether_setup(dev);
#ifdef MODULE
@@ -2630,6 +2696,11 @@ __initfunc(int happy_meal_pci_init(struct device *dev, struct pci_dev *pdev))
pdev->devfn,
PCI_COMMAND, pci_command);
+ /* Set the latency timer as well, PROM leaves it at zero. */
+ pcibios_write_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_LATENCY_TIMER, 240);
+
#ifdef MODULE
/* We are home free at this point, link us in to the happy
* module device list.
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 38730b0d7..15b408ece 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -468,9 +468,9 @@ struct happy_meal_txd {
(hp)->tx_old - (hp)->tx_new - 1)
#define RX_OFFSET 2
-#define RX_BUF_ALLOC_SIZE (ETH_FRAME_LEN + RX_OFFSET + (64 * 3))
+#define RX_BUF_ALLOC_SIZE (1546 + RX_OFFSET + 64)
-#define RX_COPY_THRESHOLD 128
+#define RX_COPY_THRESHOLD 256
struct hmeal_init_block {
struct happy_meal_rxd happy_meal_rxd[RX_RING_MAXSIZE];
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 4edbeba69..b0bfeb813 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.74 1998/02/12 07:37:25 davem Exp $
+/* $Id: sunlance.c,v 1.79 1998/06/04 09:54:58 jj Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
@@ -672,39 +672,11 @@ static int lance_open (struct device *dev)
last_dev = dev;
-#ifdef __sparc_v9__
- if (sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = dev;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = lp->sbus;
- if(request_irq(dev->irq, &lance_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- lancestr, &dcookie)) {
- printk ("Lance: Can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
- }
-#else
- if (sparc_cpu_model == sun4d) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = dev;
- dcookie.bus_cookie = (void *)dev->base_addr;
- if(request_irq(dev->irq, &lance_interrupt,
- (SA_SHIRQ | SA_DCOOKIE),
- lancestr, &dcookie)) {
- printk ("Lance: Can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
- } else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
+ if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
lancestr, (void *) dev)) {
- printk ("Lance: Can't get irq %d\n", dev->irq);
+ printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
return -EAGAIN;
}
-#endif
/* Stop the Lance */
ll->rap = LE_CSR0;
@@ -1124,7 +1096,7 @@ no_link_test:
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
- dev->irq = (unsigned char) sdev->irqs [0].pri;
+ dev->irq = sdev->irqs[0];
dev->dma = 0;
ether_setup (dev);
@@ -1166,7 +1138,7 @@ __initfunc(int sparc_lance_probe (struct device *dev))
if (idprom->id_machtype == (SM_SUN4|SM_4_330)) {
memset (&sdev, 0, sizeof(sdev));
sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR;
- sdev.irqs[0].pri = 6;
+ sdev.irqs[0] = 6;
return sparc_lance_init(dev, &sdev, 0, 0);
}
return ENODEV;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index b1b19a3c8..83b95a72a 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -263,7 +263,7 @@ static int qe_init(struct sunqe *qep, int from_irq)
/* Wait a little bit for the link to come up... */
if(!(mregs->phyconfig & MREGS_PHYCONFIG_LTESTDIS)) {
- udelay(5000);
+ mdelay(5);
if(!(mregs->phyconfig & MREGS_PHYCONFIG_LSTAT))
printk("%s: Warning, link state is down.\n", qep->dev->name);
}
@@ -1103,7 +1103,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
qe_devs[i]->hard_start_xmit = qe_start_xmit;
qe_devs[i]->get_stats = qe_get_stats;
qe_devs[i]->set_multicast_list = qe_set_multicast;
- qe_devs[i]->irq = (unsigned char) sdev->irqs[0].pri;
+ qe_devs[i]->irq = sdev->irqs[0];
qe_devs[i]->dma = 0;
ether_setup(qe_devs[i]);
}
@@ -1114,32 +1114,14 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
* for it now.
*/
if(sparc_cpu_model == sun4c) {
- if(request_irq(sdev->irqs[0].pri, &sun4c_qec_interrupt,
+ if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt,
SA_SHIRQ, "QuadEther", (void *) qecp)) {
printk("QuadEther: Can't register QEC master irq handler.\n");
res = EAGAIN;
goto qec_free_devs;
}
- }
-#ifdef __sparc_v9__
- else if(sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = qecp;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = sdev->my_bus;
- if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- "QuadEther", &dcookie)) {
- printk("QuadEther: Can't register QEC master irq handler.\n");
- res = EAGAIN;
- goto qec_free_devs;
- }
- }
-#endif
- else {
- if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
+ } else {
+ if(request_irq(sdev->irqs[0], &qec_interrupt,
SA_SHIRQ, "QuadEther", (void *) qecp)) {
printk("QuadEther: Can't register QEC master irq handler.\n");
res = EAGAIN;
@@ -1241,7 +1223,7 @@ cleanup_module(void)
unregister_netdev(root_qec_dev->qes[i]->dev);
kfree(root_qec_dev->qes[i]);
}
- free_irq(root_qec_dev->qec_sbus_dev->irqs[0].pri, (void *)root_qec_dev);
+ free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev);
kfree(root_qec_dev);
root_qec_dev = next_qec;
}
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index 486e3b3ac..18b52feda 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -309,8 +309,8 @@ struct qe_txd {
(qp)->tx_old - (qp)->tx_new - (TX_RING_SIZE - SUN4C_TX_RING_SIZE))
-#define RX_COPY_THRESHOLD 128
-#define RX_BUF_ALLOC_SIZE (ETH_FRAME_LEN + (64 * 3))
+#define RX_COPY_THRESHOLD 256
+#define RX_BUF_ALLOC_SIZE (1546 + 64)
struct qe_init_block {
struct qe_rxd qe_rxd[RX_RING_MAXSIZE];
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 92d4b9e69..7d4eaa225 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -3,20 +3,23 @@
* Linux ThunderLAN Driver
*
* tlan.c
- * by James Banks, james.banks@caldera.com
+ * by James Banks
*
- * (C) 1997 Caldera, Inc.
+ * (C) 1997-1998 Caldera, Inc.
+ * (C) 1998 James Banks
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
- ** This file is best viewed/edited with tabstop=4 and colums>=132.
+ ** This file is best viewed/edited with columns>=132.
*
** Useful (if not required) reading:
*
* Texas Instruments, ThunderLAN Programmer's Guide,
* TI Literature Number SPWU013A
* available in PDF format from www.ti.com
+ * Level One, LXT901 and LXT970 Data Sheets
+ * available in PDF format from www.level1.com
* National Semiconductor, DP83840A Data Sheet
* available in PDF format from www.national.com
* Microchip Technology, 24C01A/02A/04A Data Sheet
@@ -29,6 +32,7 @@
#include "tlan.h"
+#include <linux/bios32.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
@@ -44,58 +48,111 @@ typedef u32 (TLanIntVectorFunc)( struct device *, u16 );
static struct device *TLanDevices = NULL;
static int TLanDevicesInstalled = 0;
+static int aui = 0;
+static int sa_int = 0;
+static int duplex = 0;
+static int speed = 0;
+
#endif
static int debug = 0;
-static int aui = 0;
+static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
-static int TLanVersionMajor = 0;
-static int TLanVersionMinor = 38;
+static int TLanVersionMajor = 1;
+static int TLanVersionMinor = 0;
-static TLanPciId TLanDeviceList[] = {
+static TLanAdapterEntry TLanAdapterList[] = {
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETELLIGENT_10,
- "Compaq Netelligent 10"
+ "Compaq Netelligent 10 T PCI UTP",
+ TLAN_ADAPTER_ACTIVITY_LED,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETELLIGENT_10_100,
- "Compaq Netelligent 10/100"
+ "Compaq Netelligent 10/100 TX PCI UTP",
+ TLAN_ADAPTER_ACTIVITY_LED,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED,
- "Compaq Integrated NetFlex-3/P"
+ "Compaq Integrated NetFlex-3/P",
+ TLAN_ADAPTER_NONE,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETFLEX_3P,
- "Compaq NetFlex-3/P"
+ "Compaq NetFlex-3/P",
+ TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETFLEX_3P_BNC,
- "Compaq NetFlex-3/P"
+ "Compaq NetFlex-3/P",
+ TLAN_ADAPTER_NONE,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT,
- "Compaq ProLiant Netelligent 10/100"
+ "Compaq Netelligent Integrated 10/100 TX UTP",
+ TLAN_ADAPTER_NONE,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL,
- "Compaq Dual Port Netelligent 10/100"
+ "Compaq Netelligent Dual 10/100 TX PCI UTP",
+ TLAN_ADAPTER_NONE,
+ 0x83
},
{ PCI_VENDOR_ID_COMPAQ,
PCI_DEVICE_ID_DESKPRO_4000_5233MMX,
- "Compaq Deskpro 4000 5233MMX"
+ "Compaq Netelligent 10/100 TX Embedded UTP",
+ TLAN_ADAPTER_NONE,
+ 0x83
+ },
+ { PCI_VENDOR_ID_OLICOM,
+ PCI_DEVICE_ID_OLICOM_OC2183,
+ "Olicom OC-2183/2185",
+ TLAN_ADAPTER_USE_INTERN_10,
+ 0xF8
+ },
+ { PCI_VENDOR_ID_OLICOM,
+ PCI_DEVICE_ID_OLICOM_OC2325,
+ "Olicom OC-2325",
+ TLAN_ADAPTER_UNMANAGED_PHY,
+ 0xF8
+ },
+ { PCI_VENDOR_ID_OLICOM,
+ PCI_DEVICE_ID_OLICOM_OC2326,
+ "Olicom OC-2326",
+ TLAN_ADAPTER_USE_INTERN_10,
+ 0xF8
+ },
+ { PCI_VENDOR_ID_COMPAQ,
+ PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100,
+ "Compaq Netelligent 10/100 TX UTP",
+ TLAN_ADAPTER_ACTIVITY_LED,
+ 0x83
+ },
+ { PCI_VENDOR_ID_COMPAQ,
+ PCI_DEVICE_ID_NETELLIGENT_10_T2,
+ "Compaq Netelligent 10 T/2 PCI UTP/Coax",
+ TLAN_ADAPTER_NONE,
+ 0x83
},
{ 0,
0,
- NULL
+ NULL,
+ 0,
+ 0
} /* End of List */
};
-static int TLan_PciProbe( u8 *, u8 *, int *, u8 *, u32 *, u32 * );
+static int TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * );
static int TLan_Init( struct device * );
static int TLan_Open(struct device *dev);
static int TLan_StartTx(struct sk_buff *, struct device *);
@@ -116,28 +173,37 @@ static u32 TLan_HandleRxEOC( struct device *, u16 );
static void TLan_Timer( unsigned long );
static void TLan_ResetLists( struct device * );
+static void TLan_FreeLists( struct device * );
static void TLan_PrintDio( u16 );
static void TLan_PrintList( TLanList *, char *, int );
static void TLan_ReadAndClearStats( struct device *, int );
-static int TLan_Reset( struct device * );
+static void TLan_ResetAdapter( struct device * );
+static void TLan_FinishReset( struct device * );
static void TLan_SetMac( struct device *, int areg, char *mac );
-static int TLan_PhyNop( struct device * );
static void TLan_PhyPrint( struct device * );
-static void TLan_PhySelect( struct device * );
+static void TLan_PhyDetect( struct device * );
+static void TLan_PhyPowerDown( struct device * );
+static void TLan_PhyPowerUp( struct device * );
+static void TLan_PhyReset( struct device * );
+static void TLan_PhyStartLink( struct device * );
+static void TLan_PhyFinishAutoNeg( struct device * );
+/*
+static int TLan_PhyNop( struct device * );
static int TLan_PhyInternalCheck( struct device * );
static int TLan_PhyInternalService( struct device * );
static int TLan_PhyDp83840aCheck( struct device * );
+*/
-static int TLan_MiiReadReg(u16, u16, u16, u16 *);
+static int TLan_MiiReadReg( struct device *, u16, u16, u16 * );
static void TLan_MiiSendData( u16, u32, unsigned );
-static void TLan_MiiSync(u16);
-static void TLan_MiiWriteReg(u16, u16, u16, u16);
+static void TLan_MiiSync( u16 );
+static void TLan_MiiWriteReg( struct device *, u16, u16, u16 );
static void TLan_EeSendStart( u16 );
static int TLan_EeSendByte( u16, u8, int );
static void TLan_EeReceiveByte( u16, u8 *, int );
-static int TLan_EeReadByte( u16, u8, u8 * );
+static int TLan_EeReadByte( struct device *, u8, u8 * );
static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
@@ -151,6 +217,25 @@ static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
TLan_HandleRxEOC
};
+static inline void
+TLan_SetTimer( struct device *dev, u32 ticks, u32 type )
+{
+ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+
+ cli();
+ if ( priv->timer.function != NULL ) {
+ return;
+ }
+ priv->timer.function = &TLan_Timer;
+ sti();
+
+ priv->timer.data = (unsigned long) dev;
+ priv->timer.expires = jiffies + ticks;
+ priv->timerSetAt = jiffies;
+ priv->timerType = type;
+ add_timer( &priv->timer );
+
+} /* TLan_SetTimer */
/*****************************************************************************
@@ -176,7 +261,7 @@ static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
*
* This function begins the setup of the driver creating a
* pad buffer, finding all TLAN devices (matching
- * TLanDeviceList entries), and creating and initializing a
+ * TLanAdapterList entries), and creating and initializing a
* device structure for each adapter.
*
**************************************************************/
@@ -188,14 +273,14 @@ extern int init_module(void)
struct device *dev;
size_t dev_size;
u8 dfn;
- u32 dl_ix;
+ u32 index;
int failed;
int found;
u32 io_base;
- int irq;
+ u8 irq;
u8 rev;
- printk( "TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n",
+ printk( "TLAN driver, v%d.%d, (C) 1997-8 Caldera, Inc.\n",
TLanVersionMajor,
TLanVersionMinor
);
@@ -211,8 +296,7 @@ extern int init_module(void)
dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo);
- while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) )
- {
+ while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index ) ) ) {
dev = (struct device *) kmalloc( dev_size, GFP_KERNEL );
if ( dev == NULL ) {
printk( "TLAN: Could not allocate memory for device.\n" );
@@ -227,23 +311,37 @@ extern int init_module(void)
dev->irq = irq;
dev->init = TLan_Init;
- priv->pciBus = bus;
- priv->pciDeviceFn = dfn;
- priv->pciRevision = rev;
- priv->pciEntry = dl_ix;
+ priv->adapter = &TLanAdapterList[index];
+ priv->adapterRev = rev;
+ priv->aui = aui;
+ if ( ( duplex != 1 ) && ( duplex != 2 ) ) {
+ duplex = 0;
+ }
+ priv->duplex = duplex;
+ if ( ( speed != 10 ) && ( speed != 100 ) ) {
+ speed = 0;
+ }
+ priv->speed = speed;
+ priv->sa_int = sa_int;
+ priv->debug = debug;
ether_setup( dev );
failed = register_netdev( dev );
if ( failed ) {
- printk( "TLAN: Could not register network device. Freeing struct.\n" );
+ printk( "TLAN: Could not register device.\n" );
kfree( dev );
} else {
priv->nextDevice = TLanDevices;
TLanDevices = dev;
TLanDevicesInstalled++;
- printk("TLAN: %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName );
+ printk("TLAN: %s irq=%2d io=%04x, %s, Rev. %d\n",
+ dev->name,
+ (int) dev->irq,
+ (int) dev->base_addr,
+ priv->adapter->deviceLabel,
+ priv->adapterRev );
}
}
@@ -276,11 +374,12 @@ extern void cleanup_module(void)
struct device *dev;
TLanPrivateInfo *priv;
- while (TLanDevicesInstalled) {
+ while ( TLanDevicesInstalled ) {
dev = TLanDevices;
priv = (TLanPrivateInfo *) dev->priv;
- if ( priv->dmaStorage )
+ if ( priv->dmaStorage ) {
kfree( priv->dmaStorage );
+ }
release_region( dev->base_addr, 0x10 );
unregister_netdev( dev );
TLanDevices = priv->nextDevice;
@@ -315,54 +414,79 @@ extern void cleanup_module(void)
extern int tlan_probe( struct device *dev )
{
+ TLanPrivateInfo *priv;
static int pad_allocated = 0;
int found;
- TLanPrivateInfo *priv;
- u8 bus, dfn, rev;
- int irq;
- u32 io_base, dl_ix;
-
- found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix );
- if ( found ) {
- dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
- if ( dev->priv == NULL ) {
- printk( "TLAN: Could not allocate memory for device.\n" );
+ u8 bus, dfn, irq, rev;
+ u32 io_base, index;
+
+ found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index );
+
+ if ( ! found ) {
+ return -ENODEV;
+ }
+
+ dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
+
+ if ( dev->priv == NULL ) {
+ printk( "TLAN: Could not allocate memory for device.\n" );
+ return -ENOMEM;
+ }
+
+ memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
+
+ if ( ! pad_allocated ) {
+ TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE,
+// ( GFP_KERNEL | GFP_DMA )
+ ( GFP_KERNEL )
+ );
+ if ( TLanPadBuffer == NULL ) {
+ printk( "TLAN: Could not allocate memory for padding.\n" );
+ kfree( dev->priv );
+ return -ENOMEM;
+ } else {
+ pad_allocated = 1;
+ memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
}
- memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
- priv = (TLanPrivateInfo *) dev->priv;
+ }
- dev->name = priv->devName;
- strcpy( priv->devName, " " );
+ priv = (TLanPrivateInfo *) dev->priv;
- dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
+ dev->name = priv->devName;
+ strcpy( priv->devName, " " );
- dev->base_addr = io_base;
- dev->irq = irq;
+ dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
- priv->pciBus = bus;
- priv->pciDeviceFn = dfn;
- priv->pciRevision = rev;
- priv->pciEntry = dl_ix;
+ dev->base_addr = io_base;
+ dev->irq = irq;
- if ( ! pad_allocated ) {
- TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA );
- if ( TLanPadBuffer == NULL ) {
- printk( "TLAN: Could not allocate memory for pad buffer.\n" );
- } else {
- pad_allocated = 1;
- memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
- }
- }
- printk("TLAN %d.%d: %s irq=%2d io=%04x, %s\n",TLanVersionMajor,
- TLanVersionMinor,
- dev->name,
- (int) irq,
- io_base,
- TLanDeviceList[dl_ix].deviceName );
- TLan_Init( dev );
+
+ priv->adapter = &TLanAdapterList[index];
+ priv->adapterRev = rev;
+ priv->aui = dev->mem_start & 0x01;
+ priv->duplex = ( ( dev->mem_start & 0x0C ) == 0x0C ) ? 0 : ( dev->mem_start & 0x0C ) >> 2;
+ priv->speed = ( ( dev->mem_start & 0x30 ) == 0x30 ) ? 0 : ( dev->mem_start & 0x30 ) >> 4;
+ if ( priv->speed == 0x1 ) {
+ priv->speed = TLAN_SPEED_10;
+ } else if ( priv->speed == 0x2 ) {
+ priv->speed = TLAN_SPEED_100;
}
+ priv->sa_int = dev->mem_start & 0x02;
+ priv->debug = dev->mem_end;
+
+
+ printk("TLAN %d.%d: %s irq=%2d io=%04x, %s, Rev. %d\n",
+ TLanVersionMajor,
+ TLanVersionMinor,
+ dev->name,
+ (int) irq,
+ io_base,
+ priv->adapter->deviceLabel,
+ priv->adapterRev );
+
+ TLan_Init( dev );
- return ( ( found ) ? 0 : -ENODEV );
+ return 0;
} /* tlan_probe */
@@ -390,7 +514,7 @@ extern int tlan_probe( struct device *dev )
* of the adapter.
*
* This function searches for an adapter with PCI vendor
- * and device IDs matching those in the TLanDeviceList.
+ * and device IDs matching those in the TLanAdapterList.
* The function 'remembers' the last device it found,
* and so finds a new device (if anymore are to be found)
* each time the function is called. It then looks up
@@ -398,7 +522,7 @@ extern int tlan_probe( struct device *dev )
*
**************************************************************/
-int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, int *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
+int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
{
static int dl_index = 0;
static int pci_index = 0;
@@ -409,43 +533,43 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, int *pci_irq, u8 *pci_rev, u32 *pci
int reg;
- if ( ! pci_present() ) {
+ if ( ! pcibios_present() ) {
printk( "TLAN: PCI Bios not present.\n" );
return 0;
}
- for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) {
+ for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) {
not_found = pcibios_find_device(
- TLanDeviceList[dl_index].vendorId,
- TLanDeviceList[dl_index].deviceId,
+ TLanAdapterList[dl_index].vendorId,
+ TLanAdapterList[dl_index].deviceId,
pci_index,
pci_bus,
pci_dfn
);
if ( ! not_found ) {
- struct pci_dev *pdev = pci_find_slot(*pci_bus, *pci_dfn);
TLAN_DBG(
TLAN_DEBUG_GNRL,
"TLAN: found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
- TLanDeviceList[dl_index].vendorId,
- TLanDeviceList[dl_index].deviceId
+ TLanAdapterList[dl_index].vendorId,
+ TLanAdapterList[dl_index].deviceId
);
- pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev);
- *pci_irq = pdev->irq;
- pci_read_config_word ( pdev, PCI_COMMAND, &pci_command);
- pci_read_config_byte ( pdev, PCI_LATENCY_TIMER, &pci_latency);
+ pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev);
+ pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq);
+ pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command);
+ pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base);
+ pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 0x10) {
- pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 0xff);
+ pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff);
TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Setting latency timer to max.\n");
}
- for ( reg = 0; reg <= 5; reg ++ ) {
- *pci_io_base = pdev->base_address[reg];
+ for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) {
+ pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base);
if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) {
*pci_io_base &= PCI_BASE_ADDRESS_IO_MASK;
TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base);
@@ -458,8 +582,9 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, int *pci_irq, u8 *pci_rev, u32 *pci
if ( *pci_io_base == 0 )
printk("TLAN: IO mapping not available, ignoring device.\n");
- if (pci_command & PCI_COMMAND_MASTER) {
- TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Bus mastering is active.\n");
+ if ( ! ( pci_command & PCI_COMMAND_MASTER ) ) {
+ pcibios_write_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, pci_command | PCI_COMMAND_MASTER );
+ printk( "TLAN: Activating PCI bus mastering for this device.\n" );
}
pci_index++;
@@ -500,9 +625,9 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, int *pci_irq, u8 *pci_rev, u32 *pci
int TLan_Init( struct device *dev )
{
- int dma_size;
- int err;
- int i;
+ int dma_size;
+ int err;
+ int i;
TLanPrivateInfo *priv;
priv = (TLanPrivateInfo *) dev->priv;
@@ -517,8 +642,14 @@ int TLan_Init( struct device *dev )
}
request_region( dev->base_addr, 0x10, TLanSignature );
- dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+ if ( bbuf ) {
+ dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
* ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
+ } else {
+ dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+ * ( sizeof(TLanList) );
+ }
+
priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA );
if ( priv->dmaStorage == NULL ) {
printk( "TLAN: Could not allocate lists and buffers for %s.\n",
@@ -529,19 +660,24 @@ int TLan_Init( struct device *dev )
priv->rxList = (TLanList *)
( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
- priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
- priv->txBuffer = priv->rxBuffer
- + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+
+ if ( bbuf ) {
+ priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
+ priv->txBuffer = priv->rxBuffer
+ + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+ }
err = 0;
for ( i = 0; i < 6 ; i++ )
- err |= TLan_EeReadByte( dev->base_addr,
- (u8) 0x83 + i,
+ err |= TLan_EeReadByte( dev,
+ (u8) priv->adapter->addrOfs + i,
(u8 *) &dev->dev_addr[i] );
- if ( err )
+ if ( err ) {
printk( "TLAN: %s: Error reading MAC from eeprom: %d\n",
dev->name,
err );
+ }
+
dev->addr_len = 6;
dev->open = &TLan_Open;
@@ -550,12 +686,6 @@ int TLan_Init( struct device *dev )
dev->get_stats = &TLan_GetStats;
dev->set_multicast_list = &TLan_SetMulticastList;
-#ifndef MODULE
-
- aui = dev->mem_start & 0x01;
- debug = dev->mem_end;
-
-#endif /* MODULE */
return 0;
@@ -583,16 +713,21 @@ int TLan_Init( struct device *dev )
int TLan_Open( struct device *dev )
{
- int err;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ int err;
priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
- err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev);
+ if ( priv->sa_int ) {
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Using SA_INTERRUPT\n" );
+ err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ | SA_INTERRUPT, TLanSignature, dev );
+ } else {
+ err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
+ }
if ( err ) {
- printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name , dev->irq );
+ printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
return -EAGAIN;
}
-
+
MOD_INC_USE_COUNT;
dev->tbusy = 0;
@@ -604,27 +739,9 @@ int TLan_Open( struct device *dev )
*/
TLan_ResetLists( dev );
TLan_ReadAndClearStats( dev, TLAN_IGNORE );
- TLan_Reset( dev );
- TLan_Reset( dev );
- TLan_SetMac( dev, 0, dev->dev_addr );
- outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
- if ( debug >= 1 )
- outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
-
- init_timer( &priv->timer );
- priv->timer.data = (unsigned long) dev;
- priv->timer.function = &TLan_Timer;
- if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
- priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
- priv->timerSetAt = jiffies;
- priv->timerType = TLAN_TIMER_LINK;
- add_timer( &priv->timer );
- } else {
- outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
- outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
- }
+ TLan_ResetAdapter( dev );
- TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s opened. Revision = %x\n", dev->name, priv->tlanRev );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev );
return 0;
@@ -657,9 +774,9 @@ int TLan_Open( struct device *dev )
int TLan_StartTx( struct sk_buff *skb, struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- TLanList *tail_list;
- u8 *tail_buffer;
- int pad;
+ TLanList *tail_list;
+ u8 *tail_buffer;
+ int pad;
if ( ! priv->phyOnline ) {
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name );
@@ -668,16 +785,26 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
}
tail_list = priv->txList + priv->txTail;
+
if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
dev->tbusy = 1;
priv->txBusyCount++;
return 1;
}
+
tail_list->forward = 0;
- tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
- memcpy( tail_buffer, skb->data, skb->len );
+
+ if ( bbuf ) {
+ tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
+ memcpy( tail_buffer, skb->data, skb->len );
+ } else {
+ tail_list->buffer[0].address = virt_to_bus( skb->data );
+ tail_list->buffer[9].address = (u32) skb;
+ }
+
pad = TLAN_MIN_FRAME_SIZE - skb->len;
+
if ( pad > 0 ) {
tail_list->frameSize = (u16) skb->len + pad;
tail_list->buffer[0].count = (u32) skb->len;
@@ -689,7 +816,7 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
tail_list->buffer[1].count = 0;
tail_list->buffer[1].address = 0;
}
- /* are we transferring? */
+
cli();
tail_list->cStat = TLAN_CSTAT_READY;
if ( ! priv->txInProgress ) {
@@ -700,17 +827,19 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
} else {
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail );
- if ( priv->txTail == 0 )
+ if ( priv->txTail == 0 ) {
( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );
- else
+ } else {
( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );
+ }
}
sti();
- priv->txTail++;
- if ( priv->txTail >= TLAN_NUM_TX_LISTS )
- priv->txTail = 0;
- dev_kfree_skb( skb );
+ CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
+
+ if ( bbuf ) {
+ dev_kfree_skb( skb );
+ }
dev->trans_start = jiffies;
return 0;
@@ -743,35 +872,34 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- u32 ack;
+ u32 ack;
struct device *dev;
- u32 host_cmd;
- u16 host_int;
- int type;
+ u32 host_cmd;
+ u16 host_int;
+ int type;
dev = (struct device *) dev_id;
- if ( dev->interrupt )
- printk( "TLAN: Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
- dev->interrupt++;
-
cli();
+ if ( dev->interrupt ) {
+ printk( "TLAN: Re-entering interrupt handler for %s: %ld.\n" , dev->name, dev->interrupt );
+ }
+ dev->interrupt++;
host_int = inw( dev->base_addr + TLAN_HOST_INT );
- outw( host_int, dev->base_addr + TLAN_HOST_INT ); /* Deactivate Ints */
+ outw( host_int, dev->base_addr + TLAN_HOST_INT );
type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
ack = TLanIntVector[type]( dev, host_int );
- sti();
-
if ( ack ) {
host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
}
dev->interrupt--;
+ sti();
} /* TLan_HandleInterrupts */
@@ -802,10 +930,11 @@ int TLan_Close(struct device *dev)
TLan_ReadAndClearStats( dev, TLAN_RECORD );
outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
- if ( priv->timerSetAt != 0 )
+ if ( priv->timer.function != NULL )
del_timer( &priv->timer );
free_irq( dev->irq, dev );
- TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s closed.\n", dev->name );
+ TLan_FreeLists( dev );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s closed.\n", dev->name );
MOD_DEC_USE_COUNT;
@@ -882,11 +1011,11 @@ struct net_device_stats *TLan_GetStats( struct device *dev )
void TLan_SetMulticastList( struct device *dev )
{
struct dev_mc_list *dmi = dev->mc_list;
- u32 hash1 = 0;
- u32 hash2 = 0;
- int i;
- u32 offset;
- u8 tmp;
+ u32 hash1 = 0;
+ u32 hash2 = 0;
+ int i;
+ u32 offset;
+ u8 tmp;
if ( dev->flags & IFF_PROMISC ) {
tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
@@ -989,19 +1118,24 @@ u32 TLan_HandleInvalid( struct device *dev, u16 host_int )
u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- int eoc = 0;
- TLanList *head_list;
- u32 ack = 1;
+ int eoc = 0;
+ TLanList *head_list;
+ u32 ack = 1;
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
host_int = 0;
head_list = priv->txList + priv->txHead;
+
+ if ( ! bbuf ) {
+ dev_kfree_skb( (struct sk_buff *) head_list->buffer[9].address );
+ head_list->buffer[9].address = 0;
+ }
+
if ( head_list->cStat & TLAN_CSTAT_EOC )
eoc = 1;
if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
printk( "TLAN: Received interrupt for uncompleted TX frame.\n" );
}
- /* printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); */
#if LINUX_KERNEL_VERSION > 0x20100
priv->stats->tx_bytes += head_list->frameSize;
@@ -1009,9 +1143,7 @@ u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
head_list->cStat = TLAN_CSTAT_UNUSED;
dev->tbusy = 0;
- priv->txHead++;
- if ( priv->txHead >= TLAN_NUM_TX_LISTS )
- priv->txHead = 0;
+ CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
if ( eoc ) {
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
head_list = priv->txList + priv->txHead;
@@ -1022,17 +1154,13 @@ u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
priv->txInProgress = 0;
}
}
- TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
- if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
- if ( priv->timerSetAt == 0 ) {
- /* printk("TxEOF Starting timer...\n"); */
- priv->timerSetAt = jiffies;
- priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
- priv->timerType = TLAN_TIMER_ACT;
- add_timer( &priv->timer );
- } else if ( priv->timerType == TLAN_TIMER_ACT ) {
+
+ if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+ if ( priv->timer.function == NULL ) {
+ TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+ } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
priv->timerSetAt = jiffies;
- /* printk("TxEOF continuing timer...\n"); */
}
}
@@ -1112,11 +1240,14 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
host_int = 0;
head_list = priv->rxList + priv->rxHead;
tail_list = priv->rxList + priv->rxTail;
- if ( head_list->cStat & TLAN_CSTAT_EOC )
+
+ if ( head_list->cStat & TLAN_CSTAT_EOC ) {
eoc = 1;
+ }
+
if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
printk( "TLAN: Received interrupt for uncompleted RX frame.\n" );
- } else {
+ } else if ( bbuf ) {
skb = dev_alloc_skb( head_list->frameSize + 7 );
if ( skb == NULL ) {
printk( "TLAN: Couldn't allocate memory for received data.\n" );
@@ -1125,7 +1256,6 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
skb->dev = dev;
skb_reserve( skb, 2 );
t = (void *) skb_put( skb, head_list->frameSize );
- /* printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); */
#if LINUX_KERNEL_VERSION > 0x20100
priv->stats->rx_bytes += head_list->frameSize;
@@ -1135,17 +1265,39 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
}
+ } else {
+ skb = (struct sk_buff *) head_list->buffer[9].address;
+ head_list->buffer[9].address = 0;
+ skb_trim( skb, head_list->frameSize );
+
+#if LINUX_KERNEL_VERSION > 0x20100
+ priv->stats->rx_bytes += head_list->frameSize;
+#endif
+
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
+
+ skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+ if ( skb == NULL ) {
+ printk( "TLAN: Couldn't allocate memory for received data.\n" );
+ /* If this ever happened it would be a problem */
+ } else {
+ skb->dev = dev;
+ skb_reserve( skb, 2 );
+ t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
+ head_list->buffer[0].address = virt_to_bus( t );
+ head_list->buffer[9].address = (u32) skb;
+ }
}
+
head_list->forward = 0;
head_list->frameSize = TLAN_MAX_FRAME_SIZE;
head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
tail_list->forward = virt_to_bus( head_list );
- priv->rxHead++;
- if ( priv->rxHead >= TLAN_NUM_RX_LISTS )
- priv->rxHead = 0;
- priv->rxTail++;
- if ( priv->rxTail >= TLAN_NUM_RX_LISTS )
- priv->rxTail = 0;
+
+ CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );
+ CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );
+
if ( eoc ) {
TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
head_list = priv->rxList + priv->rxHead;
@@ -1153,19 +1305,16 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
ack |= TLAN_HC_GO | TLAN_HC_RT;
priv->rxEocCount++;
}
- TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
- if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
- if ( priv->timerSetAt == 0 ) {
- /* printk("RxEOF Starting timer...\n"); */
- priv->timerSetAt = jiffies;
- priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
- priv->timerType = TLAN_TIMER_ACT;
- add_timer( &priv->timer );
- } else if ( priv->timerType == TLAN_TIMER_ACT ) {
- /* printk("RxEOF tarting continuing timer...\n"); */
+
+ if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+ if ( priv->timer.function == NULL ) {
+ TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+ } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
priv->timerSetAt = jiffies;
}
}
+
dev->last_rx = jiffies;
return ack;
@@ -1195,7 +1344,7 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
u32 TLan_HandleDummy( struct device *dev, u16 host_int )
{
host_int = 0;
- printk( "TLAN: Dummy interrupt on %s.\n", dev->name );
+ printk( "TLAN: Test interrupt on %s.\n", dev->name );
return 1;
} /* TLan_HandleDummy */
@@ -1270,45 +1419,49 @@ u32 TLan_HandleTxEOC( struct device *dev, u16 host_int )
u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
{
- u32 ack;
- u32 error;
- u8 net_sts;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ u32 ack;
+ u32 error;
+ u8 net_sts;
+ u32 phy;
+ u16 tlphy_ctl;
+ u16 tlphy_sts;
ack = 1;
if ( host_int & TLAN_HI_IV_MASK ) {
error = inl( dev->base_addr + TLAN_CH_PARM );
- printk( "TLAN: Adaptor Check on device %s err = 0x%x\n", dev->name, error );
+ printk( "TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error );
TLan_ReadAndClearStats( dev, TLAN_RECORD );
outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
+ TLan_FreeLists( dev );
TLan_ResetLists( dev );
- TLan_Reset( dev );
+ TLan_ResetAdapter( dev );
dev->tbusy = 0;
- TLan_SetMac( dev, 0, dev->dev_addr );
- if ( priv->timerType == 0 ) {
- if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
- priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
- priv->timerSetAt = jiffies;
- priv->timerType = TLAN_TIMER_LINK;
- add_timer( &priv->timer );
- } else {
- /*printk( " RX GO---->\n" ); */
- outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
- outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
- }
- }
ack = 0;
} else {
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Status Check\n", dev->name );
+ phy = priv->phy[priv->phyNum];
+
net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
- if ( net_sts )
+ if ( net_sts ) {
TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
- if ( net_sts & TLAN_NET_STS_MIRQ ) {
- (*priv->phyService)( dev );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Net_Sts = %x\n", dev->name, (unsigned) net_sts );
+ }
+ if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) {
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
+ if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+ tlphy_ctl |= TLAN_TC_SWAPOL;
+ TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
+ } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+ tlphy_ctl &= ~TLAN_TC_SWAPOL;
+ TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
+ }
+
if (debug) {
TLan_PhyPrint( dev );
}
}
- TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
}
return ack;
@@ -1341,8 +1494,8 @@ u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- TLanList *head_list;
- u32 ack = 1;
+ TLanList *head_list;
+ u32 ack = 1;
host_int = 0;
if ( priv->tlanRev < 0x30 ) {
@@ -1402,34 +1555,44 @@ u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
void TLan_Timer( unsigned long data )
{
struct device *dev = (struct device *) data;
- u16 gen_sts;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ u32 elapsed;
- /* printk( "TLAN: %s Entered Timer, type = %d\n", dev->name, priv->timerType ); */
+ priv->timer.function = NULL;
switch ( priv->timerType ) {
- case TLAN_TIMER_LINK:
- TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts );
- if ( gen_sts & MII_GS_LINK ) {
- priv->phyOnline = 1;
- outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
- outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
- priv->timerSetAt = 0;
- priv->timerType = 0;
- } else {
- priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 );
- add_timer( &priv->timer );
- }
+ case TLAN_TIMER_PHY_PDOWN:
+ TLan_PhyPowerDown( dev );
break;
- case TLAN_TIMER_ACT:
- if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) {
- TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
- priv->timerSetAt = 0;
- priv->timerType = 0;
- } else {
- priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
- add_timer( &priv->timer );
+ case TLAN_TIMER_PHY_PUP:
+ TLan_PhyPowerUp( dev );
+ break;
+ case TLAN_TIMER_PHY_RESET:
+ TLan_PhyReset( dev );
+ break;
+ case TLAN_TIMER_PHY_START_LINK:
+ TLan_PhyStartLink( dev );
+ break;
+ case TLAN_TIMER_PHY_FINISH_AN:
+ TLan_PhyFinishAutoNeg( dev );
+ break;
+ case TLAN_TIMER_FINISH_RESET:
+ TLan_FinishReset( dev );
+ break;
+ case TLAN_TIMER_ACTIVITY:
+ cli();
+ if ( priv->timer.function == NULL ) {
+ elapsed = jiffies - priv->timerSetAt;
+ if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+ } else {
+ priv->timer.function = &TLan_Timer;
+ priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+ sti();
+ add_timer( &priv->timer );
+ }
}
+ sti();
break;
default:
break;
@@ -1468,13 +1631,19 @@ void TLan_ResetLists( struct device *dev )
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
int i;
TLanList *list;
+ struct sk_buff *skb;
+ void *t = NULL;
priv->txHead = 0;
priv->txTail = 0;
for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
list = priv->txList + i;
list->cStat = TLAN_CSTAT_UNUSED;
- list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+ if ( bbuf ) {
+ list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+ } else {
+ list->buffer[0].address = 0;
+ }
list->buffer[2].count = 0;
list->buffer[2].address = 0;
}
@@ -1486,7 +1655,21 @@ void TLan_ResetLists( struct device *dev )
list->cStat = TLAN_CSTAT_READY;
list->frameSize = TLAN_MAX_FRAME_SIZE;
list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
- list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+ if ( bbuf ) {
+ list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+ } else {
+ skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+ if ( skb == NULL ) {
+ printk( "TLAN: Couldn't allocate memory for received data.\n" );
+ /* If this ever happened it would be a problem */
+ } else {
+ skb->dev = dev;
+ skb_reserve( skb, 2 );
+ t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
+ }
+ list->buffer[0].address = virt_to_bus( t );
+ list->buffer[9].address = (u32) skb;
+ }
list->buffer[1].count = 0;
list->buffer[1].address = 0;
if ( i < TLAN_NUM_RX_LISTS - 1 )
@@ -1498,6 +1681,36 @@ void TLan_ResetLists( struct device *dev )
} /* TLan_ResetLists */
+void TLan_FreeLists( struct device *dev )
+{
+ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ int i;
+ TLanList *list;
+ struct sk_buff *skb;
+
+ if ( ! bbuf ) {
+ for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
+ list = priv->txList + i;
+ skb = (struct sk_buff *) list->buffer[9].address;
+ if ( skb ) {
+ dev_kfree_skb( skb );
+ list->buffer[9].address = 0;
+ }
+ }
+
+ for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
+ list = priv->rxList + i;
+ skb = (struct sk_buff *) list->buffer[9].address;
+ if ( skb ) {
+ dev_kfree_skb( skb );
+ list->buffer[9].address = 0;
+ }
+ }
+ }
+
+} /* TLan_FreeLists */
+
+
/***************************************************************
@@ -1588,11 +1801,11 @@ void TLan_PrintList( TLanList *list, char *type, int num)
void TLan_ReadAndClearStats( struct device *dev, int record )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- u32 tx_good, tx_under;
- u32 rx_good, rx_over;
- u32 def_tx, crc, code;
- u32 multi_col, single_col;
- u32 excess_col, late_col, loss;
+ u32 tx_good, tx_under;
+ u32 rx_good, rx_over;
+ u32 def_tx, crc, code;
+ u32 multi_col, single_col;
+ u32 excess_col, late_col, loss;
outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR );
tx_good = inb( dev->base_addr + TLAN_DIO_DATA );
@@ -1660,7 +1873,8 @@ void TLan_ReadAndClearStats( struct device *dev, int record )
*
**************************************************************/
-int TLan_Reset( struct device *dev )
+void
+TLan_ResetAdapter( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
int i;
@@ -1668,11 +1882,14 @@ int TLan_Reset( struct device *dev )
u32 data;
u8 data8;
+ priv->tlanFullDuplex = FALSE;
/* 1. Assert reset bit. */
data = inl(dev->base_addr + TLAN_HOST_CMD);
data |= TLAN_HC_AD_RST;
outl(data, dev->base_addr + TLAN_HOST_CMD);
+
+ udelay(1000);
/* 2. Turn off interrupts. ( Probably isn't necessary ) */
@@ -1708,37 +1925,97 @@ int TLan_Reset( struct device *dev )
data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 );
}
- TLan_PhySelect( dev );
+ TLan_PhyDetect( dev );
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
- if ( priv->phyFlags & TLAN_PHY_BIT_RATE ) {
+ if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) {
data |= TLAN_NET_CFG_BIT;
- if ( aui == 1 ) {
+ if ( priv->aui == 1 ) {
TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a );
+ } else if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+ TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 );
+ priv->tlanFullDuplex = TRUE;
} else {
TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
}
}
- if ( priv->phyFlags & TLAN_PHY_INTERNAL ) {
+ if ( priv->phyNum == 0 ) {
data |= TLAN_NET_CFG_PHY_EN;
}
TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );
- (*priv->phyCheck)( dev );
- data8 = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
- TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data8 );
- data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
- if ( priv->phyFlags & TLAN_PHY_INTS ) {
- data8 |= TLAN_NET_MASK_MASK7;
- }
- TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 );
+
+ if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
+ TLan_FinishReset( dev );
+ } else {
+ TLan_PhyPowerDown( dev );
+ }
+
+} /* TLan_ResetAdapter */
+
+
+
+
+void
+TLan_FinishReset( struct device *dev )
+{
+ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ u8 data;
+ u32 phy;
+ u8 sio;
+ u16 status;
+ u16 tlphy_ctl;
+
+ phy = priv->phy[priv->phyNum];
+
+ data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
+ if ( priv->tlanFullDuplex ) {
+ data |= TLAN_NET_CMD_DUPLEX;
+ }
+ TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data );
+ data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
+ if ( priv->phyNum == 0 ) {
+ data |= TLAN_NET_MASK_MASK7;
+ }
+ TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data );
TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE );
- if ( priv->phyFlags & TLAN_PHY_UNMANAGED ) {
- priv->phyOnline = 1;
+ if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
+ status = MII_GS_LINK;
+ printk( "TLAN: %s: Link forced.\n", dev->name );
+ } else {
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+ udelay( 1000 );
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+ if ( status & MII_GS_LINK ) {
+ printk( "TLAN: %s: Link active.\n", dev->name );
+ TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+ }
}
- return 0;
+ if ( priv->phyNum == 0 ) {
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
+ tlphy_ctl |= TLAN_TC_INTEN;
+ TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl );
+ sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
+ sio |= TLAN_NET_SIO_MINTEN;
+ TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
+ }
+
+ if ( status & MII_GS_LINK ) {
+ TLan_SetMac( dev, 0, dev->dev_addr );
+ priv->phyOnline = 1;
+ outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+ if ( debug >= 1 ) {
+ outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+ }
+ outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+ outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+ } else {
+ printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name );
+ TLan_SetTimer( dev, 1000, TLAN_TIMER_FINISH_RESET );
+ return;
+ }
-} /* TLan_Reset */
+} /* TLan_FinishReset */
@@ -1788,56 +2065,10 @@ void TLan_SetMac( struct device *dev, int areg, char *mac )
ThunderLAN Driver PHY Layer Routines
- The TLAN chip can drive any number of PHYs (physical devices). Rather
- than having lots of 'if' or '#ifdef' statements, I have created a
- second driver layer for the PHYs. Each PHY can be identified from its
- id in registers 2 and 3, and can be given a Check and Service routine
- that will be called when the adapter is reset and when the adapter
- receives a Network Status interrupt, respectively.
-
******************************************************************************
*****************************************************************************/
-static TLanPhyIdEntry TLanPhyIdTable[] = {
- { 0x4000,
- 0x5014,
- &TLan_PhyInternalCheck,
- &TLan_PhyInternalService,
- TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
- { 0x4000,
- 0x5015,
- &TLan_PhyInternalCheck,
- &TLan_PhyInternalService,
- TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
- { 0x4000,
- 0x5016,
- &TLan_PhyInternalCheck,
- &TLan_PhyInternalService,
- TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
- { 0x2000,
- 0x5C00,
- &TLan_PhyDp83840aCheck,
- &TLan_PhyNop,
- TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
- { 0x2000,
- 0x5C01,
- &TLan_PhyDp83840aCheck,
- &TLan_PhyNop,
- TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
- { 0x7810,
- 0x0000,
- &TLan_PhyDp83840aCheck,
- &TLan_PhyNop,
- TLAN_PHY_AUTONEG },
- { 0x0000,
- 0x0000,
- NULL,
- NULL,
- 0
- }
- };
-
/*********************************************************************
* TLan_PhyPrint
@@ -1845,10 +2076,10 @@ static TLanPhyIdEntry TLanPhyIdTable[] = {
* Returns:
* Nothing
* Parms:
- * dev A pointer to the device structure of the adapter
- * which the desired PHY is located.
+ * dev A pointer to the device structure of the
+ * TLAN device having the PHYs to be detailed.
*
- * This function prints the registers a PHY.
+ * This function prints the registers a PHY (aka tranceiver).
*
********************************************************************/
@@ -1856,30 +2087,27 @@ void TLan_PhyPrint( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
u16 i, data0, data1, data2, data3, phy;
- u32 io;
- phy = priv->phyAddr;
- io = dev->base_addr;
+ phy = priv->phy[priv->phyNum];
- if ( ( phy > 0 ) && ( phy <= TLAN_PHY_MAX_ADDR ) ) {
+ if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
+ printk( "TLAN: Device %s, Unmanaged PHY.\n", dev->name );
+ } else if ( phy <= TLAN_PHY_MAX_ADDR ) {
printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy );
printk( "TLAN: Off. +0 +1 +2 +3 \n" );
for ( i = 0; i < 0x20; i+= 4 ) {
printk( "TLAN: 0x%02x", i );
- TLan_MiiReadReg( io, phy, i, &data0 );
+ TLan_MiiReadReg( dev, phy, i, &data0 );
printk( " 0x%04hx", data0 );
- TLan_MiiReadReg( io, phy, i + 1, &data1 );
+ TLan_MiiReadReg( dev, phy, i + 1, &data1 );
printk( " 0x%04hx", data1 );
- TLan_MiiReadReg( io, phy, i + 2, &data2 );
+ TLan_MiiReadReg( dev, phy, i + 2, &data2 );
printk( " 0x%04hx", data2 );
- TLan_MiiReadReg( io, phy, i + 3, &data3 );
+ TLan_MiiReadReg( dev, phy, i + 3, &data3 );
printk( " 0x%04hx\n", data3 );
}
} else {
- printk( "TLAN: Device %s, PHY 0x%02x (Unmanaged/Unknown).\n",
- dev->name,
- phy
- );
+ printk( "TLAN: Device %s, Invalid PHY.\n", dev->name );
}
} /* TLan_PhyPrint */
@@ -1888,7 +2116,7 @@ void TLan_PhyPrint( struct device *dev )
/*********************************************************************
- * TLan_PhySelect
+ * TLan_PhyDetect
*
* Returns:
* Nothing
@@ -1896,352 +2124,271 @@ void TLan_PhyPrint( struct device *dev )
* dev A pointer to the device structure of the adapter
* for which the PHY needs determined.
*
- * This function decides which PHY amoung those attached to the
- * TLAN chip is to be used. The TLAN chip can be attached to
- * multiple PHYs, and the driver needs to decide which one to
- * talk to. Currently this routine picks the PHY with the lowest
- * address as the internal PHY address is 0x1F, the highest
- * possible. This strategy assumes that there can be only one
- * other PHY, and, if it exists, it is the one to be used. If
- * token ring PHYs are ever supported, this routine will become
- * a little more interesting...
+ * So far I've found that adapters which have external PHYs
+ * may also use the internal PHY for part of the functionality.
+ * (eg, AUI/Thinnet). This function finds out if this TLAN
+ * chip has an internal PHY, and then finds the first external
+ * PHY (starting from address 0) if it exists).
*
********************************************************************/
-void TLan_PhySelect( struct device *dev )
+void TLan_PhyDetect( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- int phy;
- int entry;
- u16 id_hi[TLAN_PHY_MAX_ADDR + 1];
- u16 id_lo[TLAN_PHY_MAX_ADDR + 1];
- u16 hi;
- u16 lo;
- u16 vendor;
- u16 device;
-
- priv->phyCheck = &TLan_PhyNop; /* Make sure these aren't ever NULL */
- priv->phyService = &TLan_PhyNop;
-
- vendor = TLanDeviceList[priv->pciEntry].vendorId;
- device = TLanDeviceList[priv->pciEntry].deviceId;
-
- /*
- * This is a bit uglier than I'd like, but the 0xF130 device must
- * NOT be assigned a valid PHY as it uses an unmanaged, bit-rate
- * PHY. It is simplest just to use another goto, rather than
- * nesting the two for loops in the if statement.
- */
- if ( ( vendor == PCI_VENDOR_ID_COMPAQ ) &&
- ( device == PCI_DEVICE_ID_NETFLEX_3P ) ) {
- entry = 0;
- phy = 0;
- goto FINISH;
+ u16 control;
+ u16 hi;
+ u16 lo;
+ u32 phy;
+
+ if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
+ priv->phyNum = 0xFFFF;
+ return;
}
- for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
- hi = lo = 0;
- TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &hi );
- TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &lo );
- id_hi[phy] = hi;
- id_lo[phy] = lo;
- TLAN_DBG( TLAN_DEBUG_GNRL,
- "TLAN: Phy %2x, hi = %hx, lo = %hx\n",
- phy,
- hi,
- lo
- );
+ TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi );
+
+ if ( hi != 0xFFFF ) {
+ priv->phy[0] = TLAN_PHY_MAX_ADDR;
+ } else {
+ priv->phy[0] = TLAN_PHY_NONE;
}
+ priv->phy[1] = TLAN_PHY_NONE;
for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
- if ( ( aui == 1 ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
- if ( id_hi[phy] != 0xFFFF ) {
- TLan_MiiSync(dev->base_addr);
- TLan_MiiWriteReg(dev->base_addr,
- phy,
- MII_GEN_CTL,
- MII_GC_PDOWN |
- MII_GC_LOOPBK |
- MII_GC_ISOLATE );
-
- }
- continue;
- }
- for ( entry = 0; TLanPhyIdTable[entry].check; entry++) {
- if ( ( id_hi[phy] == TLanPhyIdTable[entry].idHi ) &&
- ( id_lo[phy] == TLanPhyIdTable[entry].idLo ) ) {
- TLAN_DBG( TLAN_DEBUG_GNRL,
- "TLAN: Selected Phy %hx\n",
- phy
- );
- goto FINISH;
+ TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control );
+ TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi );
+ TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo );
+ if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo );
+ if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
+ priv->phy[1] = phy;
}
}
}
- entry = 0;
- phy = 0;
-
-FINISH:
-
- if ( ( entry == 0 ) && ( phy == 0 ) ) {
- priv->phyAddr = phy;
- priv->phyEntry = entry;
- priv->phyCheck = TLan_PhyNop;
- priv->phyService = TLan_PhyNop;
- priv->phyFlags = TLAN_PHY_BIT_RATE |
- TLAN_PHY_UNMANAGED |
- TLAN_PHY_ACTIVITY;
+ if ( priv->phy[1] != TLAN_PHY_NONE ) {
+ priv->phyNum = 1;
+ } else if ( priv->phy[0] != TLAN_PHY_NONE ) {
+ priv->phyNum = 0;
} else {
- priv->phyAddr = phy;
- priv->phyEntry = entry;
- priv->phyCheck = TLanPhyIdTable[entry].check;
- priv->phyService = TLanPhyIdTable[entry].service;
- priv->phyFlags = TLanPhyIdTable[entry].flags;
+ printk( "TLAN: Cannot initialize device, no PHY was found!\n" );
}
-} /* TLan_PhySelect */
-
+} /* TLan_PhyDetect */
- /***************************************************************
- * TLan_PhyNop
- *
- * Returns:
- * Nothing
- * Parms:
- * dev A pointer to a device structure.
- *
- * This function does nothing and is meant as a stand-in
- * for when a Check or Service function would be
- * meaningless.
- *
- **************************************************************/
-int TLan_PhyNop( struct device *dev )
+void TLan_PhyPowerDown( struct device *dev )
{
- dev = NULL;
- return 0;
+ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ u16 value;
+
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Powering down PHY(s).\n", dev->name );
+ value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
+ TLan_MiiSync( dev->base_addr );
+ TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
+ if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
+ TLan_MiiSync( dev->base_addr );
+ TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
+ }
-} /* TLan_PhyNop */
+ /* Wait for 5 jiffies (50 ms) and powerup
+ * This is abitrary. It is intended to make sure the
+ * tranceiver settles.
+ */
+ TLan_SetTimer( dev, 5, TLAN_TIMER_PHY_PUP );
+} /* TLan_PhyPowerDown */
- /***************************************************************
- * TLan_PhyInternalCheck
- *
- * Returns:
- * Nothing
- * Parms:
- * dev A pointer to a device structure of the
- * adapter holding the PHY to be checked.
- *
- * This function resets the internal PHY on a TLAN chip.
- * See Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
- * Programmer's Guide"
- *
- **************************************************************/
-int TLan_PhyInternalCheck( struct device *dev )
+void TLan_PhyPowerUp( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- u16 gen_ctl;
- u32 io;
- u16 phy;
- u16 value;
- u8 sio;
-
- io = dev->base_addr;
- phy = priv->phyAddr;
-
- TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
- if ( gen_ctl & MII_GC_PDOWN ) {
- TLan_MiiSync( io );
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
- udelay(50000);
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
- TLan_MiiSync( io );
- }
-
- TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
- while ( value & MII_GC_RESET )
- TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
-
- /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); */
- /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); */
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
-
- udelay(500000);
-
- TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
- if ( aui )
- value |= TLAN_TC_AUISEL;
- else
- value &= ~TLAN_TC_AUISEL;
- TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
-
- /* Read Possible Latched Link Status */
- TLan_MiiReadReg( io, phy, MII_GEN_STS, &value );
- /* Read Real Link Status */
- TLan_MiiReadReg( io, phy, MII_GEN_STS, &value );
- if ( ( value & MII_GS_LINK ) || aui ) {
- priv->phyOnline = 1;
- TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
- } else {
- priv->phyOnline = 0;
- TLan_DioWrite8( io, TLAN_LED_REG, 0 );
- }
+ u16 value;
- /* Enable Interrupts */
- TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
- value |= TLAN_TC_INTEN;
- TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Powering up PHY.\n", dev->name );
+ TLan_MiiSync( dev->base_addr );
+ value = MII_GC_LOOPBK;
+ TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
- sio = TLan_DioRead8( io, TLAN_NET_SIO );
- sio |= TLAN_NET_SIO_MINTEN;
- TLan_DioWrite8( io, TLAN_NET_SIO, sio );
-
- return 0;
-
-} /* TLanPhyInternalCheck */
+ /* Wait for 50 jiffies (500 ms) and reset the
+ * tranceiver. The TLAN docs say both 50 ms and
+ * 500 ms, so do the longer, just in case
+ */
+ TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_RESET );
+} /* TLan_PhyPowerUp */
- /***************************************************************
- * TLan_PhyInternalService
- *
- * Returns:
- * Nothing
- * Parms:
- * dev A pointer to a device structure of the
- * adapter holding the PHY to be serviced.
- *
- * This function services an interrupt generated by the
- * internal PHY. It can turn on/off the link LED. See
- * Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
- * Programmer's Guide".
- *
- **************************************************************/
-int TLan_PhyInternalService( struct device *dev )
+void TLan_PhyReset( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- u16 tlphy_sts;
- u16 gen_sts;
- u16 an_exp;
- u32 io;
- u16 phy;
-
- io = dev->base_addr;
- phy = priv->phyAddr;
-
- TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts );
- TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts );
- TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp );
- if ( ( gen_sts & MII_GS_LINK ) || aui ) {
- priv->phyOnline = 1;
- TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
- } else {
- priv->phyOnline = 0;
- TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+ u16 phy;
+ u16 value;
+
+ phy = priv->phy[priv->phyNum];
+
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Reseting PHY.\n", dev->name );
+ TLan_MiiSync( dev->base_addr );
+ value = MII_GC_LOOPBK | MII_GC_RESET;
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value );
+ TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
+ while ( value & MII_GC_RESET ) {
+ TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
}
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 );
- if ( ( tlphy_sts & TLAN_TS_POLOK ) == 0) {
- u16 value;
- TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value);
- value |= TLAN_TC_SWAPOL;
- TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value);
- }
+ /* Wait for 50 jiffies (500 ms) and initialize.
+ * I don't remember why I wait this long.
+ */
+ TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_START_LINK );
- return 0;
+} /* TLan_PhyReset */
-} /* TLan_PhyInternalService */
+void TLan_PhyStartLink( struct device *dev )
+{
+ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ u16 ability;
+ u16 control;
+ u16 data;
+ u16 phy;
+ u16 status;
+ u16 tctl;
+
+ phy = priv->phy[priv->phyNum];
+
+ TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Trying to activate link.\n", dev->name );
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+ if ( ( status & MII_GS_AUTONEG ) &&
+ ( priv->duplex == TLAN_DUPLEX_DEFAULT ) &&
+ ( priv->speed == TLAN_SPEED_DEFAULT ) &&
+ ( ! priv->aui ) ) {
+ ability = status >> 11;
+
+ if ( priv->speed == TLAN_SPEED_10 ) {
+ ability &= 0x0003;
+ } else if ( priv->speed == TLAN_SPEED_100 ) {
+ ability &= 0x001C;
+ }
- /***************************************************************
- * TLan_PhyDp83840aCheck
- *
- * Returns:
- * Nothing
- * Parms:
- * dev A pointer to a device structure of the
- * adapter holding the PHY to be reset.
- *
- * This function resets a National Semiconductor DP83840A
- * 10/100 Mb/s PHY device. See National Semiconductor's
- * data sheet for more info. This PHY is used on Compaq
- * Netelligent 10/100 cards.
- *
- **************************************************************/
+ if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+ ability &= 0x000A;
+ } else if ( priv->duplex == TLAN_DUPLEX_HALF ) {
+ ability &= 0x0005;
+ }
+
+ TLan_MiiWriteReg( dev, phy, MII_AN_ADV, ( ability << 5 ) | 1 );
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
+
+ /* Wait for 400 jiffies (4 sec) for autonegotiation
+ * to complete. The max spec time is less than this
+ * but the card need additional time to start AN.
+ * .5 sec should be plenty extra.
+ */
+ printk( "TLAN: %s: Starting autonegotiation.\n", dev->name );
+ TLan_SetTimer( dev, 400, TLAN_TIMER_PHY_FINISH_AN );
+ return;
+ }
+
+ if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
+ priv->phyNum = 0;
+ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+ TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
+ TLan_SetTimer( dev, 4, TLAN_TIMER_PHY_PDOWN );
+ return;
+ } else if ( priv->phyNum == 0 ) {
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
+ if ( priv->aui ) {
+ tctl |= TLAN_TC_AUISEL;
+ } else {
+ tctl &= ~TLAN_TC_AUISEL;
+ control = 0;
+ if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+ control |= MII_GC_DUPLEX;
+ priv->tlanFullDuplex = TRUE;
+ }
+ if ( priv->speed == TLAN_SPEED_100 ) {
+ control |= MII_GC_SPEEDSEL;
+ }
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control );
+ }
+ TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
+ }
+
+ /* Wait for 100 jiffies (1 sec) to give the tranceiver time
+ * to establish link.
+ */
+ TLan_SetTimer( dev, 100, TLAN_TIMER_FINISH_RESET );
+
+} /* TLan_PhyStartLink */
-static int TLan_PhyDp83840aCheck( struct device *dev )
+
+
+
+void TLan_PhyFinishAutoNeg( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- u16 gen_ctl;
- u32 io;
- u16 phy;
- u16 value;
- u8 sio;
-
- io = dev->base_addr;
- phy = priv->phyAddr;
-
- TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
- if ( gen_ctl & MII_GC_PDOWN ) {
- TLan_MiiSync( io );
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
- udelay(500000);
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
- TLan_MiiSync( io );
- }
-
- TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
- while ( value & MII_GC_RESET )
- TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
-
- /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); */
- /* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); */
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
- TLan_MiiReadReg( io, phy, MII_AN_ADV, &value );
- value &= ~0x0140;
- TLan_MiiWriteReg( io, phy, MII_AN_ADV, value );
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 );
- TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 );
-
- udelay(50000);
-#if 0
- /* Read Possible Latched Link Status */
- TLan_MiiReadReg( io, phy, MII_GEN_STS, &value );
- /* Read Real Link Status */
- TLan_MiiReadReg( io, phy, MII_GEN_STS, &value );
- if ( value & MII_GS_LINK ) {
- priv->phyOnline = 1;
- TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
- } else {
- priv->phyOnline = 0;
- TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+ u16 an_adv;
+ u16 an_lpa;
+ u16 data;
+ u16 mode;
+ u16 phy;
+ u16 status;
+
+ phy = priv->phy[priv->phyNum];
+
+ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+ if ( ! ( status & MII_GS_AUTOCMPLT ) ) {
+ /* Wait for 800 jiffies (8 sec) to give the process
+ * more time. Perhaps we should fail after a while.
+ */
+ printk( "TLAN: Giving autonegotiation more time.\n" );
+ TLan_SetTimer( dev, 800, TLAN_TIMER_PHY_FINISH_AN );
+ return;
}
- /* Enable Interrupts */
- TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
- value |= TLAN_TC_INTEN;
- TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
-#endif
- sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
- sio &= ~TLAN_NET_SIO_MINTEN;
- TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
-/* priv->phyOnline = 1; */
-
- return 0;
+ printk( "TLAN: %s: Autonegotiation complete.\n", dev->name );
+ TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv );
+ TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa );
+ mode = an_adv & an_lpa & 0x03E0;
+ if ( mode & 0x0100 ) {
+ priv->tlanFullDuplex = TRUE;
+ } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) {
+ priv->tlanFullDuplex = TRUE;
+ }
-} /* TLan_PhyDp83840aCheck */
+ if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) {
+ priv->phyNum = 0;
+ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+ TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
+ TLan_SetTimer( dev, 40, TLAN_TIMER_PHY_PDOWN );
+ return;
+ }
+
+ if ( priv->phyNum == 0 ) {
+ if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) {
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX );
+ printk( "TLAN: Starting internal PHY with DUPLEX\n" );
+ } else {
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB );
+ printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" );
+ }
+ }
+
+ /* Wait for 10 jiffies (100 ms). No reason in partiticular.
+ */
+ TLan_SetTimer( dev, 10, TLAN_TIMER_FINISH_RESET );
+
+} /* TLan_PhyFinishAutoNeg */
@@ -2266,9 +2413,10 @@ static int TLan_PhyDp83840aCheck( struct device *dev )
* 1 otherwise.
*
* Parms:
- * base_port The base IO port of the adapter in
- * question.
- * dev The address of the PHY to be queried.
+ * dev The device structure containing
+ * The io address and interrupt count
+ * for this device.
+ * phy The address of the PHY to be queried.
* reg The register whose contents are to be
* retreived.
* val A pointer to a variable to store the
@@ -2281,30 +2429,32 @@ static int TLan_PhyDp83840aCheck( struct device *dev )
*
**************************************************************/
-int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val)
+int TLan_MiiReadReg( struct device *dev, u16 phy, u16 reg, u16 *val )
{
u8 nack;
- u16 sio, tmp;
- u32 i;
+ u16 sio, tmp;
+ u32 i;
int err;
- int minten;
+ int minten;
err = FALSE;
- outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
- sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+ outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
+ sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
- cli();
+ if ( dev->interrupt == 0 )
+ cli();
+ dev->interrupt++;
- TLan_MiiSync(base_port);
+ TLan_MiiSync(dev->base_addr);
minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
if ( minten )
TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
- TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */
- TLan_MiiSendData( base_port, 0x2, 2 ); /* Read ( 10b ) */
- TLan_MiiSendData( base_port, dev, 5 ); /* Device # */
- TLan_MiiSendData( base_port, reg, 5 ); /* Register # */
+ TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */
+ TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Read ( 10b ) */
+ TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */
+ TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */
TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */
@@ -2340,7 +2490,9 @@ int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val)
*val = tmp;
- sti();
+ dev->interrupt--;
+ if ( dev->interrupt == 0 )
+ sti();
return err;
@@ -2434,9 +2586,9 @@ void TLan_MiiSync( u16 base_port )
* Returns:
* Nothing
* Parms:
- * base_port The base IO port of the adapter in
- * question.
- * dev The address of the PHY to be written to.
+ * dev The device structure for the device
+ * to write to.
+ * phy The address of the PHY to be written to.
* reg The register whose contents are to be
* written.
* val The value to be written to the register.
@@ -2448,29 +2600,31 @@ void TLan_MiiSync( u16 base_port )
*
**************************************************************/
-void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
+void TLan_MiiWriteReg( struct device *dev, u16 phy, u16 reg, u16 val )
{
- u16 sio;
+ u16 sio;
int minten;
- outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
- sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+ outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
+ sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
- cli();
+ if ( dev->interrupt == 0 )
+ cli();
+ dev->interrupt++;
- TLan_MiiSync( base_port );
+ TLan_MiiSync( dev->base_addr );
minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
if ( minten )
TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
- TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */
- TLan_MiiSendData( base_port, 0x1, 2 ); /* Write ( 01b ) */
- TLan_MiiSendData( base_port, dev, 5 ); /* Device # */
- TLan_MiiSendData( base_port, reg, 5 ); /* Register # */
+ TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */
+ TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Write ( 01b ) */
+ TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */
+ TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */
- TLan_MiiSendData( base_port, 0x2, 2 ); /* Send ACK */
- TLan_MiiSendData( base_port, val, 16 ); /* Send Data */
+ TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Send ACK */
+ TLan_MiiSendData( dev->base_addr, val, 16 ); /* Send Data */
TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */
TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
@@ -2478,10 +2632,15 @@ void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
if ( minten )
TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
- sti();
+ dev->interrupt--;
+ if ( dev->interrupt == 0 )
+ sti();
} /* TLan_MiiWriteReg */
+
+
+
/*****************************************************************************
******************************************************************************
@@ -2670,26 +2829,30 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
*
**************************************************************/
-int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data )
+int TLan_EeReadByte( struct device *dev, u8 ee_addr, u8 *data )
{
int err;
- cli();
+ if ( dev->interrupt == 0 )
+ cli();
+ dev->interrupt++;
- TLan_EeSendStart( io_base );
- err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK );
+ TLan_EeSendStart( dev->base_addr );
+ err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK );
if (err)
return 1;
- err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK );
+ err = TLan_EeSendByte( dev->base_addr, ee_addr, TLAN_EEPROM_ACK );
if (err)
return 2;
- TLan_EeSendStart( io_base );
- err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK );
+ TLan_EeSendStart( dev->base_addr );
+ err = TLan_EeSendByte( dev->base_addr, 0xA1, TLAN_EEPROM_ACK );
if (err)
return 3;
- TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP );
+ TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP );
- sti();
+ dev->interrupt--;
+ if ( dev->interrupt == 0 )
+ sti();
return 0;
diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
index 94613d3a6..fa1f91bbe 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/tlan.h
@@ -5,9 +5,9 @@
* Linux ThunderLAN Driver
*
* tlan.h
- * by James Banks, james.banks@caldera.com
+ * by James Banks
*
- * (C) 1997 Caldera, Inc.
+ * (C) 1997-1998 Caldera, Inc.
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
@@ -33,23 +33,23 @@
*
****************************************************************/
-#define FALSE 0
-#define TRUE 1
+#define FALSE 0
+#define TRUE 1
#define TLAN_MIN_FRAME_SIZE 64
#define TLAN_MAX_FRAME_SIZE 1600
-#define TLAN_NUM_RX_LISTS 4
-#define TLAN_NUM_TX_LISTS 8
+#define TLAN_NUM_RX_LISTS 4
+#define TLAN_NUM_TX_LISTS 8
-#define TLAN_IGNORE 0
-#define TLAN_RECORD 1
+#define TLAN_IGNORE 0
+#define TLAN_RECORD 1
#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk( format, ##args );
-#define TLAN_DEBUG_GNRL 0x0001
-#define TLAN_DEBUG_TX 0x0002
-#define TLAN_DEBUG_RX 0x0004
-#define TLAN_DEBUG_LIST 0x0008
+#define TLAN_DEBUG_GNRL 0x0001
+#define TLAN_DEBUG_TX 0x0002
+#define TLAN_DEBUG_RX 0x0004
+#define TLAN_DEBUG_LIST 0x0008
@@ -59,23 +59,47 @@
*
****************************************************************/
- /* NOTE: These have been moved to pci.h, will use them
- eventually */
-#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
-#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
-#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35
-#define PCI_DEVICE_ID_NETFLEX_3P 0xF130
-#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150
-#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43
-#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40
-#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011
-
-
-typedef struct tlan_pci_id {
+#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
+#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
+#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35
+#define PCI_DEVICE_ID_NETFLEX_3P 0xF130
+#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40
+#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011
+#define PCI_DEVICE_ID_NETELLIGENT_10_T2 0xB012
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100 0xB030
+#ifndef PCI_DEVICE_ID_OLICOM_OC2183
+#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013
+#endif
+#ifndef PCI_DEVICE_ID_OLICOM_OC2325
+#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012
+#endif
+#ifndef PCI_DEVICE_ID_OLICOM_OC2326
+#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014
+#endif
+
+typedef struct tlan_adapter_entry {
u16 vendorId;
u16 deviceId;
- char *deviceName;
-} TLanPciId;
+ char *deviceLabel;
+ u32 flags;
+ u16 addrOfs;
+} TLanAdapterEntry;
+
+#define TLAN_ADAPTER_NONE 0x00000000
+#define TLAN_ADAPTER_UNMANAGED_PHY 0x00000001
+#define TLAN_ADAPTER_BIT_RATE_PHY 0x00000002
+#define TLAN_ADAPTER_USE_INTERN_10 0x00000004
+#define TLAN_ADAPTER_ACTIVITY_LED 0x00000008
+
+#define TLAN_SPEED_DEFAULT 0
+#define TLAN_SPEED_10 10
+#define TLAN_SPEED_100 100
+
+#define TLAN_DUPLEX_DEFAULT 0
+#define TLAN_DUPLEX_HALF 1
+#define TLAN_DUPLEX_FULL 2
@@ -121,25 +145,7 @@ typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
****************************************************************/
#define TLAN_PHY_MAX_ADDR 0x1F
-
-#define TLAN_PHY_ACTIVITY 0x00000001
-#define TLAN_PHY_AUTONEG 0x00000002
-#define TLAN_PHY_INTS 0x00000004
-#define TLAN_PHY_BIT_RATE 0x00000008
-#define TLAN_PHY_UNMANAGED 0x00000010
-#define TLAN_PHY_INTERNAL 0x00000020
-
-
-typedef int (TLanPhyFunc)( struct device * );
-
-
-typedef struct tlan_phy_id_entry_tag {
- u16 idHi;
- u16 idLo;
- TLanPhyFunc *check;
- TLanPhyFunc *service;
- u32 flags;
-} TLanPhyIdEntry;
+#define TLAN_PHY_NONE 0x20
@@ -164,21 +170,22 @@ typedef struct tlan_private_tag {
u32 txInProgress;
u32 txTail;
u32 txBusyCount;
- u32 phyAddr;
- u32 phyEntry;
u32 phyOnline;
- u32 phyFlags;
- TLanPhyFunc *phyCheck;
- TLanPhyFunc *phyService;
u32 timerSetAt;
u32 timerType;
struct timer_list timer;
struct net_device_stats stats;
- u32 pciEntry;
- u8 pciRevision;
- u8 pciBus;
- u8 pciDeviceFn;
+ TLanAdapterEntry *adapter;
+ u32 adapterRev;
+ u32 aui;
+ u32 debug;
+ u32 duplex;
+ u32 phy[2];
+ u32 phyNum;
+ u32 sa_int;
+ u32 speed;
u8 tlanRev;
+ u8 tlanFullDuplex;
char devName[8];
} TLanPrivateInfo;
@@ -191,10 +198,15 @@ typedef struct tlan_private_tag {
****************************************************************/
#define TLAN_TIMER_LINK 1
-#define TLAN_TIMER_ACT 2
+#define TLAN_TIMER_ACTIVITY 2
+#define TLAN_TIMER_PHY_PDOWN 3
+#define TLAN_TIMER_PHY_PUP 4
+#define TLAN_TIMER_PHY_RESET 5
+#define TLAN_TIMER_PHY_START_LINK 6
+#define TLAN_TIMER_PHY_FINISH_AN 7
+#define TLAN_TIMER_FINISH_RESET 8
-#define TLAN_TIMER_LINK_DELAY 230
-#define TLAN_TIMER_ACT_DELAY 10
+#define TLAN_TIMER_ACT_DELAY 10
@@ -215,29 +227,29 @@ typedef struct tlan_private_tag {
*
****************************************************************/
-#define TLAN_HOST_CMD 0x00
+#define TLAN_HOST_CMD 0x00
#define TLAN_HC_GO 0x80000000
-#define TLAN_HC_STOP 0x40000000
+#define TLAN_HC_STOP 0x40000000
#define TLAN_HC_ACK 0x20000000
-#define TLAN_HC_CS_MASK 0x1FE00000
+#define TLAN_HC_CS_MASK 0x1FE00000
#define TLAN_HC_EOC 0x00100000
#define TLAN_HC_RT 0x00080000
#define TLAN_HC_NES 0x00040000
-#define TLAN_HC_AD_RST 0x00008000
-#define TLAN_HC_LD_TMR 0x00004000
-#define TLAN_HC_LD_THR 0x00002000
-#define TLAN_HC_REQ_INT 0x00001000
-#define TLAN_HC_INT_OFF 0x00000800
-#define TLAN_HC_INT_ON 0x00000400
-#define TLAN_HC_AC_MASK 0x000000FF
-#define TLAN_CH_PARM 0x04
-#define TLAN_DIO_ADR 0x08
-#define TLAN_DA_ADR_INC 0x8000
-#define TLAN_DA_RAM_ADR 0x4000
-#define TLAN_HOST_INT 0x0A
-#define TLAN_HI_IV_MASK 0x1FE0
-#define TLAN_HI_IT_MASK 0x001C
-#define TLAN_DIO_DATA 0x0C
+#define TLAN_HC_AD_RST 0x00008000
+#define TLAN_HC_LD_TMR 0x00004000
+#define TLAN_HC_LD_THR 0x00002000
+#define TLAN_HC_REQ_INT 0x00001000
+#define TLAN_HC_INT_OFF 0x00000800
+#define TLAN_HC_INT_ON 0x00000400
+#define TLAN_HC_AC_MASK 0x000000FF
+#define TLAN_CH_PARM 0x04
+#define TLAN_DIO_ADR 0x08
+#define TLAN_DA_ADR_INC 0x8000
+#define TLAN_DA_RAM_ADR 0x4000
+#define TLAN_HOST_INT 0x0A
+#define TLAN_HI_IV_MASK 0x1FE0
+#define TLAN_HI_IT_MASK 0x001C
+#define TLAN_DIO_DATA 0x0C
/* ThunderLAN Internal Register DIO Offsets */
@@ -264,7 +276,7 @@ typedef struct tlan_private_tag {
#define TLAN_NET_STS_MIRQ 0x80
#define TLAN_NET_STS_HBEAT 0x40
#define TLAN_NET_STS_TXSTOP 0x20
-#define TLAN_NET_STS_RXSTOP 0x10
+#define TLAN_NET_STS_RXSTOP 0x10
#define TLAN_NET_STS_RSRVD 0x0F
#define TLAN_NET_MASK 0x03
#define TLAN_NET_MASK_MASK7 0x80
@@ -283,36 +295,36 @@ typedef struct tlan_private_tag {
#define TLAN_NET_CFG_MTEST 0x0100
#define TLAN_NET_CFG_PHY_EN 0x0080
#define TLAN_NET_CFG_MSMASK 0x007F
-#define TLAN_MAN_TEST 0x06
-#define TLAN_DEF_VENDOR_ID 0x08
-#define TLAN_DEF_DEVICE_ID 0x0A
-#define TLAN_DEF_REVISION 0x0C
-#define TLAN_DEF_SUBCLASS 0x0D
-#define TLAN_DEF_MIN_LAT 0x0E
-#define TLAN_DEF_MAX_LAT 0x0F
+#define TLAN_MAN_TEST 0x06
+#define TLAN_DEF_VENDOR_ID 0x08
+#define TLAN_DEF_DEVICE_ID 0x0A
+#define TLAN_DEF_REVISION 0x0C
+#define TLAN_DEF_SUBCLASS 0x0D
+#define TLAN_DEF_MIN_LAT 0x0E
+#define TLAN_DEF_MAX_LAT 0x0F
#define TLAN_AREG_0 0x10
#define TLAN_AREG_1 0x16
#define TLAN_AREG_2 0x1C
#define TLAN_AREG_3 0x22
#define TLAN_HASH_1 0x28
#define TLAN_HASH_2 0x2C
-#define TLAN_GOOD_TX_FRMS 0x30
-#define TLAN_TX_UNDERUNS 0x33
-#define TLAN_GOOD_RX_FRMS 0x34
-#define TLAN_RX_OVERRUNS 0x37
-#define TLAN_DEFERRED_TX 0x38
-#define TLAN_CRC_ERRORS 0x3A
-#define TLAN_CODE_ERRORS 0x3B
-#define TLAN_MULTICOL_FRMS 0x3C
-#define TLAN_SINGLECOL_FRMS 0x3E
-#define TLAN_EXCESSCOL_FRMS 0x40
-#define TLAN_LATE_COLS 0x41
-#define TLAN_CARRIER_LOSS 0x42
-#define TLAN_ACOMMIT 0x43
-#define TLAN_LED_REG 0x44
-#define TLAN_LED_ACT 0x10
-#define TLAN_LED_LINK 0x01
-#define TLAN_BSIZE_REG 0x45
+#define TLAN_GOOD_TX_FRMS 0x30
+#define TLAN_TX_UNDERUNS 0x33
+#define TLAN_GOOD_RX_FRMS 0x34
+#define TLAN_RX_OVERRUNS 0x37
+#define TLAN_DEFERRED_TX 0x38
+#define TLAN_CRC_ERRORS 0x3A
+#define TLAN_CODE_ERRORS 0x3B
+#define TLAN_MULTICOL_FRMS 0x3C
+#define TLAN_SINGLECOL_FRMS 0x3E
+#define TLAN_EXCESSCOL_FRMS 0x40
+#define TLAN_LATE_COLS 0x41
+#define TLAN_CARRIER_LOSS 0x42
+#define TLAN_ACOMMIT 0x43
+#define TLAN_LED_REG 0x44
+#define TLAN_LED_ACT 0x10
+#define TLAN_LED_LINK 0x01
+#define TLAN_BSIZE_REG 0x45
#define TLAN_MAX_RX 0x46
#define TLAN_INT_DIS 0x48
#define TLAN_ID_TX_EOC 0x04
@@ -327,11 +339,11 @@ typedef struct tlan_private_tag {
#define TLAN_INT_NONE 0x0000
#define TLAN_INT_TX_EOF 0x0001
-#define TLAN_INT_STAT_OVERFLOW 0x0002
+#define TLAN_INT_STAT_OVERFLOW 0x0002
#define TLAN_INT_RX_EOF 0x0003
#define TLAN_INT_DUMMY 0x0004
#define TLAN_INT_TX_EOC 0x0005
-#define TLAN_INT_STATUS_CHECK 0x0006
+#define TLAN_INT_STATUS_CHECK 0x0006
#define TLAN_INT_RX_EOC 0x0007
@@ -340,7 +352,7 @@ typedef struct tlan_private_tag {
/* Generic MII/PHY Registers */
-#define MII_GEN_CTL 0x00
+#define MII_GEN_CTL 0x00
#define MII_GC_RESET 0x8000
#define MII_GC_LOOPBK 0x4000
#define MII_GC_SPEEDSEL 0x2000
@@ -351,7 +363,7 @@ typedef struct tlan_private_tag {
#define MII_GC_DUPLEX 0x0100
#define MII_GC_COLTEST 0x0080
#define MII_GC_RESERVED 0x007F
-#define MII_GEN_STS 0x01
+#define MII_GEN_STS 0x01
#define MII_GS_100BT4 0x8000
#define MII_GS_100BTXFD 0x4000
#define MII_GS_100BTXHD 0x2000
@@ -359,19 +371,19 @@ typedef struct tlan_private_tag {
#define MII_GS_10BTHD 0x0800
#define MII_GS_RESERVED 0x07C0
#define MII_GS_AUTOCMPLT 0x0020
-#define MII_GS_RFLT 0x0010
+#define MII_GS_RFLT 0x0010
#define MII_GS_AUTONEG 0x0008
-#define MII_GS_LINK 0x0004
+#define MII_GS_LINK 0x0004
#define MII_GS_JABBER 0x0002
#define MII_GS_EXTCAP 0x0001
#define MII_GEN_ID_HI 0x02
#define MII_GEN_ID_LO 0x03
-#define MII_GIL_OUI 0xFC00
+#define MII_GIL_OUI 0xFC00
#define MII_GIL_MODEL 0x03F0
#define MII_GIL_REVISION 0x000F
-#define MII_AN_ADV 0x04
-#define MII_AN_LPA 0x05
-#define MII_AN_EXP 0x06
+#define MII_AN_ADV 0x04
+#define MII_AN_LPA 0x05
+#define MII_AN_EXP 0x06
/* ThunderLAN Specific MII/PHY Registers */
@@ -394,6 +406,7 @@ typedef struct tlan_private_tag {
#define TLAN_TS_RESERVED 0x0FFF
+#define CIRC_INC( a, b ) if ( ++a >= b ) a = 0
/* Routines to access internal registers. */
@@ -456,7 +469,7 @@ inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
-
+#if 0
inline void TLan_ClearBit(u8 bit, u16 port)
{
outb_p(inb_p(port) & ~bit, port);
@@ -477,7 +490,30 @@ inline void TLan_SetBit(u8 bit, u16 port)
{
outb_p(inb_p(port) | bit, port);
}
+#endif
+
+#define TLan_ClearBit( bit, port ) outb_p(inb_p(port) & ~bit, port)
+#define TLan_GetBit( bit, port ) ((int) (inb_p(port) & bit))
+#define TLan_SetBit( bit, port ) outb_p(inb_p(port) | bit, port)
+
+#ifdef I_LIKE_A_FAST_HASH_FUNCTION
+/* given 6 bytes, view them as 8 6-bit numbers and return the XOR of those */
+/* the code below is about seven times as fast as the original code */
+inline u32 TLan_HashFunc( u8 *a )
+{
+ u8 hash;
+
+ hash = (a[0]^a[3]); /* & 077 */
+ hash ^= ((a[0]^a[3])>>6); /* & 003 */
+ hash ^= ((a[1]^a[4])<<2); /* & 074 */
+ hash ^= ((a[1]^a[4])>>4); /* & 017 */
+ hash ^= ((a[2]^a[5])<<4); /* & 060 */
+ hash ^= ((a[2]^a[5])>>2); /* & 077 */
+
+ return (hash & 077);
+}
+#else /* original code */
inline u32 xor( u32 a, u32 b )
{
@@ -501,7 +537,5 @@ inline u32 TLan_HashFunc( u8 *a )
}
-
-
-
+#endif /* I_LIKE_A_FAST_HASH_FUNCTION */
#endif
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index 0abf814e5..04ddcef20 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -42,9 +42,9 @@ static int reverse_probe = 0;
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
#ifdef __alpha__
-static const rx_copybreak = 1518;
+static const int rx_copybreak = 1518;
#else
-static const rx_copybreak = 100;
+static const int rx_copybreak = 100;
#endif
/* The following example shows how to always use the 10base2 port. */
@@ -472,11 +472,12 @@ int tulip_probe(struct device *dev)
if (pcibios_find_class
(PCI_CLASS_NETWORK_ETHERNET << 8,
reverse_probe ? 0xfe - pci_index : pci_index,
- &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+ &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
if (reverse_probe)
continue;
else
break;
+ }
pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_VENDOR_ID, &vendor);
pcibios_read_config_word(pci_bus, pci_device_fn,
@@ -577,7 +578,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
/* Stop the chip's Tx and Rx processes. */
outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile)inl(ioaddr + CSR8);
+ (volatile int)inl(ioaddr + CSR8);
if (chip_id == DC21041) {
if (inl(ioaddr + CSR9) & 0x8000) {
@@ -803,7 +804,7 @@ static void parse_eeprom(struct device *dev)
/* The last media info list parsed, for multiport boards. */
static struct mediatable *last_mediatable = NULL;
static unsigned char *last_ee_data = NULL;
- static controller_index = 0;
+ static int controller_index = 0;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int ioaddr = dev->base_addr;
unsigned char *ee_data = tp->eeprom;
@@ -1658,13 +1659,15 @@ static void tulip_tx_timeout(struct device *dev)
dev->name, inl(ioaddr + CSR5), csr12,
inl(ioaddr + CSR13), inl(ioaddr + CSR14));
tp->mediasense = 1;
- if (dev->if_port == 1 || dev->if_port == 2)
+
+ if (dev->if_port == 1 || dev->if_port == 2) {
if (csr12 & 0x0004) {
dev->if_port = 2 - dev->if_port;
} else
dev->if_port = 0;
- else
+ } else
dev->if_port = 1;
+
select_media(dev, 0);
tp->stats.tx_errors++;
dev->trans_start = jiffies;
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index d49388b28..0c46649d3 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -1,10 +1,10 @@
/*
- * Wavelan ISA driver
+ * WaveLAN ISA driver
*
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
- * Original copyrigth follow (see also end of this file).
+ * Original copyright follows (also see the end of this file).
* See wavelan.p.h for details.
*/
@@ -19,7 +19,7 @@
/************************* MISC SUBROUTINES **************************/
/*
* Subroutines which won't fit in one of the following category
- * (wavelan modem or i82586)
+ * (WaveLAN modem or i82586)
*/
/*------------------------------------------------------------------*/
@@ -95,14 +95,14 @@ wv_struct_check(void)
#undef SC
return((char *) NULL);
-} /* wv_structuct_check */
+} /* wv_struct_check */
#endif /* STRUCT_CHECK */
/********************* HOST ADAPTER SUBROUTINES *********************/
/*
- * Usefull subroutines to manage the wavelan ISA interface
+ * Useful subroutines to manage the WaveLAN ISA interface
*
- * One major difference with the Pcmcia hardware (exept the port mapping)
+ * One major difference with the PCMCIA hardware (except the port mapping)
* is that we have to keep the state of the Host Control Register
* because of the interrupt enable & bus size flags.
*/
@@ -139,7 +139,7 @@ hacr_write_slow(u_long ioaddr,
{
hacr_write(ioaddr, hacr);
/* delay might only be needed sometimes */
- udelay(1000L);
+ mdelay(1);
} /* hacr_write_slow */
/*------------------------------------------------------------------*/
@@ -166,7 +166,7 @@ wv_hacr_reset(u_long ioaddr)
/*------------------------------------------------------------------*/
/*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
*/
static inline void
wv_16_off(u_long ioaddr,
@@ -178,7 +178,7 @@ wv_16_off(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
*/
static inline void
wv_16_on(u_long ioaddr,
@@ -190,7 +190,7 @@ wv_16_on(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Disable interrupts on the wavelan hardware
+ * Disable interrupts on the WaveLAN hardware.
*/
static inline void
wv_ints_off(device * dev)
@@ -209,7 +209,7 @@ wv_ints_off(device * dev)
/*------------------------------------------------------------------*/
/*
- * Enable interrupts on the wavelan hardware
+ * Enable interrupts on the WaveLAN hardware.
*/
static inline void
wv_ints_on(device * dev)
@@ -228,7 +228,7 @@ wv_ints_on(device * dev)
/******************* MODEM MANAGEMENT SUBROUTINES *******************/
/*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the WaveLAN
*/
/*------------------------------------------------------------------*/
@@ -259,12 +259,12 @@ psa_read(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Write the Paramter Storage Area to the WaveLAN card's memory
+ * Write the Parameter Storage Area to the WaveLAN card's memory.
*/
static void
psa_write(u_long ioaddr,
u_short hacr,
- int o, /* Offset in psa */
+ int o, /* Offset in PSA */
u_char * b, /* Buffer in memory */
int n) /* Length of buffer */
{
@@ -284,7 +284,7 @@ psa_write(u_long ioaddr,
count = 0;
while((count++ < 100) &&
(hasr_read(ioaddr) & HASR_PSA_BUSY))
- udelay(1000);
+ mdelay(1);
}
wv_16_on(ioaddr, hacr);
@@ -294,10 +294,10 @@ psa_write(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
* Calculate the PSA CRC (not tested yet)
- * As the Wavelan drivers don't use the CRC, I won't use it either...
- * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * As the WaveLAN drivers don't use the CRC, I won't use it either.
+ * Thanks to Nico Valster <NVALSTER@wcnd.nl.lucent.com> for the code
* NOTE: By specifying a length including the CRC position the
- * returned value should be zero. (i.e. a correct checksum in the PSA)
+ * returned value should be zero. (i.e. a correct checksum in the PSA).
*/
static u_short
psa_crc(u_short * psa, /* The PSA */
@@ -344,7 +344,7 @@ mmc_out(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
* Routine to write bytes to the Modem Management Controller.
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
*/
static inline void
mmc_write(u_long ioaddr,
@@ -361,8 +361,8 @@ mmc_write(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Read 1 byte from the MMC.
- * Optimised version for 1 byte, avoid using memory...
+ * Read a byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory.
*/
static inline u_char
mmc_in(u_long ioaddr,
@@ -383,7 +383,7 @@ mmc_in(u_long ioaddr,
* The implementation is complicated by a lack of address lines,
* which prevents decoding of the low-order bit.
* (code has just been moved in the above function)
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
*/
static inline void
mmc_read(u_long ioaddr,
@@ -400,10 +400,10 @@ mmc_read(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Get the type of encryption available...
+ * Get the type of encryption available.
*/
static inline int
-mmc_encr(u_long ioaddr) /* i/o port of the card */
+mmc_encr(u_long ioaddr) /* I/O port of the card */
{
int temp;
@@ -416,11 +416,11 @@ mmc_encr(u_long ioaddr) /* i/o port of the card */
/*------------------------------------------------------------------*/
/*
- * Wait for the frequency EEprom to complete a command...
- * I hope this one will be optimally inlined...
+ * Wait for the frequency EEPROM to complete a command.
+ * I hope this one will be optimally inlined.
*/
static inline void
-fee_wait(u_long ioaddr, /* i/o port of the card */
+fee_wait(u_long ioaddr, /* I/O port of the card */
int delay, /* Base delay to wait for */
int number) /* Number of time to wait */
{
@@ -433,10 +433,10 @@ fee_wait(u_long ioaddr, /* i/o port of the card */
/*------------------------------------------------------------------*/
/*
- * Read bytes from the Frequency EEprom (frequency select cards).
+ * Read bytes from the Frequency EEPROM (frequency select cards).
*/
static void
-fee_read(u_long ioaddr, /* i/o port of the card */
+fee_read(u_long ioaddr, /* I/O port of the card */
u_short o, /* destination offset */
u_short * b, /* data buffer */
int n) /* number of registers */
@@ -452,31 +452,31 @@ fee_read(u_long ioaddr, /* i/o port of the card */
/* Write the read command */
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
- /* Wait until EEprom is ready (should be quick !) */
+ /* Wait until EEPROM is ready (should be quick). */
fee_wait(ioaddr, 10, 100);
- /* Read the value */
+ /* Read the value. */
*--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
}
}
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */
/*------------------------------------------------------------------*/
/*
- * Write bytes from the Frequency EEprom (frequency select cards).
- * This is a bit complicated, because the frequency eeprom has to
+ * Write bytes from the Frequency EEPROM (frequency select cards).
+ * This is a bit complicated, because the frequency EEPROM has to
* be unprotected and the write enabled.
* Jean II
*/
static void
-fee_write(u_long ioaddr, /* i/o port of the card */
+fee_write(u_long ioaddr, /* I/O port of the card */
u_short o, /* destination offset */
u_short * b, /* data buffer */
int n) /* number of registers */
{
- b += n; /* Position at the end of the area */
+ b += n; /* Position at the end of the area. */
#ifdef EEPROM_IS_PROTECTED /* disabled */
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
@@ -485,61 +485,61 @@ fee_write(u_long ioaddr, /* i/o port of the card */
fee_wait(ioaddr, 10, 100);
- /* Read the protected register */
- printk("Protected 2 : %02X-%02X\n",
+ /* Read the protected register. */
+ printk("Protected 2: %02X-%02X\n",
mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
#endif /* DOESNT_SEEM_TO_WORK */
- /* Enable protected register */
+ /* Enable protected register. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
fee_wait(ioaddr, 10, 100);
- /* Unprotect area */
+ /* Unprotect area. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
- /* Or use : */
+ /* or use: */
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
#endif /* DOESNT_SEEM_TO_WORK */
fee_wait(ioaddr, 10, 100);
#endif /* EEPROM_IS_PROTECTED */
- /* Write enable */
+ /* Write enable. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
fee_wait(ioaddr, 10, 100);
- /* Write the EEprom address */
+ /* Write the EEPROM address. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
/* Loop on all buffer */
while(n-- > 0)
{
- /* Write the value */
+ /* Write the value. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
- /* Write the write command */
+ /* Write the write command. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
- /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
- udelay(10000);
+ /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
+ mdelay(10);
fee_wait(ioaddr, 10, 100);
}
- /* Write disable */
+ /* Write disable. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
fee_wait(ioaddr, 10, 100);
#ifdef EEPROM_IS_PROTECTED /* disabled */
- /* Reprotect EEprom */
+ /* Reprotect EEPROM. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
@@ -550,13 +550,13 @@ fee_write(u_long ioaddr, /* i/o port of the card */
/************************ I82586 SUBROUTINES *************************/
/*
- * Usefull subroutines to manage the Ethernet controler
+ * Useful subroutines to manage the Ethernet controller
*/
/*------------------------------------------------------------------*/
/*
* Read bytes from the on-board RAM.
- * Why inlining this function make it fail ???
+ * Why does inlining this function make it fail?
*/
static /*inline*/ void
obram_read(u_long ioaddr,
@@ -584,7 +584,7 @@ obram_write(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Acknowledge the reading of the status issued by the i82586
+ * Acknowledge the reading of the status issued by the i82586.
*/
static void
wv_ack(device * dev)
@@ -626,7 +626,7 @@ wv_ack(device * dev)
/*------------------------------------------------------------------*/
/*
* Set channel attention bit and busy wait until command has
- * completed, then acknowledge the command completion.
+ * completed, then acknowledge completion of the command.
*/
static inline int
wv_synchronous_cmd(device * dev,
@@ -675,7 +675,7 @@ wv_synchronous_cmd(device * dev,
/*------------------------------------------------------------------*/
/*
* Configuration commands completion interrupt.
- * Check if done, and if ok...
+ * Check if done, and if OK.
*/
static inline int
wv_config_complete(device * dev,
@@ -693,7 +693,7 @@ wv_config_complete(device * dev,
mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
+ sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
- /* Read the status of the last command (set mc list) */
+ /* Read the status of the last command (set mc list). */
obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status));
/* If not completed -> exit */
@@ -717,7 +717,7 @@ wv_config_complete(device * dev,
printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
dev->name, str, status);
- /* Check config command */
+ /* Check config command. */
cfg_addr = ias_addr - sizeof(ac_cfg_t);
obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
if(status & AC_SFLD_OK != 0)
@@ -758,7 +758,7 @@ wv_complete(device * dev,
/* Read the first transmit buffer */
obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
- /* Hack for reconfiguration... */
+ /* Hack for reconfiguration */
if(tx_status == 0xFFFF)
if(!wv_config_complete(dev, ioaddr, lp))
break; /* Not completed */
@@ -776,7 +776,7 @@ if (lp->tx_n_in_use > 0)
printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
*/
- /* Was it the last one ? */
+ /* Was it the last one? */
if(lp->tx_n_in_use <= 0)
lp->tx_first_in_use = I82586NULL;
else
@@ -787,7 +787,7 @@ if (lp->tx_n_in_use > 0)
lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
}
- /* Hack for reconfiguration... */
+ /* Hack for reconfiguration */
if(tx_status == 0xFFFF)
continue;
@@ -882,12 +882,12 @@ if (lp->tx_n_in_use > 0)
/*------------------------------------------------------------------*/
/*
- * Reconfigure the i82586, or at least ask for it...
- * Because wv_82586_config use a transmission buffer, we must do it
+ * Reconfigure the i82586, or at least ask for it.
+ * Because wv_82586_config uses a transmission buffer, we must do it
* when we are sure that there is one left, so we do it now
* or in wavelan_packet_xmit() (I can't find any better place,
- * wavelan_interrupt is not an option...), so you may experience
- * some delay sometime...
+ * wavelan_interrupt is not an option), so you may experience
+ * delays sometimes.
*/
static inline void
wv_82586_reconfig(device * dev)
@@ -909,8 +909,8 @@ wv_82586_reconfig(device * dev)
/********************* DEBUG & INFO SUBROUTINES *********************/
/*
- * This routines are used in the code to show debug informations.
- * Most of the time, it dump the content of hardware structures...
+ * This routine is used in the code to show information for debugging.
+ * Most of the time, it dumps the contents of hardware structures.
*/
#ifdef DEBUG_PSA_SHOW
@@ -921,7 +921,7 @@ wv_82586_reconfig(device * dev)
static void
wv_psa_show(psa_t * p)
{
- printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
p->psa_io_base_addr_2,
@@ -1006,7 +1006,7 @@ wv_psa_show(psa_t * p)
/*------------------------------------------------------------------*/
/*
* Print the formatted status of the Modem Management Controller.
- * This function need to be completed...
+ * This function needs to be completed.
*/
static void
wv_mmc_show(device * dev)
@@ -1028,12 +1028,12 @@ wv_mmc_show(device * dev)
mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m));
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
/* Don't forget to update statistics */
lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
#endif /* WIRELESS_EXT */
- printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED
printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
m.mmr_unused0[0],
@@ -1045,7 +1045,7 @@ wv_mmc_show(device * dev)
m.mmr_unused0[6],
m.mmr_unused0[7]);
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+ printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
m.mmr_des_avail, m.mmr_des_status);
#ifdef DEBUG_SHOW_UNUSED
printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
@@ -1093,7 +1093,7 @@ wv_mmc_show(device * dev)
#ifdef DEBUG_I82586_SHOW
/*------------------------------------------------------------------*/
/*
- * Print the last block of the i82586 memory
+ * Print the last block of the i82586 memory.
*/
static void
wv_scb_show(u_long ioaddr)
@@ -1102,15 +1102,15 @@ wv_scb_show(u_long ioaddr)
obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
- printk(KERN_DEBUG "##### wavelan system control block: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
printk(KERN_DEBUG "status: ");
printk("stat 0x%x[%s%s%s%s] ",
(scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
- (scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "",
+ (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "",
(scb.scb_status & SCB_ST_FR) ? "frame received," : "",
- (scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "",
- (scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : "");
+ (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+ (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : "");
printk("cus 0x%x[%s%s%s] ",
(scb.scb_status & SCB_ST_CUS) >> 8,
((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
@@ -1163,17 +1163,17 @@ wv_ru_show(device * dev)
{
/* net_local *lp = (net_local *) dev->priv; */
- printk(KERN_DEBUG "##### wavelan i82586 receiver unit status: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
printk(KERN_DEBUG "ru:");
/*
- * Not implemented yet...
+ * Not implemented yet
*/
printk("\n");
} /* wv_ru_show */
/*------------------------------------------------------------------*/
/*
- * Display info about one control block of the i82586 memory
+ * Display info about one control block of the i82586 memory.
*/
static void
wv_cu_show_one(device * dev,
@@ -1206,7 +1206,7 @@ wv_cu_show_one(device * dev,
/*------------------------------------------------------------------*/
/*
- * Print status of the command unit of the i82586
+ * Print status of the command unit of the i82586.
*/
static void
wv_cu_show(device * dev)
@@ -1215,7 +1215,7 @@ wv_cu_show(device * dev)
unsigned int i;
u_short p;
- printk(KERN_DEBUG "##### wavelan i82586 command unit status: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n");
printk(KERN_DEBUG);
for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
@@ -1310,8 +1310,8 @@ wv_packet_info(u_char * p, /* Packet to dump */
/*------------------------------------------------------------------*/
/*
- * This is the information which is displayed by the driver at startup
- * There is a lot of flag to configure it at your will...
+ * This is the information which is displayed by the driver at startup.
+ * There are lots of flags for configuring it to your liking.
*/
static inline void
wv_init_info(device * dev)
@@ -1335,13 +1335,13 @@ wv_init_info(device * dev)
#endif
#ifdef DEBUG_BASIC_SHOW
- /* Now, let's go for the basic stuff */
+ /* Now, let's go for the basic stuff. */
printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
printk(", IRQ %d", dev->irq);
- /* Print current network id */
+ /* Print current network ID. */
if(psa.psa_nwid_select)
printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
else
@@ -1353,14 +1353,13 @@ wv_init_info(device * dev)
{
unsigned short freq;
- /* Ask the EEprom to read the frequency from the first area */
- fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
- &freq, 1);
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(ioaddr, 0x00, &freq, 1);
/* Print frequency */
printk(", 2.00, %ld", (freq >> 6) + 2400L);
- /* Hack !!! */
+ /* Hack! */
if(freq & 0x20)
printk(".5");
}
@@ -1381,7 +1380,7 @@ wv_init_info(device * dev)
printk("MCIA");
break;
default:
- printk("???");
+ printk("?");
}
printk(", ");
switch (psa.psa_subband)
@@ -1402,7 +1401,7 @@ wv_init_info(device * dev)
printk("2430.5");
break;
default:
- printk("???");
+ printk("?");
}
}
@@ -1417,7 +1416,7 @@ wv_init_info(device * dev)
/********************* IOCTL, STATS & RECONFIG *********************/
/*
- * We found here routines that are called by Linux on differents
+ * We found here routines that are called by Linux on different
* occasions after the configuration and not for transmitting data
* These may be called when the user use ifconfig, /proc/net/dev
* or wireless extensions
@@ -1425,7 +1424,7 @@ wv_init_info(device * dev)
/*------------------------------------------------------------------*/
/*
- * Get the current ethernet statistics. This may be called with the
+ * Get the current Ethernet statistics. This may be called with the
* card open or closed.
* Used when the user read /proc/net/dev
*/
@@ -1461,9 +1460,9 @@ wavelan_set_multicast_list(device * dev)
dev->name, dev->flags, dev->mc_count);
#endif
- /* If we ask for promiscuous mode,
- * or all multicast addresses (we don't have that !)
- * or too much multicast addresses for the hardware filter */
+ /* Are we asking for promiscuous mode,
+ * or all multicast addresses (we don't have that!)
+ * or too many multicast addresses for the hardware filter? */
if((dev->flags & IFF_PROMISC) ||
(dev->flags & IFF_ALLMULTI) ||
(dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES))
@@ -1478,12 +1477,12 @@ wavelan_set_multicast_list(device * dev)
wv_82586_reconfig(dev);
- /* Tell the kernel that we are doing a really bad job... */
+ /* Tell the kernel that we are doing a really bad job. */
dev->flags |= IFF_PROMISC;
}
}
else
- /* If there is some multicast addresses to send */
+ /* Are there multicast addresses to send? */
if(dev->mc_list != (struct dev_mc_list *) NULL)
{
/*
@@ -1522,7 +1521,7 @@ wavelan_set_multicast_list(device * dev)
/*------------------------------------------------------------------*/
/*
- * This function doesn't exist...
+ * This function doesn't exist.
*/
static int
wavelan_set_mac_address(device * dev,
@@ -1530,25 +1529,25 @@ wavelan_set_mac_address(device * dev,
{
struct sockaddr * mac = addr;
- /* Copy the address */
+ /* Copy the address. */
memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
- /* Reconfig the beast */
+ /* Reconfigure the beast. */
wv_82586_reconfig(dev);
return 0;
}
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */
/*------------------------------------------------------------------*/
/*
- * Frequency setting (for hardware able of it)
- * It's a bit complicated and you don't really want to look into it...
+ * Frequency setting (for hardware capable of it)
+ * It's a bit complicated and you don't really want to look into it.
* (called in wavelan_ioctl)
*/
static inline int
-wv_set_frequency(u_long ioaddr, /* i/o port of the card */
+wv_set_frequency(u_long ioaddr, /* I/O port of the card */
iw_freq * frequency)
{
const int BAND_NUM = 10; /* Number of bands */
@@ -1558,10 +1557,10 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
#endif
/* Setting by frequency */
- /* Theoritically, you may set any frequency between
+ /* Theoretically, you may set any frequency between
* the two limits with a 0.5 MHz precision. In practice,
- * I don't want you to have trouble with local
- * regulations... */
+ * I don't want you to have trouble with local regulations.
+ */
if((frequency->e == 1) &&
(frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
{
@@ -1569,29 +1568,28 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
}
/* Setting by channel (same as wfreqsel) */
- /* Warning : each channel is 22MHz wide, so some of the channels
- * will interfere... */
+ /* Warning: each channel is 22 MHz wide, so some of the channels
+ * will interfere. */
if((frequency->e == 0) &&
(frequency->m >= 0) && (frequency->m < BAND_NUM))
{
- /* frequency in 1/4 of MHz (as read in the offset register) */
+ /* frequency in units of 250 kHz (as read in the offset register) */
short bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 };
- /* Get frequency offset */
+ /* Get frequency offset. */
freq = bands[frequency->m] >> 1;
}
- /* Verify if the frequency is allowed */
+ /* Verify that the frequency is allowed. */
if(freq != 0L)
{
u_short table[10]; /* Authorized frequency table */
- /* Read the frequency table */
- fee_read(ioaddr, 0x71 /* frequency table */,
- table, 10);
+ /* Read the frequency table. */
+ fee_read(ioaddr, 0x71, table, 10);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Frequency table :");
+ printk(KERN_DEBUG "Frequency table: ");
for(i = 0; i < 10; i++)
{
printk(" %04X",
@@ -1600,7 +1598,7 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
printk("\n");
#endif
- /* Look in the table if the frequency is allowed */
+ /* Look in the table to see whether the frequency is allowed. */
if(!(table[9 - ((freq - 24) / 16)] &
(1 << ((freq - 24) % 16))))
return -EINVAL; /* not allowed */
@@ -1608,7 +1606,7 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
else
return -EINVAL;
- /* If we get a usable frequency */
+ /* if we get a usable frequency */
if(freq != 0L)
{
unsigned short area[16];
@@ -1616,36 +1614,33 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
unsigned short area_verify[16];
unsigned short dac_verify[2];
/* Corresponding gain (in the power adjust value table)
- * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
- * & WCIN062D.DOC, page 6.2.9 */
+ * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+ * and WCIN062D.DOC, page 6.2.9. */
unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
int power_band = 0; /* Selected band */
unsigned short power_adjust; /* Correct value */
- /* Search for the gain */
+ /* Search for the gain. */
power_band = 0;
while((freq > power_limit[power_band]) &&
(power_limit[++power_band] != 0))
;
- /* Read the first area */
- fee_read(ioaddr, 0x00,
- area, 16);
+ /* Read the first area. */
+ fee_read(ioaddr, 0x00, area, 16);
- /* Read the DAC */
- fee_read(ioaddr, 0x60,
- dac, 2);
+ /* Read the DAC. */
+ fee_read(ioaddr, 0x60, dac, 2);
- /* Read the new power adjust value */
- fee_read(ioaddr, 0x6B - (power_band >> 1),
- &power_adjust, 1);
+ /* Read the new power adjust value. */
+ fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1);
if(power_band & 0x1)
power_adjust >>= 8;
else
power_adjust &= 0xFF;
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
for(i = 0; i < 16; i++)
{
printk(" %04X",
@@ -1653,11 +1648,11 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
}
printk("\n");
- printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+ printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
dac[0], dac[1]);
#endif
- /* Frequency offset (for info only...) */
+ /* Frequency offset (for info only) */
area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
/* Receiver Principle main divider coefficient */
@@ -1668,64 +1663,62 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
area[13] = (freq >> 1) + 2400L;
area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
- /* Others part of the area are flags, bit streams or unused... */
+ /* Other parts of the area are flags, bit streams or unused. */
- /* Set the value in the DAC */
+ /* Set the value in the DAC. */
dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
- /* Write the first area */
+ /* Write the first area. */
fee_write(ioaddr, 0x00,
area, 16);
- /* Write the DAC */
+ /* Write the DAC. */
fee_write(ioaddr, 0x60,
dac, 2);
- /* We now should verify here that the EEprom writting was ok */
+ /* We now should verify here that the writing of the EEPROM went OK. */
- /* ReRead the first area */
- fee_read(ioaddr, 0x00,
- area_verify, 16);
+ /* Reread the first area. */
+ fee_read(ioaddr, 0x00, area_verify, 16);
- /* ReRead the DAC */
- fee_read(ioaddr, 0x60,
- dac_verify, 2);
+ /* Reread the DAC. */
+ fee_read(ioaddr, 0x60, dac_verify, 2);
- /* Compare */
+ /* Compare. */
if(memcmp(area, area_verify, 16 * 2) ||
memcmp(dac, dac_verify, 2 * 2))
{
#ifdef DEBUG_IOCTL_ERROR
- printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+ printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
#endif
return -EOPNOTSUPP;
}
/* We must download the frequency parameters to the
- * synthetisers (from the EEprom - area 1)
- * Note : as the EEprom is auto decremented, we set the end
+ * synthesizers (from the EEPROM - area 1)
+ * Note: as the EEPROM is automatically decremented, we set the end
* if the area... */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
- /* Wait until the download is finished */
+ /* Wait until the download is finished. */
fee_wait(ioaddr, 100, 100);
/* We must now download the power adjust value (gain) to
- * the synthetisers (from the EEprom - area 7 - DAC) */
+ * the synthesizers (from the EEPROM - area 7 - DAC). */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
- /* Wait until the download is finished */
+ /* Wait for the download to finish. */
fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_IOCTL_INFO
- /* Verification of what we have done... */
+ /* Verification of what we have done */
- printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
for(i = 0; i < 16; i++)
{
printk(" %04X",
@@ -1733,7 +1726,7 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
}
printk("\n");
- printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+ printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
dac_verify[0], dac_verify[1]);
#endif
@@ -1745,22 +1738,21 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */
/*------------------------------------------------------------------*/
/*
- * Give the list of available frequencies
+ * Give the list of available frequencies.
*/
static inline int
-wv_frequency_list(u_long ioaddr, /* i/o port of the card */
- iw_freq * list, /* List of frequency to fill */
+wv_frequency_list(u_long ioaddr, /* I/O port of the card */
+ iw_freq * list, /* List of frequencies to fill */
int max) /* Maximum number of frequencies */
{
u_short table[10]; /* Authorized frequency table */
long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */
int i; /* index in the table */
- /* Read the frequency table */
- fee_read(ioaddr, 0x71 /* frequency table */,
- table, 10);
+ /* Read the frequency table. */
+ fee_read(ioaddr, 0x71 /* frequency table */, table, 10);
- /* Look all frequencies */
+ /* Check all frequencies. */
i = 0;
for(freq = 0; freq < 150; freq++)
/* Look in the table if the frequency is allowed */
@@ -1770,7 +1762,7 @@ wv_frequency_list(u_long ioaddr, /* i/o port of the card */
list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
list[i++].e = 1;
- /* Check number */
+ /* Check number. */
if(i >= max)
return(i);
}
@@ -1781,9 +1773,9 @@ wv_frequency_list(u_long ioaddr, /* i/o port of the card */
#ifdef WIRELESS_SPY
/*------------------------------------------------------------------*/
/*
- * Gather wireless spy statistics : for each packet, compare the source
- * address with out list, and if match, get the stats...
- * Sorry, but this function really need wireless extensions...
+ * Gather wireless spy statistics: for each packet, compare the source
+ * address with our list, and if they match, get the statistics.
+ * Sorry, but this function really needs the wireless extensions.
*/
static inline void
wl_spy_gather(device * dev,
@@ -1793,7 +1785,7 @@ wl_spy_gather(device * dev,
net_local * lp = (net_local *) dev->priv;
int i;
- /* Look all addresses */
+ /* Check all addresses. */
for(i = 0; i < lp->spy_number; i++)
/* If match */
if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
@@ -1810,12 +1802,12 @@ wl_spy_gather(device * dev,
#ifdef HISTOGRAM
/*------------------------------------------------------------------*/
/*
- * This function calculate an histogram on the signal level.
+ * This function calculates a histogram of the signal level.
* As the noise is quite constant, it's like doing it on the SNR.
* We have defined a set of interval (lp->his_range), and each time
* the level goes in that interval, we increment the count (lp->his_sum).
- * With this histogram you may detect if one wavelan is really weak,
- * or you may also calculate the mean and standard deviation of the level...
+ * With this histogram you may detect if one WaveLAN is really weak,
+ * or you may also calculate the mean and standard deviation of the level.
*/
static inline void
wl_his_gather(device * dev,
@@ -1825,25 +1817,25 @@ wl_his_gather(device * dev,
u_char level = stats[0] & MMR_SIGNAL_LVL;
int i;
- /* Find the correct interval */
+ /* Find the correct interval. */
i = 0;
while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
;
- /* Increment interval counter */
+ /* Increment interval counter. */
(lp->his_sum[i])++;
}
#endif /* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
- * Perform ioctl : config & info stuff
- * This is here that are treated the wireless extensions (iwconfig)
+ * Perform ioctl for configuration and information.
+ * It is here that the wireless extensions are treated (iwconfig).
*/
static int
-wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
- struct ifreq * rq, /* Data passed */
- int cmd) /* Ioctl number */
+wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */
+ struct ifreq * rq, /* data passed */
+ int cmd) /* ioctl number */
{
u_long ioaddr = dev->base_addr;
net_local * lp = (net_local *)dev->priv; /* lp is not unused */
@@ -1857,7 +1849,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#endif
- /* Disable interrupts & save flags */
+ /* Disable interrupts and save flags. */
x = wv_splhi();
/* Look what is the request */
@@ -1866,21 +1858,21 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
- strcpy(wrq->u.name, "Wavelan");
+ strcpy(wrq->u.name, "WaveLAN");
break;
case SIOCSIWNWID:
- /* Set NWID in wavelan */
+ /* Set NWID in WaveLAN. */
if(wrq->u.nwid.on)
{
- /* Set NWID in psa */
+ /* Set NWID in psa. */
psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
psa.psa_nwid_select = 0x01;
psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
- /* Set NWID in mmc */
+ /* Set NWID in mmc. */
m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF;
m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8;
mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
@@ -1889,19 +1881,19 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
}
else
{
- /* Disable nwid in the psa */
+ /* Disable NWID in the psa. */
psa.psa_nwid_select = 0x00;
psa_write(ioaddr, lp->hacr,
(char *)&psa.psa_nwid_select - (char *)&psa,
(unsigned char *)&psa.psa_nwid_select, 1);
- /* Disable nwid in the mmc (no filtering) */
+ /* Disable NWID in the mmc (no filtering). */
mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
}
break;
case SIOCGIWNWID:
- /* Read the NWID */
+ /* Read the NWID. */
psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
@@ -1909,7 +1901,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCSIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
@@ -1918,16 +1910,15 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCGIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ??? - especially old cards...) */
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+ * Does it work for everybody, especially old cards? */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
unsigned short freq;
- /* Ask the EEprom to read the frequency from the first area */
- fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
- &freq, 1);
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(ioaddr, 0x00, &freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1;
}
@@ -1949,7 +1940,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCSIWSENS:
- /* Set the level threshold */
+ /* Set the level threshold. */
if(!suser())
return -EPERM;
psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
@@ -1959,14 +1950,14 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCGIWSENS:
- /* Read the level threshold */
+ /* Read the level threshold. */
psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
break;
case SIOCSIWENCODE:
- /* Set encryption key */
+ /* Set encryption key. */
if(!mmc_encr(ioaddr))
{
ret = -EOPNOTSUPP;
@@ -1974,7 +1965,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
}
if(wrq->u.encoding.method)
- { /* enable encryption */
+ { /* Enable encryption. */
int i;
long long key = wrq->u.encoding.code;
@@ -1994,7 +1985,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
(unsigned char *) &psa.psa_encryption_key, 8);
}
else
- { /* disable encryption */
+ { /* Disable encryption. */
psa.psa_encryption_select = 0;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa,
@@ -2005,14 +1996,14 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCGIWENCODE:
- /* Read the encryption key */
+ /* Read the encryption key. */
if(!mmc_encr(ioaddr))
{
ret = -EOPNOTSUPP;
break;
}
- /* only super-user can see encryption key */
+ /* Only super-user can see encryption key. */
if(!suser())
{
ret = -EPERM;
@@ -2042,26 +2033,26 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCGIWRANGE:
- /* Basic checking... */
+ /* basic checking */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_range range;
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
sizeof(struct iw_range));
if(ret)
break;
- /* Set the length (useless : its constant...) */
+ /* Set the length (useless: it's constant). */
wrq->u.data.length = sizeof(struct iw_range);
- /* Set information in the range struct */
+ /* Set information in the range struct. */
range.throughput = 1.6 * 1024 * 1024; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0xFFFF;
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
@@ -2077,14 +2068,14 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
range.max_qual.level = MMR_SIGNAL_LVL;
range.max_qual.noise = MMR_SILENCE_LVL;
- /* Copy structure to the user buffer */
+ /* Copy structure to the user buffer. */
copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range));
}
break;
case SIOCGIWPRIV:
- /* Basic checking... */
+ /* Basic checking */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_priv_args priv[] =
@@ -2096,16 +2087,16 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
};
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
sizeof(priv));
if(ret)
break;
- /* Set the number of ioctl available */
+ /* Set the number of available ioctls. */
wrq->u.data.length = 4;
- /* Copy structure to the user buffer */
+ /* Copy structure to the user buffer. */
copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv));
}
@@ -2115,7 +2106,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
case SIOCSIWSPY:
/* Set the spy list */
- /* Check the number of addresses */
+ /* Check the number of addresses. */
if(wrq->u.data.length > IW_MAX_SPY)
{
ret = -E2BIG;
@@ -2123,33 +2114,33 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
}
lp->spy_number = wrq->u.data.length;
- /* If there is some addresses to copy */
+ /* Are there are addresses to copy? */
if(lp->spy_number > 0)
{
struct sockaddr address[IW_MAX_SPY];
int i;
- /* Verify where the user has set his addresses */
+ /* Verify where the user has set his addresses. */
ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
sizeof(struct sockaddr) * lp->spy_number);
if(ret)
break;
- /* Copy addresses to the driver */
+ /* Copy addresses to the driver. */
copy_from_user(address, wrq->u.data.pointer,
sizeof(struct sockaddr) * lp->spy_number);
- /* Copy addresses to the lp structure */
+ /* Copy addresses to the lp structure. */
for(i = 0; i < lp->spy_number; i++)
{
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
}
- /* Reset structure... */
+ /* Reset structure. */
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+ printk(KERN_DEBUG "SetSpy: set of new addresses is: \n");
for(i = 0; i < wrq->u.data.length; i++)
printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
@@ -2164,25 +2155,25 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
break;
case SIOCGIWSPY:
- /* Get the spy list and spy stats */
+ /* Get the spy list and spy stats. */
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
- /* If the user want to have the addresses back... */
+ /* Does the user want to have the addresses back? */
if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{
struct sockaddr address[IW_MAX_SPY];
int i;
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
(sizeof(iw_qual) + sizeof(struct sockaddr))
* IW_MAX_SPY);
if(ret)
break;
- /* Copy addresses from the lp structure */
+ /* Copy addresses from the lp structure. */
for(i = 0; i < lp->spy_number; i++)
{
memcpy(address[i].sa_data, lp->spy_address[i],
@@ -2190,16 +2181,16 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
address[i].sa_family = AF_UNIX;
}
- /* Copy addresses to the user buffer */
+ /* Copy addresses to the user buffer. */
copy_to_user(wrq->u.data.pointer, address,
sizeof(struct sockaddr) * lp->spy_number);
- /* Copy stats to the user buffer (just after) */
+ /* Copy stats to the user buffer (just after). */
copy_to_user(wrq->u.data.pointer +
(sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
- /* Reset updated flags */
+ /* Reset updated flags. */
for(i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
} /* if(pointer != NULL) */
@@ -2226,11 +2217,11 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
#ifdef HISTOGRAM
case SIOCSIPHISTO:
- /* Verif if the user is root */
+ /* Verify that the user is root. */
if(!suser())
return -EPERM;
- /* Check the number of intervals */
+ /* Check the number of intervals. */
if(wrq->u.data.length > 16)
{
ret = -E2BIG;
@@ -2238,10 +2229,10 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
}
lp->his_number = wrq->u.data.length;
- /* If there is some addresses to copy */
+ /* Are there addresses to copy? */
if(lp->his_number > 0)
{
- /* Verify where the user has set his addresses */
+ /* Verify where the user has set his addresses. */
ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
sizeof(char) * lp->his_number);
if(ret)
@@ -2250,25 +2241,25 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
copy_from_user(lp->his_range, wrq->u.data.pointer,
sizeof(char) * lp->his_number);
- /* Reset structure... */
+ /* Reset structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
}
break;
case SIOCGIPHISTO:
- /* Set the number of intervals */
+ /* Set the number of intervals. */
wrq->u.data.length = lp->his_number;
/* Give back the distribution statistics */
if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
sizeof(long) * 16);
if(ret)
break;
- /* Copy data to the user buffer */
+ /* Copy data to the user buffer. */
copy_to_user(wrq->u.data.pointer, lp->his_sum,
sizeof(long) * lp->his_number);
} /* if(pointer != NULL) */
@@ -2281,7 +2272,7 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
ret = -EOPNOTSUPP;
}
- /* ReEnable interrupts & restore flags */
+ /* Enable interrupts and restore flags. */
wv_splx(x);
#ifdef DEBUG_IOCTL_TRACE
@@ -2292,8 +2283,8 @@ wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
/*------------------------------------------------------------------*/
/*
- * Get wireless statistics
- * Called by /proc/net/wireless...
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
*/
static iw_stats *
wavelan_get_wireless_stats(device * dev)
@@ -2308,14 +2299,14 @@ wavelan_get_wireless_stats(device * dev)
printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
#endif
- /* Disable interrupts & save flags */
+ /* Disable interrupts and save flags. */
x = wv_splhi();
if(lp == (net_local *) NULL)
return (iw_stats *) NULL;
wstats = &lp->wstats;
- /* Get data from the mmc */
+ /* Get data from the mmc. */
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
@@ -2324,7 +2315,7 @@ wavelan_get_wireless_stats(device * dev)
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
- /* Copy data to wireless stuff */
+ /* Copy data to wireless stuff. */
wstats->status = m.mmr_dce_status;
wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
@@ -2336,7 +2327,7 @@ wavelan_get_wireless_stats(device * dev)
wstats->discard.code = 0L;
wstats->discard.misc = 0L;
- /* ReEnable interrupts & restore flags */
+ /* Enable interrupts and restore flags. */
wv_splx(x);
#ifdef DEBUG_IOCTL_TRACE
@@ -2348,22 +2339,22 @@ wavelan_get_wireless_stats(device * dev)
/************************* PACKET RECEPTION *************************/
/*
- * This part deal with receiving the packets.
- * The interrupt handler get an interrupt when a packet has been
- * successfully received and called this part...
+ * This part deals with receiving the packets.
+ * The interrupt handler gets an interrupt when a packet has been
+ * successfully received and calls this part.
*/
/*------------------------------------------------------------------*/
/*
- * This routine does the actual copy of data (including the ethernet
+ * This routine does the actual copying of data (including the Ethernet
* header structure) from the WaveLAN card to an sk_buff chain that
- * will be passed up to the network interface layer. NOTE: We
+ * will be passed up to the network interface layer. NOTE: we
* currently don't handle trailer protocols (neither does the rest of
* the network interface), so if that is needed, it will (at least in
* part) be added here. The contents of the receive ring buffer are
* copied to a message chain that is then passed to the kernel.
*
- * Note: if any errors occur, the packet is "dropped on the floor"
+ * Note: if any errors occur, the packet is "dropped on the floor".
* (called by wv_packet_rcv())
*/
static inline void
@@ -2393,7 +2384,7 @@ wv_packet_read(device * dev,
skb->dev = dev;
- /* Copy the packet to the buffer */
+ /* Copy the packet to the buffer. */
obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
skb->protocol=eth_type_trans(skb, dev);
@@ -2401,7 +2392,7 @@ wv_packet_read(device * dev,
wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
#endif /* DEBUG_RX_INFO */
- /* Statistics gathering & stuff associated.
+ /* Statistics-gathering and associated stuff.
* It seem a bit messy with all the define, but it's really simple... */
#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
if(
@@ -2413,13 +2404,14 @@ wv_packet_read(device * dev,
#endif /* HISTOGRAM */
0)
{
- u_char stats[3]; /* Signal level, Noise level, Signal quality */
+ u_char stats[3]; /* signal level, noise level, signal quality */
- /* read signal level, silence level and signal quality bytes */
- /* Note : in the Pcmcia hardware, these are part of the frame. It seem
+ /* Read signal level, silence level and signal quality bytes. */
+ /* Note: in the PCMCIA hardware, these are part of the frame. It seems
* that for the ISA hardware, it's nowhere to be found in the frame,
- * so I'm oblige to do this (it has side effect on /proc/net/wireless)
- * Any idea ? */
+ * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+ * Any ideas?
+ */
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
@@ -2440,11 +2432,11 @@ wv_packet_read(device * dev,
#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
/*
- * Hand the packet to the Network Module
+ * Hand the packet to the network module.
*/
netif_rx(skb);
- /* Keep stats up to date */
+ /* Keep statistics up to date */
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
@@ -2470,7 +2462,7 @@ wv_receive(device * dev)
printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
#endif
- /* Loop on each received packet */
+ /* Loop on each received packet. */
for(;;)
{
fd_t fd;
@@ -2479,13 +2471,13 @@ wv_receive(device * dev)
obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
- /* If the current frame is not complete, we have reach the end... */
+ /* If the current frame is not complete, we have reached the end. */
if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
- break; /* This is how we exit the loop */
+ break; /* This is how we exit the loop. */
nreaped++;
- /* Check if frame correctly received */
+ /* Check whether frame was correctly received. */
if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) !=
(FD_STATUS_B | FD_STATUS_OK))
{
@@ -2508,7 +2500,7 @@ wv_receive(device * dev)
#endif
}
- /* Check is there was problems in the frame processing */
+ /* Were there problems in processing the frame? Let's check. */
if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 |
FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11))
!= 0)
@@ -2565,7 +2557,7 @@ wv_receive(device * dev)
}
}
- /* Check if frame contain a pointer to the data */
+ /* Does the frame contain a pointer to the data? Let's check. */
if(fd.fd_rbd_offset == I82586NULL)
#ifdef DEBUG_RX_ERROR
printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name);
@@ -2618,7 +2610,7 @@ wv_receive(device * dev)
/*********************** PACKET TRANSMISSION ***********************/
/*
- * This part deal with sending packet through the wavelan
+ * This part deals with sending packets through the WaveLAN.
*
*/
@@ -2628,13 +2620,13 @@ wv_receive(device * dev)
* locations on the WaveLAN card and starts the card off on
* the transmit.
*
- * The principle :
- * Each block contain a transmit command, a nop command,
+ * The principle:
+ * Each block contains a transmit command, a NOP command,
* a transmit block descriptor and a buffer.
* The CU read the transmit block which point to the tbd,
- * read the tbd and the the content of the buffer.
+ * read the tbd and the content of the buffer.
* When it has finish with it, it goes to the next command
- * which in our case is the nop. The nop point on itself,
+ * which in our case is the NOP. The NOP points on itself,
* so the CU stop here.
* When we add the next block, we modify the previous nop
* to make it point on the new tx command.
@@ -2665,13 +2657,13 @@ wv_packet_write(device * dev,
printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
#endif
- /* Check if we need some padding */
+ /* Do we need some padding? */
if(clen < ETH_ZLEN)
clen = ETH_ZLEN;
x = wv_splhi();
- /* Calculate addresses of next block and previous block */
+ /* Calculate addresses of next block and previous block. */
txblock = lp->tx_first_free;
txpred = txblock - TXBLOCKZ;
if(txpred < OFFSET_CU)
@@ -2687,14 +2679,14 @@ if (lp->tx_n_in_use > 0)
lp->tx_n_in_use++;
- /* Calculate addresses of the differents part of the block */
+ /* Calculate addresses of the different parts of the block. */
tx_addr = txblock;
nop_addr = tx_addr + sizeof(tx);
tbd_addr = nop_addr + sizeof(nop);
buf_addr = tbd_addr + sizeof(tbd);
/*
- * Transmit command.
+ * Transmit command
*/
tx.tx_h.ac_status = 0;
obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
@@ -2702,7 +2694,7 @@ if (lp->tx_n_in_use > 0)
sizeof(tx.tx_h.ac_status));
/*
- * NOP command.
+ * NOP command
*/
nop.nop_h.ac_status = 0;
obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
@@ -2714,7 +2706,7 @@ if (lp->tx_n_in_use > 0)
sizeof(nop.nop_h.ac_link));
/*
- * Transmit buffer descriptor.
+ * Transmit buffer descriptor
*/
tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
tbd.tbd_next_bd_offset = I82586NULL;
@@ -2723,7 +2715,7 @@ if (lp->tx_n_in_use > 0)
obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
/*
- * Data.
+ * Data
*/
obram_write(ioaddr, buf_addr, buf, clen);
@@ -2741,13 +2733,13 @@ if (lp->tx_n_in_use > 0)
(unsigned char *) &nop.nop_h.ac_link,
sizeof(nop.nop_h.ac_link));
- /* Keep stats up to date */
+ /* Keep stats up to date. */
lp->stats.tx_bytes += length;
/* If watchdog not already active, activate it... */
if(lp->watchdog.prev == (timer_list *) NULL)
{
- /* set timer to expire in WATCHDOG_JIFFIES */
+ /* Set timer to expire in WATCHDOG_JIFFIES. */
lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
add_timer(&lp->watchdog);
}
@@ -2772,9 +2764,9 @@ if (lp->tx_n_in_use > 0)
/*------------------------------------------------------------------*/
/*
* This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the the harware is ready to accept
- * the packet. We also prevent reentrance. Then, we call the function
- * to send the packet...
+ * In this routine, we check if the harware is ready to accept
+ * the packet. We also prevent reentrance. Then we call the function
+ * to send the packet.
*/
static int
wavelan_packet_xmit(struct sk_buff * skb,
@@ -2788,9 +2780,9 @@ wavelan_packet_xmit(struct sk_buff * skb,
#endif
/* This flag indicate that the hardware can't perform a transmission.
- * Theoritically, NET3 check it before sending a packet to the driver,
- * but in fact it never do that and pool continuously.
- * As the watchdog will abort too long transmissions, we are quite safe...
+ * Theoretically, NET3 checks it before sending a packet to the driver,
+ * but in fact it never does that and pools continuously.
+ * As the watchdog will abort overly long transmissions, we are quite safe.
*/
if(dev->tbusy)
return 1;
@@ -2805,7 +2797,9 @@ wavelan_packet_xmit(struct sk_buff * skb,
#endif
else
{
- /* If somebody has asked to reconfigure the controler, we can do it now */
+ /* If somebody has asked to reconfigure the controller,
+ * we can do it now.
+ */
if(lp->reconfig_82586)
{
wv_82586_config(dev);
@@ -2829,12 +2823,12 @@ wavelan_packet_xmit(struct sk_buff * skb,
return 0;
}
-/********************** HARDWARE CONFIGURATION **********************/
+/*********************** HARDWARE CONFIGURATION ***********************/
/*
- * This part do the real job of starting and configuring the hardware.
+ * This part does the real job of starting and configuring the hardware.
*/
-/*------------------------------------------------------------------*/
+/*--------------------------------------------------------------------*/
/*
* Routine to initialize the Modem Management Controller.
* (called by wv_hw_reset())
@@ -2852,7 +2846,7 @@ wv_mmc_init(device * dev)
printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
#endif
- /* Read the parameter storage area */
+ /* Read the parameter storage area. */
psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
#ifdef USE_PSA_CONFIG
@@ -2864,17 +2858,17 @@ wv_mmc_init(device * dev)
/* Is the PSA is not configured */
if(!configured)
{
- /* User will be able to configure NWID after (with iwconfig) */
+ /* User will be able to configure NWID later (with iwconfig). */
psa.psa_nwid[0] = 0;
psa.psa_nwid[1] = 0;
- /* As NWID is not set : no NWID checking */
+ /* no NWID checking since NWID is not set */
psa.psa_nwid_select = 0;
/* Disable encryption */
psa.psa_encryption_select = 0;
- /* Set to standard values
+ /* Set to standard values:
* 0x04 for AT,
* 0x01 for MCA,
* 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
@@ -2889,7 +2883,7 @@ wv_mmc_init(device * dev)
psa.psa_conf_status |= 1;
#ifdef USE_PSA_CONFIG
- /* Write the psa */
+ /* Write the psa. */
psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 4);
psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
@@ -2901,10 +2895,10 @@ wv_mmc_init(device * dev)
#endif
}
- /* Zero the mmc structure */
+ /* Zero the mmc structure. */
memset(&m, 0x00, sizeof(m));
- /* Copy PSA info to the mmc */
+ /* Copy PSA info to the mmc. */
m.mmw_netw_id_l = psa.psa_nwid[1];
m.mmw_netw_id_h = psa.psa_nwid[0];
@@ -2924,7 +2918,7 @@ wv_mmc_init(device * dev)
m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
- /* Missing : encryption stuff... */
+ /* Encryption stuff is missing. */
/*
* Set default modem control parameters.
@@ -2942,58 +2936,58 @@ wv_mmc_init(device * dev)
m.mmw_decay_prm = 0;
m.mmw_decay_updat_prm = 0;
- /* Write all info to mmc */
+ /* Write all info to MMC. */
mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
- /* The following code start the modem of the 2.00 frequency
- * selectable cards at power on. It's not strictly needed for the
- * following boots...
+ /* The following code starts the modem of the 2.00 frequency
+ * selectable cards at power on. It's not strictly needed for the
+ * following boots.
* The original patch was by Joe Finney for the PCMCIA driver, but
- * I've cleaned it a bit and add documentation.
+ * I've cleaned it up a bit and added documentation.
* Thanks to Loeke Brederveld from Lucent for the info.
*/
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ??? - especially old cards...) */
- /* Note : WFREQSEL verify that it is able to read from EEprom
- * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
- * is 0xA (Xilinx version) or 0xB (Ariadne version).
- * My test is more crude but do work... */
+ * Does it work for everybody, especially old cards? */
+ /* Note: WFREQSEL verifies that it is able to read a sensible
+ * frequency from from EEPROM (address 0x00) and that
+ * MMR_FEE_STATUS_ID is 0xA (Xilinx version) or 0xB (Ariadne version).
+ * My test is more crude but does work. */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
/* We must download the frequency parameters to the
- * synthetisers (from the EEprom - area 1)
- * Note : as the EEprom is auto decremented, we set the end
+ * synthesizers (from the EEPROM - area 1)
+ * Note: as the EEPROM is automatically decremented, we set the end
* if the area... */
m.mmw_fee_addr = 0x0F;
m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
(unsigned char *)&m.mmw_fee_ctrl, 2);
- /* Wait until the download is finished */
+ /* Wait until the download is finished. */
fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_CONFIG_INFO
- /* The frequency was in the last word downloaded... */
+ /* The frequency was in the last word downloaded. */
mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m,
(unsigned char *)&m.mmw_fee_data_l, 2);
- /* Print some info for the user */
- printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+ /* Print some info for the user. */
+ printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n",
dev->name,
((m.mmw_fee_data_h << 4) |
(m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
#endif
/* We must now download the power adjust value (gain) to
- * the synthetisers (from the EEprom - area 7 - DAC) */
+ * the synthesizers (from the EEPROM - area 7 - DAC). */
m.mmw_fee_addr = 0x61;
m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
(unsigned char *)&m.mmw_fee_ctrl, 2);
- /* Wait until the download is finished */
+ /* Wait until the download is finished. */
} /* if 2.00 card */
#ifdef DEBUG_CONFIG_TRACE
@@ -3091,13 +3085,13 @@ wv_ru_start(device * dev)
* Start the command unit executing the NOP
* self-loop of the first transmit block.
*
- * Here, we create the list of send buffer used to transmit packets
+ * Here we create the list of send buffers used to transmit packets
* between the PC and the command unit. For each buffer, we create a
* buffer descriptor (pointing on the buffer), a transmit command
- * (pointing to the buffer descriptor) and a nop command.
- * The transmit command is linked to the nop, and the nop to itself.
- * When we will have finish to execute the transmit command, we will
- * then loop on the nop. By releasing the nop link to a new command,
+ * (pointing to the buffer descriptor) and a NOP command.
+ * The transmit command is linked to the NOP, and the NOP to itself.
+ * When we will have finished executing the transmit command, we will
+ * then loop on the NOP. By releasing the NOP link to a new command,
* we may send another buffer.
*
* (called by wv_hw_reset())
@@ -3194,12 +3188,13 @@ wv_cu_start(device * dev)
/*------------------------------------------------------------------*/
/*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
*
- * It initialise the scp, iscp and scb structure
- * The two first are only pointer to the next.
+ * It initialises the scp, iscp and scb structure
+ * The first two are just pointers to the next.
* The last one is used for basic configuration and for basic
- * communication (interrupt status)
+ * communication (interrupt status).
*
* (called by wv_hw_reset())
*/
@@ -3240,7 +3235,7 @@ wv_82586_start(device * dev)
iscp.iscp_offset = OFFSET_SCB;
obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
- /* Our first command is to reset the i82586 */
+ /* Our first command is to reset the i82586. */
memset(&scb, 0x00, sizeof(scb));
scb.scb_command = SCB_CMD_RESET;
scb.scb_cbl_offset = OFFSET_CU;
@@ -3249,7 +3244,7 @@ wv_82586_start(device * dev)
set_chan_attn(ioaddr, lp->hacr);
- /* Wait for command to finish */
+ /* Wait for command to finish. */
for(i = 1000; i > 0; i--)
{
obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp));
@@ -3269,7 +3264,7 @@ wv_82586_start(device * dev)
return -1;
}
- /* Check command completion */
+ /* Check command completion. */
for(i = 15; i > 0; i--)
{
obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb));
@@ -3291,7 +3286,7 @@ wv_82586_start(device * dev)
wv_ack(dev);
- /* Set the action command header */
+ /* Set the action command header. */
memset(&cb, 0x00, sizeof(cb));
cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
cb.ac_link = OFFSET_CU;
@@ -3322,14 +3317,15 @@ wv_82586_start(device * dev)
/*------------------------------------------------------------------*/
/*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
*
* This routine is a violent hack. We use the first free transmit block
* to make our configuration. In the buffer area, we create the three
- * configure command (linked). We make the previous nop point to the
- * beggining of the buffer instead of the tx command. After, we go as
- * usual to the nop command...
- * Note that only the last command (mc_set) will generate an interrupt...
+ * configuration commands (linked). We make the previous NOP point to
+ * the beginning of the buffer instead of the tx command. After, we go
+ * as usual to the NOP command.
+ * Note that only the last command (mc_set) will generate an interrupt.
*
* (called by wv_hw_reset(), wv_82586_reconfig())
*/
@@ -3360,7 +3356,7 @@ wv_82586_config(device * dev)
x = wv_splhi();
- /* Calculate addresses of next block and previous block */
+ /* Calculate addresses of next block and previous block. */
txblock = lp->tx_first_free;
txpred = txblock - TXBLOCKZ;
if(txpred < OFFSET_CU)
@@ -3371,16 +3367,16 @@ wv_82586_config(device * dev)
lp->tx_n_in_use++;
- /* Calculate addresses of the differents part of the block */
+ /* Calculate addresses of the different parts of the block. */
tx_addr = txblock;
nop_addr = tx_addr + sizeof(tx);
tbd_addr = nop_addr + sizeof(nop);
- cfg_addr = tbd_addr + sizeof(tbd_t); /* beggining of the buffer */
+ cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */
ias_addr = cfg_addr + sizeof(cfg);
mcs_addr = ias_addr + sizeof(ias);
/*
- * Transmit command.
+ * Transmit command
*/
tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */
obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
@@ -3388,7 +3384,7 @@ wv_82586_config(device * dev)
sizeof(tx.tx_h.ac_status));
/*
- * NOP command.
+ * NOP command
*/
nop.nop_h.ac_status = 0;
obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
@@ -3399,23 +3395,23 @@ wv_82586_config(device * dev)
(unsigned char *) &nop.nop_h.ac_link,
sizeof(nop.nop_h.ac_link));
- /* Create a configure action */
+ /* Create a configure action. */
memset(&cfg, 0x00, sizeof(cfg));
#if 0
/*
- * The default board configuration.
+ * The default board configuration
*/
cfg.fifolim_bytecnt = 0x080c;
cfg.addrlen_mode = 0x2600;
cfg.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
cfg.slot_time = 0xf00c; /* slottime=12 */
- cfg.hardware = 0x0008; /* tx even w/o CD */
+ cfg.hardware = 0x0008; /* tx even without CD */
cfg.min_frame_len = 0x0040;
#endif /* 0 */
/*
- * For Linux we invert AC_CFG_ALOC(..) so as to conform
+ * For Linux we invert AC_CFG_ALOC() so as to conform
* to the way that net packets reach us from above.
* (See also ac_tx_t.)
*/
@@ -3456,21 +3452,21 @@ wv_82586_config(device * dev)
cfg.cfg_h.ac_link = ias_addr;
obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg));
- /* Setup the MAC address */
+ /* Set up the MAC address */
memset(&ias, 0x00, sizeof(ias));
ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
ias.ias_h.ac_link = mcs_addr;
memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias));
- /* Initialize adapter's ethernet multicast addresses */
+ /* Initialize adapter's Ethernet multicast addresses */
memset(&mcs, 0x00, sizeof(mcs));
mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
mcs.mcs_h.ac_link = nop_addr;
mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs));
- /* If any address to set */
+ /* Any address to set? */
if(lp->mc_count)
{
for(dmi=dev->mc_list; dmi; dmi=dmi->next)
@@ -3526,8 +3522,8 @@ wv_82586_config(device * dev)
/*------------------------------------------------------------------*/
/*
- * This routine stop gracefully the WaveLAN controler (i82586).
- * (called by wavelan_close())
+ * This routine, called by wavelan_close(), gracefully stops the
+ * WaveLAN controller (i82586).
*/
static inline void
wv_82586_stop(device * dev)
@@ -3540,7 +3536,7 @@ wv_82586_stop(device * dev)
printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
#endif
- /* Suspend both command unit and receive unit */
+ /* Suspend both command unit and receive unit. */
scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
(unsigned char *)&scb_cmd, sizeof(scb_cmd));
@@ -3556,7 +3552,7 @@ wv_82586_stop(device * dev)
/*------------------------------------------------------------------*/
/*
- * Totally reset the wavelan and restart it.
+ * Totally reset the WaveLAN and restart it.
* Performs the following actions:
* 1. A power reset (reset DMA)
* 2. Initialize the radio modem (using wv_mmc_init)
@@ -3575,11 +3571,11 @@ wv_hw_reset(device * dev)
(unsigned int)dev);
#endif
- /* If watchdog was activated, kill it ! */
+ /* If watchdog was activated, kill it! */
if(lp->watchdog.prev != (timer_list *) NULL)
del_timer(&lp->watchdog);
- /* Increase the number of resets done */
+ /* Increase the number of resets done. */
lp->nresets++;
wv_hacr_reset(ioaddr);
@@ -3589,7 +3585,7 @@ wv_hw_reset(device * dev)
(wv_82586_start(dev) < 0))
return -1;
- /* Enable the card to send interrupts */
+ /* Enable the card to send interrupts. */
wv_ints_on(dev);
/* Start card functions */
@@ -3597,7 +3593,7 @@ wv_hw_reset(device * dev)
(wv_cu_start(dev) < 0))
return -1;
- /* Finish configuration */
+ /* Finish configuration. */
wv_82586_config(dev);
#ifdef DEBUG_CONFIG_TRACE
@@ -3608,8 +3604,8 @@ wv_hw_reset(device * dev)
/*------------------------------------------------------------------*/
/*
- * Check if there is a wavelan at the specific base address.
- * As a side effect, it read the MAC address.
+ * Check if there is a WaveLAN at the specific base address.
+ * As a side effect, this reads the MAC address.
* (called in wavelan_probe() and init_module())
*/
static int
@@ -3618,22 +3614,22 @@ wv_check_ioaddr(u_long ioaddr,
{
int i; /* Loop counter */
- /* Check if the base address if available */
+ /* Check if the base address if available. */
if(check_region(ioaddr, sizeof(ha_t)))
- return EADDRINUSE; /* ioaddr already used... */
+ return EADDRINUSE; /* ioaddr already used */
/* Reset host interface */
wv_hacr_reset(ioaddr);
- /* Read the MAC address from the parameter storage area */
+ /* Read the MAC address from the parameter storage area. */
psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
mac, 6);
/*
- * Check the first three octets of the addr for the manufacturer's code.
- * Note: If you can't find your wavelan card, you've got a
- * non-NCR/AT&T/Lucent ISA cards, see wavelan.p.h for detail on
- * how to configure your card...
+ * Check the first three octets of the address for the manufacturer's code.
+ * Note: if this can't find your WaveLAN card, you've got a
+ * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on
+ * how to configure your card.
*/
for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
if((mac[0] == MAC_ADDRESSES[i][0]) &&
@@ -3642,7 +3638,7 @@ wv_check_ioaddr(u_long ioaddr,
return 0;
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_WARNING "Wavelan (0x%3X) : Your MAC address might be : %02X:%02X:%02X...\n",
+ printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
ioaddr, mac[0], mac[1], mac[2]);
#endif
return ENODEV;
@@ -3675,7 +3671,7 @@ wavelan_interrupt(int irq,
lp = (net_local *) dev->priv;
ioaddr = dev->base_addr;
- /* Prevent reentrance. What should we do here ? */
+ /* Prevent reentrance. What should we do here? */
#ifdef DEBUG_INTERRUPT_ERROR
if(dev->interrupt)
printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
@@ -3708,7 +3704,7 @@ wavelan_interrupt(int irq,
return;
}
- /* Read interrupt data */
+ /* Read interrupt data. */
obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
(unsigned char *) &status, sizeof(status));
@@ -3755,7 +3751,7 @@ wavelan_interrupt(int irq,
wv_receive(dev);
}
- /* Check the state of the command unit */
+ /* Check the state of the command unit. */
if(((status & SCB_ST_CNA) == SCB_ST_CNA) ||
(((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start))
{
@@ -3766,7 +3762,7 @@ wavelan_interrupt(int irq,
wv_hw_reset(dev);
}
- /* Check the state of the command unit */
+ /* Check the state of the command unit. */
if(((status & SCB_ST_RNR) == SCB_ST_RNR) ||
(((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start))
{
@@ -3786,14 +3782,14 @@ wavelan_interrupt(int irq,
/*------------------------------------------------------------------*/
/*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel. If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, we set a timer in the
+ * kernel. If the transmission completes, this timer is disabled. If
+ * the timer expires, we try to unlock the hardware.
*
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the previous version of the ISA driver. I make it this
+ * Note: this watchdog doesn't work on the same principle as the
+ * watchdog in the previous version of the ISA driver. I made it this
* way because the overhead of add_timer() and del_timer() is nothing
- * and that it avoid calling the watchdog, saving some CPU...
+ * and because it avoids calling the watchdog, saving some CPU.
*/
static void
wavelan_watchdog(u_long a)
@@ -3860,7 +3856,7 @@ wavelan_watchdog(u_long a)
wv_hw_reset(dev);
}
else
- /* Re-set watchodog for next transmission */
+ /* Reset watchdog for next transmission. */
if(lp->tx_n_in_use > 0)
{
/* set timer to expire in WATCHDOG_JIFFIES */
@@ -3877,15 +3873,15 @@ wavelan_watchdog(u_long a)
/********************* CONFIGURATION CALLBACKS *********************/
/*
- * Here are the functions called by the linux networking (NET3) for
- * initialization, configuration and deinstallations of the Wavelan
- * ISA Hardware.
+ * Here are the functions called by the Linux networking code (NET3)
+ * for initialization, configuration and deinstallations of the
+ * WaveLAN ISA hardware.
*/
/*------------------------------------------------------------------*/
/*
* Configure and start up the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "open" the device.
+ * Called by NET3 when it "opens" the device.
*/
static int
wavelan_open(device * dev)
@@ -3901,7 +3897,7 @@ wavelan_open(device * dev)
if(dev->irq == 0)
{
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "%s: wavelan_open(): no irq\n", dev->name);
+ printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
#endif
return -ENXIO;
}
@@ -3909,7 +3905,7 @@ wavelan_open(device * dev)
if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
{
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "%s: wavelan_open(): invalid irq\n", dev->name);
+ printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
#endif
return -EAGAIN;
}
@@ -3941,8 +3937,8 @@ wavelan_open(device * dev)
/*------------------------------------------------------------------*/
/*
- * Shutdown the WaveLAN ISA card.
- * Called by NET3 when it "close" the device.
+ * Shut down the WaveLAN ISA card.
+ * Called by NET3 when it "closes" the device.
*/
static int
wavelan_close(device * dev)
@@ -3954,14 +3950,14 @@ wavelan_close(device * dev)
(unsigned int) dev);
#endif
- /* Not do the job twice... */
+ /* Don't do the job twice. */
if(dev->start == 0)
return 0;
dev->tbusy = 1;
dev->start = 0;
- /* If watchdog was activated, kill it ! */
+ /* If watchdog was activated, kill it! */
if(lp->watchdog.prev != (timer_list *) NULL)
del_timer(&lp->watchdog);
@@ -3982,9 +3978,9 @@ wavelan_close(device * dev)
/*------------------------------------------------------------------*/
/*
- * Probe an i/o address, and if the wavelan is there configure the
+ * Probe an I/O address, and if the WaveLAN is there configure the
* device structure
- * (called by wavelan_probe() & via init_module())
+ * (called by wavelan_probe() and via init_module()).
*/
__initfunc(static int
wavelan_config(device * dev))
@@ -3999,7 +3995,7 @@ wavelan_config(device * dev))
(unsigned int)dev, ioaddr);
#endif
- /* Check irq arg on command line */
+ /* Check IRQ argument on command line. */
if(dev->irq != 0)
{
irq_mask = wv_irq_to_psa(dev->irq);
@@ -4007,7 +4003,7 @@ wavelan_config(device * dev))
if(irq_mask == 0)
{
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "%s: wavelan_config(): invalid irq %d -- ignored.\n",
+ printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n",
dev->name, dev->irq);
#endif
dev->irq = 0;
@@ -4015,7 +4011,7 @@ wavelan_config(device * dev))
else
{
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: wavelan_config(): changing irq to %d\n",
+ printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n",
dev->name, dev->irq);
#endif
psa_write(ioaddr, HACR_DEFAULT,
@@ -4049,9 +4045,9 @@ wavelan_config(device * dev))
memset(dev->priv, 0x00, sizeof(net_local));
lp = (net_local *)dev->priv;
- /* Back link to the device structure */
+ /* Back link to the device structure. */
lp->dev = dev;
- /* Add the device at the beggining of the linked list */
+ /* Add the device at the beginning of the linked list. */
lp->next = wavelan_list;
wavelan_list = lp;
@@ -4064,7 +4060,7 @@ wavelan_config(device * dev))
/*
* Fill in the fields of the device structure
- * with ethernet-generic values.
+ * with generic Ethernet values.
*/
ether_setup(dev);
@@ -4075,14 +4071,14 @@ wavelan_config(device * dev))
dev->set_multicast_list = &wavelan_set_multicast_list;
dev->set_mac_address = &wavelan_set_mac_address;
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->do_ioctl = wavelan_ioctl;
dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif
dev->mtu = WAVELAN_MTU;
- /* Display nice info */
+ /* Display nice information. */
wv_init_info(dev);
#ifdef DEBUG_CALLBACK_TRACE
@@ -4093,18 +4089,17 @@ wavelan_config(device * dev))
/*------------------------------------------------------------------*/
/*
- * Check for a network adaptor of this type.
- * Return '0' iff one exists.
- * (There seem to be different interpretations of
+ * Check for a network adaptor of this type. Return '0' iff one
+ * exists. There seem to be different interpretations of
* the initial value of dev->base_addr.
- * We follow the example in drivers/net/ne.c.)
+ * We follow the example in drivers/net/ne.c.
* (called in "Space.c")
*/
__initfunc(int
wavelan_probe(device * dev))
{
short base_addr;
- mac_addr mac; /* Mac address (check wavelan existence) */
+ mac_addr mac; /* MAC address (check existence of WaveLAN) */
int i;
int r;
@@ -4122,7 +4117,7 @@ wavelan_probe(device * dev))
}
#endif /* STRUCT_CHECK */
- /* Check the value of the command line parameter for base address */
+ /* Check the value of the command line parameter for base address. */
base_addr = dev->base_addr;
/* Don't probe at all. */
@@ -4138,10 +4133,10 @@ wavelan_probe(device * dev))
/* Check a single specified location. */
if(base_addr > 0x100)
{
- /* Check if the is something at this base address */
+ /* Check if there is something at this base address */
if((r = wv_check_ioaddr(base_addr, mac)) == 0)
{
- memcpy(dev->dev_addr, mac, 6); /* Copy mac address */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
r = wavelan_config(dev);
}
@@ -4157,14 +4152,14 @@ wavelan_probe(device * dev))
return r;
}
- /* Scan all possible address of the wavelan hardware */
+ /* Scan all possible addresses of the WaveLAN hardware. */
for(i = 0; i < NELS(iobase); i++)
{
- /* Check if the is something at this base address */
+ /* Check whether there is something at this base address. */
if(wv_check_ioaddr(iobase[i], mac) == 0)
{
- dev->base_addr = iobase[i]; /* Copy base address */
- memcpy(dev->dev_addr, mac, 6); /* Copy mac address */
+ dev->base_addr = iobase[i]; /* Copy base address. */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
if(wavelan_config(dev) == 0)
{
#ifdef DEBUG_CALLBACK_TRACE
@@ -4175,7 +4170,7 @@ wavelan_probe(device * dev))
}
}
- /* We may have touch base_addr : another driver may not like it... */
+ /* We may have touched base_addr. Another driver may not like it. */
dev->base_addr = base_addr;
#ifdef DEBUG_CONFIG_INFO
@@ -4188,19 +4183,19 @@ wavelan_probe(device * dev))
/****************************** MODULE ******************************/
/*
- * Module entry point : insertion & removal
+ * Module entry point: insertion and removal
*/
#ifdef MODULE
/*------------------------------------------------------------------*/
/*
- * Insertion of the module...
- * I'm now quite proud of the multi-device support...
+ * Insertion of the module
+ * I'm now quite proud of the multi-device support.
*/
int
init_module(void)
{
- mac_addr mac; /* Mac address (check wavelan existence) */
+ mac_addr mac; /* MAC address (check WaveLAN existence) */
int ret = 0;
int i;
@@ -4212,48 +4207,48 @@ init_module(void)
if(io[0] == 0)
{
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "wavelan init_module(): doing device probing (bad !)\n");
+ printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
#endif
- /* Copy the basic set of address to be probed */
+ /* Copy the basic set of address to be probed. */
for(i = 0; i < NELS(iobase); i++)
io[i] = iobase[i];
}
- /* Loop on all possible base addresses */
+ /* Loop on all possible base addresses. */
i = -1;
while((io[++i] != 0) && (i < NELS(io)))
{
- /* Check if the is something at this base address */
+ /* Check if there is something at this base address. */
if(wv_check_ioaddr(io[i], mac) == 0)
{
device * dev;
- /* Create device and set basics args */
+ /* Create device and set basic arguments. */
dev = kmalloc(sizeof(struct device), GFP_KERNEL);
memset(dev, 0x00, sizeof(struct device));
dev->name = name[i];
dev->base_addr = io[i];
dev->irq = irq[i];
dev->init = &wavelan_config;
- memcpy(dev->dev_addr, mac, 6); /* Copy mac address */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
- /* Try to create the device */
+ /* Try to create the device. */
if(register_netdev(dev) != 0)
{
- /* DeAllocate everything */
- /* Note : if dev->priv is mallocated, there is no way to fail */
+ /* Deallocate everything. */
+ /* Note: if dev->priv is mallocated, there is no way to fail. */
kfree_s(dev, sizeof(struct device));
ret = -EIO;
}
- } /* If there is something at the address */
- } /* Loop on all addresses */
+ } /* if there is something at the address */
+ } /* Loop on all addresses. */
#ifdef DEBUG_CONFIG_ERRORS
if(wavelan_list == (net_local *) NULL)
- printk(KERN_WARNING "wavelan init_module(): No device found\n");
+ printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
#endif
#ifdef DEBUG_MODULE_TRACE
@@ -4273,7 +4268,7 @@ cleanup_module(void)
printk(KERN_DEBUG "-> cleanup_module()\n");
#endif
- /* Loop on all devices and release them */
+ /* Loop on all devices and release them. */
while(wavelan_list != (net_local *) NULL)
{
device * dev = wavelan_list->dev;
@@ -4283,16 +4278,16 @@ cleanup_module(void)
dev->name, (unsigned int) dev);
#endif
- /* Release the ioport-region. */
+ /* Release the ioport region. */
release_region(dev->base_addr, sizeof(ha_t));
- /* Remove definitely the device */
+ /* Definitely remove the device. */
unregister_netdev(dev);
- /* Unlink the device */
+ /* Unlink the device. */
wavelan_list = wavelan_list->next;
- /* Free pieces */
+ /* Free pieces. */
kfree_s(dev->priv, sizeof(struct net_local));
kfree_s(dev, sizeof(struct device));
}
diff --git a/drivers/net/wavelan.h b/drivers/net/wavelan.h
index 2e92c798e..ca67dbf66 100644
--- a/drivers/net/wavelan.h
+++ b/drivers/net/wavelan.h
@@ -1,34 +1,34 @@
/*
- * Wavelan ISA driver
+ * WaveLAN ISA driver
*
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
- * Original copyrigth follow. See wavelan.p.h for details.
+ * Original copyright follows. See wavelan.p.h for details.
*
- * This file contain the declarations of the Wavelan hardware. Note that
- * the Wavelan ISA include a i82586 controler (see definitions in
+ * This file contains the declarations for the WaveLAN hardware. Note that
+ * the WaveLAN ISA includes a i82586 controller (see definitions in
* file i82586.h).
*
- * The main difference between the ISA hardware and the pcmcia one is
- * the Ethernet Controler (i82586 instead of i82593).
- * The i82586 allow multiple transmit buffers. The PSA need to be accessed
+ * The main difference between the ISA hardware and the PCMCIA one is
+ * the Ethernet controller (i82586 instead of i82593).
+ * The i82586 allows multiple transmit buffers. The PSA needs to be accessed
* through the host interface.
*/
#ifndef _WAVELAN_H
#define _WAVELAN_H
-/* The detection of the wavelan card is made by reading the MAC
- * address from the card and checking it. If you have a non AT&T
- * product (OEM, like DEC RoamAbout, or Digital Ocean, Epson, ...),
- * you might need to modify this part to accomodate your hardware...
+/* Detection of the WaveLAN card is done by reading the MAC
+ * address from the card and checking it. If you have a non-AT&T
+ * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson),
+ * you might need to modify this part to accommodate your hardware.
*/
const char MAC_ADDRESSES[][3] =
{
- { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */
- { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */
- /* Add your card here and send me the patch ! */
+ { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */
+ { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */
+ /* Add your card here and send me the patch! */
};
#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */
@@ -49,7 +49,7 @@ union hacs_u
unsigned short hu_command; /* Command register */
#define HACR_RESET 0x0001 /* Reset board */
#define HACR_CA 0x0002 /* Set Channel Attention for 82586 */
-#define HACR_16BITS 0x0004 /* 16 bits operation (0 => 8bits) */
+#define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */
#define HACR_OUT0 0x0008 /* General purpose output pin 0 */
/* not used - must be 1 */
#define HACR_OUT1 0x0010 /* General purpose output pin 1 */
@@ -112,11 +112,11 @@ struct ha_t
/************************** MEMORY LAYOUT **************************/
/*
- * Onboard 64k RAM layout.
+ * Onboard 64 k RAM layout.
* (Offsets from 0x0000.)
*/
-#define OFFSET_RU 0x0000 /* 75 % memory */
-#define OFFSET_CU 0xC000 /* 25 % memory */
+#define OFFSET_RU 0x0000 /* 75% memory */
+#define OFFSET_CU 0xC000 /* 25% memory */
#define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t))
#define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t))
#define OFFSET_SCP I82586_SCP_ADDR
@@ -151,26 +151,26 @@ struct psa_t
unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */
#define PSA_UNIVERSAL 0 /* Universal (factory) */
#define PSA_LOCAL 1 /* Local */
- unsigned char psa_comp_number; /* [0x1D] Compatability Number: */
-#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */
-#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */
-#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */
-#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */
+ unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */
+#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */
+#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */
+#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */
+#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */
#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */
unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */
unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */
#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */
- unsigned char psa_subband; /* [0x20] Subband */
+ unsigned char psa_subband; /* [0x20] Subband */
#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */
-#define PSA_SUBBAND_2425 1 /* 2425 MHz */
-#define PSA_SUBBAND_2460 2 /* 2460 MHz */
-#define PSA_SUBBAND_2484 3 /* 2484 MHz */
-#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */
+#define PSA_SUBBAND_2425 1 /* 2425 MHz */
+#define PSA_SUBBAND_2460 2 /* 2460 MHz */
+#define PSA_SUBBAND_2484 3 /* 2484 MHz */
+#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */
unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */
- unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */
+ unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */
unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */
- unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */
- unsigned char psa_encryption_select; /* [0x26] Encryption On Off */
+ unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */
+ unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */
unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */
unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */
unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */
@@ -183,8 +183,8 @@ struct psa_t
#define PSA_SIZE 64
-/* Calculate offset of a field in the above structure
- * Warning : only even addresses are used */
+/* Calculate offset of a field in the above structure.
+ * Warning: only even addresses are used. */
#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
/******************** MODEM MANAGEMENT INTERFACE ********************/
@@ -196,25 +196,25 @@ typedef struct mmw_t mmw_t;
struct mmw_t
{
unsigned char mmw_encr_key[8]; /* encryption key */
- unsigned char mmw_encr_enable; /* enable/disable encryption */
-#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */
-#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */
+ unsigned char mmw_encr_enable; /* Enable or disable encryption. */
+#define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */
+#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */
unsigned char mmw_unused0[1]; /* unused */
- unsigned char mmw_des_io_invert; /* Encryption option */
-#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */
-#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */
+ unsigned char mmw_des_io_invert; /* encryption option */
+#define MMW_DES_IO_INVERT_RES 0x0F /* reserved */
+#define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */
unsigned char mmw_unused1[5]; /* unused */
unsigned char mmw_loopt_sel; /* looptest selection */
-#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */
-#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */
-#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */
+#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */
+#define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */
+#define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */
#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */
#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */
#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */
#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */
unsigned char mmw_jabber_enable; /* jabber timer enable */
/* Abort transmissions > 200 ms */
- unsigned char mmw_freeze; /* freeze / unfreeeze signal level */
+ unsigned char mmw_freeze; /* freeze or unfreeze signal level */
/* 0 : signal level & qual updated for every new message, 1 : frozen */
unsigned char mmw_anten_sel; /* antenna selection */
#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */
@@ -227,7 +227,7 @@ struct mmw_t
unsigned char mmw_thr_pre_set; /* level threshold preset */
/* Discard all packet with signal < this value (4) */
unsigned char mmw_decay_prm; /* decay parameters */
- unsigned char mmw_decay_updat_prm; /* decay update parameterz */
+ unsigned char mmw_decay_updat_prm; /* decay update parameters */
unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */
/* Discard all packet with quality < this value (3) */
unsigned char mmw_netw_id_l; /* NWID low order byte */
@@ -237,31 +237,31 @@ struct mmw_t
/* 2.0 Hardware extension - frequency selection support */
unsigned char mmw_mode_select; /* for analog tests (set to 0) */
unsigned char mmw_unused3[1]; /* unused */
- unsigned char mmw_fee_ctrl; /* frequency eeprom control */
-#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */
-#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */
-#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */
+ unsigned char mmw_fee_ctrl; /* frequency EEPROM control */
+#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */
+#define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */
+#define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */
#define MMW_FEE_CTRL_READ 0x06 /* Read */
#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */
-#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */
-#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */
+#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */
+#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */
#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */
#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */
#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */
-#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */
-#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */
+#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */
+#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */
#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */
- /* Never issue this command (PRDS) : it's irreversible !!! */
+ /* Never issue the PRDS command: it's irreversible! */
- unsigned char mmw_fee_addr; /* EEprom address */
-#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */
+ unsigned char mmw_fee_addr; /* EEPROM address */
+#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */
#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */
#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */
#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */
#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */
#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */
- unsigned char mmw_fee_data_l; /* Write data to EEprom */
+ unsigned char mmw_fee_data_l; /* Write data to EEPROM. */
unsigned char mmw_fee_data_h; /* high octet */
unsigned char mmw_ext_ant; /* Setting for external antenna */
#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */
@@ -293,13 +293,13 @@ struct mmr_t
#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */
#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */
#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */
- unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */
+ unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */
unsigned char mmr_unused2[2]; /* unused */
- unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */
- unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */
- /* Warning : Read high order octet first !!! */
- unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */
- unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */
+ unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */
+ unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */
+ /* Warning: read high-order octet first! */
+ unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */
+ unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */
unsigned char mmr_thr_pre_set; /* level threshold preset */
#define MMR_THR_PRE_SET 0x3F /* level threshold preset */
#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */
@@ -312,17 +312,17 @@ struct mmr_t
unsigned char mmr_sgnl_qual; /* signal quality */
#define MMR_SGNL_QUAL 0x0F /* signal quality */
#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */
- unsigned char mmr_netw_id_l; /* NWID low order byte ??? */
+ unsigned char mmr_netw_id_l; /* NWID low order byte (?) */
unsigned char mmr_unused3[3]; /* unused */
/* 2.0 Hardware extension - frequency selection support */
- unsigned char mmr_fee_status; /* Status of frequency eeprom */
-#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */
+ unsigned char mmr_fee_status; /* Status of frequency EEPROM */
+#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */
#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */
-#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */
+#define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */
unsigned char mmr_unused4[1]; /* unused */
- unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */
- unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */
+ unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */
+ unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */
};
#define MMR_SIZE 36
diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h
index 18320dcc4..251f2b98e 100644
--- a/drivers/net/wavelan.p.h
+++ b/drivers/net/wavelan.p.h
@@ -1,79 +1,79 @@
/*
- * Wavelan ISA driver
+ * WaveLAN ISA driver
*
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
*
- * This file contain all definition and declarations necessary for the
- * wavelan isa driver. This file is a private header, so it should
- * be included only on wavelan.c !!!
+ * This file contains all definitions and declarations necessary for the
+ * WaveLAN ISA driver. This file is a private header, so it should
+ * be included only in wavelan.c!
*/
#ifndef WAVELAN_P_H
#define WAVELAN_P_H
-/************************** DOCUMENTATION **************************/
+/************************** DOCUMENTATION ***************************/
/*
- * This driver provide a Linux interface to the Wavelan ISA hardware
- * The Wavelan is a product of Lucent ("http://wavelan.netland.nl/").
+ * This driver provides a Linux interface to the WaveLAN ISA hardware.
+ * The WaveLAN is a product of Lucent (http://www.wavelan.com/).
* This division was formerly part of NCR and then AT&T.
- * Wavelan are also distributed by DEC (RoamAbout), Digital Ocean and
- * Aironet (Arlan). If you have one of those product, you will need to
- * make some changes below...
+ * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and
+ * Aironet (Arlan). If you have one of those products, you will need to
+ * make some changes below.
*
- * This driver is still a beta software. A lot of bugs have been corrected,
- * a lot of functionalities are implemented, the whole appear pretty stable,
- * but there is still some area of improvement (encryption, performance...).
+ * This driver is still beta software. A lot of bugs have been corrected,
+ * a lot of functionality is implemented, and the whole appears stable,
+ * but there is still room for improvement (encryption, performance).
*
- * To know how to use this driver, read the NET3 HOWTO.
- * If you want to exploit the many other fonctionalities, look comments
- * in the code...
+ * To learn how to use this driver, read the NET3 HOWTO.
+ * If you want to exploit the many other functionalities, read the comments
+ * in the code.
*
- * This driver is the result of the effort of many peoples (see below).
+ * This driver is the result of the effort of many people (see below).
*/
/* ------------------------ SPECIFIC NOTES ------------------------ */
/*
- * wavelan.o is darn too big
- * -------------------------
- * That's true ! There is a very simple way to reduce the driver
- * object by 33% (yes !). Comment out the following line :
+ * wavelan.o is too darned big
+ * ---------------------------
+ * That's true! There is a very simple way to reduce the driver
+ * object by 33%! Comment out the following line:
* #include <linux/wireless.h>
*
- * MAC address and hardware detection :
- * ----------------------------------
- * The detection code of the wavelan chech that the first 3
- * octets of the MAC address fit the company code. This type of
- * detection work well for AT&T cards (because the AT&T code is
+ * MAC address and hardware detection:
+ * -----------------------------------
+ * The detection code for the WaveLAN checks that the first three
+ * octets of the MAC address fit the company code. This type of
+ * detection works well for AT&T cards (because the AT&T code is
* hardcoded in wavelan.h), but of course will fail for other
- * manufacturer.
+ * manufacturers.
*
- * If you are sure that your card is derived from the wavelan,
- * here is the way to configure it :
+ * If you are sure that your card is derived from the WaveLAN,
+ * here is the way to configure it:
* 1) Get your MAC address
- * a) With your card utilities (wfreqsel, instconf, ...)
- * b) With the driver :
+ * a) With your card utilities (wfreqsel, instconf, etc.)
+ * b) With the driver:
* o compile the kernel with DEBUG_CONFIG_INFO enabled
* o Boot and look the card messages
* 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
- * 3) Compile & verify
- * 4) Send me the MAC code - I will include it in the next version...
+ * 3) Compile and verify
+ * 4) Send me the MAC code. I will include it in the next version.
*
- * "CU Inactive" message at boot up :
+ * "CU Inactive" message at boot up:
* -----------------------------------
- * It seem that there is some weird timings problems with the
- * Intel microcontroler. In fact, this message is triggered by a
- * bad reading of the on board ram the first time we read the
- * control block. If you ignore this message, all is ok (but in
- * fact, currently, it reset the wavelan hardware).
+ * It seems that there is some weird timing problem with the
+ * Intel microcontroller. In fact, this message is triggered by a
+ * bad reading of the onboard RAM the first time we read the
+ * control block. If you ignore this message, all is OK (but in
+ * fact, currently, it resets the WaveLAN hardware).
*
- * To get rid of that problem, there is two solution. The first
+ * There are two ways to get rid of that problem. The first
* is to add a dummy read of the scb at the end of
- * wv_82586_config. The second is to add the timers
+ * wv_82586_config. The second is to add the timers
* wv_synchronous_cmd and wv_ack (the udelay just after the
- * waiting loops - seem that the controler is not totally ready
- * when it say it is !).
+ * waiting loops--it seems that the controller is not totally ready
+ * when it says it is).
*
* In the current code, I use the second solution (to be
* consistent with the original solution of Bruce Janson).
@@ -81,10 +81,10 @@
/* --------------------- WIRELESS EXTENSIONS --------------------- */
/*
- * This driver is the first one to support "wireless extensions".
- * This set of extensions provide you some way to control the wireless
- * caracteristics of the hardware in a standard way and support for
- * applications for taking advantage of it (like Mobile IP).
+ * This driver is the first to support "wireless extensions".
+ * This set of extensions provides a standard way to control the wireless
+ * characteristics of the hardware. Applications such as mobile IP may
+ * take advantage of it.
*
* You will need to enable the CONFIG_NET_RADIO define in the kernel
* configuration to enable the wireless extensions (this is the one
@@ -96,64 +96,64 @@
/* ---------------------------- FILES ---------------------------- */
/*
- * wavelan.c : The actual code for the driver - C functions
+ * wavelan.c: actual code for the driver: C functions
*
- * wavelan.p.h : Private header : local types / vars for the driver
+ * wavelan.p.h: private header: local types and variables for driver
*
- * wavelan.h : Description of the hardware interface & structs
+ * wavelan.h: description of the hardware interface and structs
*
- * i82586.h : Description if the Ethernet controler
+ * i82586.h: description of the Ethernet controller
*/
/* --------------------------- HISTORY --------------------------- */
/*
- * (Made with information in drivers headers. It may not be accurate,
- * and I garantee nothing except my best effort...)
+ * This is based on information in the drivers' headers. It may not be
+ * accurate, and I guarantee only my best effort.
*
- * The history of the Wavelan drivers is as complicated as history of
- * the Wavelan itself (NCR -> AT&T -> Lucent).
+ * The history of the WaveLAN drivers is as complicated as the history of
+ * the WaveLAN itself (NCR -> AT&T -> Lucent).
*
- * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * It all started with Anders Klemets <klemets@paul.rutgers.edu>
+ * writing a WaveLAN ISA driver for the Mach microkernel. Girish
* Welling <welling@paul.rutgers.edu> had also worked on it.
- * Keith Moore modify this for the Pcmcia hardware.
+ * Keith Moore modified this for the PCMCIA hardware.
*
- * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
- * and add specific Pcmcia support (there is currently no equivalent
- * of the PCMCIA package under BSD...).
+ * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI
+ * and added specific PCMCIA support (there is currently no equivalent
+ * of the PCMCIA package under BSD).
*
- * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to freeBSD.
+ * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD.
*
- * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux.
*
- * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver
* (with help of the BSDI PCMCIA driver) for PCMCIA.
- * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
* Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
- * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * 2.00 cards correctly (2.4 GHz with frequency selection).
* David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
- * Pcmcia package (+ bug corrections).
+ * PCMCIA package (and bug corrections).
*
* I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
- * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * patches to the PCMCIA driver. Later, I added code in the ISA driver
* for Wireless Extensions and full support of frequency selection
- * cards. Then, I've done the same to the Pcmcia driver + some
- * reorganisation. Finally, I came back to the ISA driver to
- * upgrade it at the same level as the Pcmcia one and reorganise
- * the code
+ * cards. Then, I did the same to the PCMCIA driver, and did some
+ * reorganisation. Finally, I came back to the ISA driver to
+ * upgrade it at the same level as the PCMCIA one and reorganise
+ * the code.
* Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
- * much needed informations on the Wavelan hardware.
+ * much needed information on the WaveLAN hardware.
*/
-/* The original copyrights and litteratures mention others names and
- * credits. I don't know what there part in this development was...
+/* The original copyrights and literature mention others' names and
+ * credits. I don't know what their part in this development was.
*/
-/* By the way : for the copyright & legal stuff :
- * Almost everybody wrote code under GNU or BSD license (or alike),
- * and want that their original copyright remain somewhere in the
+/* By the way, for the copyright and legal stuff:
+ * almost everybody wrote code under the GNU or BSD license (or similar),
+ * and want their original copyright to remain somewhere in the
* code (for myself, I go with the GPL).
- * Nobody want to take responsibility for anything, except the fame...
+ * Nobody wants to take responsibility for anything, except the fame.
*/
/* --------------------------- CREDITS --------------------------- */
@@ -162,121 +162,120 @@
* Linux operating system.
* It is based on other device drivers and information
* either written or supplied by:
- * Ajay Bakre (bakre@paul.rutgers.edu),
- * Donald Becker (becker@cesdis.gsfc.nasa.gov),
- * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
+ * Ajay Bakre <bakre@paul.rutgers.edu>,
+ * Donald Becker <becker@cesdis.gsfc.nasa.gov>,
+ * Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>,
* Brent Elphick <belphick@uwaterloo.ca>,
- * Anders Klemets (klemets@it.kth.se),
- * Vladimir V. Kolpakov (w@stier.koenig.ru),
- * Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
- * Pauline Middelink (middelin@polyware.iaf.nl),
- * Robert Morris (rtm@das.harvard.edu),
- * Jean Tourrilhes (jt@hplb.hpl.hp.com),
- * Girish Welling (welling@paul.rutgers.edu),
+ * Anders Klemets <klemets@it.kth.se>,
+ * Vladimir V. Kolpakov <w@stier.koenig.ru>,
+ * Marc Meertens <Marc.Meertens@Utrecht.NCR.com>,
+ * Pauline Middelink <middelin@polyware.iaf.nl>,
+ * Robert Morris <rtm@das.harvard.edu>,
+ * Jean Tourrilhes <jt@hplb.hpl.hp.com>,
+ * Girish Welling <welling@paul.rutgers.edu>,
* Clark Woodworth <clark@hiway1.exit109.com>
- * Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ * Yongguang Zhang <ygz@isl.hrl.hac.com>
*
* Thanks go also to:
- * James Ashton (jaa101@syseng.anu.edu.au),
- * Alan Cox (iialan@iiit.swan.ac.uk),
- * Allan Creighton (allanc@cs.usyd.edu.au),
- * Matthew Geier (matthew@cs.usyd.edu.au),
- * Remo di Giovanni (remo@cs.usyd.edu.au),
- * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
- * Vipul Gupta (vgupta@cs.binghamton.edu),
- * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- * Tim Nicholson (tim@cs.usyd.edu.au),
- * Ian Parkin (ian@cs.usyd.edu.au),
- * John Rosenberg (johnr@cs.usyd.edu.au),
- * George Rossi (george@phm.gov.au),
- * Arthur Scott (arthur@cs.usyd.edu.au),
+ * James Ashton <jaa101@syseng.anu.edu.au>,
+ * Alan Cox <iialan@iiit.swan.ac.uk>,
+ * Allan Creighton <allanc@cs.usyd.edu.au>,
+ * Matthew Geier <matthew@cs.usyd.edu.au>,
+ * Remo di Giovanni <remo@cs.usyd.edu.au>,
+ * Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>,
+ * Vipul Gupta <vgupta@cs.binghamton.edu>,
+ * Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>,
+ * Tim Nicholson <tim@cs.usyd.edu.au>,
+ * Ian Parkin <ian@cs.usyd.edu.au>,
+ * John Rosenberg <johnr@cs.usyd.edu.au>,
+ * George Rossi <george@phm.gov.au>,
+ * Arthur Scott <arthur@cs.usyd.edu.au>,
* Stanislav Sinyagin <stas@isf.ru>
- * Peter Storey,
- * for their assistance and advice.
+ * and Peter Storey for their assistance and advice.
*
* Additional Credits:
*
- * My developpement has been done under Linux 2.0.x (Debian 1.1) with
+ * My development has been done under Linux 2.0.x (Debian 1.1) with
* an HP Vectra XP/60.
*
*/
/* ------------------------- IMPROVEMENTS ------------------------- */
/*
- * I proudly present :
+ * I proudly present:
*
- * Changes mades in first pre-release :
+ * Changes made in first pre-release:
* ----------------------------------
- * - Reorganisation of the code, function name change
- * - Creation of private header (wavelan.p.h)
- * - Reorganised debug messages
- * - More comments, history, ...
- * - mmc_init : configure the PSA if not done
- * - mmc_init : correct default value of level threshold for pcmcia
- * - mmc_init : 2.00 detection better code for 2.00 init
+ * - reorganisation of the code, function name change
+ * - creation of private header (wavelan.p.h)
+ * - reorganised debug messages
+ * - more comments, history, etc.
+ * - mmc_init: configure the PSA if not done
+ * - mmc_init: correct default value of level threshold for PCMCIA
+ * - mmc_init: 2.00 detection better code for 2.00 initialization
* - better info at startup
- * - irq setting (note : this setting is permanent...)
- * - Watchdog : change strategy (+ solve module removal problems)
- * - add wireless extensions (ioctl & get_wireless_stats)
+ * - IRQ setting (note: this setting is permanent)
+ * - watchdog: change strategy (and solve module removal problems)
+ * - add wireless extensions (ioctl and get_wireless_stats)
* get/set nwid/frequency on fly, info for /proc/net/wireless
- * - More wireless extension : SETSPY and GETSPY
- * - Make wireless extensions optional
- * - Private ioctl to set/get quality & level threshold, histogram
- * - Remove /proc/net/wavelan
- * - Supress useless stuff from lp (net_local)
+ * - more wireless extensions: SETSPY and GETSPY
+ * - make wireless extensions optional
+ * - private ioctl to set/get quality and level threshold, histogram
+ * - remove /proc/net/wavelan
+ * - suppress useless stuff from lp (net_local)
* - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
- * - Add message level (debug stuff in /var/adm/debug & errors not
+ * - add message level (debug stuff in /var/adm/debug and errors not
* displayed at console and still in /var/adm/messages)
* - multi device support
- * - Start fixing the probe (init code)
- * - More inlines
+ * - start fixing the probe (init code)
+ * - more inlines
* - man page
- * - Lot of others minor details & cleanups
- *
- * Changes made in second pre-release :
- * ----------------------------------
- * - Cleanup init code (probe & module init)
- * - Better multi device support (module)
- * - name assignement (module)
+ * - many other minor details and cleanups
*
- * Changes made in third pre-release :
- * ---------------------------------
- * - Be more conservative on timers
- * - Preliminary support for multicast (I still lack some details...)
+ * Changes made in second pre-release:
+ * -----------------------------------
+ * - clean up init code (probe and module init)
+ * - better multiple device support (module)
+ * - name assignment (module)
*
- * Changes made in fourth pre-release :
+ * Changes made in third pre-release:
* ----------------------------------
+ * - be more conservative on timers
+ * - preliminary support for multicast (I still lack some details)
+ *
+ * Changes made in fourth pre-release:
+ * -----------------------------------
* - multicast (revisited and finished)
- * - Avoid reset in set_multicast_list (a really big hack)
- * if somebody could apply this code for other i82586 based driver...
- * - Share on board memory 75% RU / 25% CU (instead of 50/50)
+ * - avoid reset in set_multicast_list (a really big hack)
+ * if somebody could apply this code for other i82586 based drivers
+ * - share onboard memory 75% RU and 25% CU (instead of 50/50)
*
- * Changes made for release in 2.1.15 :
- * ----------------------------------
- * - Change the detection code for multi manufacturer code support
+ * Changes made for release in 2.1.15:
+ * -----------------------------------
+ * - change the detection code for multi manufacturer code support
*
- * Changes made for release in 2.1.17 :
- * ----------------------------------
- * - Update to wireless extensions changes
- * - Silly bug in card initial configuration (psa_conf_status)
- *
- * Changes made for release in 2.1.27 & 2.0.30 :
- * -------------------------------------------
- * - Small bug in debug code (probably not the last one...)
- * - Remove extern kerword for wavelan_probe()
- * - Level threshold is now a standard wireless extension (version 4 !)
+ * Changes made for release in 2.1.17:
+ * -----------------------------------
+ * - update to wireless extensions changes
+ * - silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made for release in 2.1.27 & 2.0.30:
+ * --------------------------------------------
+ * - small bug in debug code (probably not the last one...)
+ * - remove extern keyword for wavelan_probe()
+ * - level threshold is now a standard wireless extension (version 4 !)
* - modules parameters types (new module interface)
*
- * Changes made for release in 2.1.36 :
- * ----------------------------------
+ * Changes made for release in 2.1.36:
+ * -----------------------------------
* - byte count stats (courtesy of David Hinds)
- * - Remove dev_tint stuff (courtesy of David Hinds)
- * - Encryption setting from Brent Elphick (thanks a lot !)
+ * - remove dev_tint stuff (courtesy of David Hinds)
+ * - encryption setting from Brent Elphick (thanks a lot!)
* - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
*
- * Wishes & dreams :
- * ---------------
- * - Roaming
+ * Wishes & dreams:
+ * ----------------
+ * - roaming
*/
/***************************** INCLUDES *****************************/
@@ -309,52 +308,52 @@
#include <linux/wireless.h> /* Wireless extensions */
-/* Wavelan declarations */
+/* WaveLAN declarations */
#include "i82586.h"
#include "wavelan.h"
/****************************** DEBUG ******************************/
-#undef DEBUG_MODULE_TRACE /* Module insertion/removal */
-#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */
-#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */
-#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */
+#undef DEBUG_MODULE_TRACE /* module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE /* calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE /* calls to handler */
+#undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */
#define DEBUG_INTERRUPT_ERROR /* problems */
-#undef DEBUG_CONFIG_TRACE /* Trace the config functions */
-#undef DEBUG_CONFIG_INFO /* What's going on... */
-#define DEBUG_CONFIG_ERRORS /* Errors on configuration */
-#undef DEBUG_TX_TRACE /* Transmission calls */
-#undef DEBUG_TX_INFO /* Header of the transmited packet */
+#undef DEBUG_CONFIG_TRACE /* Trace the config functions. */
+#undef DEBUG_CONFIG_INFO /* what's going on */
+#define DEBUG_CONFIG_ERRORS /* errors on configuration */
+#undef DEBUG_TX_TRACE /* transmission calls */
+#undef DEBUG_TX_INFO /* header of the transmitted packet */
#define DEBUG_TX_ERROR /* unexpected conditions */
-#undef DEBUG_RX_TRACE /* Transmission calls */
-#undef DEBUG_RX_INFO /* Header of the transmited packet */
+#undef DEBUG_RX_TRACE /* transmission calls */
+#undef DEBUG_RX_INFO /* header of the transmitted packet */
#define DEBUG_RX_ERROR /* unexpected conditions */
-#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen */
-#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */
-#undef DEBUG_IOCTL_INFO /* Various debug info */
-#define DEBUG_IOCTL_ERROR /* What's going wrong */
-#define DEBUG_BASIC_SHOW /* Show basic startup info */
-#undef DEBUG_VERSION_SHOW /* Print version info */
-#undef DEBUG_PSA_SHOW /* Dump psa to screen */
-#undef DEBUG_MMC_SHOW /* Dump mmc to screen */
-#undef DEBUG_SHOW_UNUSED /* Show also unused fields */
-#undef DEBUG_I82586_SHOW /* Show i82586 status */
-#undef DEBUG_DEVICE_SHOW /* Show device parameters */
-
-/* Options : */
-#define USE_PSA_CONFIG /* Use info from the PSA */
-#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions */
-#undef STRUCT_CHECK /* Verify padding of structures */
-#undef PSA_CRC /* Check CRC in PSA */
-#undef OLDIES /* Old code (to redo) */
-#undef RECORD_SNR /* To redo */
-#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */
-#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */
-
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY /* Enable spying addresses */
-#undef HISTOGRAM /* Enable histogram of sig level... */
+#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen. */
+#undef DEBUG_IOCTL_TRACE /* misc. call by Linux */
+#undef DEBUG_IOCTL_INFO /* various debugging info */
+#define DEBUG_IOCTL_ERROR /* what's going wrong */
+#define DEBUG_BASIC_SHOW /* Show basic startup info. */
+#undef DEBUG_VERSION_SHOW /* Print version info. */
+#undef DEBUG_PSA_SHOW /* Dump PSA to screen. */
+#undef DEBUG_MMC_SHOW /* Dump mmc to screen. */
+#undef DEBUG_SHOW_UNUSED /* Show unused fields too. */
+#undef DEBUG_I82586_SHOW /* Show i82586 status. */
+#undef DEBUG_DEVICE_SHOW /* Show device parameters. */
+
+/* Options */
+#define USE_PSA_CONFIG /* Use info from the PSA. */
+#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions. */
+#undef STRUCT_CHECK /* Verify padding of structures. */
+#undef PSA_CRC /* Check CRC in PSA. */
+#undef OLDIES /* old code (to redo) */
+#undef RECORD_SNR /* to redo */
+#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */
+#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */
+
+#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */
+/* Warning: this stuff will slow down the driver. */
+#define WIRELESS_SPY /* Enable spying addresses. */
+#undef HISTOGRAM /* Enable histogram of signal level. */
#endif
/************************ CONSTANTS & MACROS ************************/
@@ -364,7 +363,7 @@ static const char *version = "wavelan.c : v16 (wireless extensions) 17/4/97\n";
#endif
/* Watchdog temporisation */
-#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */
+#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */
/* Macro to get the number of elements in an array */
#define NELS(a) (sizeof(a) / sizeof(a[0]))
@@ -396,23 +395,23 @@ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */
/*
* Static specific data for the interface.
*
- * For each network interface, Linux keep data in two structure. "device"
- * keep the generic data (same format for everybody) and "net_local" keep
- * the additional specific data.
+ * For each network interface, Linux keeps data in two structures: "device"
+ * keeps the generic data (same format for everybody) and "net_local" keeps
+ * additional specific data.
* Note that some of this specific data is in fact generic (en_stats, for
* example).
*/
struct net_local
{
- net_local * next; /* Linked list of the devices */
- device * dev; /* Reverse link... */
+ net_local * next; /* linked list of the devices */
+ device * dev; /* reverse link */
en_stats stats; /* Ethernet interface statistics */
- int nresets; /* Number of hw resets */
- u_char reconfig_82586; /* Need to reconfigure the controler */
- u_char promiscuous; /* Promiscuous mode */
- int mc_count; /* Number of multicast addresses */
- timer_list watchdog; /* To avoid blocking state */
- u_short hacr; /* Current host interface state */
+ int nresets; /* number of hardware resets */
+ u_char reconfig_82586; /* We need to reconfigure the controller. */
+ u_char promiscuous; /* promiscuous mode */
+ int mc_count; /* number of multicast addresses */
+ timer_list watchdog; /* to avoid blocking state */
+ u_short hacr; /* current host interface state */
int tx_n_in_use;
u_short rx_head;
@@ -421,82 +420,83 @@ struct net_local
u_short tx_first_in_use;
#ifdef WIRELESS_EXT
- iw_stats wstats; /* Wireless specific stats */
+ iw_stats wstats; /* Wireless-specific statistics */
#endif
#ifdef WIRELESS_SPY
- int spy_number; /* Number of addresses to spy */
- mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */
- iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */
+ int spy_number; /* number of addresses to spy */
+ mac_addr spy_address[IW_MAX_SPY]; /* the addresses to spy */
+ iw_qual spy_stat[IW_MAX_SPY]; /* statistics gathered */
#endif /* WIRELESS_SPY */
+
#ifdef HISTOGRAM
- int his_number; /* Number of intervals */
- u_char his_range[16]; /* Boundaries of interval ]n-1; n] */
- u_long his_sum[16]; /* Sum in interval */
+ int his_number; /* number of intervals */
+ u_char his_range[16]; /* boundaries of interval ]n-1; n] */
+ u_long his_sum[16]; /* sum in interval */
#endif /* HISTOGRAM */
};
/**************************** PROTOTYPES ****************************/
-/* ----------------------- MISC SUBROUTINES ------------------------ */
+/* ----------------------- MISC. SUBROUTINES ------------------------ */
static inline unsigned long /* flags */
wv_splhi(void); /* Disable interrupts */
static inline void
- wv_splx(unsigned long); /* ReEnable interrupts : flags */
+ wv_splx(unsigned long); /* Enable interrupts: flags */
static u_char
wv_irq_to_psa(int);
static int
wv_psa_to_irq(u_char);
/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */
static inline u_short /* data */
- hasr_read(u_long); /* Read the host interface : base address */
+ hasr_read(u_long); /* Read the host interface: base address */
static inline void
- hacr_write(u_long, /* Write to host interface : base address */
+ hacr_write(u_long, /* Write to host interface: base address */
u_short), /* data */
hacr_write_slow(u_long,
u_short),
set_chan_attn(u_long, /* ioaddr */
- u_short), /* hacr */
+ u_short), /* hacr */
wv_hacr_reset(u_long), /* ioaddr */
wv_16_off(u_long, /* ioaddr */
- u_short), /* hacr */
+ u_short), /* hacr */
wv_16_on(u_long, /* ioaddr */
- u_short), /* hacr */
+ u_short), /* hacr */
wv_ints_off(device *),
wv_ints_on(device *);
/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
static void
- psa_read(u_long, /* Read the Parameter Storage Area */
+ psa_read(u_long, /* Read the Parameter Storage Area. */
u_short, /* hacr */
int, /* offset in PSA */
u_char *, /* buffer to fill */
int), /* size to read */
- psa_write(u_long, /* Write to the PSA */
+ psa_write(u_long, /* Write to the PSA. */
u_short, /* hacr */
- int, /* Offset in psa */
- u_char *, /* Buffer in memory */
- int); /* Length of buffer */
+ int, /* offset in PSA */
+ u_char *, /* buffer in memory */
+ int); /* length of buffer */
static inline void
- mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */
+ mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */
u_short,
u_char),
- mmc_write(u_long, /* Write n bytes to the MMC */
+ mmc_write(u_long, /* Write n bytes to the MMC. */
u_char,
u_char *,
int);
-static inline u_char /* Read 1 byte from the MMC */
+static inline u_char /* Read 1 byte from the MMC. */
mmc_in(u_long,
u_short);
static inline void
- mmc_read(u_long, /* Read n bytes from the MMC */
+ mmc_read(u_long, /* Read n bytes from the MMC. */
u_char,
u_char *,
int),
- fee_wait(u_long, /* Wait for frequency EEprom : base address */
- int, /* Base delay to wait for */
- int); /* Number of time to wait */
+ fee_wait(u_long, /* Wait for frequency EEPROM: base address */
+ int, /* base delay to wait for */
+ int); /* time to wait */
static void
- fee_read(u_long, /* Read the frequency EEprom : base address */
+ fee_read(u_long, /* Read the frequency EEPROM: base address */
u_short, /* destination offset */
u_short *, /* data buffer */
int); /* number of registers */
@@ -539,60 +539,59 @@ static void
wavelan_set_multicast_list(device *);
/* ----------------------- PACKET RECEPTION ----------------------- */
static inline void
- wv_packet_read(device *, /* Read a packet from a frame */
+ wv_packet_read(device *, /* Read a packet from a frame. */
u_short,
int),
- wv_receive(device *); /* Read all packets waiting */
+ wv_receive(device *); /* Read all packets waiting. */
/* --------------------- PACKET TRANSMISSION --------------------- */
static inline void
- wv_packet_write(device *, /* Write a packet to the Tx buffer */
+ wv_packet_write(device *, /* Write a packet to the Tx buffer. */
void *,
short);
static int
- wavelan_packet_xmit(struct sk_buff *, /* Send a packet */
+ wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */
device *);
/* -------------------- HARDWARE CONFIGURATION -------------------- */
static inline int
- wv_mmc_init(device *), /* Initialize the modem */
- wv_ru_start(device *), /* Start the i82586 receiver unit */
- wv_cu_start(device *), /* Start the i82586 command unit */
- wv_82586_start(device *); /* Start the i82586 */
+ wv_mmc_init(device *), /* Initialize the modem. */
+ wv_ru_start(device *), /* Start the i82586 receiver unit. */
+ wv_cu_start(device *), /* Start the i82586 command unit. */
+ wv_82586_start(device *); /* Start the i82586. */
static void
- wv_82586_config(device *); /* Configure the i82586 */
+ wv_82586_config(device *); /* Configure the i82586. */
static inline void
wv_82586_stop(device *);
static int
- wv_hw_reset(device *), /* Reset the wavelan hardware */
+ wv_hw_reset(device *), /* Reset the WaveLAN hardware. */
wv_check_ioaddr(u_long, /* ioaddr */
u_char *); /* mac address (read) */
/* ---------------------- INTERRUPT HANDLING ---------------------- */
static void
- wavelan_interrupt(int, /* Interrupt handler */
+ wavelan_interrupt(int, /* interrupt handler */
void *,
struct pt_regs *);
static void
- wavelan_watchdog(u_long); /* Transmission watchdog */
+ wavelan_watchdog(u_long); /* transmission watchdog */
/* ------------------- CONFIGURATION CALLBACKS ------------------- */
static int
- wavelan_open(device *), /* Open the device */
- wavelan_close(device *), /* Close the device */
- wavelan_config(device *); /* Configure one device */
+ wavelan_open(device *), /* Open the device. */
+ wavelan_close(device *), /* Close the device. */
+ wavelan_config(device *); /* Configure one device. */
extern int
- wavelan_probe(device *); /* See Space.c */
+ wavelan_probe(device *); /* See Space.c. */
/**************************** VARIABLES ****************************/
/*
- * This is the root of the linked list of wavelan drivers
+ * This is the root of the linked list of WaveLAN drivers
* It is use to verify that we don't reuse the same base address
- * for two differents drivers and to make the cleanup when
- * removing the module.
+ * for two different drivers and to clean up when removing the module.
*/
static net_local * wavelan_list = (net_local *) NULL;
/*
- * This table is used to translate the psa value to irq number
- * and vice versa...
+ * This table is used to translate the PSA value to IRQ number
+ * and vice versa.
*/
static u_char irqvals[] =
{
@@ -603,7 +602,7 @@ static u_char irqvals[] =
};
/*
- * Table of the available i/o address (base address) for wavelan
+ * Table of the available I/O addresses (base addresses) for WaveLAN
*/
static unsigned short iobase[] =
{
@@ -612,7 +611,7 @@ static unsigned short iobase[] =
* controllers.
* Leave out the others too -- we will always use 0x390 and leave
* 0x300 for the Ethernet device.
- * Jean II : 0x3E0 is really fine as well...
+ * Jean II: 0x3E0 is fine as well.
*/
0x300, 0x390, 0x3E0, 0x3C0
#endif /* 0 */
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 51b7e83cc..52cc5815a 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -56,7 +56,7 @@ static void wd_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void wd_block_output(struct device *dev, int count,
const unsigned char *buf, int start_page);
-static int wd_close_card(struct device *dev);
+static int wd_close(struct device *dev);
#define WD_START_PG 0x00 /* First page of TX buffer */
@@ -124,6 +124,10 @@ __initfunc(int wd_probe1(struct device *dev, int ioaddr))
|| (checksum & 0xff) != 0xFF)
return ENODEV;
+ /* Looks like we have a card. Make sure 8390 support is available. */
+ if (load_8390_module("wd.c"))
+ return -ENOSYS;
+
/* We should have a "dev" from Space.c or the static module table. */
if (dev == NULL) {
printk("wd.c: Passed a NULL device.\n");
@@ -140,7 +144,7 @@ __initfunc(int wd_probe1(struct device *dev, int ioaddr))
if (ei_debug && version_printed++ == 0)
printk(version);
- printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
+ printk("%s: WD80x3 at %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
@@ -252,20 +256,21 @@ __initfunc(int wd_probe1(struct device *dev, int ioaddr))
} else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */
dev->irq = 9;
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk (" unable to get memory for dev->priv.\n");
+ return -ENOMEM;
+ }
+
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
if (request_irq(dev->irq, ei_interrupt, 0, model_name, dev)) {
printk (" unable to get IRQ %d.\n", dev->irq);
+ kfree(dev->priv);
+ dev->priv = NULL;
return EAGAIN;
}
- /* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (ethdev_init(dev)) {
- printk (" unable to get memory for dev->priv.\n");
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
-
/* OK, were are certain this is going to work. Setup the device. */
request_region(ioaddr, WD_IO_EXTENT, model_name);
@@ -294,7 +299,7 @@ __initfunc(int wd_probe1(struct device *dev, int ioaddr))
ei_status.block_output = &wd_block_output;
ei_status.get_8390_hdr = &wd_get_8390_hdr;
dev->open = &wd_open;
- dev->stop = &wd_close_card;
+ dev->stop = &wd_close;
NS8390_init(dev, 0);
#if 1
@@ -414,7 +419,7 @@ wd_block_output(struct device *dev, int count, const unsigned char *buf,
static int
-wd_close_card(struct device *dev)
+wd_close(struct device *dev)
{
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
@@ -479,12 +484,15 @@ init_module(void)
}
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
return -ENXIO;
}
found++;
}
-
+ lock_8390_module();
return 0;
}
@@ -496,12 +504,14 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
struct device *dev = &dev_wd[this_dev];
if (dev->priv != NULL) {
+ void *priv = dev->priv;
int ioaddr = dev->base_addr - WD_NIC_OFFSET;
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
free_irq(dev->irq, dev);
release_region(ioaddr, WD_IO_EXTENT);
+ dev->priv = NULL;
+ unregister_netdev(dev);
+ kfree(priv);
+ unlock_8390_module();
}
}
}
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
new file mode 100644
index 000000000..93f5f7ea7
--- /dev/null
+++ b/drivers/net/yellowfin.c
@@ -0,0 +1,1309 @@
+/* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
+/*
+ Written 1997 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter.
+
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Support and updates available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html
+*/
+
+static const char *version = "yellowfin.c:v0.10 12/5/97 becker@cesdis.gsfc.nasa.gov\n";
+
+/* A few user-configurable values. */
+
+static int max_interrupt_work = 20;
+static int min_pci_latency = 64;
+static int mtu = 0;
+#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
+/* System-wide count of bogus-rx frames. */
+static int bogus_rx = 0;
+static int dma_ctrl = 0x004A0263; /* Constrained by errata */
+static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */
+#elif YF_NEW
+static int dma_ctrl = 0x00CAC277; /* Override when loading module! */
+static int fifo_cfg = 0x0028;
+#else
+static int dma_ctrl = 0x004A0263; /* Constrained by errata */
+static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */
+#endif
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+ Setting to > 1518 effectively disables this feature. */
+static const int rx_copybreak = 100;
+
+/* Keep the ring sizes a power of two for efficiency.
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT ((2000*HZ)/1000)
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#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/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+#include <linux/version.h> /* Evil, but neccessary */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x) /* What to put in timer->expires. */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr) ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+
+#else /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
+#ifdef MODULE
+#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#undef MOD_INC_USE_COUNT
+#define MOD_INC_USE_COUNT
+#undef MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+#endif /* 1.3.38 */
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+#if (LINUX_VERSION_CODE >= 0x20100)
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+#endif
+#endif
+#ifdef SA_SHIRQ
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#include <linux/bios32.h>
+#endif
+
+static const char *card_name = "Yellowfin G-NIC Gbit Ethernet";
+
+/* The PCI I/O space extent. */
+#define YELLOWFIN_TOTAL_SIZE 0x100
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry yellowfin_drv =
+{card_name, yellowfin_pci_probe, YELLOWFIN_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef YELLOWFIN_DEBUG
+int yellowfin_debug = YELLOWFIN_DEBUG;
+#else
+int yellowfin_debug = 1;
+#endif
+
+/*
+ Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the Packet Engines "Yellowfin" Gigabit
+Ethernet adapter. The only PCA currently supported is the G-NIC 64-bit
+PCI card.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Yellowfin uses the Descriptor Based DMA Architecture specified by Apple.
+This is a descriptor list scheme similar to that used by the EEPro100 and
+Tulip. This driver uses two statically allocated fixed-size descriptor lists
+formed into rings by a branch from the final descriptor to the beginning of
+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
+
+The driver allocates full frame size skbuffs for the Rx ring buffers at
+open() time and passes the skb->data field to the Yellowfin as receive data
+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
+a fresh skbuff is allocated and the frame is copied to the new skbuff.
+When the incoming frame is larger, the skbuff is passed directly up the
+protocol stack and replaced by a newly allocated skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames. For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information). For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data.
+
+IIIC. Synchronization
+
+The driver runs as two independent, single-threaded flows of control. One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag. The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'yp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'yp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Kim Stearns of Packet Engines for providing a pair of G-NIC boards.
+
+IVb. References
+
+Yellowfin Engineering Design Specification, 4/23/97 Preliminary/Confidential
+http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
+
+IVc. Errata
+
+See Packet Engines confidential appendix.
+
+*/
+
+/* A few values that may be tweaked. */
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+
+#ifndef PCI_VENDOR_ID_PKT_ENG /* To be defined in linux/pci.h */
+#define PCI_VENDOR_ID_PKT_ENG 0x1000 /* Hmm, likely number.. */
+#define PCI_DEVICE_ID_YELLOWFIN 0x0702
+#endif
+
+/* The rest of these values should never change. */
+
+static void yellowfin_timer(unsigned long data);
+
+/* Offsets to the Yellowfin registers. Various sizes and alignments. */
+enum yellowfin_offsets {
+ TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C,
+ TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18,
+ RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C,
+ RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58,
+ EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86,
+ ChipRev=0x8C, DMACtrl=0x90, Cnfg=0xA0, RxDepth=0xB8, FlowCtrl=0xBC,
+ AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8,
+};
+
+/* The Yellowfin Rx and Tx buffer descriptors. */
+struct yellowfin_desc {
+ u16 request_cnt;
+ u16 cmd;
+ u32 addr;
+ u32 branch_addr;
+ u16 result_cnt;
+ u16 status;
+};
+
+struct tx_status_words {
+ u16 tx_cnt;
+ u16 tx_errs;
+ u16 total_tx_cnt;
+ u16 paused;
+};
+
+/* Bits in yellowfin_desc.cmd */
+enum desc_cmd_bits {
+ CMD_TX_PKT=0x1000, CMD_RX_BUF=0x2000, CMD_TXSTATUS=0x3000,
+ CMD_NOP=0x6000, CMD_STOP=0x7000,
+ BRANCH_ALWAYS=0x0C, INTR_ALWAYS=0x30, WAIT_ALWAYS=0x03,
+ BRANCH_IFTRUE=0x04,
+};
+
+/* Bits in yellowfin_desc.status */
+enum desc_status_bits { RX_EOP=0x0040, };
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+ IntrRxDone=0x01, IntrRxInvalid=0x02, IntrRxPCIFault=0x04,IntrRxPCIErr=0x08,
+ IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80,
+ IntrEarlyRx=0x100, IntrWakeup=0x200, };
+
+struct yellowfin_private {
+ /* Descriptor rings first for alignment. Tx requires a second descriptor
+ for status. */
+ struct yellowfin_desc rx_ring[RX_RING_SIZE];
+ struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
+ const char *product_name;
+ struct device *next_module;
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ struct tx_status_words tx_status[TX_RING_SIZE];
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ int chip_id;
+ struct enet_statistics stats;
+ struct timer_list timer; /* Media selection timer. */
+ unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int medialock:1; /* Do not sense media. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ u32 pad[4]; /* Used for 32-byte alignment */
+};
+
+#ifdef MODULE
+/* Used to pass the media type, etc. */
+#define MAX_UNITS 8 /* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+#if LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(min_pci_latency, "i");
+MODULE_PARM(mtu, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
+
+#endif
+
+static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,
+ int chip_id, int options);
+static int yellowfin_open(struct device *dev);
+static void yellowfin_timer(unsigned long data);
+static void yellowfin_tx_timeout(struct device *dev);
+static void yellowfin_init_ring(struct device *dev);
+static int yellowfin_start_xmit(struct sk_buff *skb, struct device *dev);
+static int yellowfin_rx(struct device *dev);
+static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
+static int yellowfin_close(struct device *dev);
+static struct enet_statistics *yellowfin_get_stats(struct device *dev);
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev);
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+
+#ifdef MODULE
+/* A list of all installed Yellowfin devices, for removing the driver module. */
+static struct device *root_yellowfin_dev = NULL;
+#endif
+
+int yellowfin_probe(struct device *dev)
+{
+ int cards_found = 0;
+ static int pci_index = 0; /* Static, for multiple probe calls. */
+
+ /* Ideally we would detect all network cards in slot order. That would
+ be best done a central PCI probe dispatch, which wouldn't work
+ well with the current structure. So instead we detect just the
+ Yellowfin cards in slot order. */
+
+ if (pci_present()) {
+ unsigned char pci_bus, pci_device_fn;
+
+ for (;pci_index < 0xff; pci_index++) {
+#if LINUX_VERSION_CODE >= 0x20155
+ unsigned int pci_irq_line;
+ struct pci_dev *pdev;
+#else
+ unsigned char pci_irq_line;
+#endif
+ unsigned char pci_latency;
+ unsigned short pci_command, vendor, device;
+ unsigned int pci_ioaddr, chip_idx = 0;
+
+#ifdef REVERSE_PROBE_ORDER
+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+ 0xfe - pci_index,
+ &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ continue;
+#else
+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+ pci_index,
+ &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ break;
+#endif
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+#if LINUX_VERSION_CODE >= 0x20155
+ pdev = pci_find_slot(pci_bus, pci_device_fn);
+ pci_irq_line = pdev->irq;
+ pci_ioaddr = pdev->base_address[0];
+#else
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+#endif
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
+
+ if (vendor != PCI_VENDOR_ID_PKT_ENG)
+ continue;
+
+ if (device != PCI_DEVICE_ID_YELLOWFIN)
+ continue;
+
+ if (yellowfin_debug > 2)
+ printk("Found Packet Engines Yellowfin G-NIC at I/O %#x, IRQ %d.\n",
+ pci_ioaddr, pci_irq_line);
+
+ if (check_region(pci_ioaddr, YELLOWFIN_TOTAL_SIZE))
+ continue;
+
+#ifdef MODULE
+ dev = yellowfin_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+ cards_found < MAX_UNITS ? options[cards_found] : 0);
+#else
+ dev = yellowfin_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+ dev ? dev->mem_start : 0);
+#endif
+
+ if (dev) {
+ /* Get and check the bus-master and latency values. */
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+ printk(" PCI Master Bit has not been set! Setting...\n");
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, pci_command);
+ }
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < min_pci_latency) {
+ printk(" PCI latency timer (CFLT) is unreasonably low at %d."
+ " Setting to %d clocks.\n",
+ pci_latency, min_pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, min_pci_latency);
+ } else if (yellowfin_debug > 1)
+ printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
+ dev = 0;
+ cards_found++;
+ }
+ }
+ }
+
+#if defined (MODULE)
+ return cards_found;
+#else
+ return 0;
+#endif
+}
+
+static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,
+ int chip_id, int options)
+{
+ static int did_version = 0; /* Already printed version info. */
+ struct yellowfin_private *yp;
+ int i;
+
+ if (yellowfin_debug > 0 && did_version++ == 0)
+ printk(version);
+
+ dev = init_etherdev(dev, sizeof(struct yellowfin_private));
+
+ printk("%s: P-E Yellowfin type %8x at %#3x, ",
+ dev->name, inl(ioaddr + ChipRev), ioaddr);
+
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", inb(ioaddr + StnAddr + i));
+ printk("%2.2x, IRQ %d.\n", inb(ioaddr + StnAddr + i), irq);
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
+
+ /* Reset the chip. */
+ outl(0x80000000, ioaddr + DMACtrl);
+
+
+ /* We do a request_region() only to register /proc/ioports info. */
+ request_region(ioaddr, YELLOWFIN_TOTAL_SIZE, card_name);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ /* Make certain the descriptor lists are aligned. */
+ yp = (void *)(((long)kmalloc(sizeof(*yp), GFP_KERNEL) + 31) & ~31);
+ memset(yp, 0, sizeof(*yp));
+ dev->priv = yp;
+
+#ifdef MODULE
+ yp->next_module = root_yellowfin_dev;
+ root_yellowfin_dev = dev;
+#endif
+
+ yp->chip_id = chip_id;
+
+ yp->full_duplex = 1;
+#ifdef YELLOWFIN_DEFAULT_MEDIA
+ yp->default_port = YELLOWFIN_DEFAULT_MEDIA;
+#endif
+#ifdef YELLOWFIN_NO_MEDIA_SWITCH
+ yp->medialock = 1;
+#endif
+
+ /* The lower four bits are the media type. */
+ if (options > 0) {
+ yp->full_duplex = (options & 16) ? 1 : 0;
+ yp->default_port = options & 15;
+ if (yp->default_port)
+ yp->medialock = 1;
+ }
+
+ /* The Yellowfin-specific entries in the device structure. */
+ dev->open = &yellowfin_open;
+ dev->hard_start_xmit = &yellowfin_start_xmit;
+ dev->stop = &yellowfin_close;
+ dev->get_stats = &yellowfin_get_stats;
+ dev->set_multicast_list = &set_rx_mode;
+ if (mtu)
+ dev->mtu = mtu;
+
+ /* todo: Reset the xcvr interface and turn on heartbeat. */
+
+ return dev;
+}
+
+
+static int
+yellowfin_open(struct device *dev)
+{
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ /* Reset the chip. */
+ outl(0x80000000, ioaddr + DMACtrl);
+
+#ifdef SA_SHIRQ
+ if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ,
+ card_name, dev)) {
+ return -EAGAIN;
+ }
+#else
+ if (irq2dev_map[dev->irq] != NULL
+ || (irq2dev_map[dev->irq] = dev) == NULL
+ || dev->irq == 0
+ || request_irq(dev->irq, &yellowfin_interrupt, 0, card_name)) {
+ return -EAGAIN;
+ }
+#endif
+
+ if (yellowfin_debug > 1)
+ printk("%s: yellowfin_open() irq %d.\n", dev->name, dev->irq);
+
+ MOD_INC_USE_COUNT;
+
+ yellowfin_init_ring(dev);
+
+ outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);
+ outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr);
+
+ /* Set up various condition 'select' registers.
+ There are no options here. */
+ outl(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */
+ outl(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */
+ outl(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */
+ outl(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */
+ outl(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */
+ outl(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */
+
+ /* Initialize other registers: with so many this eventually this will
+ converted to an offset/value list. */
+ outl(dma_ctrl, ioaddr + DMACtrl);
+ outw(fifo_cfg, ioaddr + FIFOcfg);
+ /* Enable automatic generation of flow control frames, period 0xffff. */
+ outl(0x0030FFFF, ioaddr + FlowCtrl);
+
+ if (dev->if_port == 0)
+ dev->if_port = yp->default_port;
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+
+ /* We are always in full-duplex mode with the current chip! */
+ yp->full_duplex = 1;
+
+ /* Setting the Rx mode will start the Rx process. */
+ outw(0x01CD | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
+#ifdef NEW_MULTICAST
+ set_rx_mode(dev);
+#else
+ set_rx_mode(dev, 0, 0);
+#endif
+
+ dev->start = 1;
+
+ /* Enable interrupts by setting the interrupt mask. */
+ outw(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */
+ outw(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */
+ outl(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */
+ outl(0x80008000, ioaddr + TxCtrl);
+
+ if (yellowfin_debug > 2) {
+ printk("%s: Done yellowfin_open().\n",
+ dev->name);
+ }
+ /* Set the timer to check for link beat. */
+ init_timer(&yp->timer);
+ yp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ yp->timer.data = (unsigned long)dev;
+ yp->timer.function = &yellowfin_timer; /* timer handler */
+ add_timer(&yp->timer);
+
+ return 0;
+}
+
+static void yellowfin_timer(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int next_tick = 0;
+
+ if (yellowfin_debug > 3) {
+ printk("%s: Yellowfin timer tick, status %8.8x.\n",
+ dev->name, inl(ioaddr + IntrStatus));
+ }
+ if (next_tick) {
+ yp->timer.expires = RUN_AT(next_tick);
+ add_timer(&yp->timer);
+ }
+}
+
+static void yellowfin_tx_timeout(struct device *dev)
+{
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int i;
+
+ printk("%s: Yellowfin transmit timed out, status %8.8x, resetting...\n",
+ dev->name, inl(ioaddr));
+
+#ifndef __alpha__
+ printk(" Rx ring %8.8x: ", (int)yp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)yp->rx_ring[i].status);
+ printk("\n Tx ring %8.8x: ", (int)yp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %4.4x /%4.4x", yp->tx_status[i].tx_errs, yp->tx_ring[i].status);
+ printk("\n");
+#endif
+
+ /* Perhaps we should reinitialize the hardware here. */
+ dev->if_port = 0;
+ /* Stop and restart the chip's Tx processes . */
+
+ /* Trigger an immediate transmit demand. */
+
+ dev->trans_start = jiffies;
+ yp->stats.tx_errors++;
+ return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+yellowfin_init_ring(struct device *dev)
+{
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ int i;
+
+ yp->tx_full = 0;
+ yp->cur_rx = yp->cur_tx = 0;
+ yp->dirty_rx = yp->dirty_tx = 0;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb;
+ int pkt_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+ yp->rx_ring[i].request_cnt = pkt_buf_sz;
+ yp->rx_ring[i].cmd = CMD_RX_BUF | INTR_ALWAYS;
+
+ skb = DEV_ALLOC_SKB(pkt_buf_sz);
+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
+ yp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break; /* Bad news! */
+ skb->dev = dev; /* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+ yp->rx_ring[i].addr = virt_to_bus(skb->tail);
+#else
+ yp->rx_ring[i].addr = virt_to_bus(skb->data);
+#endif
+ yp->rx_ring[i].branch_addr = virt_to_bus(&yp->rx_ring[i+1]);
+ }
+ /* Mark the last entry as wrapping the ring. */
+ yp->rx_ring[i-1].cmd = CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
+ yp->rx_ring[i-1].branch_addr = virt_to_bus(&yp->rx_ring[0]);
+
+/*#define NO_TXSTATS*/
+#ifdef NO_TXSTATS
+ /* In this mode the Tx ring needs only a single descriptor. */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ yp->tx_skbuff[i] = 0;
+ yp->tx_ring[i].cmd = CMD_STOP;
+ yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ }
+ yp->tx_ring[--i].cmd = CMD_STOP | BRANCH_ALWAYS; /* Wrap ring */
+ yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+#else
+ /* Tx ring needs a pair of descriptors, the second for the status. */
+ for (i = 0; i < TX_RING_SIZE*2; i++) {
+ yp->tx_skbuff[i/2] = 0;
+ yp->tx_ring[i].cmd = CMD_STOP; /* Branch on Tx error. */
+ yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ i++;
+ yp->tx_ring[i].cmd = CMD_TXSTATUS; /* Interrupt, no wait. */
+ yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);
+ yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2]);
+ yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ }
+ /* Wrap ring */
+ yp->tx_ring[--i].cmd = CMD_TXSTATUS | BRANCH_ALWAYS | INTR_ALWAYS;
+ yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+#endif
+}
+
+static int
+yellowfin_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ unsigned entry;
+
+ /* 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 (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (jiffies - dev->trans_start < TX_TIMEOUT)
+ return 1;
+ yellowfin_tx_timeout(dev);
+ return 1;
+ }
+
+ /* Caution: the write order is important here, set the base address
+ with the "ownership" bits last. */
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = yp->cur_tx % TX_RING_SIZE;
+
+ yp->tx_skbuff[entry] = skb;
+
+#ifdef NO_TXSTATS
+ yp->tx_ring[entry].request_cnt = skb->len;
+ yp->tx_ring[entry].addr = virt_to_bus(skb->data);
+ yp->tx_ring[entry].status = 0;
+ if (entry >= TX_RING_SIZE-1) {
+ yp->tx_ring[0].cmd = CMD_STOP; /* New stop command. */
+ yp->tx_ring[TX_RING_SIZE-1].cmd = CMD_TX_PKT | BRANCH_ALWAYS;
+ } else {
+ yp->tx_ring[entry+1].cmd = CMD_STOP; /* New stop command. */
+ yp->tx_ring[entry].cmd = CMD_TX_PKT | BRANCH_IFTRUE;
+ }
+ yp->cur_tx++;
+#else
+ yp->tx_ring[entry<<1].request_cnt = skb->len;
+ yp->tx_ring[entry<<1].addr = virt_to_bus(skb->data);
+ /* The input_last (status-write) command is constant, but we must rewrite
+ the subsequent 'stop' command. */
+
+ yp->cur_tx++;
+ {
+ unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
+ yp->tx_ring[next_entry<<1].cmd = CMD_STOP;
+ }
+ /* Final step -- overwrite the old 'stop' command. */
+
+ yp->tx_ring[entry<<1].cmd =
+ (entry % 6) == 0 ? CMD_TX_PKT | INTR_ALWAYS | BRANCH_IFTRUE :
+ CMD_TX_PKT | BRANCH_IFTRUE;
+#endif
+
+ /* Todo: explicitly flush cache lines here. */
+
+ /* Wake the potentially-idle transmit channel. */
+ outl(0x10001000, dev->base_addr + TxCtrl);
+
+ if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)
+ dev->tbusy = 0; /* Typical path */
+ else
+ yp->tx_full = 1;
+ dev->trans_start = jiffies;
+
+ if (yellowfin_debug > 4) {
+ printk("%s: Yellowfin transmit frame #%d queued in slot %d.\n",
+ dev->name, yp->cur_tx, entry);
+ }
+ return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+{
+#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
+ struct device *dev = (struct device *)dev_instance;
+#else
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+
+ struct yellowfin_private *lp;
+ int ioaddr, boguscnt = max_interrupt_work;
+
+ if (dev == NULL) {
+ printk ("yellowfin_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+
+ ioaddr = dev->base_addr;
+ lp = (struct yellowfin_private *)dev->priv;
+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+ printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+ return;
+ }
+
+ do {
+ u16 intr_status = inw(ioaddr + IntrClear);
+ unsigned dirty_tx = lp->dirty_tx;
+
+ if (yellowfin_debug > 4)
+ printk("%s: Yellowfin interrupt, status %4.4x.\n",
+ dev->name, intr_status);
+
+ if (intr_status == 0)
+ break;
+
+ if (intr_status & (IntrRxDone | IntrEarlyRx))
+ yellowfin_rx(dev);
+
+#ifdef NO_TXSTATS
+ for (; dirty_tx < lp->cur_tx; dirty_tx++) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ if (lp->tx_ring[entry].status == 0)
+ break;
+ /* Free the original skb. */
+ dev_kfree_skb(lp->tx_skbuff[entry]);
+ lp->tx_skbuff[entry] = 0;
+ lp->stats.tx_packets++;
+ }
+ if (lp->tx_full && dev->tbusy
+ && dirty_tx > lp->cur_tx - TX_RING_SIZE + 4) {
+ /* The ring is no longer full, clear tbusy. */
+ lp->tx_full = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+ lp->dirty_tx = dirty_tx;
+#else
+ if (intr_status & IntrTxDone
+ || lp->tx_status[dirty_tx % TX_RING_SIZE].tx_errs) {
+
+ for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+ /* Todo: optimize this. */
+ int entry = dirty_tx % TX_RING_SIZE;
+ u16 tx_errs = lp->tx_status[entry].tx_errs;
+
+ if (tx_errs == 0)
+ break; /* It still hasn't been Txed */
+ if (tx_errs & 0xF8100000) {
+ /* There was an major error, log it. */
+#ifndef final_version
+ if (yellowfin_debug > 1)
+ printk("%s: Transmit error, Tx status %4.4x.\n",
+ dev->name, tx_errs);
+#endif
+ lp->stats.tx_errors++;
+ if (tx_errs & 0xF800) lp->stats.tx_aborted_errors++;
+ if (tx_errs & 0x0800) lp->stats.tx_carrier_errors++;
+ if (tx_errs & 0x2000) lp->stats.tx_window_errors++;
+ if (tx_errs & 0x8000) lp->stats.tx_fifo_errors++;
+#ifdef ETHER_STATS
+ if (tx_errs & 0x1000) lp->stats.collisions16++;
+#endif
+ } else {
+#ifdef ETHER_STATS
+ if (status & 0x0400) lp->stats.tx_deferred++;
+#endif
+ lp->stats.collisions += tx_errs & 15;
+ lp->stats.tx_packets++;
+ }
+
+ /* Free the original skb. */
+ dev_kfree_skb(lp->tx_skbuff[entry]);
+ lp->tx_skbuff[entry] = 0;
+ /* Mark status as empty. */
+ lp->tx_status[entry].tx_errs = 0;
+ }
+
+#ifndef final_version
+ if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+ printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+ dirty_tx += TX_RING_SIZE;
+ }
+#endif
+
+ if (lp->tx_full && dev->tbusy
+ && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+ /* The ring is no longer full, clear tbusy. */
+ lp->tx_full = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+
+ lp->dirty_tx = dirty_tx;
+ }
+#endif
+
+ /* Log errors and other events. */
+ if (intr_status & 0x2ee) { /* Abnormal error summary. */
+ printk("%s: Something Wicked happened! %4.4x.\n",
+ dev->name, intr_status);
+ /* Hmmmmm, it's not clear what to do here. */
+ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
+ lp->stats.tx_errors++;
+ if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
+ lp->stats.rx_errors++;
+ }
+ if (--boguscnt < 0) {
+ printk("%s: Too much work at interrupt, status=0x%4.4x.\n",
+ dev->name, intr_status);
+ break;
+ }
+ } while (1);
+
+ if (yellowfin_debug > 3)
+ printk("%s: exiting interrupt, status=%#4.4x.\n",
+ dev->name, inw(ioaddr + IntrStatus));
+
+ /* Code that should never be run! Perhaps remove after testing.. */
+ {
+ static int stopit = 10;
+ if (dev->start == 0 && --stopit < 0) {
+ printk("%s: Emergency stop, looping startup interrupt.\n",
+ dev->name);
+#ifdef SA_SHIRQ
+ free_irq(irq, dev);
+#else
+ free_irq(irq);
+#endif
+ }
+ }
+
+ dev->interrupt = 0;
+ return;
+}
+
+/* This routine is logically part of the interrupt handler, but separated
+ for clarity and better register allocation. */
+static int
+yellowfin_rx(struct device *dev)
+{
+ struct yellowfin_private *lp = (struct yellowfin_private *)dev->priv;
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ int entry = lp->cur_rx % RX_RING_SIZE;
+ int boguscnt = 20;
+
+ if (yellowfin_debug > 4) {
+ printk(" In yellowfin_rx(), entry %d status %4.4x.\n", entry,
+ yp->rx_ring[entry].status);
+ printk(" #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x.\n",
+ entry, yp->rx_ring[entry].cmd,
+ yp->rx_ring[entry].request_cnt, yp->rx_ring[entry].addr,
+ yp->rx_ring[entry].result_cnt, yp->rx_ring[entry].status);
+ }
+
+
+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
+ while (yp->rx_ring[entry].status) {
+ /* Todo: optimize this mess. */
+ u16 desc_status = yp->rx_ring[entry].status;
+ struct yellowfin_desc *desc = &lp->rx_ring[entry];
+ int frm_size = desc->request_cnt - desc->result_cnt;
+ u8 *buf_addr = bus_to_virt(lp->rx_ring[entry].addr);
+ s16 frame_status = *(s16*)&(buf_addr[frm_size - 2]);
+
+ if (yellowfin_debug > 4)
+ printk(" yellowfin_rx() status was %4.4x.\n", frame_status);
+ if (--boguscnt < 0)
+ break;
+ if ( ! (desc_status & RX_EOP)) {
+ printk("%s: Oversized Ethernet frame spanned multiple buffers,"
+ " status %4.4x!\n", dev->name, desc_status);
+ lp->stats.rx_length_errors++;
+ } else if (frame_status & 0x0038) {
+ /* There was a error. */
+ if (yellowfin_debug > 3)
+ printk(" yellowfin_rx() Rx error was %4.4x.\n", frame_status);
+ lp->stats.rx_errors++;
+ if (frame_status & 0x0060) lp->stats.rx_length_errors++;
+ if (frame_status & 0x0008) lp->stats.rx_frame_errors++;
+ if (frame_status & 0x0010) lp->stats.rx_crc_errors++;
+ if (frame_status < 0) lp->stats.rx_dropped++;
+#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
+ } else if (memcmp(bus_to_virt(lp->rx_ring[entry].addr),
+ dev->dev_addr, 6) != 0
+ && memcmp(bus_to_virt(lp->rx_ring[entry].addr),
+ "\0377\0377\0377\0377\0377\0377", 6) != 0) {
+ printk("%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ dev->name,
+ ((char *)bus_to_virt(lp->rx_ring[entry].addr))[0],
+ ((char *)bus_to_virt(lp->rx_ring[entry].addr))[1],
+ ((char *)bus_to_virt(lp->rx_ring[entry].addr))[2],
+ ((char *)bus_to_virt(lp->rx_ring[entry].addr))[3],
+ ((char *)bus_to_virt(lp->rx_ring[entry].addr))[4],
+ ((char *)bus_to_virt(lp->rx_ring[entry].addr))[5]);
+ bogus_rx++;
+#endif
+ } else {
+ u8 bogus_cnt = buf_addr[frm_size - 8];
+ short pkt_len = frm_size - 8 - bogus_cnt;
+ struct sk_buff *skb;
+ int rx_in_place = 0;
+
+ /* Check if the packet is long enough to just accept without
+ copying to a properly sized skbuff. */
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+ char *temp;
+
+ /* Get a fresh skbuff to replace the filled one. */
+ newskb = DEV_ALLOC_SKB(dev->mtu <= 1500 ? PKT_BUF_SZ
+ : dev->mtu + 32);
+ if (newskb == NULL) {
+ skb = 0; /* No memory, drop the packet. */
+ goto memory_squeeze;
+ }
+ /* Pass up the skb already on the Rx ring. */
+ skb = lp->rx_skbuff[entry];
+ temp = skb_put(skb, pkt_len);
+ if (bus_to_virt(lp->rx_ring[entry].addr) != temp)
+ printk("%s: Warning -- the skbuff addresses do not match"
+ " in yellowfin_rx: %p vs. %p / %p.\n", dev->name,
+ bus_to_virt(lp->rx_ring[entry].addr),
+ skb->head, temp);
+ rx_in_place = 1;
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ skb_reserve(newskb, 2); /* 16 byte align IP header */
+ lp->rx_ring[entry].addr = virt_to_bus(newskb->tail);
+ } else
+ skb = DEV_ALLOC_SKB(pkt_len + 2);
+ memory_squeeze:
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+ /* todo: Check that at least two ring entries are free.
+ If not, free one and mark stats->rx_dropped++. */
+ break;
+ }
+ skb->dev = dev;
+ if (! rx_in_place) {
+ skb_reserve(skb, 2); /* 16 byte align the data fields */
+ memcpy(skb_put(skb, pkt_len),
+ bus_to_virt(lp->rx_ring[entry].addr), pkt_len);
+ }
+#if LINUX_VERSION_CODE > 0x10300
+ skb->protocol = eth_type_trans(skb, dev);
+#else
+ skb->len = pkt_len;
+#endif
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ }
+
+ /* Mark this entry as being the end-of-list, and the prior entry
+ as now valid. */
+ lp->rx_ring[entry].cmd = CMD_STOP;
+ yp->rx_ring[entry].status = 0;
+ {
+ int prev_entry = entry - 1;
+ if (prev_entry < 0)
+ lp->rx_ring[RX_RING_SIZE - 1].cmd =
+ CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
+ else
+ lp->rx_ring[prev_entry].cmd = CMD_RX_BUF | INTR_ALWAYS;
+ }
+ entry = (++lp->cur_rx) % RX_RING_SIZE;
+ }
+ /* todo: restart Rx engine if stopped. For now we just make the Rx ring
+ large enough to avoid this. */
+
+ return 0;
+}
+
+static int
+yellowfin_close(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ int i;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ if (yellowfin_debug > 1) {
+ printk("%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",
+ dev->name, inw(ioaddr + TxStatus),
+ inw(ioaddr + RxStatus), inl(ioaddr + IntrStatus));
+ printk("%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
+ dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);
+ }
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ outw(0x0000, ioaddr + IntrEnb);
+
+ /* Stop the chip's Tx and Rx processes. */
+ outl(0x80000000, ioaddr + RxCtrl);
+ outl(0x80000000, ioaddr + TxCtrl);
+
+ del_timer(&yp->timer);
+
+ if (yellowfin_debug > 2) {
+ printk("\n Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));
+ for (i = 0; i < TX_RING_SIZE*2; i++)
+ printk(" %c #%d desc. %4.4x %4.4x %8.8x %8.8x %4.4x %4.4x.\n",
+ inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
+ i, yp->tx_ring[i].cmd,
+ yp->tx_ring[i].request_cnt, yp->tx_ring[i].addr,
+ yp->tx_ring[i].branch_addr,
+ yp->tx_ring[i].result_cnt, yp->tx_ring[i].status);
+ printk(" Tx status %p:\n", yp->tx_status);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" #%d status %4.4x %4.4x %4.4x %4.4x.\n",
+ i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
+ yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
+
+ printk("\n Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ printk(" %c #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x\n",
+ inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
+ i, yp->rx_ring[i].cmd,
+ yp->rx_ring[i].request_cnt, yp->rx_ring[i].addr,
+ yp->rx_ring[i].result_cnt, yp->rx_ring[i].status);
+ if (yellowfin_debug > 5) {
+ if (*(u8*)yp->rx_ring[i].addr != 0x69) {
+ int j;
+ for (j = 0; j < 0x50; j++)
+ printk(" %4.4x", ((u16*)yp->rx_ring[i].addr)[j]);
+ printk("\n");
+ }
+ }
+ }
+ }
+
+#ifdef SA_SHIRQ
+ free_irq(dev->irq, dev);
+#else
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = 0;
+#endif
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ yp->rx_ring[i].cmd = CMD_STOP;
+ yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+ if (yp->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+ yp->rx_skbuff[i]->free = 1;
+#endif
+ dev_kfree_skb(yp->rx_skbuff[i]);
+ }
+ yp->rx_skbuff[i] = 0;
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (yp->tx_skbuff[i])
+ dev_kfree_skb(yp->tx_skbuff[i]);
+ yp->tx_skbuff[i] = 0;
+ }
+
+#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
+ if (yellowfin_debug > 0) {
+ printk("%s: Received %d frames that we should not have.\n",
+ dev->name, bogus_rx);
+ }
+#endif
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static struct enet_statistics *
+yellowfin_get_stats(struct device *dev)
+{
+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
+ return &yp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+ N.B. Do not use for bulk data, use a table-based routine instead.
+ This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+ unsigned int crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+
+
+static void
+#ifdef NEW_MULTICAST
+set_rx_mode(struct device *dev)
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+{
+ int ioaddr = dev->base_addr;
+ u16 cfg_value = inw(ioaddr + Cnfg);
+
+ /* Stop the Rx process to change any value. */
+ outw(cfg_value & ~0x1000, ioaddr + Cnfg);
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ /* Unconditionally log net taps. */
+ printk("%s: Promiscuous mode enabled.\n", dev->name);
+ outw(0x000F, ioaddr + AddrMode);
+ } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter well, or accept all multicasts. */
+ printk("%s: Set all-multicast mode.\n", dev->name);
+ outw(0x000B, ioaddr + AddrMode);
+ } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */
+ struct dev_mc_list *mclist;
+ u16 hash_table[4];
+ int i;
+ memset(hash_table, 0, sizeof(hash_table));
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ /* Due to a bug in the early chip versions, multiple filter
+ slots must be set for each address. */
+ set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
+ hash_table);
+ set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
+ hash_table);
+ set_bit((ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f,
+ hash_table);
+ set_bit((ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f,
+ hash_table);
+ }
+ /* Copy the hash table to the chip. */
+ for (i = 0; i < 4; i++)
+ outw(hash_table[i], ioaddr + HashTbl + i*2);
+ printk("%s: Set multicast mode.\n", dev->name);
+ outw(0x0003, ioaddr + AddrMode);
+ } else { /* Normal, unicast/broadcast-only mode. */
+ printk("%s: Set unicast mode.\n", dev->name);
+ outw(0x0001, ioaddr + AddrMode);
+ }
+ /* Restart the Rx process. */
+ outw(cfg_value | 0x1000, ioaddr + Cnfg);
+}
+
+#ifdef MODULE
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+ int cards_found;
+
+ if (debug >= 0)
+ yellowfin_debug = debug;
+
+ root_yellowfin_dev = NULL;
+ cards_found = yellowfin_probe(0);
+
+ return cards_found ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+ struct device *next_dev;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ while (root_yellowfin_dev) {
+ next_dev = ((struct yellowfin_private *)root_yellowfin_dev->priv)->next_module;
+ unregister_netdev(root_yellowfin_dev);
+ release_region(root_yellowfin_dev->base_addr, YELLOWFIN_TOTAL_SIZE);
+ kfree(root_yellowfin_dev);
+ root_yellowfin_dev = next_dev;
+ }
+}
+
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */