patch-2.1.129 linux/drivers/net/ltpc.c
Next file: linux/drivers/net/net_init.c
Previous file: linux/drivers/net/hostess_sv11.c
Back to the patch index
Back to the overall index
- Lines: 739
- Date:
Fri Nov 13 10:29:43 1998
- Orig file:
v2.1.128/linux/drivers/net/ltpc.c
- Orig date:
Fri Oct 23 22:01:21 1998
diff -u --recursive --new-file v2.1.128/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
@@ -67,6 +67,25 @@
* Hacked about a bit to clean things up - Alan Cox
* Probably broken it from the origina 1.8
*
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+ and to probe for things in the standard order of i/o, irq, dma. This
+ removes the "reset the reset" hack, because I couldn't figure out an
+ easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+ line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+ other localtalk driver, and to clear up the inconsistency between the
+ module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+ codes and the register offsets, but I'm still not sure exactly what their
+ semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+ I'm responsible for that...
+
+ *
* Revision 1.7 1996/12/12 03:42:33 bradford
* DMA alloc cribbed from 3c505.c.
*
@@ -180,6 +199,9 @@
#define DEBUG_UPPER 2
#define DEBUG_LOWER 4
+static int io=0;
+static int irq=0;
+static int dma=0;
#ifdef MODULE
#include <linux/module.h>
@@ -245,25 +267,34 @@
return __get_dma_pages(GFP_KERNEL, order);
}
+/* DMA data buffer, DMA command buffer */
static unsigned char *ltdmabuf;
static unsigned char *ltdmacbuf;
+/* private struct, holds our appletalk address */
+
struct ltpc_private
{
struct net_device_stats stats;
struct at_addr my_addr;
};
+/* transmit queue element struct */
+
struct xmitQel {
struct xmitQel *next;
+ /* command buffer */
unsigned char *cbuf;
short cbuflen;
+ /* data buffer */
unsigned char *dbuf;
short dbuflen;
unsigned char QWrite; /* read or write data */
unsigned char mailbox;
};
+/* the transmit queue itself */
+
static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
static void enQ(struct xmitQel *qel)
@@ -310,8 +341,10 @@
return qel;
}
+/* and... the queue elements we'll be using */
static struct xmitQel qels[16];
+/* and their corresponding mailboxes */
static unsigned char mailbox[16];
static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -331,6 +364,8 @@
return 1; /* timed out */
}
+/* get the first free mailbox */
+
static int getmbox(void)
{
unsigned long flags;
@@ -347,6 +382,7 @@
return 0;
}
+/* read a command from the card */
static void handlefc(struct device *dev)
{
/* called *only* from idle, non-reentrant */
@@ -370,6 +406,7 @@
if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
}
+/* read data from the card */
static void handlefd(struct device *dev)
{
int dma = dev->dma;
@@ -463,7 +500,8 @@
if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
}
-static unsigned char rescbuf[2] = {0,0};
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,0};
static unsigned char resdbuf[2];
static int QInIdle=0;
@@ -482,7 +520,7 @@
struct xmitQel *q=0;
int oops;
int i;
- int statusPort = dev->base_addr+6;
+ int base = dev->base_addr;
save_flags(flags);
cli();
@@ -495,8 +533,8 @@
restore_flags(flags);
-
- (void) inb_p(statusPort); /* this tri-states the IRQ line */
+ /* this tri-states the IRQ line */
+ (void) inb_p(base+6);
oops = 100;
@@ -506,19 +544,22 @@
goto done;
}
- state = inb_p(statusPort);
- if (state != inb_p(statusPort)) goto loop;
+ state = inb_p(base+6);
+ if (state != inb_p(base+6)) goto loop;
switch(state) {
- case 0xfc:
+ case 0xfc:
+ /* incoming command */
if (debug&DEBUG_LOWER) printk("idle: fc\n");
handlefc(dev);
break;
- case 0xfd:
+ case 0xfd:
+ /* incoming data */
if(debug&DEBUG_LOWER) printk("idle: fd\n");
handlefd(dev);
break;
- case 0xf9:
+ case 0xf9:
+ /* result ready */
if (debug&DEBUG_LOWER) printk("idle: f9\n");
if(!mboxinuse[0]) {
mboxinuse[0] = 1;
@@ -536,6 +577,7 @@
printk("timed out idle f9\n");
break;
case 0xf8:
+ /* ?? */
if (xmQhd) {
inb_p(dev->base_addr+1);
inb_p(dev->base_addr+0);
@@ -545,7 +587,8 @@
goto done;
}
break;
- case 0xfa:
+ case 0xfa:
+ /* waiting for command */
if(debug&DEBUG_LOWER) printk("idle: fa\n");
if (xmQhd) {
q=deQ();
@@ -561,7 +604,7 @@
printk("\n");
}
handlecommand(dev);
- if(0xfa==inb_p(statusPort)) {
+ if(0xfa==inb_p(base+6)) {
/* we timed out, so return */
goto done;
}
@@ -582,13 +625,17 @@
}
}
break;
- case 0xfb:
+ case 0Xfb:
+ /* data transfer ready */
if(debug&DEBUG_LOWER) printk("idle: fb\n");
if(q->QWrite) {
memcpy(ltdmabuf,q->dbuf,q->dbuflen);
handlewrite(dev);
} else {
handleread(dev);
+ /* non-zero mailbox numbers are for
+ commmands, 0 is for GETRESULT
+ requests */
if(q->mailbox) {
memcpy(q->dbuf,ltdmabuf,q->dbuflen);
} else {
@@ -605,13 +652,14 @@
QInIdle=0;
/* now set the interrupts back as appropriate */
- /* the first 7 takes it out of tri-state (but still high) */
+ /* the first read takes it out of tri-state (but still high) */
/* the second resets it */
- /* note that after this point, any read of 6 will trigger an interrupt */
+ /* note that after this point, any read of base+6 will
+ trigger an interrupt */
if (dev->irq) {
- inb_p(dev->base_addr+7);
- inb_p(dev->base_addr+7);
+ inb_p(base+7);
+ inb_p(base+7);
}
return;
}
@@ -703,6 +751,8 @@
return do_write(dev, &c, sizeof(c.setflags),&c,0);
}
+/* LLAP to DDP translation */
+
static int sendup_buffer (struct device *dev)
{
/* on entry, command is in ltdmacbuf, data in ltdmabuf */
@@ -912,23 +962,14 @@
if (!dev)
return; /* we've been downed */
- if (dev->irq)
- {
- /* we're set up for interrupts */
- if (0xf8 != inb_p(dev->base_addr+7)) {
- /* trigger an interrupt */
- (void) inb_p(dev->base_addr+6);
- }
- ltpc_timer.expires = jiffies+100;
- } else {
- /* we're strictly polling mode */
- idle(dev);
- ltpc_timer.expires = jiffies+5;
- }
-
+ idle(dev);
+ ltpc_timer.expires = jiffies+5;
+
add_timer(<pc_timer);
}
+/* DDP to LLAP translation */
+
static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
{
/* in kernel 1.3.xx, on entry skb->data points to ddp header,
@@ -975,150 +1016,18 @@
return stats;
}
-static unsigned short irqhitmask;
-
-__initfunc(static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr))
-{
- irqhitmask |= 1<<irq;
-}
-
-__initfunc(int ltpc_probe(struct device *dev))
+/* initialization stuff */
+
+__initfunc(int ltpc_probe_dma(int base))
{
- int err;
- unsigned char dma=0;
- short base=0;
- unsigned char irq=0;
- int x=0,y=0;
- int timeout;
- int probe3, probe4, probe9;
- unsigned short straymask;
- unsigned long flags;
- unsigned long f;
-
- err = ltpc_init(dev);
- if (err) return err;
-
- /* occasionally the card comes up with reset latched, so we need
- * to "reset the reset" first of all -- check the irq first also
- */
-
- save_flags(flags);
- cli();
-
- probe3 = request_irq( 3, <_probe_handler, 0, "ltpc_probe",dev);
- probe4 = request_irq( 4, <_probe_handler, 0, "ltpc_probe",dev);
- probe9 = request_irq( 9, <_probe_handler, 0, "ltpc_probe",dev);
-
- irqhitmask = 0;
-
- sti();
-
- timeout = jiffies+2;
- while(timeout>jiffies) ; /* wait for strays */
-
- straymask = irqhitmask; /* pick up any strays */
-
- /* if someone already owns this address, don't probe */
- if (!check_region(0x220,8)) {
- inb_p(0x227);
- inb_p(0x227);
- x=inb_p(0x226);
- timeout = jiffies+2;
- while(timeout>jiffies) ;
- if(straymask != irqhitmask) base = 0x220;
- }
- if (!check_region(0x240,8)) {
- inb_p(0x247);
- inb_p(0x247);
- y=inb_p(0x246);
- timeout = jiffies+2;
- while(timeout>jiffies) ;
- if(straymask != irqhitmask) base = 0x240;
- }
-
- /* at this point, either we have an irq and the base addr, or
- * there isn't any irq and we don't know the base address, but
- * in either event the card is no longer latched in reset and
- * the irq request line is tri-stated.
- */
-
- cli();
-
- if (!probe3) free_irq(3,dev);
- if (!probe4) free_irq(4,dev);
- if (!probe9) free_irq(9,dev);
-
- sti();
-
- irqhitmask &= ~straymask;
-
- irq = ffz(~irqhitmask);
- if (irqhitmask != 1<<irq)
- printk("ltpc card raised more than one interrupt!\n");
-
- if (!base) {
- if (!check_region(0x220,8)) {
- x = inb_p(0x220+6);
- if ( (x!=0xff) && (x>=0xf0) ) base = 0x220;
- }
-
- if (!check_region(0x240,8)) {
- y = inb_p(0x240+6);
- if ( (y!=0xff) && (y>=0xf0) ) base = 0x240;
- }
- }
-
- if(base) {
- request_region(base,8,"ltpc");
- } else {
- printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y);
- restore_flags(flags);
- return -1;
- }
-
- ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-
- if (ltdmabuf) ltdmacbuf = <dmabuf[800];
-
- if (!ltdmabuf) {
- printk("ltpc: mem alloc failed\n");
- restore_flags(flags);
- return(-1);
- }
-
- if(debug&DEBUG_VERBOSE) {
- printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
- }
-
- /* reset the card */
-
- inb_p(base+1);
- inb_p(base+3);
- timeout = jiffies+2;
- while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
- inb_p(base+0);
- inb_p(base+2);
- inb_p(base+7); /* clear reset */
- inb_p(base+4);
- inb_p(base+5);
- inb_p(base+5); /* enable dma */
- inb_p(base+6); /* tri-state interrupt line */
-
- timeout = jiffies+100;
-
- while(timeout>jiffies) {
- /* wait for the card to complete initialization */
- }
-
- /* now, figure out which dma channel we're using */
-
- /* set up both dma 1 and 3 for read call */
-
- if (!request_dma(1,"ltpc")) {
-
- f=claim_dma_lock();
- disable_dma(1);
- clear_dma_ff(1);
+ int dma = 0;
+ int timeout;
+ unsigned long f;
+
+ if (!request_dma(1,"ltpc")) {
+ f=claim_dma_lock();
+ disable_dma(1);
+ clear_dma_ff(1);
set_dma_mode(1,DMA_MODE_WRITE);
set_dma_addr(1,virt_to_bus(ltdmabuf));
set_dma_count(1,sizeof(struct lt_mem));
@@ -1142,26 +1051,26 @@
/* FIXME -- do timings better! */
- ltdmabuf[0] = 2; /* read request */
+ ltdmabuf[0] = LT_READMEM;
ltdmabuf[1] = 1; /* mailbox */
ltdmabuf[2] = 0; ltdmabuf[3] = 0; /* address */
ltdmabuf[4] = 0; ltdmabuf[5] = 1; /* read 0x0100 bytes */
ltdmabuf[6] = 0; /* dunno if this is necessary */
- inb_p(base+1);
- inb_p(base+0);
+ inb_p(io+1);
+ inb_p(io+0);
timeout = jiffies+100;
while(timeout>jiffies) {
- if ( 0xfa == inb_p(base+6) ) break;
+ if ( 0xfa == inb_p(io+6) ) break;
}
- inb_p(base+3);
- inb_p(base+2);
+ inb_p(io+3);
+ inb_p(io+2);
while(timeout>jiffies) {
- if ( 0xfb == inb_p(base+6) ) break;
+ if ( 0xfb == inb_p(io+6) ) break;
}
- /* release the other dma channel */
+ /* release the other dma channel (if we opened both of them) */
if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
dma&=1;
@@ -1172,31 +1081,134 @@
dma&=0x2;
free_dma(1);
}
-
- if (!dma) { /* no dma channel */
- printk("No DMA channel found on ltpc card.\n");
- restore_flags(flags);
- return -1;
- }
-
+
/* fix up dma number */
dma|=1;
- /* set up read */
+ return dma;
+}
+
+__initfunc(int ltpc_probe(struct device *dev))
+{
+ int err;
+ int x=0,y=0;
+ int timeout;
+ int autoirq;
+ unsigned long flags;
+ unsigned long f;
+
+ save_flags(flags);
+
+ /* probe for the I/O port address */
+ if (io != 0x240 && !check_region(0x220,8)) {
+ x = inb_p(0x220+6);
+ if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
+ }
+
+ if (io != 0x220 && !check_region(0x240,8)) {
+ y = inb_p(0x240+6);
+ if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
+ }
+
+ if(io) {
+ /* found it, now grab it */
+ request_region(io,8,"ltpc");
+ } else {
+ /* give up in despair */
+ printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
+ x,y);
+ restore_flags(flags);
+ return -1;
+ }
+
+ /* probe for the IRQ line */
+ if (irq < 2) {
+ autoirq_setup(2);
+
+ /* reset the interrupt line */
+ inb_p(io+7);
+ inb_p(io+7);
+ /* trigger an interrupt (I hope) */
+ inb_p(io+6);
+
+ autoirq = autoirq_report(1);
+
+ if (autoirq == 0) {
+ printk("ltpc: probe at %#x failed to detect IRQ line.\n",
+ io);
+ }
+ else {
+ irq = autoirq;
+ }
+ }
+
+ /* allocate a DMA buffer */
+ ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+ if (ltdmabuf) ltdmacbuf = <dmabuf[800];
+
+ if (!ltdmabuf) {
+ printk("ltpc: mem alloc failed\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ if(debug&DEBUG_VERBOSE) {
+ printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+ }
+
+ /* reset the card */
+
+ inb_p(io+1);
+ inb_p(io+3);
+ timeout = jiffies+2;
+ while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
+ inb_p(io+0);
+ inb_p(io+2);
+ inb_p(io+7); /* clear reset */
+ inb_p(io+4);
+ inb_p(io+5);
+ inb_p(io+5); /* enable dma */
+ inb_p(io+6); /* tri-state interrupt line */
+
+ timeout = jiffies+100;
+
+ while(timeout>jiffies) {
+ /* wait for the card to complete initialization */
+ }
+
+ /* now, figure out which dma channel we're using, unless it's
+ already been specified */
+ /* well, 0 is a legal DMA channel, but the LTPC card doesn't
+ use it... */
+ if (dma == 0) {
+ dma = ltpc_probe_dma(io);
+ if (!dma) { /* no dma channel */
+ printk("No DMA channel found on ltpc card.\n");
+ restore_flags(flags);
+ return -1;
+ }
+ }
+
+ /* print out friendly message */
if(irq)
- printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma);
+ printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
else
- printk("LocalTalk card found at %03x, DMA%d. Using polled mode.\n",base,dma);
-
- dev->base_addr = base;
+ printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma);
+
+ /* seems more logical to do this *after* probing the card... */
+ err = ltpc_init(dev);
+ if (err) return err;
+
+ dev->base_addr = io;
dev->irq = irq;
dev->dma = dma;
- if(debug&DEBUG_VERBOSE) {
- printk("finishing up transfer\n");
- }
-
+ /* the card will want to send a result at this point */
+ /* (I think... leaving out this part makes the kernel crash,
+ so I put it back in...) */
+
f=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
@@ -1206,41 +1218,65 @@
enable_dma(dma);
release_dma_lock(f);
- (void) inb_p(base+3);
- (void) inb_p(base+2);
+ (void) inb_p(io+3);
+ (void) inb_p(io+2);
timeout = jiffies+100;
while(timeout>jiffies) {
- if( 0xf9 == inb_p(base+6)) break;
+ if( 0xf9 == inb_p(io+6)) break;
}
if(debug&DEBUG_VERBOSE) {
printk("setting up timer and irq\n");
}
- init_timer(<pc_timer);
- ltpc_timer.function=ltpc_poll;
- ltpc_timer.data = (unsigned long) dev;
-
if (irq) {
+ /* grab it and don't let go :-) */
(void) request_irq( irq, <pc_interrupt, 0, "ltpc", dev);
- (void) inb_p(base+7); /* enable interrupts from board */
- (void) inb_p(base+7); /* and reset irq line */
- ltpc_timer.expires = 100;
- /* poll it once per second just in case */
+ (void) inb_p(io+7); /* enable interrupts from board */
+ (void) inb_p(io+7); /* and reset irq line */
} else {
- ltpc_timer.expires = 5;
- /* polled mode -- 20 times per second */
- }
-
- ltpc_timer.expires += jiffies; /* 1.2 to 1.3 change... */
+ /* polled mode -- 20 times per second */
+ /* this is really, really slow... should it poll more often? */
+ init_timer(<pc_timer);
+ ltpc_timer.function=ltpc_poll;
+ ltpc_timer.data = (unsigned long) dev;
- add_timer(<pc_timer);
-
- restore_flags(flags);
+ ltpc_timer.expires = jiffies + 5;
+ add_timer(<pc_timer);
+ restore_flags(flags);
+ }
return 0;
}
+/* handles "ltpc=io,irq,dma" kernel command lines */
+__initfunc(void ltpc_setup(char *str, int *ints))
+{
+ if (ints[0] == 0) {
+ if (str && !strncmp(str, "auto", 4)) {
+ /* do nothing :-) */
+ }
+ else {
+ /* usage message */
+ printk (KERN_ERR
+ "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+ }
+ return;
+ } else {
+ io = ints[1];
+ if (ints[0] > 1) {
+ irq = ints[2];
+ return;
+ }
+ if (ints[0] > 2) {
+ dma = ints[3];
+ return;
+ }
+ /* ignore any other paramters */
+ }
+ return;
+}
+
#ifdef MODULE
static char dev_name[8];
@@ -1251,17 +1287,28 @@
0x0, 0,
0, 0, 0, NULL, ltpc_probe };
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+
int init_module(void)
{
+ int err, result;
+
+ if(io == 0)
+ printk(KERN_NOTICE
+ "ltpc: Autoprobing is not recommended for modules\n");
+
/* Find a name for this unit */
- int err=dev_alloc_name(&dev_ltpc,"lt%d");
+ err=dev_alloc_name(&dev_ltpc,"lt%d");
if(err<0)
return err;
- if (register_netdev(&dev_ltpc) != 0) {
- if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n");
- return -EIO;
+ if ((result = register_netdev(&dev_ltpc)) != 0) {
+ printk(KERN_DEBUG "could not register Localtalk-PC device\n");
+ return result;
} else {
if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
return 0;
@@ -1322,3 +1369,4 @@
if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
}
#endif /* MODULE */
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov