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); 1951da177e4SLinus Torvalds static int cops_send_packet (struct sk_buff *skb, 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 2611da177e4SLinus Torvalds /* 2621da177e4SLinus Torvalds * This is the real probe routine. Linux has a history of friendly device 2631da177e4SLinus Torvalds * probes on the ISA bus. A good device probes avoids doing writes, and 2641da177e4SLinus Torvalds * verifies that the correct device exists and functions. 2651da177e4SLinus Torvalds */ 2661da177e4SLinus Torvalds static int __init cops_probe1(struct net_device *dev, int ioaddr) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds struct cops_local *lp; 2691da177e4SLinus Torvalds static unsigned version_printed; 2701da177e4SLinus Torvalds int board = board_type; 2711da177e4SLinus Torvalds int retval; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds if(cops_debug && version_printed++ == 0) 2741da177e4SLinus Torvalds printk("%s", version); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /* Grab the region so no one else tries to probe our ioports. */ 2771da177e4SLinus Torvalds if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name)) 2781da177e4SLinus Torvalds return -EBUSY; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds /* 2811da177e4SLinus Torvalds * Since this board has jumpered interrupts, allocate the interrupt 2821da177e4SLinus Torvalds * vector now. There is no point in waiting since no other device 2831da177e4SLinus Torvalds * can use the interrupt, and this marks the irq as busy. Jumpered 2841da177e4SLinus Torvalds * interrupts are typically not reported by the boards, and we must 2851da177e4SLinus Torvalds * used AutoIRQ to find them. 2861da177e4SLinus Torvalds */ 2871da177e4SLinus Torvalds dev->irq = irq; 2881da177e4SLinus Torvalds switch (dev->irq) 2891da177e4SLinus Torvalds { 2901da177e4SLinus Torvalds case 0: 2911da177e4SLinus Torvalds /* COPS AutoIRQ routine */ 2921da177e4SLinus Torvalds dev->irq = cops_irq(ioaddr, board); 2931da177e4SLinus Torvalds if (dev->irq) 2941da177e4SLinus Torvalds break; 2951da177e4SLinus Torvalds /* No IRQ found on this port, fallthrough */ 2961da177e4SLinus Torvalds case 1: 2971da177e4SLinus Torvalds retval = -EINVAL; 2981da177e4SLinus Torvalds goto err_out; 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* Fixup for users that don't know that IRQ 2 is really 3011da177e4SLinus Torvalds * IRQ 9, or don't know which one to set. 3021da177e4SLinus Torvalds */ 3031da177e4SLinus Torvalds case 2: 3041da177e4SLinus Torvalds dev->irq = 9; 3051da177e4SLinus Torvalds break; 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds /* Polled operation requested. Although irq of zero passed as 3081da177e4SLinus Torvalds * a parameter tells the init routines to probe, we'll 3091da177e4SLinus Torvalds * overload it to denote polled operation at runtime. 3101da177e4SLinus Torvalds */ 3111da177e4SLinus Torvalds case 0xff: 3121da177e4SLinus Torvalds dev->irq = 0; 3131da177e4SLinus Torvalds break; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds default: 3161da177e4SLinus Torvalds break; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds /* Reserve any actual interrupt. */ 3201da177e4SLinus Torvalds if (dev->irq) { 3211da177e4SLinus Torvalds retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); 3221da177e4SLinus Torvalds if (retval) 3231da177e4SLinus Torvalds goto err_out; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds dev->base_addr = ioaddr; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds lp = netdev_priv(dev); 3291da177e4SLinus Torvalds spin_lock_init(&lp->lock); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* Copy local board variable to lp struct. */ 3321da177e4SLinus Torvalds lp->board = board; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds dev->hard_start_xmit = cops_send_packet; 3351da177e4SLinus Torvalds dev->tx_timeout = cops_timeout; 3361da177e4SLinus Torvalds dev->watchdog_timeo = HZ * 2; 3373b04dddeSStephen Hemminger 3381da177e4SLinus Torvalds dev->open = cops_open; 3391da177e4SLinus Torvalds dev->stop = cops_close; 3401da177e4SLinus Torvalds dev->do_ioctl = cops_ioctl; 3411da177e4SLinus Torvalds dev->set_multicast_list = set_multicast_list; 3421da177e4SLinus Torvalds dev->mc_list = NULL; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* Tell the user where the card is and what mode we're in. */ 3451da177e4SLinus Torvalds if(board==DAYNA) 3461da177e4SLinus Torvalds printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 3471da177e4SLinus Torvalds dev->name, cardname, ioaddr, dev->irq); 3481da177e4SLinus Torvalds if(board==TANGENT) { 3491da177e4SLinus Torvalds if(dev->irq) 3501da177e4SLinus Torvalds printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 3511da177e4SLinus Torvalds dev->name, cardname, ioaddr, dev->irq); 3521da177e4SLinus Torvalds else 3531da177e4SLinus Torvalds printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 3541da177e4SLinus Torvalds dev->name, cardname, ioaddr); 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds return 0; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds err_out: 3601da177e4SLinus Torvalds release_region(ioaddr, COPS_IO_EXTENT); 3611da177e4SLinus Torvalds return retval; 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds static int __init cops_irq (int ioaddr, int board) 3651da177e4SLinus Torvalds { /* 3661da177e4SLinus Torvalds * This does not use the IRQ to determine where the IRQ is. We just 3671da177e4SLinus Torvalds * assume that when we get a correct status response that it's the IRQ. 3681da177e4SLinus Torvalds * This really just verifies the IO port but since we only have access 3691da177e4SLinus Torvalds * to such a small number of IRQs (5, 4, 3) this is not bad. 3701da177e4SLinus Torvalds * This will probably not work for more than one card. 3711da177e4SLinus Torvalds */ 3721da177e4SLinus Torvalds int irqaddr=0; 3731da177e4SLinus Torvalds int i, x, status; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds if(board==DAYNA) 3761da177e4SLinus Torvalds { 3771da177e4SLinus Torvalds outb(0, ioaddr+DAYNA_RESET); 3781da177e4SLinus Torvalds inb(ioaddr+DAYNA_RESET); 3791da177e4SLinus Torvalds mdelay(333); 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds if(board==TANGENT) 3821da177e4SLinus Torvalds { 3831da177e4SLinus Torvalds inb(ioaddr); 3841da177e4SLinus Torvalds outb(0, ioaddr); 3851da177e4SLinus Torvalds outb(0, ioaddr+TANG_RESET); 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds for(i=0; cops_irqlist[i] !=0; i++) 3891da177e4SLinus Torvalds { 3901da177e4SLinus Torvalds irqaddr = cops_irqlist[i]; 3911da177e4SLinus Torvalds for(x = 0xFFFF; x>0; x --) /* wait for response */ 3921da177e4SLinus Torvalds { 3931da177e4SLinus Torvalds if(board==DAYNA) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); 3961da177e4SLinus Torvalds if(status == 1) 3971da177e4SLinus Torvalds return irqaddr; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds if(board==TANGENT) 4001da177e4SLinus Torvalds { 4011da177e4SLinus Torvalds if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0) 4021da177e4SLinus Torvalds return irqaddr; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds } 4061da177e4SLinus Torvalds return 0; /* no IRQ found */ 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* 4101da177e4SLinus Torvalds * Open/initialize the board. This is called (in the current kernel) 4111da177e4SLinus Torvalds * sometime after booting when the 'ifconfig' program is run. 4121da177e4SLinus Torvalds */ 4131da177e4SLinus Torvalds static int cops_open(struct net_device *dev) 4141da177e4SLinus Torvalds { 4151da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds if(dev->irq==0) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds /* 4201da177e4SLinus Torvalds * I don't know if the Dayna-style boards support polled 4211da177e4SLinus Torvalds * operation. For now, only allow it for Tangent. 4221da177e4SLinus Torvalds */ 4231da177e4SLinus Torvalds if(lp->board==TANGENT) /* Poll 20 times per second */ 4241da177e4SLinus Torvalds { 4251da177e4SLinus Torvalds init_timer(&cops_timer); 4261da177e4SLinus Torvalds cops_timer.function = cops_poll; 4271da177e4SLinus Torvalds cops_timer.data = (unsigned long)dev; 4281da177e4SLinus Torvalds cops_timer.expires = jiffies + HZ/20; 4291da177e4SLinus Torvalds add_timer(&cops_timer); 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds else 4321da177e4SLinus Torvalds { 4331da177e4SLinus Torvalds printk(KERN_WARNING "%s: No irq line set\n", dev->name); 4341da177e4SLinus Torvalds return -EAGAIN; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds cops_jumpstart(dev); /* Start the card up. */ 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds netif_start_queue(dev); 4411da177e4SLinus Torvalds return 0; 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds /* 4451da177e4SLinus Torvalds * This allows for a dynamic start/restart of the entire card. 4461da177e4SLinus Torvalds */ 4471da177e4SLinus Torvalds static int cops_jumpstart(struct net_device *dev) 4481da177e4SLinus Torvalds { 4491da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds /* 4521da177e4SLinus Torvalds * Once the card has the firmware loaded and has acquired 4531da177e4SLinus Torvalds * the nodeid, if it is reset it will lose it all. 4541da177e4SLinus Torvalds */ 4551da177e4SLinus Torvalds cops_reset(dev,1); /* Need to reset card before load firmware. */ 4561da177e4SLinus Torvalds cops_load(dev); /* Load the firmware. */ 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds /* 4591da177e4SLinus Torvalds * If atalkd already gave us a nodeid we will use that 4601da177e4SLinus Torvalds * one again, else we wait for atalkd to give us a nodeid 4611da177e4SLinus Torvalds * in cops_ioctl. This may cause a problem if someone steals 4621da177e4SLinus Torvalds * our nodeid while we are resetting. 4631da177e4SLinus Torvalds */ 4641da177e4SLinus Torvalds if(lp->nodeid == 1) 4651da177e4SLinus Torvalds cops_nodeid(dev,lp->node_acquire); 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds return 0; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds static void tangent_wait_reset(int ioaddr) 4711da177e4SLinus Torvalds { 4721da177e4SLinus Torvalds int timeout=0; 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) 4751da177e4SLinus Torvalds mdelay(1); /* Wait 1 second */ 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds /* 4791da177e4SLinus Torvalds * Reset the LocalTalk board. 4801da177e4SLinus Torvalds */ 4811da177e4SLinus Torvalds static void cops_reset(struct net_device *dev, int sleep) 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 4841da177e4SLinus Torvalds int ioaddr=dev->base_addr; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds if(lp->board==TANGENT) 4871da177e4SLinus Torvalds { 4881da177e4SLinus Torvalds inb(ioaddr); /* Clear request latch. */ 4891da177e4SLinus Torvalds outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */ 4901da177e4SLinus Torvalds outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */ 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds tangent_wait_reset(ioaddr); 4931da177e4SLinus Torvalds outb(0, ioaddr+TANG_CLEAR_INT); 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds if(lp->board==DAYNA) 4961da177e4SLinus Torvalds { 4971da177e4SLinus Torvalds outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */ 4981da177e4SLinus Torvalds inb(ioaddr+DAYNA_RESET); /* Clear the reset */ 4991da177e4SLinus Torvalds if (sleep) 5007ab267d4SJeff Garzik msleep(333); 5011da177e4SLinus Torvalds else 5021da177e4SLinus Torvalds mdelay(333); 5031da177e4SLinus Torvalds } 5047ab267d4SJeff Garzik 5051da177e4SLinus Torvalds netif_wake_queue(dev); 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds static void cops_load (struct net_device *dev) 5091da177e4SLinus Torvalds { 5101da177e4SLinus Torvalds struct ifreq ifr; 5111da177e4SLinus Torvalds struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru; 5121da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 5131da177e4SLinus Torvalds int ioaddr=dev->base_addr; 5141da177e4SLinus Torvalds int length, i = 0; 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds strcpy(ifr.ifr_name,"lt0"); 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds /* Get card's firmware code and do some checks on it. */ 5191da177e4SLinus Torvalds #ifdef CONFIG_COPS_DAYNA 5201da177e4SLinus Torvalds if(lp->board==DAYNA) 5211da177e4SLinus Torvalds { 5221da177e4SLinus Torvalds ltf->length=sizeof(ffdrv_code); 5231da177e4SLinus Torvalds ltf->data=ffdrv_code; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds else 5261da177e4SLinus Torvalds #endif 5271da177e4SLinus Torvalds #ifdef CONFIG_COPS_TANGENT 5281da177e4SLinus Torvalds if(lp->board==TANGENT) 5291da177e4SLinus Torvalds { 5301da177e4SLinus Torvalds ltf->length=sizeof(ltdrv_code); 5311da177e4SLinus Torvalds ltf->data=ltdrv_code; 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds else 5341da177e4SLinus Torvalds #endif 5351da177e4SLinus Torvalds { 5361da177e4SLinus Torvalds printk(KERN_INFO "%s; unsupported board type.\n", dev->name); 5371da177e4SLinus Torvalds return; 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds /* Check to make sure firmware is correct length. */ 5411da177e4SLinus Torvalds if(lp->board==DAYNA && ltf->length!=5983) 5421da177e4SLinus Torvalds { 5431da177e4SLinus Torvalds printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name); 5441da177e4SLinus Torvalds return; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds if(lp->board==TANGENT && ltf->length!=2501) 5471da177e4SLinus Torvalds { 5481da177e4SLinus Torvalds printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name); 5491da177e4SLinus Torvalds return; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds if(lp->board==DAYNA) 5531da177e4SLinus Torvalds { 5541da177e4SLinus Torvalds /* 5551da177e4SLinus Torvalds * We must wait for a status response 5561da177e4SLinus Torvalds * with the DAYNA board. 5571da177e4SLinus Torvalds */ 5581da177e4SLinus Torvalds while(++i<65536) 5591da177e4SLinus Torvalds { 5601da177e4SLinus Torvalds if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1) 5611da177e4SLinus Torvalds break; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds if(i==65536) 5651da177e4SLinus Torvalds return; 5661da177e4SLinus Torvalds } 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* 5691da177e4SLinus Torvalds * Upload the firmware and kick. Byte-by-byte works nicely here. 5701da177e4SLinus Torvalds */ 5711da177e4SLinus Torvalds i=0; 5721da177e4SLinus Torvalds length = ltf->length; 5731da177e4SLinus Torvalds while(length--) 5741da177e4SLinus Torvalds { 5751da177e4SLinus Torvalds outb(ltf->data[i], ioaddr); 5761da177e4SLinus Torvalds i++; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds if(cops_debug > 1) 5801da177e4SLinus Torvalds printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 5811da177e4SLinus Torvalds dev->name, i, ltf->length); 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */ 5841da177e4SLinus Torvalds outb(1, ioaddr+DAYNA_INT_CARD); 5851da177e4SLinus Torvalds else /* Tell Tang to run the firmware code. */ 5861da177e4SLinus Torvalds inb(ioaddr); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds if(lp->board==TANGENT) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds tangent_wait_reset(ioaddr); 5911da177e4SLinus Torvalds inb(ioaddr); /* Clear initial ready signal. */ 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds return; 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 6761da177e4SLinus Torvalds static void cops_poll(unsigned long ltdev) 6771da177e4SLinus Torvalds { 6781da177e4SLinus Torvalds int ioaddr, status; 6791da177e4SLinus Torvalds int boguscount = 0; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds struct net_device *dev = (struct net_device *)ltdev; 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds del_timer(&cops_timer); 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds if(dev == NULL) 6861da177e4SLinus Torvalds return; /* We've been downed */ 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds ioaddr = dev->base_addr; 6891da177e4SLinus Torvalds do { 6901da177e4SLinus Torvalds status=inb(ioaddr+TANG_CARD_STATUS); 6911da177e4SLinus Torvalds if(status & TANG_RX_READY) 6921da177e4SLinus Torvalds cops_rx(dev); 6931da177e4SLinus Torvalds if(status & TANG_TX_READY) 6941da177e4SLinus Torvalds netif_wake_queue(dev); 6951da177e4SLinus Torvalds status = inb(ioaddr+TANG_CARD_STATUS); 6961da177e4SLinus Torvalds } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* poll 20 times per second */ 6991da177e4SLinus Torvalds cops_timer.expires = jiffies + HZ/20; 7001da177e4SLinus Torvalds add_timer(&cops_timer); 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds return; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds /* 7061da177e4SLinus Torvalds * The typical workload of the driver: 7071da177e4SLinus Torvalds * Handle the network interface interrupts. 7081da177e4SLinus Torvalds */ 7097d12e780SDavid Howells static irqreturn_t cops_interrupt(int irq, void *dev_id) 7101da177e4SLinus Torvalds { 7111da177e4SLinus Torvalds struct net_device *dev = dev_id; 7121da177e4SLinus Torvalds struct cops_local *lp; 7131da177e4SLinus Torvalds int ioaddr, status; 7141da177e4SLinus Torvalds int boguscount = 0; 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds ioaddr = dev->base_addr; 7171da177e4SLinus Torvalds lp = netdev_priv(dev); 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds if(lp->board==DAYNA) 7201da177e4SLinus Torvalds { 7211da177e4SLinus Torvalds do { 7221da177e4SLinus Torvalds outb(0, ioaddr + COPS_CLEAR_INT); 7231da177e4SLinus Torvalds status=inb(ioaddr+DAYNA_CARD_STATUS); 7241da177e4SLinus Torvalds if((status&0x03)==DAYNA_RX_REQUEST) 7251da177e4SLinus Torvalds cops_rx(dev); 7261da177e4SLinus Torvalds netif_wake_queue(dev); 7271da177e4SLinus Torvalds } while(++boguscount < 20); 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds else 7301da177e4SLinus Torvalds { 7311da177e4SLinus Torvalds do { 7321da177e4SLinus Torvalds status=inb(ioaddr+TANG_CARD_STATUS); 7331da177e4SLinus Torvalds if(status & TANG_RX_READY) 7341da177e4SLinus Torvalds cops_rx(dev); 7351da177e4SLinus Torvalds if(status & TANG_TX_READY) 7361da177e4SLinus Torvalds netif_wake_queue(dev); 7371da177e4SLinus Torvalds status=inb(ioaddr+TANG_CARD_STATUS); 7381da177e4SLinus Torvalds } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds return IRQ_HANDLED; 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds /* 7451da177e4SLinus Torvalds * We have a good packet(s), get it/them out of the buffers. 7461da177e4SLinus Torvalds */ 7471da177e4SLinus Torvalds static void cops_rx(struct net_device *dev) 7481da177e4SLinus Torvalds { 7491da177e4SLinus Torvalds int pkt_len = 0; 7501da177e4SLinus Torvalds int rsp_type = 0; 7511da177e4SLinus Torvalds struct sk_buff *skb = NULL; 7521da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 7531da177e4SLinus Torvalds int ioaddr = dev->base_addr; 7541da177e4SLinus Torvalds int boguscount = 0; 7551da177e4SLinus Torvalds unsigned long flags; 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds if(lp->board==DAYNA) 7611da177e4SLinus Torvalds { 7621da177e4SLinus Torvalds outb(0, ioaddr); /* Send out Zero length. */ 7631da177e4SLinus Torvalds outb(0, ioaddr); 7641da177e4SLinus Torvalds outb(DATA_READ, ioaddr); /* Send read command out. */ 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds /* Wait for DMA to turn around. */ 7671da177e4SLinus Torvalds while(++boguscount<1000000) 7681da177e4SLinus Torvalds { 7691da177e4SLinus Torvalds barrier(); 7701da177e4SLinus Torvalds if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) 7711da177e4SLinus Torvalds break; 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds if(boguscount==1000000) 7751da177e4SLinus Torvalds { 7761da177e4SLinus Torvalds printk(KERN_WARNING "%s: DMA timed out.\n",dev->name); 7771da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 7781da177e4SLinus Torvalds return; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds /* Get response length. */ 7831da177e4SLinus Torvalds if(lp->board==DAYNA) 7841da177e4SLinus Torvalds pkt_len = inb(ioaddr) & 0xFF; 7851da177e4SLinus Torvalds else 7861da177e4SLinus Torvalds pkt_len = inb(ioaddr) & 0x00FF; 7871da177e4SLinus Torvalds pkt_len |= (inb(ioaddr) << 8); 7881da177e4SLinus Torvalds /* Input IO code. */ 7891da177e4SLinus Torvalds rsp_type=inb(ioaddr); 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds /* Malloc up new buffer. */ 7921da177e4SLinus Torvalds skb = dev_alloc_skb(pkt_len); 7931da177e4SLinus Torvalds if(skb == NULL) 7941da177e4SLinus Torvalds { 7951da177e4SLinus Torvalds printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", 7961da177e4SLinus Torvalds dev->name); 7978bbce3f6SStephen Hemminger dev->stats.rx_dropped++; 7981da177e4SLinus Torvalds while(pkt_len--) /* Discard packet */ 7991da177e4SLinus Torvalds inb(ioaddr); 8001da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 8011da177e4SLinus Torvalds return; 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds skb->dev = dev; 8041da177e4SLinus Torvalds skb_put(skb, pkt_len); 8051da177e4SLinus Torvalds skb->protocol = htons(ETH_P_LOCALTALK); 8061da177e4SLinus Torvalds 8071da177e4SLinus Torvalds insb(ioaddr, skb->data, pkt_len); /* Eat the Data */ 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds if(lp->board==DAYNA) 8101da177e4SLinus Torvalds outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */ 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); /* Restore interrupts. */ 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds /* Check for bad response length */ 8151da177e4SLinus Torvalds if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) 8161da177e4SLinus Torvalds { 8171da177e4SLinus Torvalds printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 8181da177e4SLinus Torvalds dev->name, pkt_len); 8198bbce3f6SStephen Hemminger dev->stats.tx_errors++; 8201da177e4SLinus Torvalds dev_kfree_skb_any(skb); 8211da177e4SLinus Torvalds return; 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds /* Set nodeid and then get out. */ 8251da177e4SLinus Torvalds if(rsp_type == LAP_INIT_RSP) 8261da177e4SLinus Torvalds { /* Nodeid taken from received packet. */ 8271da177e4SLinus Torvalds lp->node_acquire = skb->data[0]; 8281da177e4SLinus Torvalds dev_kfree_skb_any(skb); 8291da177e4SLinus Torvalds return; 8301da177e4SLinus Torvalds } 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds /* One last check to make sure we have a good packet. */ 8331da177e4SLinus Torvalds if(rsp_type != LAP_RESPONSE) 8341da177e4SLinus Torvalds { 8351da177e4SLinus Torvalds printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); 8368bbce3f6SStephen Hemminger dev->stats.tx_errors++; 8371da177e4SLinus Torvalds dev_kfree_skb_any(skb); 8381da177e4SLinus Torvalds return; 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds 841459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb); /* Point to entire packet. */ 8421da177e4SLinus Torvalds skb_pull(skb,3); 843badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb); /* Point to data (Skip header). */ 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds /* Update the counters. */ 8468bbce3f6SStephen Hemminger dev->stats.rx_packets++; 8478bbce3f6SStephen Hemminger dev->stats.rx_bytes += skb->len; 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds /* Send packet to a higher place. */ 8501da177e4SLinus Torvalds netif_rx(skb); 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds static void cops_timeout(struct net_device *dev) 8541da177e4SLinus Torvalds { 8551da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 8561da177e4SLinus Torvalds int ioaddr = dev->base_addr; 8571da177e4SLinus Torvalds 8588bbce3f6SStephen Hemminger dev->stats.tx_errors++; 8591da177e4SLinus Torvalds if(lp->board==TANGENT) 8601da177e4SLinus Torvalds { 8611da177e4SLinus Torvalds if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) 8621da177e4SLinus Torvalds printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name); 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name); 8651da177e4SLinus Torvalds cops_jumpstart(dev); /* Restart the card. */ 8661da177e4SLinus Torvalds dev->trans_start = jiffies; 8671da177e4SLinus Torvalds netif_wake_queue(dev); 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds /* 8721da177e4SLinus Torvalds * Make the card transmit a LocalTalk packet. 8731da177e4SLinus Torvalds */ 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) 8761da177e4SLinus Torvalds { 8771da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 8781da177e4SLinus Torvalds int ioaddr = dev->base_addr; 8791da177e4SLinus Torvalds unsigned long flags; 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds /* 8821da177e4SLinus Torvalds * Block a timer-based transmit from overlapping. 8831da177e4SLinus Torvalds */ 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds netif_stop_queue(dev); 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 8881da177e4SLinus Torvalds if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */ 8891da177e4SLinus Torvalds while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) 8901da177e4SLinus Torvalds cpu_relax(); 8911da177e4SLinus Torvalds if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */ 8921da177e4SLinus Torvalds while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) 8931da177e4SLinus Torvalds cpu_relax(); 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds /* Output IO length. */ 8961da177e4SLinus Torvalds outb(skb->len, ioaddr); 8971da177e4SLinus Torvalds if(lp->board == DAYNA) 8981da177e4SLinus Torvalds outb(skb->len >> 8, ioaddr); 8991da177e4SLinus Torvalds else 9001da177e4SLinus Torvalds outb((skb->len >> 8)&0x0FF, ioaddr); 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds /* Output IO code. */ 9031da177e4SLinus Torvalds outb(LAP_WRITE, ioaddr); 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds if(lp->board == DAYNA) /* Check the transmit buffer again. */ 9061da177e4SLinus Torvalds while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds outsb(ioaddr, skb->data, skb->len); /* Send out the data. */ 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds if(lp->board==DAYNA) /* Dayna requires you kick the card */ 9111da177e4SLinus Torvalds outb(1, ioaddr+DAYNA_INT_CARD); 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); /* Restore interrupts. */ 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds /* Done sending packet, update counters and cleanup. */ 9168bbce3f6SStephen Hemminger dev->stats.tx_packets++; 9178bbce3f6SStephen Hemminger dev->stats.tx_bytes += skb->len; 9181da177e4SLinus Torvalds dev->trans_start = jiffies; 9191da177e4SLinus Torvalds dev_kfree_skb (skb); 9201da177e4SLinus Torvalds return 0; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds /* 9241da177e4SLinus Torvalds * Dummy function to keep the Appletalk layer happy. 9251da177e4SLinus Torvalds */ 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds static void set_multicast_list(struct net_device *dev) 9281da177e4SLinus Torvalds { 9291da177e4SLinus Torvalds if(cops_debug >= 3) 9301da177e4SLinus Torvalds printk("%s: set_multicast_list executed\n", dev->name); 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds /* 9341da177e4SLinus Torvalds * System ioctls for the COPS LocalTalk card. 9351da177e4SLinus Torvalds */ 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 9381da177e4SLinus Torvalds { 9391da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 9401da177e4SLinus Torvalds struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr; 9411da177e4SLinus Torvalds struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr; 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds switch(cmd) 9441da177e4SLinus Torvalds { 9451da177e4SLinus Torvalds case SIOCSIFADDR: 9461da177e4SLinus Torvalds /* Get and set the nodeid and network # atalkd wants. */ 9471da177e4SLinus Torvalds cops_nodeid(dev, sa->sat_addr.s_node); 9481da177e4SLinus Torvalds aa->s_net = sa->sat_addr.s_net; 9491da177e4SLinus Torvalds aa->s_node = lp->node_acquire; 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds /* Set broardcast address. */ 9521da177e4SLinus Torvalds dev->broadcast[0] = 0xFF; 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds /* Set hardware address. */ 9551da177e4SLinus Torvalds dev->dev_addr[0] = aa->s_node; 9561da177e4SLinus Torvalds dev->addr_len = 1; 9571da177e4SLinus Torvalds return 0; 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds case SIOCGIFADDR: 9601da177e4SLinus Torvalds sa->sat_addr.s_net = aa->s_net; 9611da177e4SLinus Torvalds sa->sat_addr.s_node = aa->s_node; 9621da177e4SLinus Torvalds return 0; 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds default: 9651da177e4SLinus Torvalds return -EOPNOTSUPP; 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds } 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds /* 9701da177e4SLinus Torvalds * The inverse routine to cops_open(). 9711da177e4SLinus Torvalds */ 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds static int cops_close(struct net_device *dev) 9741da177e4SLinus Torvalds { 9751da177e4SLinus Torvalds struct cops_local *lp = netdev_priv(dev); 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds /* If we were running polled, yank the timer. 9781da177e4SLinus Torvalds */ 9791da177e4SLinus Torvalds if(lp->board==TANGENT && dev->irq==0) 9801da177e4SLinus Torvalds del_timer(&cops_timer); 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds netif_stop_queue(dev); 9831da177e4SLinus Torvalds return 0; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds #ifdef MODULE 9881da177e4SLinus Torvalds static struct net_device *cops_dev; 9891da177e4SLinus Torvalds 9901da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 9911da177e4SLinus Torvalds module_param(io, int, 0); 9921da177e4SLinus Torvalds module_param(irq, int, 0); 9931da177e4SLinus Torvalds module_param(board_type, int, 0); 9941da177e4SLinus Torvalds 995b32dac08SJon Schindler static int __init cops_module_init(void) 9961da177e4SLinus Torvalds { 9971da177e4SLinus Torvalds if (io == 0) 9981da177e4SLinus Torvalds printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", 9991da177e4SLinus Torvalds cardname); 10001da177e4SLinus Torvalds cops_dev = cops_probe(-1); 10011da177e4SLinus Torvalds if (IS_ERR(cops_dev)) 10021da177e4SLinus Torvalds return PTR_ERR(cops_dev); 10031da177e4SLinus Torvalds return 0; 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds 1006b32dac08SJon Schindler static void __exit cops_module_exit(void) 10071da177e4SLinus Torvalds { 10081da177e4SLinus Torvalds unregister_netdev(cops_dev); 10091da177e4SLinus Torvalds cleanup_card(cops_dev); 10101da177e4SLinus Torvalds free_netdev(cops_dev); 10111da177e4SLinus Torvalds } 1012b32dac08SJon Schindler module_init(cops_module_init); 1013b32dac08SJon Schindler module_exit(cops_module_exit); 10141da177e4SLinus Torvalds #endif /* MODULE */ 1015