18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers) 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Written 1994-1999 by Avery Pennarun. 58c2ecf20Sopenharmony_ci * Written 1999 by Martin Mares <mj@ucw.cz>. 68c2ecf20Sopenharmony_ci * Derived from skeleton.c by Donald Becker. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) 98c2ecf20Sopenharmony_ci * for sponsoring the further development of this driver. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * ********************** 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * The original copyright of skeleton.c was as follows: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * skeleton.c Written 1993 by Donald Becker. 168c2ecf20Sopenharmony_ci * Copyright 1993 United States Government as represented by the 178c2ecf20Sopenharmony_ci * Director, National Security Agency. This software may only be used 188c2ecf20Sopenharmony_ci * and distributed according to the terms of the GNU General Public License as 198c2ecf20Sopenharmony_ci * modified by SRC, incorporated herein by reference. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * ********************** 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * For more details, see drivers/net/arcnet.c 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * ********************** 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 328c2ecf20Sopenharmony_ci#include <linux/init.h> 338c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 348c2ecf20Sopenharmony_ci#include <linux/ioport.h> 358c2ecf20Sopenharmony_ci#include <linux/delay.h> 368c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/io.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "arcdevice.h" 418c2ecf20Sopenharmony_ci#include "com9026.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Define this to speed up the autoprobe by assuming if only one io port and 448c2ecf20Sopenharmony_ci * shmem are left in the list at Stage 5, they must correspond to each 458c2ecf20Sopenharmony_ci * other. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * This is undefined by default because it might not always be true, and the 488c2ecf20Sopenharmony_ci * extra check makes the autoprobe even more careful. Speed demons can turn 498c2ecf20Sopenharmony_ci * it on - I think it should be fine if you only have one ARCnet card 508c2ecf20Sopenharmony_ci * installed. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * If no ARCnet cards are installed, this delay never happens anyway and thus 538c2ecf20Sopenharmony_ci * the option has no effect. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci#undef FAST_PROBE 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Internal function declarations */ 588c2ecf20Sopenharmony_cistatic int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *); 598c2ecf20Sopenharmony_cistatic void com90xx_command(struct net_device *dev, int command); 608c2ecf20Sopenharmony_cistatic int com90xx_status(struct net_device *dev); 618c2ecf20Sopenharmony_cistatic void com90xx_setmask(struct net_device *dev, int mask); 628c2ecf20Sopenharmony_cistatic int com90xx_reset(struct net_device *dev, int really_reset); 638c2ecf20Sopenharmony_cistatic void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, 648c2ecf20Sopenharmony_ci void *buf, int count); 658c2ecf20Sopenharmony_cistatic void com90xx_copy_from_card(struct net_device *dev, int bufnum, 668c2ecf20Sopenharmony_ci int offset, void *buf, int count); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Known ARCnet cards */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic struct net_device *cards[16]; 718c2ecf20Sopenharmony_cistatic int numcards; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Handy defines for ARCnet specific stuff */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* The number of low I/O ports used by the card */ 768c2ecf20Sopenharmony_ci#define ARCNET_TOTAL_SIZE 16 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Amount of I/O memory used by the card */ 798c2ecf20Sopenharmony_ci#define BUFFER_SIZE (512) 808c2ecf20Sopenharmony_ci#define MIRROR_SIZE (BUFFER_SIZE * 4) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int com90xx_skip_probe __initdata = 0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Module parameters */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int io; /* use the insmod io= irq= shmem= options */ 878c2ecf20Sopenharmony_cistatic int irq; 888c2ecf20Sopenharmony_cistatic int shmem; 898c2ecf20Sopenharmony_cistatic char device[9]; /* use eg. device=arc1 to change name */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cimodule_param_hw(io, int, ioport, 0); 928c2ecf20Sopenharmony_cimodule_param_hw(irq, int, irq, 0); 938c2ecf20Sopenharmony_cimodule_param(shmem, int, 0); 948c2ecf20Sopenharmony_cimodule_param_string(device, device, sizeof(device), 0); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void __init com90xx_probe(void) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci int count, status, ioaddr, numprint, airq, openparen = 0; 998c2ecf20Sopenharmony_ci unsigned long airqmask; 1008c2ecf20Sopenharmony_ci int ports[(0x3f0 - 0x200) / 16 + 1] = { 0 }; 1018c2ecf20Sopenharmony_ci unsigned long *shmems; 1028c2ecf20Sopenharmony_ci void __iomem **iomem; 1038c2ecf20Sopenharmony_ci int numports, numshmems, *port; 1048c2ecf20Sopenharmony_ci u_long *p; 1058c2ecf20Sopenharmony_ci int index; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (!io && !irq && !shmem && !*device && com90xx_skip_probe) 1088c2ecf20Sopenharmony_ci return; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci shmems = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(unsigned long), 1118c2ecf20Sopenharmony_ci GFP_KERNEL); 1128c2ecf20Sopenharmony_ci if (!shmems) 1138c2ecf20Sopenharmony_ci return; 1148c2ecf20Sopenharmony_ci iomem = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(void __iomem *), 1158c2ecf20Sopenharmony_ci GFP_KERNEL); 1168c2ecf20Sopenharmony_ci if (!iomem) { 1178c2ecf20Sopenharmony_ci kfree(shmems); 1188c2ecf20Sopenharmony_ci return; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (BUGLVL(D_NORMAL)) 1228c2ecf20Sopenharmony_ci pr_info("%s\n", "COM90xx chipset support"); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* set up the arrays where we'll store the possible probe addresses */ 1258c2ecf20Sopenharmony_ci numports = numshmems = 0; 1268c2ecf20Sopenharmony_ci if (io) 1278c2ecf20Sopenharmony_ci ports[numports++] = io; 1288c2ecf20Sopenharmony_ci else 1298c2ecf20Sopenharmony_ci for (count = 0x200; count <= 0x3f0; count += 16) 1308c2ecf20Sopenharmony_ci ports[numports++] = count; 1318c2ecf20Sopenharmony_ci if (shmem) 1328c2ecf20Sopenharmony_ci shmems[numshmems++] = shmem; 1338c2ecf20Sopenharmony_ci else 1348c2ecf20Sopenharmony_ci for (count = 0xA0000; count <= 0xFF800; count += 2048) 1358c2ecf20Sopenharmony_ci shmems[numshmems++] = count; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Stage 1: abandon any reserved ports, or ones with status==0xFF 1388c2ecf20Sopenharmony_ci * (empty), and reset any others by reading the reset port. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci numprint = -1; 1418c2ecf20Sopenharmony_ci for (port = &ports[0]; port - ports < numports; port++) { 1428c2ecf20Sopenharmony_ci numprint++; 1438c2ecf20Sopenharmony_ci numprint %= 8; 1448c2ecf20Sopenharmony_ci if (!numprint) { 1458c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 1468c2ecf20Sopenharmony_ci arc_cont(D_INIT, "S1: "); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci arc_cont(D_INIT, "%Xh ", *port); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci ioaddr = *port; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (!request_region(*port, ARCNET_TOTAL_SIZE, 1538c2ecf20Sopenharmony_ci "arcnet (90xx)")) { 1548c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(request_region)\n"); 1558c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S1: "); 1568c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 1578c2ecf20Sopenharmony_ci numprint = 0; 1588c2ecf20Sopenharmony_ci *port-- = ports[--numports]; 1598c2ecf20Sopenharmony_ci continue; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) { 1628c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(empty)\n"); 1638c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S1: "); 1648c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 1658c2ecf20Sopenharmony_ci numprint = 0; 1668c2ecf20Sopenharmony_ci release_region(*port, ARCNET_TOTAL_SIZE); 1678c2ecf20Sopenharmony_ci *port-- = ports[--numports]; 1688c2ecf20Sopenharmony_ci continue; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci /* begin resetting card */ 1718c2ecf20Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_RESET); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "\n"); 1748c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S1: "); 1758c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 1768c2ecf20Sopenharmony_ci numprint = 0; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (!numports) { 1818c2ecf20Sopenharmony_ci arc_cont(D_NORMAL, "S1: No ARCnet cards found.\n"); 1828c2ecf20Sopenharmony_ci kfree(shmems); 1838c2ecf20Sopenharmony_ci kfree(iomem); 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci /* Stage 2: we have now reset any possible ARCnet cards, so we can't 1878c2ecf20Sopenharmony_ci * do anything until they finish. If D_INIT, print the list of 1888c2ecf20Sopenharmony_ci * cards that are left. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci numprint = -1; 1918c2ecf20Sopenharmony_ci for (port = &ports[0]; port < ports + numports; port++) { 1928c2ecf20Sopenharmony_ci numprint++; 1938c2ecf20Sopenharmony_ci numprint %= 8; 1948c2ecf20Sopenharmony_ci if (!numprint) { 1958c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 1968c2ecf20Sopenharmony_ci arc_cont(D_INIT, "S2: "); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci arc_cont(D_INIT, "%Xh ", *port); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 2018c2ecf20Sopenharmony_ci mdelay(RESETtime); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Stage 3: abandon any shmem addresses that don't have the signature 2048c2ecf20Sopenharmony_ci * 0xD1 byte in the right place, or are read-only. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci numprint = -1; 2078c2ecf20Sopenharmony_ci for (index = 0, p = &shmems[0]; index < numshmems; p++, index++) { 2088c2ecf20Sopenharmony_ci void __iomem *base; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci numprint++; 2118c2ecf20Sopenharmony_ci numprint %= 8; 2128c2ecf20Sopenharmony_ci if (!numprint) { 2138c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 2148c2ecf20Sopenharmony_ci arc_cont(D_INIT, "S3: "); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci arc_cont(D_INIT, "%lXh ", *p); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) { 2198c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(request_mem_region)\n"); 2208c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "Stage 3: "); 2218c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 2228c2ecf20Sopenharmony_ci numprint = 0; 2238c2ecf20Sopenharmony_ci goto out; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci base = ioremap(*p, MIRROR_SIZE); 2268c2ecf20Sopenharmony_ci if (!base) { 2278c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(ioremap)\n"); 2288c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "Stage 3: "); 2298c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 2308c2ecf20Sopenharmony_ci numprint = 0; 2318c2ecf20Sopenharmony_ci goto out1; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci if (arcnet_readb(base, COM9026_REG_R_STATUS) != TESTvalue) { 2348c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(%02Xh != %02Xh)\n", 2358c2ecf20Sopenharmony_ci arcnet_readb(base, COM9026_REG_R_STATUS), 2368c2ecf20Sopenharmony_ci TESTvalue); 2378c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S3: "); 2388c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 2398c2ecf20Sopenharmony_ci numprint = 0; 2408c2ecf20Sopenharmony_ci goto out2; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci /* By writing 0x42 to the TESTvalue location, we also make 2438c2ecf20Sopenharmony_ci * sure no "mirror" shmem areas show up - if they occur 2448c2ecf20Sopenharmony_ci * in another pass through this loop, they will be discarded 2458c2ecf20Sopenharmony_ci * because *cptr != TESTvalue. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci arcnet_writeb(0x42, base, COM9026_REG_W_INTMASK); 2488c2ecf20Sopenharmony_ci if (arcnet_readb(base, COM9026_REG_R_STATUS) != 0x42) { 2498c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(read only)\n"); 2508c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S3: "); 2518c2ecf20Sopenharmony_ci goto out2; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "\n"); 2548c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S3: "); 2558c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 2568c2ecf20Sopenharmony_ci numprint = 0; 2578c2ecf20Sopenharmony_ci iomem[index] = base; 2588c2ecf20Sopenharmony_ci continue; 2598c2ecf20Sopenharmony_ci out2: 2608c2ecf20Sopenharmony_ci iounmap(base); 2618c2ecf20Sopenharmony_ci out1: 2628c2ecf20Sopenharmony_ci release_mem_region(*p, MIRROR_SIZE); 2638c2ecf20Sopenharmony_ci out: 2648c2ecf20Sopenharmony_ci *p-- = shmems[--numshmems]; 2658c2ecf20Sopenharmony_ci index--; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (!numshmems) { 2708c2ecf20Sopenharmony_ci arc_cont(D_NORMAL, "S3: No ARCnet cards found.\n"); 2718c2ecf20Sopenharmony_ci for (port = &ports[0]; port < ports + numports; port++) 2728c2ecf20Sopenharmony_ci release_region(*port, ARCNET_TOTAL_SIZE); 2738c2ecf20Sopenharmony_ci kfree(shmems); 2748c2ecf20Sopenharmony_ci kfree(iomem); 2758c2ecf20Sopenharmony_ci return; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci /* Stage 4: something of a dummy, to report the shmems that are 2788c2ecf20Sopenharmony_ci * still possible after stage 3. 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci numprint = -1; 2818c2ecf20Sopenharmony_ci for (p = &shmems[0]; p < shmems + numshmems; p++) { 2828c2ecf20Sopenharmony_ci numprint++; 2838c2ecf20Sopenharmony_ci numprint %= 8; 2848c2ecf20Sopenharmony_ci if (!numprint) { 2858c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 2868c2ecf20Sopenharmony_ci arc_cont(D_INIT, "S4: "); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci arc_cont(D_INIT, "%lXh ", *p); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Stage 5: for any ports that have the correct status, can disable 2938c2ecf20Sopenharmony_ci * the RESET flag, and (if no irq is given) generate an autoirq, 2948c2ecf20Sopenharmony_ci * register an ARCnet device. 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * Currently, we can only register one device per probe, so quit 2978c2ecf20Sopenharmony_ci * after the first one is found. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci numprint = -1; 3008c2ecf20Sopenharmony_ci for (port = &ports[0]; port < ports + numports; port++) { 3018c2ecf20Sopenharmony_ci int found = 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci numprint++; 3048c2ecf20Sopenharmony_ci numprint %= 8; 3058c2ecf20Sopenharmony_ci if (!numprint) { 3068c2ecf20Sopenharmony_ci arc_cont(D_INIT, "\n"); 3078c2ecf20Sopenharmony_ci arc_cont(D_INIT, "S5: "); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci arc_cont(D_INIT, "%Xh ", *port); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ioaddr = *port; 3128c2ecf20Sopenharmony_ci status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if ((status & 0x9D) 3158c2ecf20Sopenharmony_ci != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { 3168c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(status=%Xh)\n", status); 3178c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S5: "); 3188c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 3198c2ecf20Sopenharmony_ci numprint = 0; 3208c2ecf20Sopenharmony_ci release_region(*port, ARCNET_TOTAL_SIZE); 3218c2ecf20Sopenharmony_ci *port-- = ports[--numports]; 3228c2ecf20Sopenharmony_ci continue; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear, 3258c2ecf20Sopenharmony_ci ioaddr, COM9026_REG_W_COMMAND); 3268c2ecf20Sopenharmony_ci status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 3278c2ecf20Sopenharmony_ci if (status & RESETflag) { 3288c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", 3298c2ecf20Sopenharmony_ci status); 3308c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S5: "); 3318c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 3328c2ecf20Sopenharmony_ci numprint = 0; 3338c2ecf20Sopenharmony_ci release_region(*port, ARCNET_TOTAL_SIZE); 3348c2ecf20Sopenharmony_ci *port-- = ports[--numports]; 3358c2ecf20Sopenharmony_ci continue; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci /* skip this completely if an IRQ was given, because maybe 3388c2ecf20Sopenharmony_ci * we're on a machine that locks during autoirq! 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci if (!irq) { 3418c2ecf20Sopenharmony_ci /* if we do this, we're sure to get an IRQ since the 3428c2ecf20Sopenharmony_ci * card has just reset and the NORXflag is on until 3438c2ecf20Sopenharmony_ci * we tell it to start receiving. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci airqmask = probe_irq_on(); 3468c2ecf20Sopenharmony_ci arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK); 3478c2ecf20Sopenharmony_ci udelay(1); 3488c2ecf20Sopenharmony_ci arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK); 3498c2ecf20Sopenharmony_ci airq = probe_irq_off(airqmask); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (airq <= 0) { 3528c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "(airq=%d)\n", airq); 3538c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "S5: "); 3548c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 3558c2ecf20Sopenharmony_ci numprint = 0; 3568c2ecf20Sopenharmony_ci release_region(*port, ARCNET_TOTAL_SIZE); 3578c2ecf20Sopenharmony_ci *port-- = ports[--numports]; 3588c2ecf20Sopenharmony_ci continue; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } else { 3618c2ecf20Sopenharmony_ci airq = irq; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci arc_cont(D_INIT, "(%d,", airq); 3658c2ecf20Sopenharmony_ci openparen = 1; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Everything seems okay. But which shmem, if any, puts 3688c2ecf20Sopenharmony_ci * back its signature byte when the card is reset? 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * If there are multiple cards installed, there might be 3718c2ecf20Sopenharmony_ci * multiple shmems still in the list. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci#ifdef FAST_PROBE 3748c2ecf20Sopenharmony_ci if (numports > 1 || numshmems > 1) { 3758c2ecf20Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_RESET); 3768c2ecf20Sopenharmony_ci mdelay(RESETtime); 3778c2ecf20Sopenharmony_ci } else { 3788c2ecf20Sopenharmony_ci /* just one shmem and port, assume they match */ 3798c2ecf20Sopenharmony_ci arcnet_writeb(TESTvalue, iomem[0], 3808c2ecf20Sopenharmony_ci COM9026_REG_W_INTMASK); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci#else 3838c2ecf20Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_RESET); 3848c2ecf20Sopenharmony_ci mdelay(RESETtime); 3858c2ecf20Sopenharmony_ci#endif 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci for (index = 0; index < numshmems; index++) { 3888c2ecf20Sopenharmony_ci u_long ptr = shmems[index]; 3898c2ecf20Sopenharmony_ci void __iomem *base = iomem[index]; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (arcnet_readb(base, COM9026_REG_R_STATUS) == TESTvalue) { /* found one */ 3928c2ecf20Sopenharmony_ci arc_cont(D_INIT, "%lXh)\n", *p); 3938c2ecf20Sopenharmony_ci openparen = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* register the card */ 3968c2ecf20Sopenharmony_ci if (com90xx_found(*port, airq, ptr, base) == 0) 3978c2ecf20Sopenharmony_ci found = 1; 3988c2ecf20Sopenharmony_ci numprint = -1; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* remove shmem from the list */ 4018c2ecf20Sopenharmony_ci shmems[index] = shmems[--numshmems]; 4028c2ecf20Sopenharmony_ci iomem[index] = iomem[numshmems]; 4038c2ecf20Sopenharmony_ci break; /* go to the next I/O port */ 4048c2ecf20Sopenharmony_ci } else { 4058c2ecf20Sopenharmony_ci arc_cont(D_INIT_REASONS, "%Xh-", 4068c2ecf20Sopenharmony_ci arcnet_readb(base, COM9026_REG_R_STATUS)); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (openparen) { 4118c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT)) 4128c2ecf20Sopenharmony_ci pr_cont("no matching shmem)\n"); 4138c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) { 4148c2ecf20Sopenharmony_ci pr_cont("S5: "); 4158c2ecf20Sopenharmony_ci numprint = 0; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci if (!found) 4198c2ecf20Sopenharmony_ci release_region(*port, ARCNET_TOTAL_SIZE); 4208c2ecf20Sopenharmony_ci *port-- = ports[--numports]; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (BUGLVL(D_INIT_REASONS)) 4248c2ecf20Sopenharmony_ci pr_cont("\n"); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Now put back TESTvalue on all leftover shmems. */ 4278c2ecf20Sopenharmony_ci for (index = 0; index < numshmems; index++) { 4288c2ecf20Sopenharmony_ci arcnet_writeb(TESTvalue, iomem[index], COM9026_REG_W_INTMASK); 4298c2ecf20Sopenharmony_ci iounmap(iomem[index]); 4308c2ecf20Sopenharmony_ci release_mem_region(shmems[index], MIRROR_SIZE); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci kfree(shmems); 4338c2ecf20Sopenharmony_ci kfree(iomem); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int __init check_mirror(unsigned long addr, size_t size) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci void __iomem *p; 4398c2ecf20Sopenharmony_ci int res = -1; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (!request_mem_region(addr, size, "arcnet (90xx)")) 4428c2ecf20Sopenharmony_ci return -1; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci p = ioremap(addr, size); 4458c2ecf20Sopenharmony_ci if (p) { 4468c2ecf20Sopenharmony_ci if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue) 4478c2ecf20Sopenharmony_ci res = 1; 4488c2ecf20Sopenharmony_ci else 4498c2ecf20Sopenharmony_ci res = 0; 4508c2ecf20Sopenharmony_ci iounmap(p); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci release_mem_region(addr, size); 4548c2ecf20Sopenharmony_ci return res; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci/* Set up the struct net_device associated with this card. Called after 4588c2ecf20Sopenharmony_ci * probing succeeds. 4598c2ecf20Sopenharmony_ci */ 4608c2ecf20Sopenharmony_cistatic int __init com90xx_found(int ioaddr, int airq, u_long shmem, 4618c2ecf20Sopenharmony_ci void __iomem *p) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 4648c2ecf20Sopenharmony_ci struct arcnet_local *lp; 4658c2ecf20Sopenharmony_ci u_long first_mirror, last_mirror; 4668c2ecf20Sopenharmony_ci int mirror_size; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* allocate struct net_device */ 4698c2ecf20Sopenharmony_ci dev = alloc_arcdev(device); 4708c2ecf20Sopenharmony_ci if (!dev) { 4718c2ecf20Sopenharmony_ci arc_cont(D_NORMAL, "com90xx: Can't allocate device!\n"); 4728c2ecf20Sopenharmony_ci iounmap(p); 4738c2ecf20Sopenharmony_ci release_mem_region(shmem, MIRROR_SIZE); 4748c2ecf20Sopenharmony_ci return -ENOMEM; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci lp = netdev_priv(dev); 4778c2ecf20Sopenharmony_ci /* find the real shared memory start/end points, including mirrors */ 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* guess the actual size of one "memory mirror" - the number of 4808c2ecf20Sopenharmony_ci * bytes between copies of the shared memory. On most cards, it's 4818c2ecf20Sopenharmony_ci * 2k (or there are no mirrors at all) but on some, it's 4k. 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_ci mirror_size = MIRROR_SIZE; 4848c2ecf20Sopenharmony_ci if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue && 4858c2ecf20Sopenharmony_ci check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 && 4868c2ecf20Sopenharmony_ci check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1) 4878c2ecf20Sopenharmony_ci mirror_size = 2 * MIRROR_SIZE; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci first_mirror = shmem - mirror_size; 4908c2ecf20Sopenharmony_ci while (check_mirror(first_mirror, mirror_size) == 1) 4918c2ecf20Sopenharmony_ci first_mirror -= mirror_size; 4928c2ecf20Sopenharmony_ci first_mirror += mirror_size; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci last_mirror = shmem + mirror_size; 4958c2ecf20Sopenharmony_ci while (check_mirror(last_mirror, mirror_size) == 1) 4968c2ecf20Sopenharmony_ci last_mirror += mirror_size; 4978c2ecf20Sopenharmony_ci last_mirror -= mirror_size; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci dev->mem_start = first_mirror; 5008c2ecf20Sopenharmony_ci dev->mem_end = last_mirror + MIRROR_SIZE - 1; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci iounmap(p); 5038c2ecf20Sopenharmony_ci release_mem_region(shmem, MIRROR_SIZE); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (!request_mem_region(dev->mem_start, 5068c2ecf20Sopenharmony_ci dev->mem_end - dev->mem_start + 1, 5078c2ecf20Sopenharmony_ci "arcnet (90xx)")) 5088c2ecf20Sopenharmony_ci goto err_free_dev; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* reserve the irq */ 5118c2ecf20Sopenharmony_ci if (request_irq(airq, arcnet_interrupt, 0, "arcnet (90xx)", dev)) { 5128c2ecf20Sopenharmony_ci arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", airq); 5138c2ecf20Sopenharmony_ci goto err_release_mem; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci dev->irq = airq; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Initialize the rest of the device structure. */ 5188c2ecf20Sopenharmony_ci lp->card_name = "COM90xx"; 5198c2ecf20Sopenharmony_ci lp->hw.command = com90xx_command; 5208c2ecf20Sopenharmony_ci lp->hw.status = com90xx_status; 5218c2ecf20Sopenharmony_ci lp->hw.intmask = com90xx_setmask; 5228c2ecf20Sopenharmony_ci lp->hw.reset = com90xx_reset; 5238c2ecf20Sopenharmony_ci lp->hw.owner = THIS_MODULE; 5248c2ecf20Sopenharmony_ci lp->hw.copy_to_card = com90xx_copy_to_card; 5258c2ecf20Sopenharmony_ci lp->hw.copy_from_card = com90xx_copy_from_card; 5268c2ecf20Sopenharmony_ci lp->mem_start = ioremap(dev->mem_start, 5278c2ecf20Sopenharmony_ci dev->mem_end - dev->mem_start + 1); 5288c2ecf20Sopenharmony_ci if (!lp->mem_start) { 5298c2ecf20Sopenharmony_ci arc_printk(D_NORMAL, dev, "Can't remap device memory!\n"); 5308c2ecf20Sopenharmony_ci goto err_free_irq; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* get and check the station ID from offset 1 in shmem */ 5348c2ecf20Sopenharmony_ci dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci dev->base_addr = ioaddr; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci arc_printk(D_NORMAL, dev, "COM90xx station %02Xh found at %03lXh, IRQ %d, ShMem %lXh (%ld*%xh).\n", 5398c2ecf20Sopenharmony_ci dev->dev_addr[0], 5408c2ecf20Sopenharmony_ci dev->base_addr, dev->irq, dev->mem_start, 5418c2ecf20Sopenharmony_ci (dev->mem_end - dev->mem_start + 1) / mirror_size, 5428c2ecf20Sopenharmony_ci mirror_size); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (register_netdev(dev)) 5458c2ecf20Sopenharmony_ci goto err_unmap; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci cards[numcards++] = dev; 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cierr_unmap: 5518c2ecf20Sopenharmony_ci iounmap(lp->mem_start); 5528c2ecf20Sopenharmony_cierr_free_irq: 5538c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 5548c2ecf20Sopenharmony_cierr_release_mem: 5558c2ecf20Sopenharmony_ci release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); 5568c2ecf20Sopenharmony_cierr_free_dev: 5578c2ecf20Sopenharmony_ci free_arcdev(dev); 5588c2ecf20Sopenharmony_ci return -EIO; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic void com90xx_command(struct net_device *dev, int cmd) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci short ioaddr = dev->base_addr; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int com90xx_status(struct net_device *dev) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci short ioaddr = dev->base_addr; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic void com90xx_setmask(struct net_device *dev, int mask) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci short ioaddr = dev->base_addr; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/* Do a hardware reset on the card, and set up necessary registers. 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci * This should be called as little as possible, because it disrupts the 5858c2ecf20Sopenharmony_ci * token on the network (causes a RECON) and requires a significant delay. 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * However, it does make sure the card is in a defined state. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_cistatic int com90xx_reset(struct net_device *dev, int really_reset) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct arcnet_local *lp = netdev_priv(dev); 5928c2ecf20Sopenharmony_ci short ioaddr = dev->base_addr; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci arc_printk(D_INIT, dev, "Resetting (status=%02Xh)\n", 5958c2ecf20Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_STATUS)); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (really_reset) { 5988c2ecf20Sopenharmony_ci /* reset the card */ 5998c2ecf20Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_RESET); 6008c2ecf20Sopenharmony_ci mdelay(RESETtime); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci /* clear flags & end reset */ 6038c2ecf20Sopenharmony_ci arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND); 6048c2ecf20Sopenharmony_ci arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci#if 0 6078c2ecf20Sopenharmony_ci /* don't do this until we verify that it doesn't hurt older cards! */ 6088c2ecf20Sopenharmony_ci arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) | ENABLE16flag, 6098c2ecf20Sopenharmony_ci ioaddr, COM9026_REG_RW_CONFIG); 6108c2ecf20Sopenharmony_ci#endif 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* verify that the ARCnet signature byte is present */ 6138c2ecf20Sopenharmony_ci if (arcnet_readb(lp->mem_start, COM9026_REG_R_STATUS) != TESTvalue) { 6148c2ecf20Sopenharmony_ci if (really_reset) 6158c2ecf20Sopenharmony_ci arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n"); 6168c2ecf20Sopenharmony_ci return 1; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci /* enable extended (512-byte) packets */ 6198c2ecf20Sopenharmony_ci arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* clean out all the memory to make debugging make more sense :) */ 6228c2ecf20Sopenharmony_ci if (BUGLVL(D_DURING)) 6238c2ecf20Sopenharmony_ci memset_io(lp->mem_start, 0x42, 2048); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* done! return success. */ 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic void com90xx_copy_to_card(struct net_device *dev, int bufnum, 6308c2ecf20Sopenharmony_ci int offset, void *buf, int count) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct arcnet_local *lp = netdev_priv(dev); 6338c2ecf20Sopenharmony_ci void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count)); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic void com90xx_copy_from_card(struct net_device *dev, int bufnum, 6398c2ecf20Sopenharmony_ci int offset, void *buf, int count) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct arcnet_local *lp = netdev_priv(dev); 6428c2ecf20Sopenharmony_ci void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int __init com90xx_init(void) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci if (irq == 2) 6528c2ecf20Sopenharmony_ci irq = 9; 6538c2ecf20Sopenharmony_ci com90xx_probe(); 6548c2ecf20Sopenharmony_ci if (!numcards) 6558c2ecf20Sopenharmony_ci return -EIO; 6568c2ecf20Sopenharmony_ci return 0; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic void __exit com90xx_exit(void) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct net_device *dev; 6628c2ecf20Sopenharmony_ci struct arcnet_local *lp; 6638c2ecf20Sopenharmony_ci int count; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci for (count = 0; count < numcards; count++) { 6668c2ecf20Sopenharmony_ci dev = cards[count]; 6678c2ecf20Sopenharmony_ci lp = netdev_priv(dev); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci unregister_netdev(dev); 6708c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 6718c2ecf20Sopenharmony_ci iounmap(lp->mem_start); 6728c2ecf20Sopenharmony_ci release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 6738c2ecf20Sopenharmony_ci release_mem_region(dev->mem_start, 6748c2ecf20Sopenharmony_ci dev->mem_end - dev->mem_start + 1); 6758c2ecf20Sopenharmony_ci free_arcdev(dev); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cimodule_init(com90xx_init); 6808c2ecf20Sopenharmony_cimodule_exit(com90xx_exit); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci#ifndef MODULE 6838c2ecf20Sopenharmony_cistatic int __init com90xx_setup(char *s) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci int ints[8]; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci s = get_options(s, 8, ints); 6888c2ecf20Sopenharmony_ci if (!ints[0] && !*s) { 6898c2ecf20Sopenharmony_ci pr_notice("Disabled\n"); 6908c2ecf20Sopenharmony_ci return 1; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci switch (ints[0]) { 6948c2ecf20Sopenharmony_ci default: /* ERROR */ 6958c2ecf20Sopenharmony_ci pr_err("Too many arguments\n"); 6968c2ecf20Sopenharmony_ci fallthrough; 6978c2ecf20Sopenharmony_ci case 3: /* Mem address */ 6988c2ecf20Sopenharmony_ci shmem = ints[3]; 6998c2ecf20Sopenharmony_ci fallthrough; 7008c2ecf20Sopenharmony_ci case 2: /* IRQ */ 7018c2ecf20Sopenharmony_ci irq = ints[2]; 7028c2ecf20Sopenharmony_ci fallthrough; 7038c2ecf20Sopenharmony_ci case 1: /* IO address */ 7048c2ecf20Sopenharmony_ci io = ints[1]; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (*s) 7088c2ecf20Sopenharmony_ci snprintf(device, sizeof(device), "%s", s); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 1; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci__setup("com90xx=", com90xx_setup); 7148c2ecf20Sopenharmony_ci#endif 715