patch-1.3.89 linux/drivers/net/sdla.c
Next file: linux/drivers/net/tulip.c
Previous file: linux/drivers/net/dlci.c
Back to the patch index
Back to the overall index
- Lines: 658
- Date:
Sun Apr 14 11:43:55 1996
- Orig file:
v1.3.88/linux/drivers/net/sdla.c
- Orig date:
Fri Apr 12 15:51:56 1996
diff -u --recursive --new-file v1.3.88/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
@@ -1,25 +1,32 @@
/*
- * SDLA An implementation of a driver for the Sangoma S502/S508 series
- * multi-protocol PC interface card. Initial offering is with
- * the DLCI driver, providing Frame Relay support for linux.
+ * SDLA An implementation of a driver for the Sangoma S502/S508 series
+ * multi-protocol PC interface card. Initial offering is with
+ * the DLCI driver, providing Frame Relay support for linux.
*
- * Global definitions for the Frame relay interface.
+ * Global definitions for the Frame relay interface.
*
- * Version: @(#)sdla.c 0.10 23 Mar 1996
+ * Version: @(#)sdla.c 0.20 13 Apr 1996
*
- * Credits: Sangoma Technologies, for the use of 2 cards for an extended
- * period of time.
- * David Mandelstam <dm@sangoma.com> for getting me started on
- * this project, and incentive to complete it.
- * Gene Kozen <74604.152@compuserve.com> for providing me with
- * important information about the cards.
+ * Credits: Sangoma Technologies, for the use of 2 cards for an extended
+ * period of time.
+ * David Mandelstam <dm@sangoma.com> for getting me started on
+ * this project, and incentive to complete it.
+ * Gene Kozen <74604.152@compuserve.com> for providing me with
+ * important information about the cards.
*
- * Author: Mike McLagan <mike.mclagan@linux.org>
+ * Author: Mike McLagan <mike.mclagan@linux.org>
*
- * 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.
+ * Changes:
+ * 0.15 Mike McLagan Improved error handling, packet dropping
+ * 0.20 Mike McLagan New transmit/receive flags for config
+ * If in FR mode, don't accept packets from
+ * non-DLCI devices.
+ *
+ *
+ * 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.
*/
#include <linux/module.h>
@@ -49,7 +56,7 @@
#include <linux/sdla.h>
-static const char* version = "SDLA driver v0.10, 23 Mar 1996, mike.mclagan@linux.org";
+static const char* version = "SDLA driver v0.20, 13 Apr 1996, mike.mclagan@linux.org";
static const char* devname = "sdla";
@@ -78,14 +85,9 @@
temp = buf;
while(len)
{
- offset = addr & 0x1FFF;
- if (offset + len > 0x2000)
- bytes = 0x2000 - offset;
- else
- bytes = len;
-
- base = (void *) dev->mem_start;
- base += offset;
+ offset = addr & SDLA_ADDR_MASK;
+ bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+ base = (void *) (dev->mem_start + offset);
save_flags(flags);
cli();
@@ -108,14 +110,9 @@
temp = buf;
while(len)
{
- offset = addr & 0x1FFF;
- if (offset + len > 0x2000)
- bytes = 0x2000 - offset;
- else
- bytes = len;
-
- base = (void *) dev->mem_start;
- base += offset;
+ offset = addr & SDLA_ADDR_MASK;
+ bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+ base = (void *) (dev->mem_start + offset);
save_flags(flags);
cli();
@@ -133,30 +130,24 @@
{
unsigned long flags;
char *base;
- int offset, len, addr, bytes;
+ int len, addr, bytes;
len = 65536;
addr = 0;
+ bytes = SDLA_WINDOW_SIZE;
+ base = (void *) dev->mem_start;
+
+ save_flags(flags);
+ cli();
while(len)
{
- offset = addr & 0x1FFF;
- if (offset + len > 0x2000)
- bytes = offset + len - 0x2000;
- else
- bytes = len;
-
- base = (void *) dev->mem_start;
- base += offset;
-
- save_flags(flags);
- cli();
SDLA_WINDOW(dev, addr);
memset(base, 0, bytes);
- restore_flags(flags);
addr += bytes;
len -= bytes;
}
+ restore_flags(flags);
}
static char sdla_byte(struct device *dev, int addr)
@@ -164,8 +155,7 @@
unsigned long flags;
char byte, *temp;
- temp = (void *) dev->mem_start;
- temp += addr & 0x1FFF;
+ temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
save_flags(flags);
cli();
@@ -250,7 +240,7 @@
done = jiffies + jiffs;
temp = (void *)dev->mem_start;
- temp += z80_addr & 0x1FFF;
+ temp += z80_addr & SDLA_ADDR_MASK;
resp = ~resp1;
while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
@@ -393,18 +383,25 @@
printk(KERN_ERR "%s: Command timed out!\n", dev->name);
break;
+ case SDLA_RET_BUF_OVERSIZE:
+ printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
+ break;
+
+ case SDLA_RET_BUF_TOO_BIG:
+ printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
+ break;
+
case SDLA_RET_CHANNEL_INACTIVE:
case SDLA_RET_DLCI_INACTIVE:
- case SDLA_RET_NO_BUFF:
+ case SDLA_RET_CIR_OVERFLOW:
+ case SDLA_RET_NO_BUFS:
if (cmd == SDLA_INFORMATION_WRITE)
break;
default:
- /*
- * Further processing could be done here
- * printk(KERN_DEBUG "%s: Unhandled return code 0x%2.2X\n", dev->name, ret);
- *
- */
+ printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
+/* Further processing could be done here */
+ break;
}
}
@@ -416,16 +413,14 @@
struct sdla_cmd *cmd_buf;
unsigned long pflags;
int jiffs, ret, waiting, len;
- long temp, window;
+ long window;
flp = dev->priv;
window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
- temp = (int) dev->mem_start;
- temp += window & 0x1FFF;
- cmd_buf = (struct sdla_cmd *)temp;
+ cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
ret = 0;
- jiffs = jiffies + HZ / 2; /* 1/2 second timeout */
+ jiffs = jiffies + HZ; /* 1 second is plenty */
save_flags(pflags);
cli();
SDLA_WINDOW(dev, window);
@@ -445,7 +440,7 @@
len = 0;
while (waiting && (jiffies <= jiffs))
{
- if (waiting++ % 4)
+ if (waiting++ % 3)
{
save_flags(pflags);
cli();
@@ -462,13 +457,18 @@
SDLA_WINDOW(dev, window);
ret = cmd_buf->retval;
len = cmd_buf->length;
- if (outbuf && len)
+ if (outbuf && outlen)
{
*outlen = *outlen >= len ? len : *outlen;
- memcpy(outbuf, cmd_buf->data, *outlen);
+
+ if (*outlen)
+ memcpy(outbuf, cmd_buf->data, *outlen);
}
+
+ /* This is a local copy that's used for error handling */
if (ret)
- memcpy(&status, cmd_buf->data, len);
+ memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
+
restore_flags(pflags);
}
else
@@ -521,6 +521,9 @@
if (flp->master[i] == master)
break;
+ if (i == CONFIG_DLCI_MAX)
+ return(-ENODEV);
+
flp->dlci[i] = -abs(flp->dlci[i]);
if (slave->start && (flp->config.station == FRAD_STATION_NODE))
@@ -598,6 +601,7 @@
struct frad_local *flp;
struct frad_local *dlp;
int i;
+ short len, ret;
flp = slave->priv;
@@ -609,11 +613,18 @@
return(-ENODEV);
dlp = master->priv;
+
+ ret = SDLA_RET_OK;
+ len = sizeof(struct dlci_conf);
if (slave->start)
- sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, flp->dlci[i], 0,
- &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+ 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(0);
+ return(ret == SDLA_RET_OK ? 0 : -EIO);
}
/**************************
@@ -622,6 +633,7 @@
*
**************************/
+/* NOTE: the DLCI driver deals with freeing the SKB!! */
static int sdla_transmit(struct sk_buff *skb, struct device *dev)
{
struct frad_local *flp;
@@ -643,6 +655,31 @@
printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
else
{
+
+ /*
+ * stupid GateD insists on setting up the multicast router thru us
+ * and we're ill equipped to handle a non Frame Relay packet at this
+ * time!
+ */
+
+ switch (dev->type)
+ {
+ case ARPHRD_FRAD:
+ if (skb->dev->type != ARPHRD_DLCI)
+ {
+ printk(KERN_WARNING "%s: FRAD module accepts packets from DLCI ONLY!\n", dev->name);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+ break;
+
+ default:
+ printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+
+ /* this is frame specific, but till there's a PPP module, it's the default */
switch (flp->type)
{
case SDLA_S502A:
@@ -658,7 +695,7 @@
save_flags(flags);
cli();
SDLA_WINDOW(dev, addr);
- pbuf = (void *)(((int) dev->mem_start) + (addr & 0x1FFF));
+ pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
@@ -673,17 +710,21 @@
{
case SDLA_RET_OK:
flp->stats.tx_packets++;
- ret = 0;
+ ret = DLCI_RET_OK;
break;
+ case SDLA_RET_CIR_OVERFLOW:
+ case SDLA_RET_BUF_OVERSIZE:
+ case SDLA_RET_NO_BUFS:
+ flp->stats.tx_dropped++;
+ ret = DLCI_RET_DROP;
+ break;
+
default:
flp->stats.tx_errors++;
- ret = 1;
+ ret = DLCI_RET_ERR;
+ break;
}
-
- /* per Alan Cox, we can drop the packet on the floor if it doesn't go */
- dev_kfree_skb(skb, FREE_WRITE);
-
dev->tbusy = 0;
}
return(ret);
@@ -701,17 +742,18 @@
struct buf_entry *pbuf;
unsigned long flags;
- int i, received, success, addr;
- short dlci, len, split;
- char bogus;
+ int i, received, success, addr, buf_base, buf_top;
+ short dlci, len, len2, split;
flp = dev->priv;
- bogus = 0;
- success = 0;
- received = 0;
- addr = 0;
+ success = 1;
+ received = addr = buf_top = buf_base = 0;
+ len = dlci = 0;
skb = NULL;
master = NULL;
+ cmd = NULL;
+ pbufi = NULL;
+ pbuf = NULL;
save_flags(flags);
cli();
@@ -720,93 +762,89 @@
{
case SDLA_S502A:
case SDLA_S502E:
- cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & 0x1FFF));
+ cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
- if (!cmd->opp_flag)
+ success = cmd->opp_flag;
+ if (!success)
break;
dlci = cmd->dlci;
len = cmd->length;
-
- for (i=0;i<CONFIG_DLCI_MAX;i++)
- if (flp->dlci[i] == dlci)
- break;
-
- if (i == CONFIG_DLCI_MAX)
- {
- printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
- flp->stats.rx_errors++;
- cmd->opp_flag = 0;
- break;
- }
-
- master = flp->master[i];
- skb = dev_alloc_skb(len);
- if (skb == NULL)
- {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- flp->stats.rx_dropped++;
- cmd->opp_flag = 0;
- break;
- }
-
- /* pick up the data */
- sdla_read(dev, dev->mem_start + ((SDLA_502_RCV_BUF + SDLA_502_DATA_OFS) & 0x1FFF), skb_put(skb,len), len);
- cmd->opp_flag = 0;
- success = 1;
break;
case SDLA_S508:
- pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & 0x1FFF));
+ pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
- pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & 0x1FFF));
- if (!pbuf->opp_flag)
+ pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
+ success = pbuf->opp_flag;
+ if (!success)
break;
+ buf_top = pbufi->buf_top;
+ buf_base = pbufi->buf_base;
dlci = pbuf->dlci;
len = pbuf->length;
addr = pbuf->buf_addr;
+ break;
+ }
- for (i=0;i<CONFIG_DLCI_MAX;i++)
- if (flp->dlci[i] == dlci)
- break;
-
- if (i == CONFIG_DLCI_MAX)
- {
- printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
- flp->stats.rx_errors++;
- pbuf->opp_flag = 0;
+ /* common code, find the DLCI and get the SKB */
+ if (success)
+ {
+ for (i=0;i<CONFIG_DLCI_MAX;i++)
+ if (flp->dlci[i] == dlci)
break;
- }
- master = flp->master[i];
- skb = dev_alloc_skb(len);
- if (skb == NULL)
- {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- flp->stats.rx_dropped++;
- pbuf->opp_flag = 0;
- break;
- }
+ if (i == CONFIG_DLCI_MAX)
+ {
+ printk(KERN_NOTICE "%s: Recieved packet from invalid DLCI %i, ignoring.", dev->name, dlci);
+ flp->stats.rx_errors++;
+ success = 0;
+ }
+ }
- /* is this buffer split off the end of the internal ring buffer */
- split = addr + len > pbufi->buf_top + 1 ? pbufi->buf_top - addr + 1 : 0;
- len -= split;
-
- /* lets get the data */
- sdla_read(dev, addr, skb_put(skb, len), len);
- if (split)
+ if (success)
+ {
+ master = flp->master[i];
+ skb = dev_alloc_skb(len + sizeof(struct frhdr));
+ if (skb == NULL)
+ {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+ flp->stats.rx_dropped++;
+ success = 0;
+ }
+ else
+ skb_reserve(skb, sizeof(struct frhdr));
+ }
+
+ /* pick up the data */
+ switch (flp->type)
+ {
+ case SDLA_S502A:
+ case SDLA_S502E:
+ if (success)
+ sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
+
+ SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+ cmd->opp_flag = 0;
+ break;
+
+ case SDLA_S508:
+ if (success)
{
- SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
- sdla_read(dev, pbufi->buf_base, skb_put(skb, split), split);
+ /* is this buffer split off the end of the internal ring buffer */
+ split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
+ len2 = len - split;
+
+ sdla_read(dev, addr, skb_put(skb, len2), len2);
+ if (split)
+ sdla_read(dev, buf_base, skb_put(skb, split), split);
}
- SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
- pbuf->opp_flag = 0;
- success = 1;
-
/* increment the buffer we're looking at */
+ SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
+ pbuf->opp_flag = 0;
break;
}
@@ -838,7 +876,7 @@
if (!flp->initialized)
{
- printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
+ printk(KERN_WARNING "%s: irq %d for unintialiazed device.\n", dev->name, irq);
return;
}
@@ -872,10 +910,10 @@
outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
}
- dev->interrupt = 0;
/* this clears the byte, informing the Z80 we're done */
byte = 0;
sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+ dev->interrupt = 0;
}
static void sdla_poll(unsigned long device)
@@ -941,7 +979,6 @@
}
sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
- sdla_stop(dev);
dev->tbusy = 1;
dev->start = 0;
@@ -973,9 +1010,6 @@
if (!flp->configured)
return(-EPERM);
- /* off to the races! */
- sdla_start(dev);
-
/* time to send in the configuration */
len = 0;
for(i=0;i<CONFIG_DLCI_MAX;i++)
@@ -1116,6 +1150,9 @@
memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
flp->config.flags |= SDLA_DIRECT_RECV;
+ if (flp->type == SDLA_S508)
+ flp->config.flags |= SDLA_TX70_RX30;
+
if (dev->mtu != flp->config.mtu)
{
/* this is required to change the MTU */
@@ -1125,7 +1162,12 @@
flp->master[i]->mtu = flp->config.mtu;
}
- flp->config.mtu += sizeof(struct fradhdr);
+ flp->config.mtu += sizeof(struct frhdr);
+
+ /* off to the races! */
+ if (!flp->configured)
+ sdla_start(dev);
+
flp->configured = 1;
}
else
@@ -1134,7 +1176,7 @@
if (err)
return(err);
- /* no sense reading if the CPU isn't started */
+ /* no sense reading if the CPU isnt' started */
if (dev->start)
{
size = sizeof(data);
@@ -1148,8 +1190,8 @@
memset(&data.config, 0, sizeof(struct frad_conf));
memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
- data.config.flags &= ~SDLA_DIRECT_RECV;
- data.config.mtu -= data.config.mtu > sizeof(struct fradhdr) ? sizeof(struct fradhdr) : data.config.mtu;
+ data.config.flags &= FRAD_VALID_FLAGS;
+ data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
memcpy_tofs(conf, &data.config, sizeof(struct frad_conf));
}
@@ -1204,13 +1246,13 @@
flp = dev->priv;
- memcpy(&data, &flp->config, sizeof(struct frad_conf));
-
len = 0;
for(i=0;i<CONFIG_DLCI_MAX;i++)
if (flp->dlci[i])
data.dlci[len++] = flp->dlci[i];
len *= 2;
+
+ memcpy(&data, &flp->config, sizeof(struct frad_conf));
len += sizeof(struct frad_conf);
sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
@@ -1244,9 +1286,9 @@
/* ==========================================================
NOTE: This is rather a useless action right now, as the
- driver does not support protocols other than FR right
- now. However, Sangoma has modules for a number of
- other protocols.
+ current driver does not support protocols other than
+ FR. However, Sangoma has modules for a number of
+ other protocols in the works.
============================================================*/
case SDLA_PROTOCOL:
if (flp->configured)
@@ -1605,8 +1647,13 @@
dev->type = 0xFFFF;
dev->family = AF_UNSPEC;
- dev->pa_alen = sizeof(unsigned long);
+ dev->pa_alen = 0;
+ dev->pa_addr = 0;
+ dev->pa_dstaddr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
dev->hard_header_len = 0;
+ dev->addr_len = 0;
dev->mtu = SDLA_MAX_MTU;
for (i = 0; i < DEV_NUMBUFFS; i++)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this