📄 com90xx.c
字号:
/* * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers) * * Written 1994-1999 by Avery Pennarun. * Written 1999 by Martin Mares <mj@ucw.cz>. * Derived from skeleton.c by Donald Becker. * * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) * for sponsoring the further development of this driver. * * ********************** * * The original copyright of skeleton.c was as follows: * * skeleton.c Written 1993 by Donald Becker. * Copyright 1993 United States Government as represented by the * Director, National Security Agency. This software may only be used * and distributed according to the terms of the GNU General Public License as * modified by SRC, incorporated herein by reference. * * ********************** * * For more details, see drivers/net/arcnet.c * * ********************** */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <asm/io.h>#include <linux/arcdevice.h>#define VERSION "arcnet: COM90xx chipset support\n"/* Define this to speed up the autoprobe by assuming if only one io port and * shmem are left in the list at Stage 5, they must correspond to each * other. * * This is undefined by default because it might not always be true, and the * extra check makes the autoprobe even more careful. Speed demons can turn * it on - I think it should be fine if you only have one ARCnet card * installed. * * If no ARCnet cards are installed, this delay never happens anyway and thus * the option has no effect. */#undef FAST_PROBE/* Internal function declarations */static int com90xx_found(int ioaddr, int airq, u_long shmem);static void com90xx_command(struct net_device *dev, int command);static int com90xx_status(struct net_device *dev);static void com90xx_setmask(struct net_device *dev, int mask);static int com90xx_reset(struct net_device *dev, int really_reset);static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count);static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count);/* Known ARCnet cards */static struct net_device *cards[16];static int numcards;/* Handy defines for ARCnet specific stuff *//* The number of low I/O ports used by the card */#define ARCNET_TOTAL_SIZE 16/* Amount of I/O memory used by the card */#define BUFFER_SIZE (512)#define MIRROR_SIZE (BUFFER_SIZE*4)/* COM 9026 controller chip --> ARCnet register addresses */#define _INTMASK (ioaddr+0) /* writable */#define _STATUS (ioaddr+0) /* readable */#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */#define _CONFIG (ioaddr+2) /* Configuration register */#define _RESET (ioaddr+8) /* software reset (on read) */#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */#define _ADDR_HI (ioaddr+15) /* Control registers for said */#define _ADDR_LO (ioaddr+14)#undef ASTATUS#undef ACOMMAND#undef AINTMASK#define ASTATUS() inb(_STATUS)#define ACOMMAND(cmd) outb((cmd),_COMMAND)#define AINTMASK(msk) outb((msk),_INTMASK)static int com90xx_skip_probe __initdata = 0;/* Module parameters */static int io; /* use the insmod io= irq= shmem= options */static int irq;static int shmem;static char device[9]; /* use eg. device=arc1 to change name */module_param(io, int, 0);module_param(irq, int, 0);module_param(shmem, int, 0);module_param_string(device, device, sizeof(device), 0);static void __init com90xx_probe(void){ int count, status, ioaddr, numprint, airq, openparen = 0; unsigned long airqmask; int ports[(0x3f0 - 0x200) / 16 + 1] = {0}; u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = {0}; int numports, numshmems, *port; u_long *p; if (!io && !irq && !shmem && !*device && com90xx_skip_probe) return; BUGLVL(D_NORMAL) printk(VERSION); /* set up the arrays where we'll store the possible probe addresses */ numports = numshmems = 0; if (io) ports[numports++] = io; else for (count = 0x200; count <= 0x3f0; count += 16) ports[numports++] = count; if (shmem) shmems[numshmems++] = shmem; else for (count = 0xA0000; count <= 0xFF800; count += 2048) shmems[numshmems++] = count; /* Stage 1: abandon any reserved ports, or ones with status==0xFF * (empty), and reset any others by reading the reset port. */ numprint = -1; for (port = &ports[0]; port - ports < numports; port++) { numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S1: "); } BUGMSG2(D_INIT, "%Xh ", *port); ioaddr = *port; if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(request_region)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; *port-- = ports[--numports]; continue; } if (ASTATUS() == 0xFF) { BUGMSG2(D_INIT_REASONS, "(empty)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } inb(_RESET); /* begin resetting card */ BUGMSG2(D_INIT_REASONS, "\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; } BUGMSG2(D_INIT, "\n"); if (!numports) { BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); return; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't * do anything until they finish. If D_INIT, print the list of * cards that are left. */ numprint = -1; for (port = &ports[0]; port < ports + numports; port++) { numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S2: "); } BUGMSG2(D_INIT, "%Xh ", *port); } BUGMSG2(D_INIT, "\n"); mdelay(RESETtime); /* Stage 3: abandon any shmem addresses that don't have the signature * 0xD1 byte in the right place, or are read-only. */ numprint = -1; for (p = &shmems[0]; p < shmems + numshmems; p++) { u_long ptr = *p; numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S3: "); } BUGMSG2(D_INIT, "%lXh ", *p); if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(request_mem_region)\n"); BUGMSG2(D_INIT_REASONS, "Stage 3: "); BUGLVL(D_INIT_REASONS) numprint = 0; *p-- = shmems[--numshmems]; continue; } if (isa_readb(ptr) != TESTvalue) { BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n", isa_readb(ptr), TESTvalue); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; release_mem_region(*p, BUFFER_SIZE); *p-- = shmems[--numshmems]; continue; } /* By writing 0x42 to the TESTvalue location, we also make * sure no "mirror" shmem areas show up - if they occur * in another pass through this loop, they will be discarded * because *cptr != TESTvalue. */ isa_writeb(0x42, ptr); if (isa_readb(ptr) != 0x42) { BUGMSG2(D_INIT_REASONS, "(read only)\n"); BUGMSG2(D_INIT_REASONS, "S3: "); release_mem_region(*p, BUFFER_SIZE); *p-- = shmems[--numshmems]; continue; } BUGMSG2(D_INIT_REASONS, "\n"); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; } BUGMSG2(D_INIT, "\n"); if (!numshmems) { BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); for (port = &ports[0]; port < ports + numports; port++) release_region(*port, ARCNET_TOTAL_SIZE); return; } /* Stage 4: something of a dummy, to report the shmems that are * still possible after stage 3. */ numprint = -1; for (p = &shmems[0]; p < shmems + numshmems; p++) { numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S4: "); } BUGMSG2(D_INIT, "%lXh ", *p); } BUGMSG2(D_INIT, "\n"); /* Stage 5: for any ports that have the correct status, can disable * the RESET flag, and (if no irq is given) generate an autoirq, * register an ARCnet device. * * Currently, we can only register one device per probe, so quit * after the first one is found. */ numprint = -1; for (port = &ports[0]; port < ports + numports; port++) { int found = 0; numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S5: "); } BUGMSG2(D_INIT, "%Xh ", *port); ioaddr = *port; status = ASTATUS(); if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); status = ASTATUS(); if (status & RESETflag) { BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } /* skip this completely if an IRQ was given, because maybe * we're on a machine that locks during autoirq! */ if (!irq) { /* if we do this, we're sure to get an IRQ since the * card has just reset and the NORXflag is on until * we tell it to start receiving. */ airqmask = probe_irq_on(); AINTMASK(NORXflag); udelay(1); AINTMASK(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -