11da177e4SLinus Torvalds /* cops.c: LocalTalk driver for Linux. 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Authors: 41da177e4SLinus Torvalds * - Jay Schulist <jschlst@samba.org> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * With more than a little help from; 7113aa838SAlan Cox * - Alan Cox <alan@lxorguk.ukuu.org.uk> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Derived from: 101da177e4SLinus Torvalds * - skeleton.c: A network driver outline for linux. 111da177e4SLinus Torvalds * Written 1993-94 by Donald Becker. 121da177e4SLinus Torvalds * - ltpc.c: A driver for the LocalTalk PC card. 131da177e4SLinus Torvalds * Written by Bradford W. Johnson. 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * Copyright 1993 United States Government as represented by the 161da177e4SLinus Torvalds * Director, National Security Agency. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * This software may be used and distributed according to the terms 191da177e4SLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * Changes: 221da177e4SLinus Torvalds * 19970608 Alan Cox Allowed dual card type support 231da177e4SLinus Torvalds * Can set board type in insmod 241da177e4SLinus Torvalds * Hooks for cops_setup routine 251da177e4SLinus Torvalds * (not yet implemented). 261da177e4SLinus Torvalds * 19971101 Jay Schulist Fixes for multiple lt* devices. 271da177e4SLinus Torvalds * 19980607 Steven Hirsch Fixed the badly broken support 281da177e4SLinus Torvalds * for Tangent type cards. Only 291da177e4SLinus Torvalds * tested on Daystar LT200. Some 301da177e4SLinus Torvalds * cleanup of formatting and program 311da177e4SLinus Torvalds * logic. Added emacs 'local-vars' 321da177e4SLinus Torvalds * setup for Jay's brace style. 331da177e4SLinus Torvalds * 20000211 Alan Cox Cleaned up for softnet 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static const char *version = 371da177e4SLinus Torvalds "cops.c:v0.04 6/7/98 Jay Schulist <jschlst@samba.org>\n"; 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * Sources: 401da177e4SLinus Torvalds * COPS Localtalk SDK. This provides almost all of the information 411da177e4SLinus Torvalds * needed. 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* 451da177e4SLinus Torvalds * insmod/modprobe configurable stuff. 461da177e4SLinus Torvalds * - IO Port, choose one your card supports or 0 if you dare. 471da177e4SLinus Torvalds * - IRQ, also choose one your card supports or nothing and let 481da177e4SLinus Torvalds * the driver figure it out. 491da177e4SLinus Torvalds */ 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds #include <linux/module.h> 521da177e4SLinus Torvalds #include <linux/kernel.h> 531da177e4SLinus Torvalds #include <linux/types.h> 541da177e4SLinus Torvalds #include <linux/fcntl.h> 551da177e4SLinus Torvalds #include <linux/interrupt.h> 561da177e4SLinus Torvalds #include <linux/ptrace.h> 571da177e4SLinus Torvalds #include <linux/ioport.h> 581da177e4SLinus Torvalds #include <linux/in.h> 591da177e4SLinus Torvalds #include <linux/slab.h> 601da177e4SLinus Torvalds #include <linux/string.h> 611da177e4SLinus Torvalds #include <linux/errno.h> 621da177e4SLinus Torvalds #include <linux/init.h> 631da177e4SLinus Torvalds #include <linux/netdevice.h> 641da177e4SLinus Torvalds #include <linux/etherdevice.h> 651da177e4SLinus Torvalds #include <linux/skbuff.h> 661da177e4SLinus Torvalds #include <linux/if_arp.h> 673ef4e9a8SChristoph Hellwig #include <linux/if_ltalk.h> 681da177e4SLinus Torvalds #include <linux/delay.h> /* For udelay() */ 691da177e4SLinus Torvalds #include <linux/atalk.h> 701da177e4SLinus Torvalds #include <linux/spinlock.h> 711da177e4SLinus Torvalds #include <linux/bitops.h> 72b132fba1SJulia Lawall #include <linux/jiffies.h> 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #include <asm/system.h> 751da177e4SLinus Torvalds #include <asm/io.h> 761da177e4SLinus Torvalds #include <asm/dma.h> 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds #include "cops.h" /* Our Stuff */ 791da177e4SLinus Torvalds #include "cops_ltdrv.h" /* Firmware code for Tangent type cards. */ 801da177e4SLinus Torvalds #include "cops_ffdrv.h" /* Firmware code for Dayna type cards. */ 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* 831da177e4SLinus Torvalds * The name of the card. Is used for messages and in the requests for 841da177e4SLinus Torvalds * io regions, irqs and dma channels 851da177e4SLinus Torvalds */ 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds static const char *cardname = "cops"; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds #ifdef CONFIG_COPS_DAYNA 901da177e4SLinus Torvalds static int board_type = DAYNA; /* Module exported */ 911da177e4SLinus Torvalds #else 921da177e4SLinus Torvalds static int board_type = TANGENT; 931da177e4SLinus Torvalds #endif 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds static int io = 0x240; /* Default IO for Dayna */ 961da177e4SLinus Torvalds static int irq = 5; /* Default IRQ */ 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds /* 991da177e4SLinus Torvalds * COPS Autoprobe information. 1001da177e4SLinus Torvalds * Right now if port address is right but IRQ is not 5 this will 1011da177e4SLinus Torvalds * return a 5 no matter what since we will still get a status response. 1021da177e4SLinus Torvalds * Need one more additional check to narrow down after we have gotten 1031da177e4SLinus Torvalds * the ioaddr. But since only other possible IRQs is 3 and 4 so no real 1041da177e4SLinus Torvalds * hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with 1051da177e4SLinus Torvalds * this driver. 1061da177e4SLinus Torvalds * 1071da177e4SLinus Torvalds * This driver has 2 modes and they are: Dayna mode and Tangent mode. 1081da177e4SLinus Torvalds * Each mode corresponds with the type of card. It has been found 1091da177e4SLinus Torvalds * that there are 2 main types of cards and all other cards are 1101da177e4SLinus Torvalds * the same and just have different names or only have minor differences 1111da177e4SLinus Torvalds * such as more IO ports. As this driver is tested it will 1121da177e4SLinus Torvalds * become more clear on exactly what cards are supported. The driver 1131da177e4SLinus Torvalds * defaults to using Dayna mode. To change the drivers mode, simply 1141da177e4SLinus Torvalds * select Dayna or Tangent mode when configuring the kernel. 1151da177e4SLinus Torvalds * 1161da177e4SLinus Torvalds * This driver should support: 1171da177e4SLinus Torvalds * TANGENT driver mode: 1181da177e4SLinus Torvalds * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200, 1191da177e4SLinus Torvalds * COPS LT-1 1201da177e4SLinus Torvalds * DAYNA driver mode: 1211da177e4SLinus Torvalds * Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 1221da177e4SLinus Torvalds * Farallon PhoneNET PC III, Farallon PhoneNET PC II 1231da177e4SLinus Torvalds * Other cards possibly supported mode unkown though: 1241da177e4SLinus Torvalds * Dayna DL2000 (Full length), COPS LT/M (Micro-Channel) 1251da177e4SLinus Torvalds * 1261da177e4SLinus Torvalds * Cards NOT supported by this driver but supported by the ltpc.c 1271da177e4SLinus Torvalds * driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu> 1281da177e4SLinus Torvalds * Farallon PhoneNET PC 1291da177e4SLinus Torvalds * Original Apple LocalTalk PC card 1301da177e4SLinus Torvalds * 1311da177e4SLinus Torvalds * N.B. 1321da177e4SLinus Torvalds * 1331da177e4SLinus Torvalds * The Daystar Digital LT200 boards do not support interrupt-driven 1341da177e4SLinus Torvalds * IO. You must specify 'irq=0xff' as a module parameter to invoke 1351da177e4SLinus Torvalds * polled mode. I also believe that the port probing logic is quite 1361da177e4SLinus Torvalds * dangerous at best and certainly hopeless for a polled card. Best to 1371da177e4SLinus Torvalds * specify both. - Steve H. 1381da177e4SLinus Torvalds * 1391da177e4SLinus Torvalds */ 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* 1421da177e4SLinus Torvalds * Zero terminated list of IO ports to probe. 1431da177e4SLinus Torvalds */ 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds static unsigned int ports[] = { 1461da177e4SLinus Torvalds 0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 1471da177e4SLinus Torvalds 0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360, 1481da177e4SLinus Torvalds 0 1491da177e4SLinus Torvalds }; 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* 1521da177e4SLinus Torvalds * Zero terminated list of IRQ ports to probe. 1531da177e4SLinus Torvalds */ 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds static int cops_irqlist[] = { 1561da177e4SLinus Torvalds 5, 4, 3, 0 1571da177e4SLinus Torvalds }; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds static struct timer_list cops_timer; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ 1621da177e4SLinus Torvalds #ifndef COPS_DEBUG 1631da177e4SLinus Torvalds #define COPS_DEBUG 1 1641da177e4SLinus Torvalds #endif 1651da177e4SLinus Torvalds static unsigned int cops_debug = COPS_DEBUG; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* The number of low I/O ports used by the card. */ 1681da177e4SLinus Torvalds #define COPS_IO_EXTENT 8 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* Information that needs to be kept for each board. */ 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds struct cops_local 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds int board; /* Holds what board type is. */ 1751da177e4SLinus Torvalds int nodeid; /* Set to 1 once have nodeid. */ 1761da177e4SLinus Torvalds unsigned char node_acquire; /* Node ID when acquired. */ 1771da177e4SLinus Torvalds struct atalk_addr node_addr; /* Full node address */ 1781da177e4SLinus Torvalds spinlock_t lock; /* RX/TX lock */ 1791da177e4SLinus Torvalds }; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* Index to functions, as function prototypes. */ 1821da177e4SLinus Torvalds static int cops_probe1 (struct net_device *dev, int ioaddr); 1831da177e4SLinus Torvalds static int cops_irq (int ioaddr, int board); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static int cops_open (struct net_device *dev); 1861da177e4SLinus Torvalds static int cops_jumpstart (struct net_device *dev); 1871da177e4SLinus Torvalds static void cops_reset (struct net_device *dev, int sleep); 1881da177e4SLinus Torvalds static void cops_load (struct net_device *dev); 1891da177e4SLinus Torvalds static int cops_nodeid (struct net_device *dev, int nodeid); 1901da177e4SLinus Torvalds 1917d12e780SDavid Howells static irqreturn_t cops_interrupt (int irq, void *dev_id); 1921da177e4SLinus Torvalds static void cops_poll (unsigned long ltdev); 1931da177e4SLinus Torvalds static void cops_timeout(struct net_device *dev); 1941da177e4SLinus Torvalds static void cops_rx (struct net_device *dev); 1950fc48098SStephen Hemminger static netdev_tx_t cops_send_packet (struct sk_buff *skb, 1960fc48098SStephen Hemminger struct net_device *dev); 1971da177e4SLinus Torvalds static void set_multicast_list (struct net_device *dev); 1981da177e4SLinus Torvalds static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); 1991da177e4SLinus Torvalds static int cops_close (struct net_device *dev); 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds static void cleanup_card(struct net_device *dev) 2021da177e4SLinus Torvalds { 2031da177e4SLinus Torvalds if (dev->irq) 2041da177e4SLinus Torvalds free_irq(dev->irq, dev); 2051da177e4SLinus Torvalds release_region(dev->base_addr, COPS_IO_EXTENT); 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* 2091da177e4SLinus Torvalds * Check for a network adaptor of this type, and return '0' iff one exists. 2101da177e4SLinus Torvalds * If dev->base_addr == 0, probe all likely locations. 2111da177e4SLinus Torvalds * If dev->base_addr in [1..0x1ff], always return failure. 2121da177e4SLinus Torvalds * otherwise go with what we pass in. 2131da177e4SLinus Torvalds */ 2141da177e4SLinus Torvalds struct net_device * __init cops_probe(int unit) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds struct net_device *dev; 2171da177e4SLinus Torvalds unsigned *port; 2181da177e4SLinus Torvalds int base_addr; 2191da177e4SLinus Torvalds int err = 0; 2201da177e4SLinus Torvalds 2213ef4e9a8SChristoph Hellwig dev = alloc_ltalkdev(sizeof(struct cops_local)); 2221da177e4SLinus Torvalds if (!dev) 2231da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds if (unit >= 0) { 2261da177e4SLinus Torvalds sprintf(dev->name, "lt%d", unit); 2271da177e4SLinus Torvalds netdev_boot_setup_check(dev); 2281da177e4SLinus Torvalds irq = dev->irq; 2291da177e4SLinus Torvalds base_addr = dev->base_addr; 2301da177e4SLinus Torvalds } else { 2311da177e4SLinus Torvalds base_addr = dev->base_addr = io; 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds if (base_addr > 0x1ff) { /* Check a single specified location. */ 2351da177e4SLinus Torvalds err = cops_probe1(dev, base_addr); 2361da177e4SLinus Torvalds } else if (base_addr != 0) { /* Don't probe at all. */ 2371da177e4SLinus Torvalds err = -ENXIO; 2381da177e4SLinus Torvalds } else { 2391da177e4SLinus Torvalds /* FIXME Does this really work for cards which generate irq? 2401da177e4SLinus Torvalds * It's definitely N.G. for polled Tangent. sh 2411da177e4SLinus Torvalds * Dayna cards don't autoprobe well at all, but if your card is 2421da177e4SLinus Torvalds * at IRQ 5 & IO 0x240 we find it every time. ;) JS 2431da177e4SLinus Torvalds */ 2441da177e4SLinus Torvalds for (port = ports; *port && cops_probe1(dev, *port) < 0; port++) 2451da177e4SLinus Torvalds ; 2461da177e4SLinus Torvalds if (!*port) 2471da177e4SLinus Torvalds err = -ENODEV; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds if (err) 2501da177e4SLinus Torvalds goto out; 2511da177e4SLinus Torvalds err = register_netdev(dev); 2521da177e4SLinus Torvalds if (err) 2531da177e4SLinus Torvalds goto out1; 2541da177e4SLinus Torvalds return dev; 2551da177e4SLinus Torvalds out1: 2561da177e4SLinus Torvalds cleanup_card(dev); 2571da177e4SLinus Torvalds out: 2581da177e4SLinus Torvalds free_netdev(dev); 2591da177e4SLinus Torvalds return ERR_PTR(err); 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 262c2839d43SStephen Hemminger static const struct net_device_ops cops_netdev_ops = { 263c2839d43SStephen Hemminger .ndo_open = cops_open, 264c2839d43SStephen Hemminger .ndo_stop = cops_close, 265c2839d43SStephen Hemminger .ndo_start_xmit = cops_send_packet, 266c2839d43SStephen Hemminger .ndo_tx_timeout = cops_timeout, 267c2839d43SStephen Hemminger .ndo_do_ioctl = cops_ioctl, 268c2839d43SStephen Hemminger .ndo_set_multicast_list = set_multicast_list, 269c2839d43SStephen Hemminger }; 270c2839d43SStephen Hemminger 2711da177e4SLinus Torvalds /* 2721da177e4SLinus Torvalds * This is the real probe routine. Linux has a history of friendly device 2731da177e4SLinus Torvalds * probes on the ISA bus. A good device probes avoids doing writes, and 2741da177e4SLinus Torvalds * verifies that the correct device exists and functions. 2751da177e4SLinus Torvalds */ 2761da177e4SLinus Torvalds static int __init cops_probe1(struct net_device *dev, int ioaddr) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds struct cops_local *lp; 2791da177e4SLinus Torvalds static unsigned version_printed; 2801da177e4SLinus Torvalds int board = board_type; 2811da177e4SLinus Torvalds int retval; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds if(cops_debug && version_printed++ == 0) 2841da177e4SLinus Torvalds printk("%s", version); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds /* Grab the region so no one else tries to probe our ioports. */ 2871da177e4SLinus Torvalds if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name)) 2881da177e4SLinus Torvalds return -EBUSY; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds /* 2911da177e4SLinus Torvalds * Since this board has jumpered interrupts, allocate the interrupt 2921da177e4SLinus Torvalds * vector now. There is no point in waiting since no other device 2931da177e4SLinus Torvalds * can use the interrupt, and this marks the irq as busy. Jumpered 2941da177e4SLinus Torvalds * interrupts are typically not reported by the boards, and we must 2951da177e4SLinus Torvalds * used AutoIRQ to find them. 2961da177e4SLinus Torvalds */ 2971da177e4SLinus Torvalds dev->irq = irq; 2981da177e4SLinus Torvalds switch (dev->irq) 2991da177e4SLinus Torvalds { 3001da177e4SLinus Torvalds case 0: 3011da177e4SLinus Torvalds /* COPS AutoIRQ routine */ 3021da177e4SLinus Torvalds dev->irq = cops_irq(ioaddr, board); 3031da177e4SLinus Torvalds if (dev->irq) 3041da177e4SLinus Torvalds break; 3051da177e4SLinus Torvalds /* No IRQ found on this port, fallthrough */ 3061da177e4SLinus Torvalds case 1: 3071da177e4SLinus Torvalds retval = -EINVAL; 3081da177e4SLinus Torvalds goto err_out; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* Fixup for users that don't know that IRQ 2 is really 3111da177e4SLinus Torvalds * IRQ 9, or don't know which one to set. 3121da177e4SLinus Torvalds */ 3131da177e4SLinus Torvalds case 2: 3141da177e4SLinus Torvalds dev->irq = 9; 3151da177e4SLinus Torvalds break; 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds /* Polled operation requested. Although irq of zero passed as 3181da177e4SLinus Torvalds * a parameter tells the init routines to probe, we'll 3191da177e4SLinus Torvalds * overload it to denote polled operation at runtime. 3201da177e4SLinus Torvalds */ 3211da177e4SLinus Torvalds case 0xff: 3221da177e4SLinus Torvalds dev->irq = 0; 3231da177e4SLinus Torvalds break; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds default: 3261da177e4SLinus Torvalds break; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /* Reserve any actual interrupt. */ 3301da177e4SLinus Torvalds if (dev->irq) { 3311da177e4SLinus Torvalds retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); 3321da177e4SLinus Torvalds if (retval) 3331da177e4SLinus Torvalds goto err_out; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds dev->base_addr = ioaddr; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds lp = netdev_priv(dev); 3391da177e4SLinus Torvalds spin_lock_init(&lp->lock); 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds /* Copy local board variable to lp struct. */ 3421da177e4SLinus Torvalds lp->board = board; 3431da177e4SLinus Torvalds 344c2839d43SStephen Hemminger dev->netdev_ops = &cops_netdev_ops; 3451da177e4SLinus Torvalds dev->watchdog_timeo = HZ * 2; 3463b04dddeSStephen Hemminger 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds /* Tell the user where the card is and what mode we're in. */ 3491da177e4SLinus Torvalds if(board==DAYNA) 3501da177e4SLinus Torvalds printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 3511da177e4SLinus Torvalds dev->name, cardname, ioaddr, dev->irq); 3521da177e4SLinus Torvalds if(board==TANGENT) { 3531da177e4SLinus Torvalds if(dev->irq) 3541da177e4SLinus Torvalds printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 3551da177e4SLinus Torvalds dev->name, cardname, ioaddr, dev->irq); 3561da177e4SLinus Torvalds else 3571da177e4SLinus Torvalds printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 3581da177e4SLinus Torvalds dev->name, cardname, ioaddr); 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds } 3611da177e4SLinus Torvalds return 0; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds err_out: 3641da177e4SLinus Torvalds release_region(ioaddr, COPS_IO_EXTENT); 3651da177e4SLinus Torvalds return retval; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds static int __init cops_irq (int ioaddr, int board) 3691da177e4SLinus Torvalds { /* 3701da177e4SLinus Torvalds * This does not use the IRQ to determine where the IRQ is. We just 3711da177e4SLinus Torvalds * assume that when we get a correct status response that it's the IRQ. 3721da177e4SLinus Torvalds * This really just verifies the IO port but since we only have access 3731da177e4SLinus Torvalds * to such a small number of IRQs (5, 4, 3) this is not bad. 3741da177e4SLinus Torvalds * This will probably not work for more than one card. 3751da177e4SLinus Torvalds */ 3761da177e4SLinus Torvalds int irqaddr=0; 3771da177e4SLinus Torvalds int i, x, status; 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds if(board==DAYNA) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds outb(0, ioaddr+DAYNA_RESET); 3821da177e4SLinus Torvalds inb(ioaddr+DAYNA_RESET); 3831da177e4SLinus Torvalds mdelay(333); 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds if(board==TANGENT) 3861da177e4SLinus Torvalds { 3871da177e4SLinus Torvalds inb(ioaddr); 3881da177e4SLinus Torvalds outb(0, ioaddr); 3891da177e4SLinus Torvalds outb(0, ioaddr+TANG_RESET); 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds for(i=0; cops_irqlist[i] !=0; i++) 3931da177e4SLinus Torvalds { 3941da177e4SLinus Torvalds irqaddr = cops_irqlist[i]; 3951da177e4SLinus Torvalds for(x = 0xFFFF; x>0; x --) /* wait for response */ 3961da177e4SLinus Torvalds { 3971da177e4SLinus Torvalds if(board==DAYNA) 3981da177e4SLinus Torvalds { 3991da177e4SLinus Torvalds status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); 4001da177e4SLinus Torvalds if(status == 1) 4011da177e4SLinus Torvalds return irqaddr; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds if(board==TANGENT) 4041da177e4SLinus Torvalds { 4051da177e4SLinus Torvalds if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0) 4061da177e4SLinus Torvalds return irqaddr; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds return 0; /* no IRQ found */ 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds /* 4141da177e4SLinus Torvalds * Open/initialize the board. This is called (in the current kernel) 4151da177e4SLinus Torvalds * sometime after booting when the 'ifconfig' program is run. 4161da177e4SLinus Torvalds */ 4171da177e4SLinus Torvalds static int cops_open(struct net_device *dev) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if(dev->irq==0) 4221da177e4SLinus Torvalds { 4231da177e4SLinus Torvalds /* 4241da177e4SLinus Torvalds * I don't know if the Dayna-style boards support polled 4251da177e4SLinus Torvalds * operation. For now, only allow it for Tangent. 4261da177e4SLinus Torvalds */ 4271da177e4SLinus Torvalds if(lp->board==TANGENT) /* Poll 20 times per second */ 4281da177e4SLinus Torvalds { 4291da177e4SLinus Torvalds init_timer(&cops_timer); 4301da177e4SLinus Torvalds cops_timer.function = cops_poll; 4311da177e4SLinus Torvalds cops_timer.data = (unsigned long)dev; 4321da177e4SLinus Torvalds cops_timer.expires = jiffies + HZ/20; 4331da177e4SLinus Torvalds add_timer(&cops_timer); 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds else 4361da177e4SLinus Torvalds { 4371da177e4SLinus Torvalds printk(KERN_WARNING "%s: No irq line set\n", dev->name); 4381da177e4SLinus Torvalds return -EAGAIN; 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds cops_jumpstart(dev); /* Start the card up. */ 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds netif_start_queue(dev); 4451da177e4SLinus Torvalds return 0; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds /* 4491da177e4SLinus Torvalds * This allows for a dynamic start/restart of the entire card. 4501da177e4SLinus Torvalds */ 4511da177e4SLinus Torvalds static int cops_jumpstart(struct net_device *dev) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds /* 4561da177e4SLinus Torvalds * Once the card has the firmware loaded and has acquired 4571da177e4SLinus Torvalds * the nodeid, if it is reset it will lose it all. 4581da177e4SLinus Torvalds */ 4591da177e4SLinus Torvalds cops_reset(dev,1); /* Need to reset card before load firmware. */ 4601da177e4SLinus Torvalds cops_load(dev); /* Load the firmware. */ 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds /* 4631da177e4SLinus Torvalds * If atalkd already gave us a nodeid we will use that 4641da177e4SLinus Torvalds * one again, else we wait for atalkd to give us a nodeid 4651da177e4SLinus Torvalds * in cops_ioctl. This may cause a problem if someone steals 4661da177e4SLinus Torvalds * our nodeid while we are resetting. 4671da177e4SLinus Torvalds */ 4681da177e4SLinus Torvalds if(lp->nodeid == 1) 4691da177e4SLinus Torvalds cops_nodeid(dev,lp->node_acquire); 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds return 0; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds static void tangent_wait_reset(int ioaddr) 4751da177e4SLinus Torvalds { 4761da177e4SLinus Torvalds int timeout=0; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) 4791da177e4SLinus Torvalds mdelay(1); /* Wait 1 second */ 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds /* 4831da177e4SLinus Torvalds * Reset the LocalTalk board. 4841da177e4SLinus Torvalds */ 4851da177e4SLinus Torvalds static void cops_reset(struct net_device *dev, int sleep) 4861da177e4SLinus Torvalds { 4871da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 4881da177e4SLinus Torvalds int ioaddr=dev->base_addr; 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds if(lp->board==TANGENT) 4911da177e4SLinus Torvalds { 4921da177e4SLinus Torvalds inb(ioaddr); /* Clear request latch. */ 4931da177e4SLinus Torvalds outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */ 4941da177e4SLinus Torvalds outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */ 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds tangent_wait_reset(ioaddr); 4971da177e4SLinus Torvalds outb(0, ioaddr+TANG_CLEAR_INT); 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds if(lp->board==DAYNA) 5001da177e4SLinus Torvalds { 5011da177e4SLinus Torvalds outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */ 5021da177e4SLinus Torvalds inb(ioaddr+DAYNA_RESET); /* Clear the reset */ 5031da177e4SLinus Torvalds if (sleep) 5047ab267d4SJeff Garzik msleep(333); 5051da177e4SLinus Torvalds else 5061da177e4SLinus Torvalds mdelay(333); 5071da177e4SLinus Torvalds } 5087ab267d4SJeff Garzik 5091da177e4SLinus Torvalds netif_wake_queue(dev); 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds static void cops_load (struct net_device *dev) 5131da177e4SLinus Torvalds { 5141da177e4SLinus Torvalds struct ifreq ifr; 5151da177e4SLinus Torvalds struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru; 5161da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 5171da177e4SLinus Torvalds int ioaddr=dev->base_addr; 5181da177e4SLinus Torvalds int length, i = 0; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds strcpy(ifr.ifr_name,"lt0"); 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds /* Get card's firmware code and do some checks on it. */ 5231da177e4SLinus Torvalds #ifdef CONFIG_COPS_DAYNA 5241da177e4SLinus Torvalds if(lp->board==DAYNA) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds ltf->length=sizeof(ffdrv_code); 5271da177e4SLinus Torvalds ltf->data=ffdrv_code; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds else 5301da177e4SLinus Torvalds #endif 5311da177e4SLinus Torvalds #ifdef CONFIG_COPS_TANGENT 5321da177e4SLinus Torvalds if(lp->board==TANGENT) 5331da177e4SLinus Torvalds { 5341da177e4SLinus Torvalds ltf->length=sizeof(ltdrv_code); 5351da177e4SLinus Torvalds ltf->data=ltdrv_code; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds else 5381da177e4SLinus Torvalds #endif 5391da177e4SLinus Torvalds { 5401da177e4SLinus Torvalds printk(KERN_INFO "%s; unsupported board type.\n", dev->name); 5411da177e4SLinus Torvalds return; 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds /* Check to make sure firmware is correct length. */ 5451da177e4SLinus Torvalds if(lp->board==DAYNA && ltf->length!=5983) 5461da177e4SLinus Torvalds { 5471da177e4SLinus Torvalds printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name); 5481da177e4SLinus Torvalds return; 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds if(lp->board==TANGENT && ltf->length!=2501) 5511da177e4SLinus Torvalds { 5521da177e4SLinus Torvalds printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name); 5531da177e4SLinus Torvalds return; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds if(lp->board==DAYNA) 5571da177e4SLinus Torvalds { 5581da177e4SLinus Torvalds /* 5591da177e4SLinus Torvalds * We must wait for a status response 5601da177e4SLinus Torvalds * with the DAYNA board. 5611da177e4SLinus Torvalds */ 5621da177e4SLinus Torvalds while(++i<65536) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1) 5651da177e4SLinus Torvalds break; 5661da177e4SLinus Torvalds } 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds if(i==65536) 5691da177e4SLinus Torvalds return; 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds /* 5731da177e4SLinus Torvalds * Upload the firmware and kick. Byte-by-byte works nicely here. 5741da177e4SLinus Torvalds */ 5751da177e4SLinus Torvalds i=0; 5761da177e4SLinus Torvalds length = ltf->length; 5771da177e4SLinus Torvalds while(length--) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds outb(ltf->data[i], ioaddr); 5801da177e4SLinus Torvalds i++; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds if(cops_debug > 1) 5841da177e4SLinus Torvalds printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 5851da177e4SLinus Torvalds dev->name, i, ltf->length); 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */ 5881da177e4SLinus Torvalds outb(1, ioaddr+DAYNA_INT_CARD); 5891da177e4SLinus Torvalds else /* Tell Tang to run the firmware code. */ 5901da177e4SLinus Torvalds inb(ioaddr); 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds if(lp->board==TANGENT) 5931da177e4SLinus Torvalds { 5941da177e4SLinus Torvalds tangent_wait_reset(ioaddr); 5951da177e4SLinus Torvalds inb(ioaddr); /* Clear initial ready signal. */ 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds return; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds /* 6021da177e4SLinus Torvalds * Get the LocalTalk Nodeid from the card. We can suggest 6031da177e4SLinus Torvalds * any nodeid 1-254. The card will try and get that exact 6041da177e4SLinus Torvalds * address else we can specify 0 as the nodeid and the card 6051da177e4SLinus Torvalds * will autoprobe for a nodeid. 6061da177e4SLinus Torvalds */ 6071da177e4SLinus Torvalds static int cops_nodeid (struct net_device *dev, int nodeid) 6081da177e4SLinus Torvalds { 6091da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 6101da177e4SLinus Torvalds int ioaddr = dev->base_addr; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if(lp->board == DAYNA) 6131da177e4SLinus Torvalds { 6141da177e4SLinus Torvalds /* Empty any pending adapter responses. */ 6151da177e4SLinus Torvalds while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) 6161da177e4SLinus Torvalds { 6171da177e4SLinus Torvalds outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */ 6181da177e4SLinus Torvalds if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) 6191da177e4SLinus Torvalds cops_rx(dev); /* Kick any packets waiting. */ 6201da177e4SLinus Torvalds schedule(); 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds outb(2, ioaddr); /* Output command packet length as 2. */ 6241da177e4SLinus Torvalds outb(0, ioaddr); 6251da177e4SLinus Torvalds outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */ 6261da177e4SLinus Torvalds outb(nodeid, ioaddr); /* Suggest node address. */ 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds if(lp->board == TANGENT) 6301da177e4SLinus Torvalds { 6311da177e4SLinus Torvalds /* Empty any pending adapter responses. */ 6321da177e4SLinus Torvalds while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) 6331da177e4SLinus Torvalds { 6341da177e4SLinus Torvalds outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */ 6351da177e4SLinus Torvalds cops_rx(dev); /* Kick out packets waiting. */ 6361da177e4SLinus Torvalds schedule(); 6371da177e4SLinus Torvalds } 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds /* Not sure what Tangent does if nodeid picked is used. */ 6401da177e4SLinus Torvalds if(nodeid == 0) /* Seed. */ 6411da177e4SLinus Torvalds nodeid = jiffies&0xFF; /* Get a random try */ 6421da177e4SLinus Torvalds outb(2, ioaddr); /* Command length LSB */ 6431da177e4SLinus Torvalds outb(0, ioaddr); /* Command length MSB */ 6441da177e4SLinus Torvalds outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */ 6451da177e4SLinus Torvalds outb(nodeid, ioaddr); /* LAP address hint. */ 6461da177e4SLinus Torvalds outb(0xFF, ioaddr); /* Int. level to use */ 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds lp->node_acquire=0; /* Set nodeid holder to 0. */ 6501da177e4SLinus Torvalds while(lp->node_acquire==0) /* Get *True* nodeid finally. */ 6511da177e4SLinus Torvalds { 6521da177e4SLinus Torvalds outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */ 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds if(lp->board == DAYNA) 6551da177e4SLinus Torvalds { 6561da177e4SLinus Torvalds if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) 6571da177e4SLinus Torvalds cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds if(lp->board == TANGENT) 6601da177e4SLinus Torvalds { 6611da177e4SLinus Torvalds if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) 6621da177e4SLinus Torvalds cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds schedule(); 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds if(cops_debug > 1) 6681da177e4SLinus Torvalds printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 6691da177e4SLinus Torvalds dev->name, lp->node_acquire); 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds lp->nodeid=1; /* Set got nodeid to 1. */ 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds return 0; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds /* 6771da177e4SLinus Torvalds * Poll the Tangent type cards to see if we have work. 6781da177e4SLinus Torvalds */ 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds static void cops_poll(unsigned long ltdev) 6811da177e4SLinus Torvalds { 6821da177e4SLinus Torvalds int ioaddr, status; 6831da177e4SLinus Torvalds int boguscount = 0; 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds struct net_device *dev = (struct net_device *)ltdev; 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds del_timer(&cops_timer); 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds if(dev == NULL) 6901da177e4SLinus Torvalds return; /* We've been downed */ 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds ioaddr = dev->base_addr; 6931da177e4SLinus Torvalds do { 6941da177e4SLinus Torvalds status=inb(ioaddr+TANG_CARD_STATUS); 6951da177e4SLinus Torvalds if(status & TANG_RX_READY) 6961da177e4SLinus Torvalds cops_rx(dev); 6971da177e4SLinus Torvalds if(status & TANG_TX_READY) 6981da177e4SLinus Torvalds netif_wake_queue(dev); 6991da177e4SLinus Torvalds status = inb(ioaddr+TANG_CARD_STATUS); 7001da177e4SLinus Torvalds } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds /* poll 20 times per second */ 7031da177e4SLinus Torvalds cops_timer.expires = jiffies + HZ/20; 7041da177e4SLinus Torvalds add_timer(&cops_timer); 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds return; 7071da177e4SLinus Torvalds } 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds /* 7101da177e4SLinus Torvalds * The typical workload of the driver: 7111da177e4SLinus Torvalds * Handle the network interface interrupts. 7121da177e4SLinus Torvalds */ 7137d12e780SDavid Howells static irqreturn_t cops_interrupt(int irq, void *dev_id) 7141da177e4SLinus Torvalds { 7151da177e4SLinus Torvalds struct net_device *dev = dev_id; 7161da177e4SLinus Torvalds struct cops_local *lp; 7171da177e4SLinus Torvalds int ioaddr, status; 7181da177e4SLinus Torvalds int boguscount = 0; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds ioaddr = dev->base_addr; 7211da177e4SLinus Torvalds lp = netdev_priv(dev); 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds if(lp->board==DAYNA) 7241da177e4SLinus Torvalds { 7251da177e4SLinus Torvalds do { 7261da177e4SLinus Torvalds outb(0, ioaddr + COPS_CLEAR_INT); 7271da177e4SLinus Torvalds status=inb(ioaddr+DAYNA_CARD_STATUS); 7281da177e4SLinus Torvalds if((status&0x03)==DAYNA_RX_REQUEST) 7291da177e4SLinus Torvalds cops_rx(dev); 7301da177e4SLinus Torvalds netif_wake_queue(dev); 7311da177e4SLinus Torvalds } while(++boguscount < 20); 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds else 7341da177e4SLinus Torvalds { 7351da177e4SLinus Torvalds do { 7361da177e4SLinus Torvalds status=inb(ioaddr+TANG_CARD_STATUS); 7371da177e4SLinus Torvalds if(status & TANG_RX_READY) 7381da177e4SLinus Torvalds cops_rx(dev); 7391da177e4SLinus Torvalds if(status & TANG_TX_READY) 7401da177e4SLinus Torvalds netif_wake_queue(dev); 7411da177e4SLinus Torvalds status=inb(ioaddr+TANG_CARD_STATUS); 7421da177e4SLinus Torvalds } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds return IRQ_HANDLED; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* 7491da177e4SLinus Torvalds * We have a good packet(s), get it/them out of the buffers. 7501da177e4SLinus Torvalds */ 7511da177e4SLinus Torvalds static void cops_rx(struct net_device *dev) 7521da177e4SLinus Torvalds { 7531da177e4SLinus Torvalds int pkt_len = 0; 7541da177e4SLinus Torvalds int rsp_type = 0; 7551da177e4SLinus Torvalds struct sk_buff *skb = NULL; 7561da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 7571da177e4SLinus Torvalds int ioaddr = dev->base_addr; 7581da177e4SLinus Torvalds int boguscount = 0; 7591da177e4SLinus Torvalds unsigned long flags; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds if(lp->board==DAYNA) 7651da177e4SLinus Torvalds { 7661da177e4SLinus Torvalds outb(0, ioaddr); /* Send out Zero length. */ 7671da177e4SLinus Torvalds outb(0, ioaddr); 7681da177e4SLinus Torvalds outb(DATA_READ, ioaddr); /* Send read command out. */ 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds /* Wait for DMA to turn around. */ 7711da177e4SLinus Torvalds while(++boguscount<1000000) 7721da177e4SLinus Torvalds { 7731da177e4SLinus Torvalds barrier(); 7741da177e4SLinus Torvalds if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) 7751da177e4SLinus Torvalds break; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds if(boguscount==1000000) 7791da177e4SLinus Torvalds { 7801da177e4SLinus Torvalds printk(KERN_WARNING "%s: DMA timed out.\n",dev->name); 7811da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 7821da177e4SLinus Torvalds return; 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds /* Get response length. */ 7871da177e4SLinus Torvalds if(lp->board==DAYNA) 7881da177e4SLinus Torvalds pkt_len = inb(ioaddr) & 0xFF; 7891da177e4SLinus Torvalds else 7901da177e4SLinus Torvalds pkt_len = inb(ioaddr) & 0x00FF; 7911da177e4SLinus Torvalds pkt_len |= (inb(ioaddr) << 8); 7921da177e4SLinus Torvalds /* Input IO code. */ 7931da177e4SLinus Torvalds rsp_type=inb(ioaddr); 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds /* Malloc up new buffer. */ 7961da177e4SLinus Torvalds skb = dev_alloc_skb(pkt_len); 7971da177e4SLinus Torvalds if(skb == NULL) 7981da177e4SLinus Torvalds { 7991da177e4SLinus Torvalds printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", 8001da177e4SLinus Torvalds dev->name); 8018bbce3f6SStephen Hemminger dev->stats.rx_dropped++; 8021da177e4SLinus Torvalds while(pkt_len--) /* Discard packet */ 8031da177e4SLinus Torvalds inb(ioaddr); 8041da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 8051da177e4SLinus Torvalds return; 8061da177e4SLinus Torvalds } 8071da177e4SLinus Torvalds skb->dev = dev; 8081da177e4SLinus Torvalds skb_put(skb, pkt_len); 8091da177e4SLinus Torvalds skb->protocol = htons(ETH_P_LOCALTALK); 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds insb(ioaddr, skb->data, pkt_len); /* Eat the Data */ 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds if(lp->board==DAYNA) 8141da177e4SLinus Torvalds outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */ 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); /* Restore interrupts. */ 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds /* Check for bad response length */ 8191da177e4SLinus Torvalds if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) 8201da177e4SLinus Torvalds { 8211da177e4SLinus Torvalds printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 8221da177e4SLinus Torvalds dev->name, pkt_len); 8238bbce3f6SStephen Hemminger dev->stats.tx_errors++; 8241da177e4SLinus Torvalds dev_kfree_skb_any(skb); 8251da177e4SLinus Torvalds return; 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds /* Set nodeid and then get out. */ 8291da177e4SLinus Torvalds if(rsp_type == LAP_INIT_RSP) 8301da177e4SLinus Torvalds { /* Nodeid taken from received packet. */ 8311da177e4SLinus Torvalds lp->node_acquire = skb->data[0]; 8321da177e4SLinus Torvalds dev_kfree_skb_any(skb); 8331da177e4SLinus Torvalds return; 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds /* One last check to make sure we have a good packet. */ 8371da177e4SLinus Torvalds if(rsp_type != LAP_RESPONSE) 8381da177e4SLinus Torvalds { 8391da177e4SLinus Torvalds printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); 8408bbce3f6SStephen Hemminger dev->stats.tx_errors++; 8411da177e4SLinus Torvalds dev_kfree_skb_any(skb); 8421da177e4SLinus Torvalds return; 8431da177e4SLinus Torvalds } 8441da177e4SLinus Torvalds 845459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb); /* Point to entire packet. */ 8461da177e4SLinus Torvalds skb_pull(skb,3); 847badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb); /* Point to data (Skip header). */ 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds /* Update the counters. */ 8508bbce3f6SStephen Hemminger dev->stats.rx_packets++; 8518bbce3f6SStephen Hemminger dev->stats.rx_bytes += skb->len; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds /* Send packet to a higher place. */ 8541da177e4SLinus Torvalds netif_rx(skb); 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds 8571da177e4SLinus Torvalds static void cops_timeout(struct net_device *dev) 8581da177e4SLinus Torvalds { 8591da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 8601da177e4SLinus Torvalds int ioaddr = dev->base_addr; 8611da177e4SLinus Torvalds 8628bbce3f6SStephen Hemminger dev->stats.tx_errors++; 8631da177e4SLinus Torvalds if(lp->board==TANGENT) 8641da177e4SLinus Torvalds { 8651da177e4SLinus Torvalds if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) 8661da177e4SLinus Torvalds printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name); 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name); 8691da177e4SLinus Torvalds cops_jumpstart(dev); /* Restart the card. */ 8701da177e4SLinus Torvalds dev->trans_start = jiffies; 8711da177e4SLinus Torvalds netif_wake_queue(dev); 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds /* 8761da177e4SLinus Torvalds * Make the card transmit a LocalTalk packet. 8771da177e4SLinus Torvalds */ 8781da177e4SLinus Torvalds 8790fc48098SStephen Hemminger static netdev_tx_t cops_send_packet(struct sk_buff *skb, 8800fc48098SStephen Hemminger struct net_device *dev) 8811da177e4SLinus Torvalds { 8821da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 8831da177e4SLinus Torvalds int ioaddr = dev->base_addr; 8841da177e4SLinus Torvalds unsigned long flags; 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds /* 8871da177e4SLinus Torvalds * Block a timer-based transmit from overlapping. 8881da177e4SLinus Torvalds */ 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds netif_stop_queue(dev); 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 8931da177e4SLinus Torvalds if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */ 8941da177e4SLinus Torvalds while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) 8951da177e4SLinus Torvalds cpu_relax(); 8961da177e4SLinus Torvalds if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */ 8971da177e4SLinus Torvalds while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) 8981da177e4SLinus Torvalds cpu_relax(); 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds /* Output IO length. */ 9011da177e4SLinus Torvalds outb(skb->len, ioaddr); 9021da177e4SLinus Torvalds if(lp->board == DAYNA) 9031da177e4SLinus Torvalds outb(skb->len >> 8, ioaddr); 9041da177e4SLinus Torvalds else 9051da177e4SLinus Torvalds outb((skb->len >> 8)&0x0FF, ioaddr); 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds /* Output IO code. */ 9081da177e4SLinus Torvalds outb(LAP_WRITE, ioaddr); 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds if(lp->board == DAYNA) /* Check the transmit buffer again. */ 9111da177e4SLinus Torvalds while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds outsb(ioaddr, skb->data, skb->len); /* Send out the data. */ 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds if(lp->board==DAYNA) /* Dayna requires you kick the card */ 9161da177e4SLinus Torvalds outb(1, ioaddr+DAYNA_INT_CARD); 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); /* Restore interrupts. */ 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds /* Done sending packet, update counters and cleanup. */ 9218bbce3f6SStephen Hemminger dev->stats.tx_packets++; 9228bbce3f6SStephen Hemminger dev->stats.tx_bytes += skb->len; 9231da177e4SLinus Torvalds dev->trans_start = jiffies; 9241da177e4SLinus Torvalds dev_kfree_skb (skb); 9256ed10654SPatrick McHardy return NETDEV_TX_OK; 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds /* 9291da177e4SLinus Torvalds * Dummy function to keep the Appletalk layer happy. 9301da177e4SLinus Torvalds */ 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds static void set_multicast_list(struct net_device *dev) 9331da177e4SLinus Torvalds { 9341da177e4SLinus Torvalds if(cops_debug >= 3) 9351da177e4SLinus Torvalds printk("%s: set_multicast_list executed\n", dev->name); 9361da177e4SLinus Torvalds } 9371da177e4SLinus Torvalds 9381da177e4SLinus Torvalds /* 9391da177e4SLinus Torvalds * System ioctls for the COPS LocalTalk card. 9401da177e4SLinus Torvalds */ 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 9431da177e4SLinus Torvalds { 9441da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 9451da177e4SLinus Torvalds struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr; 9461da177e4SLinus Torvalds struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr; 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds switch(cmd) 9491da177e4SLinus Torvalds { 9501da177e4SLinus Torvalds case SIOCSIFADDR: 9511da177e4SLinus Torvalds /* Get and set the nodeid and network # atalkd wants. */ 9521da177e4SLinus Torvalds cops_nodeid(dev, sa->sat_addr.s_node); 9531da177e4SLinus Torvalds aa->s_net = sa->sat_addr.s_net; 9541da177e4SLinus Torvalds aa->s_node = lp->node_acquire; 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds /* Set broardcast address. */ 9571da177e4SLinus Torvalds dev->broadcast[0] = 0xFF; 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds /* Set hardware address. */ 9601da177e4SLinus Torvalds dev->dev_addr[0] = aa->s_node; 9611da177e4SLinus Torvalds dev->addr_len = 1; 9621da177e4SLinus Torvalds return 0; 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds case SIOCGIFADDR: 9651da177e4SLinus Torvalds sa->sat_addr.s_net = aa->s_net; 9661da177e4SLinus Torvalds sa->sat_addr.s_node = aa->s_node; 9671da177e4SLinus Torvalds return 0; 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds default: 9701da177e4SLinus Torvalds return -EOPNOTSUPP; 9711da177e4SLinus Torvalds } 9721da177e4SLinus Torvalds } 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds /* 9751da177e4SLinus Torvalds * The inverse routine to cops_open(). 9761da177e4SLinus Torvalds */ 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds static int cops_close(struct net_device *dev) 9791da177e4SLinus Torvalds { 9801da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds /* If we were running polled, yank the timer. 9831da177e4SLinus Torvalds */ 9841da177e4SLinus Torvalds if(lp->board==TANGENT && dev->irq==0) 9851da177e4SLinus Torvalds del_timer(&cops_timer); 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds netif_stop_queue(dev); 9881da177e4SLinus Torvalds return 0; 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds #ifdef MODULE 9931da177e4SLinus Torvalds static struct net_device *cops_dev; 9941da177e4SLinus Torvalds 9951da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 9961da177e4SLinus Torvalds module_param(io, int, 0); 9971da177e4SLinus Torvalds module_param(irq, int, 0); 9981da177e4SLinus Torvalds module_param(board_type, int, 0); 9991da177e4SLinus Torvalds 1000b32dac08SJon Schindler static int __init cops_module_init(void) 10011da177e4SLinus Torvalds { 10021da177e4SLinus Torvalds if (io == 0) 10031da177e4SLinus Torvalds printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", 10041da177e4SLinus Torvalds cardname); 10051da177e4SLinus Torvalds cops_dev = cops_probe(-1); 10061da177e4SLinus Torvalds if (IS_ERR(cops_dev)) 10071da177e4SLinus Torvalds return PTR_ERR(cops_dev); 10081da177e4SLinus Torvalds return 0; 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 1011b32dac08SJon Schindler static void __exit cops_module_exit(void) 10121da177e4SLinus Torvalds { 10131da177e4SLinus Torvalds unregister_netdev(cops_dev); 10141da177e4SLinus Torvalds cleanup_card(cops_dev); 10151da177e4SLinus Torvalds free_netdev(cops_dev); 10161da177e4SLinus Torvalds } 1017b32dac08SJon Schindler module_init(cops_module_init); 1018b32dac08SJon Schindler module_exit(cops_module_exit); 10191da177e4SLinus Torvalds #endif /* MODULE */ 1020