patch-2.1.106 linux/drivers/net/cops.c
Next file: linux/drivers/net/hamradio/dmascc.c
Previous file: linux/drivers/net/atari_bionet.c
Back to the patch index
Back to the overall index
- Lines: 527
- Date:
Tue Jun 9 01:28:32 1998
- Orig file:
v2.1.105/linux/drivers/net/cops.c
- Orig date:
Tue Jun 9 11:57:29 1998
diff -u --recursive --new-file v2.1.105/linux/drivers/net/cops.c linux/drivers/net/cops.c
@@ -24,13 +24,16 @@
* Hooks for cops_setup routine
* (not yet implemented).
* 19971101 Jay Schulist Fixes for multiple lt* devices.
- * 19980507 Steven Hirsch Fixed the badly broken support
- * for Tangent type cards. (COPS
- * LT-1 and the like)
+ * 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.03 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
@@ -133,6 +136,15 @@
* 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.
+ *
*/
/*
@@ -155,7 +167,7 @@
static struct timer_list cops_timer;
-/* use 0 for production, 1 for verification, 2 for debug, 3 for very verbose debug */
+/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
#ifndef COPS_DEBUG
#define COPS_DEBUG 1
#endif
@@ -192,7 +204,8 @@
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);
@@ -202,9 +215,8 @@
/*
* 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))
{
@@ -219,6 +231,11 @@
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))
@@ -239,17 +256,12 @@
{
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
@@ -257,37 +269,47 @@
* 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;
@@ -298,20 +320,10 @@
/* 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;
@@ -320,14 +332,17 @@
dev->set_multicast_list = &set_multicast_list;
dev->mc_list = NULL;
- if(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);
- }
+ /* 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;
}
@@ -335,7 +350,7 @@
__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 its the IRQ.
+ * 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.
@@ -383,10 +398,27 @@
*/
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. */
@@ -428,18 +460,12 @@
return 0;
}
-static int tangent_wait_reset(int ioaddr)
+static void tangent_wait_reset(int ioaddr)
{
- long snapt=jiffies;
-
- while(jiffies-snapt<5*HZ)
- {
- if((inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)==0)
- break;
- schedule();
- }
+ int timeout=0;
- return 0;
+ while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+ mdelay(1); /* Wait 1 second */
}
/*
@@ -452,23 +478,11 @@
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)
@@ -563,12 +577,13 @@
}
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)
{
@@ -601,10 +616,10 @@
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)
@@ -612,19 +627,19 @@
/* 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. */
@@ -646,7 +661,8 @@
}
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. */
@@ -658,7 +674,6 @@
*/
static void cops_poll(unsigned long ltdev)
{
- struct cops_local *lp;
int ioaddr, status;
int boguscount = 0;
@@ -670,12 +685,6 @@
return; /* We've been downed */
ioaddr = dev->base_addr;
-
- /* Clear any interrupt. */
- outb(0, ioaddr + COPS_CLEAR_INT);
- dev->interrupt = 0;
-
- lp = (struct cops_local *)dev->priv;
do {
status=inb(ioaddr+TANG_CARD_STATUS);
if(status & TANG_RX_READY)
@@ -704,7 +713,8 @@
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;
@@ -787,7 +797,8 @@
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);
@@ -800,14 +811,15 @@
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;
@@ -815,8 +827,8 @@
/* 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;
}
@@ -878,7 +890,8 @@
* 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. */
@@ -902,7 +915,7 @@
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. */
@@ -926,7 +939,7 @@
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);
}
/*
@@ -934,7 +947,8 @@
*/
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);
@@ -983,6 +997,13 @@
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;
@@ -1024,7 +1045,8 @@
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;
@@ -1046,7 +1068,16 @@
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:
+ */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov