^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Written 1994-1999 by Avery Pennarun.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Written 1999 by Martin Mares <mj@ucw.cz>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Derived from skeleton.c by Donald Becker.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * for sponsoring the further development of this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * **********************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * The original copyright of skeleton.c was as follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * skeleton.c Written 1993 by Donald Becker.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Copyright 1993 United States Government as represented by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Director, National Security Agency. This software may only be used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * and distributed according to the terms of the GNU General Public License as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * modified by SRC, incorporated herein by reference.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * **********************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * For more details, see drivers/net/arcnet.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * **********************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include "arcdevice.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include "com9026.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Define this to speed up the autoprobe by assuming if only one io port and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * shmem are left in the list at Stage 5, they must correspond to each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * other.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * This is undefined by default because it might not always be true, and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * extra check makes the autoprobe even more careful. Speed demons can turn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * it on - I think it should be fine if you only have one ARCnet card
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * installed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * If no ARCnet cards are installed, this delay never happens anyway and thus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * the option has no effect.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #undef FAST_PROBE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Internal function declarations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void com90xx_command(struct net_device *dev, int command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static int com90xx_status(struct net_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static void com90xx_setmask(struct net_device *dev, int mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static int com90xx_reset(struct net_device *dev, int really_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void *buf, int count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int offset, void *buf, int count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Known ARCnet cards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static struct net_device *cards[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static int numcards;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* Handy defines for ARCnet specific stuff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* The number of low I/O ports used by the card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define ARCNET_TOTAL_SIZE 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Amount of I/O memory used by the card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define BUFFER_SIZE (512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define MIRROR_SIZE (BUFFER_SIZE * 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int com90xx_skip_probe __initdata = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Module parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int io; /* use the insmod io= irq= shmem= options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int shmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static char device[9]; /* use eg. device=arc1 to change name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) module_param_hw(io, int, ioport, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) module_param_hw(irq, int, irq, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) module_param(shmem, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) module_param_string(device, device, sizeof(device), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void __init com90xx_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int count, status, ioaddr, numprint, airq, openparen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) unsigned long airqmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) int ports[(0x3f0 - 0x200) / 16 + 1] = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) unsigned long *shmems;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) void __iomem **iomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int numports, numshmems, *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) u_long *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) shmems = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(unsigned long),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!shmems)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) iomem = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(void __iomem *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (!iomem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) kfree(shmems);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (BUGLVL(D_NORMAL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) pr_info("%s\n", "COM90xx chipset support");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* set up the arrays where we'll store the possible probe addresses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) numports = numshmems = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ports[numports++] = io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) for (count = 0x200; count <= 0x3f0; count += 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ports[numports++] = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (shmem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) shmems[numshmems++] = shmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) for (count = 0xA0000; count <= 0xFF800; count += 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) shmems[numshmems++] = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* Stage 1: abandon any reserved ports, or ones with status==0xFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * (empty), and reset any others by reading the reset port.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) numprint = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) for (port = &ports[0]; port - ports < numports; port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) numprint++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) numprint %= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!numprint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) arc_cont(D_INIT, "S1: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) arc_cont(D_INIT, "%Xh ", *port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ioaddr = *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (!request_region(*port, ARCNET_TOTAL_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) "arcnet (90xx)")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) arc_cont(D_INIT_REASONS, "(request_region)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) arc_cont(D_INIT_REASONS, "S1: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) *port-- = ports[--numports];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) arc_cont(D_INIT_REASONS, "(empty)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) arc_cont(D_INIT_REASONS, "S1: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) release_region(*port, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *port-- = ports[--numports];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* begin resetting card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) arcnet_inb(ioaddr, COM9026_REG_R_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) arc_cont(D_INIT_REASONS, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) arc_cont(D_INIT_REASONS, "S1: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (!numports) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) arc_cont(D_NORMAL, "S1: No ARCnet cards found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) kfree(shmems);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) kfree(iomem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* Stage 2: we have now reset any possible ARCnet cards, so we can't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * do anything until they finish. If D_INIT, print the list of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * cards that are left.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) numprint = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) for (port = &ports[0]; port < ports + numports; port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) numprint++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) numprint %= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (!numprint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) arc_cont(D_INIT, "S2: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) arc_cont(D_INIT, "%Xh ", *port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) mdelay(RESETtime);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* Stage 3: abandon any shmem addresses that don't have the signature
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * 0xD1 byte in the right place, or are read-only.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) numprint = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) for (index = 0, p = &shmems[0]; index < numshmems; p++, index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) numprint++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) numprint %= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!numprint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) arc_cont(D_INIT, "S3: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) arc_cont(D_INIT, "%lXh ", *p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) arc_cont(D_INIT_REASONS, "(request_mem_region)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) arc_cont(D_INIT_REASONS, "Stage 3: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) base = ioremap(*p, MIRROR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (!base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) arc_cont(D_INIT_REASONS, "(ioremap)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) arc_cont(D_INIT_REASONS, "Stage 3: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) goto out1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (arcnet_readb(base, COM9026_REG_R_STATUS) != TESTvalue) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) arc_cont(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) arcnet_readb(base, COM9026_REG_R_STATUS),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) TESTvalue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) arc_cont(D_INIT_REASONS, "S3: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) goto out2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /* By writing 0x42 to the TESTvalue location, we also make
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * sure no "mirror" shmem areas show up - if they occur
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * in another pass through this loop, they will be discarded
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * because *cptr != TESTvalue.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) arcnet_writeb(0x42, base, COM9026_REG_W_INTMASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (arcnet_readb(base, COM9026_REG_R_STATUS) != 0x42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) arc_cont(D_INIT_REASONS, "(read only)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) arc_cont(D_INIT_REASONS, "S3: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) goto out2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) arc_cont(D_INIT_REASONS, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) arc_cont(D_INIT_REASONS, "S3: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) iomem[index] = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) out2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) iounmap(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) out1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) release_mem_region(*p, MIRROR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *p-- = shmems[--numshmems];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) index--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (!numshmems) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) arc_cont(D_NORMAL, "S3: No ARCnet cards found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) for (port = &ports[0]; port < ports + numports; port++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) release_region(*port, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) kfree(shmems);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) kfree(iomem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* Stage 4: something of a dummy, to report the shmems that are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * still possible after stage 3.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) numprint = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) for (p = &shmems[0]; p < shmems + numshmems; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) numprint++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) numprint %= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (!numprint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) arc_cont(D_INIT, "S4: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) arc_cont(D_INIT, "%lXh ", *p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* Stage 5: for any ports that have the correct status, can disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * the RESET flag, and (if no irq is given) generate an autoirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * register an ARCnet device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * Currently, we can only register one device per probe, so quit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * after the first one is found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) numprint = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) for (port = &ports[0]; port < ports + numports; port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) int found = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) numprint++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) numprint %= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (!numprint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) arc_cont(D_INIT, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) arc_cont(D_INIT, "S5: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) arc_cont(D_INIT, "%Xh ", *port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) ioaddr = *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if ((status & 0x9D)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) arc_cont(D_INIT_REASONS, "(status=%Xh)\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) arc_cont(D_INIT_REASONS, "S5: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) release_region(*port, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) *port-- = ports[--numports];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) ioaddr, COM9026_REG_W_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (status & RESETflag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) arc_cont(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) arc_cont(D_INIT_REASONS, "S5: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) release_region(*port, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) *port-- = ports[--numports];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* skip this completely if an IRQ was given, because maybe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * we're on a machine that locks during autoirq!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (!irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /* if we do this, we're sure to get an IRQ since the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * card has just reset and the NORXflag is on until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * we tell it to start receiving.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) airqmask = probe_irq_on();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) airq = probe_irq_off(airqmask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (airq <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) arc_cont(D_INIT_REASONS, "(airq=%d)\n", airq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) arc_cont(D_INIT_REASONS, "S5: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) release_region(*port, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) *port-- = ports[--numports];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) airq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) arc_cont(D_INIT, "(%d,", airq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) openparen = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /* Everything seems okay. But which shmem, if any, puts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * back its signature byte when the card is reset?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * If there are multiple cards installed, there might be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * multiple shmems still in the list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) #ifdef FAST_PROBE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (numports > 1 || numshmems > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) arcnet_inb(ioaddr, COM9026_REG_R_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) mdelay(RESETtime);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /* just one shmem and port, assume they match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) arcnet_writeb(TESTvalue, iomem[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) COM9026_REG_W_INTMASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) arcnet_inb(ioaddr, COM9026_REG_R_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) mdelay(RESETtime);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) for (index = 0; index < numshmems; index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) u_long ptr = shmems[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) void __iomem *base = iomem[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (arcnet_readb(base, COM9026_REG_R_STATUS) == TESTvalue) { /* found one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) arc_cont(D_INIT, "%lXh)\n", *p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) openparen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* register the card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (com90xx_found(*port, airq, ptr, base) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) found = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) numprint = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) /* remove shmem from the list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) shmems[index] = shmems[--numshmems];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) iomem[index] = iomem[numshmems];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) break; /* go to the next I/O port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) arc_cont(D_INIT_REASONS, "%Xh-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) arcnet_readb(base, COM9026_REG_R_STATUS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (openparen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (BUGLVL(D_INIT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) pr_cont("no matching shmem)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (BUGLVL(D_INIT_REASONS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) pr_cont("S5: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) numprint = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (!found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) release_region(*port, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) *port-- = ports[--numports];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (BUGLVL(D_INIT_REASONS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) pr_cont("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /* Now put back TESTvalue on all leftover shmems. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) for (index = 0; index < numshmems; index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) arcnet_writeb(TESTvalue, iomem[index], COM9026_REG_W_INTMASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) iounmap(iomem[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) release_mem_region(shmems[index], MIRROR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) kfree(shmems);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) kfree(iomem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static int __init check_mirror(unsigned long addr, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) void __iomem *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) int res = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (!request_mem_region(addr, size, "arcnet (90xx)"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) p = ioremap(addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) res = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) iounmap(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) release_mem_region(addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) /* Set up the struct net_device associated with this card. Called after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * probing succeeds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static int __init com90xx_found(int ioaddr, int airq, u_long shmem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) void __iomem *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) struct net_device *dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) struct arcnet_local *lp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) u_long first_mirror, last_mirror;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) int mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* allocate struct net_device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) dev = alloc_arcdev(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (!dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) arc_cont(D_NORMAL, "com90xx: Can't allocate device!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) iounmap(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) release_mem_region(shmem, MIRROR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) lp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /* find the real shared memory start/end points, including mirrors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) /* guess the actual size of one "memory mirror" - the number of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) * bytes between copies of the shared memory. On most cards, it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * 2k (or there are no mirrors at all) but on some, it's 4k.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) mirror_size = MIRROR_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) mirror_size = 2 * MIRROR_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) first_mirror = shmem - mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) while (check_mirror(first_mirror, mirror_size) == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) first_mirror -= mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) first_mirror += mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) last_mirror = shmem + mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) while (check_mirror(last_mirror, mirror_size) == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) last_mirror += mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) last_mirror -= mirror_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) dev->mem_start = first_mirror;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) dev->mem_end = last_mirror + MIRROR_SIZE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) iounmap(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) release_mem_region(shmem, MIRROR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (!request_mem_region(dev->mem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) dev->mem_end - dev->mem_start + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) "arcnet (90xx)"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /* reserve the irq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (request_irq(airq, arcnet_interrupt, 0, "arcnet (90xx)", dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", airq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) goto err_release_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) dev->irq = airq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) /* Initialize the rest of the device structure. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) lp->card_name = "COM90xx";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) lp->hw.command = com90xx_command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) lp->hw.status = com90xx_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) lp->hw.intmask = com90xx_setmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) lp->hw.reset = com90xx_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) lp->hw.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) lp->hw.copy_to_card = com90xx_copy_to_card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) lp->hw.copy_from_card = com90xx_copy_from_card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) lp->mem_start = ioremap(dev->mem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) dev->mem_end - dev->mem_start + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (!lp->mem_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) arc_printk(D_NORMAL, dev, "Can't remap device memory!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) goto err_free_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) /* get and check the station ID from offset 1 in shmem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) dev->base_addr = ioaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) arc_printk(D_NORMAL, dev, "COM90xx station %02Xh found at %03lXh, IRQ %d, ShMem %lXh (%ld*%xh).\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) dev->dev_addr[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) dev->base_addr, dev->irq, dev->mem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) (dev->mem_end - dev->mem_start + 1) / mirror_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) mirror_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (register_netdev(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) goto err_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) cards[numcards++] = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) err_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) iounmap(lp->mem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) err_free_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) free_irq(dev->irq, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) err_release_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) err_free_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) free_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) static void com90xx_command(struct net_device *dev, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) short ioaddr = dev->base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) static int com90xx_status(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) short ioaddr = dev->base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static void com90xx_setmask(struct net_device *dev, int mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) short ioaddr = dev->base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /* Do a hardware reset on the card, and set up necessary registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * This should be called as little as possible, because it disrupts the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) * token on the network (causes a RECON) and requires a significant delay.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * However, it does make sure the card is in a defined state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) static int com90xx_reset(struct net_device *dev, int really_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) struct arcnet_local *lp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) short ioaddr = dev->base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) arc_printk(D_INIT, dev, "Resetting (status=%02Xh)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) arcnet_inb(ioaddr, COM9026_REG_R_STATUS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (really_reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) /* reset the card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) arcnet_inb(ioaddr, COM9026_REG_R_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) mdelay(RESETtime);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) /* clear flags & end reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /* don't do this until we verify that it doesn't hurt older cards! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) | ENABLE16flag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) ioaddr, COM9026_REG_RW_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /* verify that the ARCnet signature byte is present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (arcnet_readb(lp->mem_start, COM9026_REG_R_STATUS) != TESTvalue) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (really_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) /* enable extended (512-byte) packets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /* clean out all the memory to make debugging make more sense :) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (BUGLVL(D_DURING))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) memset_io(lp->mem_start, 0x42, 2048);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) /* done! return success. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) static void com90xx_copy_to_card(struct net_device *dev, int bufnum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) int offset, void *buf, int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) struct arcnet_local *lp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) int offset, void *buf, int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) struct arcnet_local *lp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static int __init com90xx_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) if (irq == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) irq = 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) com90xx_probe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (!numcards)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) static void __exit com90xx_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) struct arcnet_local *lp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) for (count = 0; count < numcards; count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) dev = cards[count];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) lp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) unregister_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) free_irq(dev->irq, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) iounmap(lp->mem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) release_mem_region(dev->mem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) dev->mem_end - dev->mem_start + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) free_netdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) module_init(com90xx_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) module_exit(com90xx_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) static int __init com90xx_setup(char *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) int ints[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) s = get_options(s, 8, ints);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (!ints[0] && !*s) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) pr_notice("Disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) switch (ints[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) default: /* ERROR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) pr_err("Too many arguments\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) case 3: /* Mem address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) shmem = ints[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) case 2: /* IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) irq = ints[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) case 1: /* IO address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) io = ints[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (*s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) snprintf(device, sizeof(device), "%s", s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) __setup("com90xx=", com90xx_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) #endif