📄 cops.c
字号:
/* cops.c: LocalTalk driver for Linux. * * Authors: * - Jay Schulist <jschlst@samba.org> * * With more than a little help from; * - Alan Cox <Alan.Cox@linux.org> * * Derived from: * - skeleton.c: A network driver outline for linux. * Written 1993-94 by Donald Becker. * - ltpc.c: A driver for the LocalTalk PC card. * Written by Bradford W. Johnson. * * 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 General Public License, incorporated herein by reference. * * Changes: * 19970608 Alan Cox Allowed dual card type support * Can set board type in insmod * 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. * 20000211 Alan Cox Cleaned up for softnet */static const char *version ="cops.c:v0.04 6/7/98 Jay Schulist <jschlst@samba.org>\n";/* * Sources: * COPS Localtalk SDK. This provides almost all of the information * needed. *//* * insmod/modprobe configurable stuff. * - IO Port, choose one your card supports or 0 if you dare. * - IRQ, also choose one your card supports or nothing and let * the driver figure it out. */#include <linux/config.h>#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/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> /* For udelay() */#include <linux/atalk.h>#include <linux/spinlock.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/io.h>#include <asm/dma.h>#include "cops.h" /* Our Stuff */#include "cops_ltdrv.h" /* Firmware code for Tangent type cards. */#include "cops_ffdrv.h" /* Firmware code for Dayna type cards. *//* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels */static const char *cardname = "cops";#ifdef CONFIG_COPS_DAYNAstatic int board_type = DAYNA; /* Module exported */#elsestatic int board_type = TANGENT;#endifstatic int io = 0x240; /* Default IO for Dayna */static int irq = 5; /* Default IRQ *//* * COPS Autoprobe information. * Right now if port address is right but IRQ is not 5 this will * return a 5 no matter what since we will still get a status response. * Need one more additional check to narrow down after we have gotten * the ioaddr. But since only other possible IRQs is 3 and 4 so no real * hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with * this driver. * * This driver has 2 modes and they are: Dayna mode and Tangent mode. * Each mode corresponds with the type of card. It has been found * that there are 2 main types of cards and all other cards are * the same and just have different names or only have minor differences * such as more IO ports. As this driver is tested it will * become more clear on exactly what cards are supported. The driver * defaults to using Dayna mode. To change the drivers mode, simply * select Dayna or Tangent mode when configuring the kernel. * * This driver should support: * TANGENT driver mode: * 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), 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 'irq=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. * *//* * Zero terminated list of IO ports to probe. */static unsigned int ports[] = { 0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360, 0};/* * Zero terminated list of IRQ ports to probe. */static int cops_irqlist[] = { 5, 4, 3, 0 };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 #endifstatic unsigned int cops_debug = COPS_DEBUG;/* The number of low I/O ports used by the card. */#define COPS_IO_EXTENT 8/* Information that needs to be kept for each board. */struct cops_local{ struct net_device_stats stats; int board; /* Holds what board type is. */ int nodeid; /* Set to 1 once have nodeid. */ unsigned char node_acquire; /* Node ID when acquired. */ struct atalk_addr node_addr; /* Full node address */ spinlock_t lock; /* RX/TX lock */};/* Index to functions, as function prototypes. */static int cops_probe1 (struct net_device *dev, int ioaddr);static int cops_irq (int ioaddr, int board);static int cops_open (struct net_device *dev);static int cops_jumpstart (struct net_device *dev);static void cops_reset (struct net_device *dev, int sleep);static void cops_load (struct net_device *dev);static int cops_nodeid (struct net_device *dev, int nodeid);static irqreturn_t cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);static void cops_poll (unsigned long ltdev);static void cops_timeout(struct net_device *dev);static void cops_rx (struct net_device *dev);static int cops_send_packet (struct sk_buff *skb, struct net_device *dev);static void set_multicast_list (struct net_device *dev);static int cops_hard_header (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);static int cops_close (struct net_device *dev);static struct net_device_stats *cops_get_stats (struct net_device *dev);static void cleanup_card(struct net_device *dev){ if (dev->irq) free_irq(dev->irq, dev); release_region(dev->base_addr, COPS_IO_EXTENT);}/* * 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 in [1..0x1ff], always return failure. * otherwise go with what we pass in. */struct net_device * __init cops_probe(int unit){ struct net_device *dev; unsigned *port; int base_addr; int err = 0; dev = alloc_ltalkdev(sizeof(struct cops_local)); if (!dev) return ERR_PTR(-ENOMEM); if (unit >= 0) { sprintf(dev->name, "lt%d", unit); netdev_boot_setup_check(dev); irq = dev->irq; base_addr = dev->base_addr; } else { base_addr = dev->base_addr = io; } SET_MODULE_OWNER(dev); if (base_addr > 0x1ff) { /* Check a single specified location. */ err = cops_probe1(dev, base_addr); } else if (base_addr != 0) { /* Don't probe at all. */ err = -ENXIO; } else { /* 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 (port = ports; *port && cops_probe1(dev, *port) < 0; port++) ; if (!*port) err = -ENODEV; } if (err) goto out; err = register_netdev(dev); if (err) goto out1; return dev;out1: cleanup_card(dev);out: free_netdev(dev); return ERR_PTR(err);}/* * This is the real probe routine. Linux has a history of friendly device * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */static int __init cops_probe1(struct net_device *dev, int ioaddr){ struct cops_local *lp; static unsigned version_printed; int board = board_type; int retval; if(cops_debug && version_printed++ == 0) printk("%s", version); /* Grab the region so no one else tries to probe our ioports. */ if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name)) return -EBUSY; /* * Since this board has jumpered interrupts, allocate the interrupt * vector now. There is no point in waiting since no other device * can use the interrupt, and this marks the irq as busy. Jumpered * interrupts are typically not reported by the boards, and we must * used AutoIRQ to find them. */ dev->irq = irq; switch (dev->irq) { case 0: /* COPS AutoIRQ routine */ dev->irq = cops_irq(ioaddr, board); if (dev->irq) break; /* No IRQ found on this port, fallthrough */ case 1: retval = -EINVAL; goto err_out; /* Fixup for users that don't know that IRQ 2 is really * IRQ 9, or don't know which one to set. */ case 2: dev->irq = 9; break; /* 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; default: break; } /* Reserve any actual interrupt. */ if (dev->irq) { retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); if (retval) goto err_out; } dev->base_addr = ioaddr; lp = netdev_priv(dev); memset(lp, 0, sizeof(struct cops_local)); spin_lock_init(&lp->lock); /* Copy local board variable to lp struct. */ lp->board = board; dev->hard_start_xmit = cops_send_packet; dev->tx_timeout = cops_timeout; dev->watchdog_timeo = HZ * 2; dev->hard_header = cops_hard_header; dev->get_stats = cops_get_stats; dev->open = cops_open; dev->stop = cops_close; dev->do_ioctl = cops_ioctl; dev->set_multicast_list = set_multicast_list; dev->mc_list = NULL; /* Tell the user where the card is and what mode we're in. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -