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