📄 ltpc.c
字号:
/*** ltpc.c -- a driver for the LocalTalk PC card. * * Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * This is ALPHA code at best. It may not work for you. It may * damage your equipment. It may damage your relations with other * users of your network. Use it at your own risk! * * Based in part on: * skeleton.c by Donald Becker * dummy.c by Nick Holloway and Alan Cox * loopback.c by Ross Biro, Fred van Kampen, Donald Becker * the netatalk source code (UMICH) * lots of work on the card... * * I do not have access to the (proprietary) SDK that goes with the card. * If you do, I don't want to know about it, and you can probably write * a better driver yourself anyway. This does mean that the pieces that * talk to the card are guesswork on my part, so use at your own risk! * * This is my first try at writing Linux networking code, and is also * guesswork. Again, use at your own risk! (Although on this part, I'd * welcome suggestions) * * This is a loadable kernel module which seems to work at my site * consisting of a 1.2.13 linux box running netatalk 1.3.3, and with * the kernel support from 1.3.3b2 including patches routing.patch * and ddp.disappears.from.chooser. In order to run it, you will need * to patch ddp.c and aarp.c in the kernel, but only a little... * * I'm fairly confident that while this is arguably badly written, the * problems that people experience will be "higher level", that is, with * complications in the netatalk code. The driver itself doesn't do * anything terribly complicated -- it pretends to be an ether device * as far as netatalk is concerned, strips the DDP data out of the ether * frame and builds a LLAP packet to send out the card. In the other * direction, it receives LLAP frames from the card and builds a fake * ether packet that it then tosses up to the networking code. You can * argue (correctly) that this is an ugly way to do things, but it * requires a minimal amount of fooling with the code in ddp.c and aarp.c. * * The card will do a lot more than is used here -- I *think* it has the * layers up through ATP. Even if you knew how that part works (which I * don't) it would be a big job to carve up the kernel ddp code to insert * things at a higher level, and probably a bad idea... * * There are a number of other cards that do LocalTalk on the PC. If * nobody finds any insurmountable (at the netatalk level) problems * here, this driver should encourage people to put some work into the * other cards (some of which I gather are still commercially available) * and also to put hooks for LocalTalk into the official ddp code. * * I welcome comments and suggestions. This is my first try at Linux * networking stuff, and there are probably lots of things that I did * suboptimally. * ***//*** * * $Log: ltpc.c,v $ * Revision 1.1.2.1 2000/03/01 05:35:07 jgarzik * at and tr cleanup * * Revision 1.8 1997/01/28 05:44:54 bradford * Clean up for non-module a little. * 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. * * Revision 1.6 1996/12/12 03:18:58 bradford * Added virt_to_bus; works in 2.1.13. * * Revision 1.5 1996/12/12 03:13:22 root * xmitQel initialization -- think through better though. * * Revision 1.4 1996/06/18 14:55:55 root * Change names to ltpc. Tabs. Took a shot at dma alloc, * although more needs to be done eventually. * * Revision 1.3 1996/05/22 14:59:39 root * Change dev->open, dev->close to track dummy.c in 1.99.(around 7) * * Revision 1.2 1996/05/22 14:58:24 root * Change tabs mostly. * * Revision 1.1 1996/04/23 04:45:09 root * Initial revision * * Revision 0.16 1996/03/05 15:59:56 root * Change ARPHRD_LOCALTLK definition to the "real" one. * * Revision 0.15 1996/03/05 06:28:30 root * Changes for kernel 1.3.70. Still need a few patches to kernel, but * it's getting closer. * * Revision 0.14 1996/02/25 17:38:32 root * More cleanups. Removed query to card on get_stats. * * Revision 0.13 1996/02/21 16:27:40 root * Refix debug_print_skb. Fix mac.raw gotcha that appeared in 1.3.65. * Clean up receive code a little. * * Revision 0.12 1996/02/19 16:34:53 root * Fix debug_print_skb. Kludge outgoing snet to 0 when using startup * range. Change debug to mask: 1 for verbose, 2 for higher level stuff * including packet printing, 4 for lower level (card i/o) stuff. * * Revision 0.11 1996/02/12 15:53:38 root * Added router sends (requires new aarp.c patch) * * Revision 0.10 1996/02/11 00:19:35 root * Change source LTALK_LOGGING debug switch to insmod ... debug=2. * * Revision 0.9 1996/02/10 23:59:35 root * Fixed those fixes for 1.2 -- DANGER! The at.h that comes with netatalk * has a *different* definition of struct sockaddr_at than the Linux kernel * does. This is an "insidious and invidious" bug... * (Actually the preceding comment is false -- it's the atalk.h in the * ancient atalk-0.06 that's the problem) * * Revision 0.8 1996/02/10 19:09:00 root * Merge 1.3 changes. Tested OK under 1.3.60. * * Revision 0.7 1996/02/10 17:56:56 root * Added debug=1 parameter on insmod for debugging prints. Tried * to fix timer unload on rmmod, but I don't think that's the problem. * * Revision 0.6 1995/12/31 19:01:09 root * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!) * Clean up initial probing -- sometimes the card wakes up latched in reset. * * Revision 0.5 1995/12/22 06:03:44 root * Added comments in front and cleaned up a bit. * This version sent out to people. * * Revision 0.4 1995/12/18 03:46:44 root * Return shortDDP to longDDP fake to 0/0. Added command structs. * ***//* ltpc jumpers are:** Interrupts -- set at most one. If none are set, the driver uses* polled mode. Because the card was developed in the XT era, the* original documentation refers to IRQ2. Since you'll be running* this on an AT (or later) class machine, that really means IRQ9.** SW1 IRQ 4* SW2 IRQ 3* SW3 IRQ 9 (2 in original card documentation only applies to XT)*** DMA -- choose DMA 1 or 3, and set both corresponding switches.** SW4 DMA 3* SW5 DMA 1* SW6 DMA 3* SW7 DMA 1*** I/O address -- choose one. ** SW8 220 / 240*//* To have some stuff logged, do * insmod ltpc.o debug=1** For a whole bunch of stuff, use higher numbers.** The default is 0, i.e. no messages except for the probe results.*//* insmod-tweakable variables */static int debug;#define DEBUG_VERBOSE 1#define DEBUG_UPPER 2#define DEBUG_LOWER 4static int io;static int irq;static int dma;#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/spinlock.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/if_ltalk.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/atalk.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/dma.h>#include <asm/io.h>/* our stuff */#include "ltpc.h"static DEFINE_SPINLOCK(txqueue_lock);static DEFINE_SPINLOCK(mbox_lock);/* function prototypes */static int do_read(struct net_device *dev, void *cbuf, int cbuflen, void *dbuf, int dbuflen);static int sendup_buffer (struct net_device *dev);/* Dma Memory related stuff, cribbed directly from 3c505.c */static unsigned long dma_mem_alloc(int size){ int order = get_order(size); 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 atalk_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, *xmQtl;static void enQ(struct xmitQel *qel){ unsigned long flags; qel->next = NULL; spin_lock_irqsave(&txqueue_lock, flags); if (xmQtl) { xmQtl->next = qel; } else { xmQhd = qel; } xmQtl = qel; spin_unlock_irqrestore(&txqueue_lock, flags); if (debug & DEBUG_LOWER) printk("enqueued a 0x%02x command\n",qel->cbuf[0]);}static struct xmitQel *deQ(void){ unsigned long flags; int i; struct xmitQel *qel=NULL; spin_lock_irqsave(&txqueue_lock, flags); if (xmQhd) { qel = xmQhd; xmQhd = qel->next; if(!xmQhd) xmQtl = NULL; } spin_unlock_irqrestore(&txqueue_lock, flags); if ((debug & DEBUG_LOWER) && qel) { int n; printk(KERN_DEBUG "ltpc: dequeued command "); n = qel->cbuflen; if (n>100) n=100; for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]); printk("\n"); } 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};static int wait_timeout(struct net_device *dev, int c){ /* returns true if it stayed c */ /* this uses base+6, but it's ok */ int i; /* twenty second or so total */ for(i=0;i<200000;i++) { if ( c != inb_p(dev->base_addr+6) ) return 0; udelay(100); } return 1; /* timed out */}/* get the first free mailbox */static int getmbox(void){ unsigned long flags; int i; spin_lock_irqsave(&mbox_lock, flags); for(i=1;i<16;i++) if(!mboxinuse[i]) { mboxinuse[i]=1; spin_unlock_irqrestore(&mbox_lock, flags); return i; } spin_unlock_irqrestore(&mbox_lock, flags); return 0;}/* read a command from the card */static void handlefc(struct net_device *dev){ /* called *only* from idle, non-reentrant */ int dma = dev->dma; int base = dev->base_addr; unsigned long flags; flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_READ); set_dma_addr(dma,virt_to_bus(ltdmacbuf)); set_dma_count(dma,50); enable_dma(dma); release_dma_lock(flags); inb_p(base+3); inb_p(base+2); if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");}/* read data from the card */static void handlefd(struct net_device *dev){ int dma = dev->dma; int base = dev->base_addr; unsigned long flags; flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_READ); set_dma_addr(dma,virt_to_bus(ltdmabuf)); set_dma_count(dma,800); enable_dma(dma); release_dma_lock(flags); inb_p(base+3); inb_p(base+2); if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n"); sendup_buffer(dev);} static void handlewrite(struct net_device *dev){ /* called *only* from idle, non-reentrant */ /* on entry, 0xfb and ltdmabuf holds data */ int dma = dev->dma; int base = dev->base_addr; unsigned long flags; flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_WRITE); set_dma_addr(dma,virt_to_bus(ltdmabuf)); set_dma_count(dma,800); enable_dma(dma); release_dma_lock(flags); inb_p(base+3); inb_p(base+2); if ( wait_timeout(dev,0xfb) ) { flags=claim_dma_lock(); printk("timed out in handlewrite, dma res %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -