/* * 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 * * **********************
*/
/* 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 */ staticint com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *); staticvoid com90xx_command(struct net_device *dev, int command); staticint com90xx_status(struct net_device *dev); staticvoid com90xx_setmask(struct net_device *dev, int mask); staticint com90xx_reset(struct net_device *dev, int really_reset); staticvoid com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); staticvoid com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count);
/* 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)
staticint com90xx_skip_probe __initdata = 0;
/* Module parameters */
staticint io; /* use the insmod io= irq= shmem= options */ staticint irq; staticint shmem; staticchar device[9]; /* use eg. device=arc1 to change name */
if (!numports) {
arc_cont(D_NORMAL, "S1: No ARCnet cards found.\n");
kfree(shmems);
kfree(iomem); 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) {
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S2: ");
}
arc_cont(D_INIT, "%Xh ", *port);
}
arc_cont(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 (index = 0, p = &shmems[0]; index < numshmems; p++, index++) { void __iomem *base;
if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) {
arc_cont(D_INIT_REASONS, "(request_mem_region)\n");
arc_cont(D_INIT_REASONS, "Stage 3: "); if (BUGLVL(D_INIT_REASONS))
numprint = 0; goto out;
}
base = ioremap(*p, MIRROR_SIZE); if (!base) {
arc_cont(D_INIT_REASONS, "(ioremap)\n");
arc_cont(D_INIT_REASONS, "Stage 3: "); if (BUGLVL(D_INIT_REASONS))
numprint = 0; goto out1;
} if (arcnet_readb(base, COM9026_REG_R_STATUS) != TESTvalue) {
arc_cont(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
arcnet_readb(base, COM9026_REG_R_STATUS),
TESTvalue);
arc_cont(D_INIT_REASONS, "S3: "); if (BUGLVL(D_INIT_REASONS))
numprint = 0; goto out2;
} /* 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.
*/
arcnet_writeb(0x42, base, COM9026_REG_W_INTMASK); if (arcnet_readb(base, COM9026_REG_R_STATUS) != 0x42) {
arc_cont(D_INIT_REASONS, "(read only)\n");
arc_cont(D_INIT_REASONS, "S3: "); goto out2;
}
arc_cont(D_INIT_REASONS, "\n");
arc_cont(D_INIT_REASONS, "S3: "); if (BUGLVL(D_INIT_REASONS))
numprint = 0;
iomem[index] = base; continue;
out2:
iounmap(base);
out1:
release_mem_region(*p, MIRROR_SIZE);
out:
*p-- = shmems[--numshmems];
index--;
}
arc_cont(D_INIT, "\n");
if (!numshmems) {
arc_cont(D_NORMAL, "S3: No ARCnet cards found.\n"); for (port = &ports[0]; port < ports + numports; port++)
release_region(*port, ARCNET_TOTAL_SIZE);
kfree(shmems);
kfree(iomem); 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) {
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S4: ");
}
arc_cont(D_INIT, "%lXh ", *p);
}
arc_cont(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;
ioaddr = *port;
status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
if ((status & 0x9D)
!= (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
arc_cont(D_INIT_REASONS, "(status=%Xh)\n", status);
arc_cont(D_INIT_REASONS, "S5: "); if (BUGLVL(D_INIT_REASONS))
numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports]; continue;
}
arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
ioaddr, COM9026_REG_W_COMMAND);
status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); if (status & RESETflag) {
arc_cont(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
arc_cont(D_INIT_REASONS, "S5: "); if (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();
arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK);
udelay(1);
arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK);
airq = probe_irq_off(airqmask);
/* Everything seems okay. But which shmem, if any, puts * back its signature byte when the card is reset? * * If there are multiple cards installed, there might be * multiple shmems still in the list.
*/ #ifdef FAST_PROBE if (numports > 1 || numshmems > 1) {
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
} else { /* just one shmem and port, assume they match */
arcnet_writeb(TESTvalue, iomem[0],
COM9026_REG_W_INTMASK);
} #else
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime); #endif
for (index = 0; index < numshmems; index++) {
u_long ptr = shmems[index]; void __iomem *base = iomem[index];
if (arcnet_readb(base, COM9026_REG_R_STATUS) == TESTvalue) { /* found one */
arc_cont(D_INIT, "%lXh)\n", *p);
openparen = 0;
/* register the card */ if (com90xx_found(*port, airq, ptr, base) == 0)
found = 1;
numprint = -1;
/* remove shmem from the list */
shmems[index] = shmems[--numshmems];
iomem[index] = iomem[numshmems]; break; /* go to the next I/O port */
} else {
arc_cont(D_INIT_REASONS, "%Xh-",
arcnet_readb(base, COM9026_REG_R_STATUS));
}
}
if (openparen) { if (BUGLVL(D_INIT))
pr_cont("no matching shmem)\n"); if (BUGLVL(D_INIT_REASONS)) {
pr_cont("S5: ");
numprint = 0;
}
} if (!found)
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
}
if (BUGLVL(D_INIT_REASONS))
pr_cont("\n");
/* Now put back TESTvalue on all leftover shmems. */ for (index = 0; index < numshmems; index++) {
arcnet_writeb(TESTvalue, iomem[index], COM9026_REG_W_INTMASK);
iounmap(iomem[index]);
release_mem_region(shmems[index], MIRROR_SIZE);
}
kfree(shmems);
kfree(iomem);
}
staticint __init check_mirror(unsignedlong addr, size_t size)
{ void __iomem *p; int res = -1;
if (!request_mem_region(addr, size, "arcnet (90xx)")) return -1;
p = ioremap(addr, size); if (p) { if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue)
res = 1; else
res = 0;
iounmap(p);
}
release_mem_region(addr, size); return res;
}
/* Set up the struct net_device associated with this card. Called after * probing succeeds.
*/ staticint __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *p)
{ struct net_device *dev = NULL; struct arcnet_local *lp;
u_long first_mirror, last_mirror; int mirror_size;
/* allocate struct net_device */
dev = alloc_arcdev(device); if (!dev) {
arc_cont(D_NORMAL, "com90xx: Can't allocate device!\n");
iounmap(p);
release_mem_region(shmem, MIRROR_SIZE); return -ENOMEM;
}
lp = netdev_priv(dev); /* find the real shared memory start/end points, including mirrors */
/* guess the actual size of one "memory mirror" - the number of * bytes between copies of the shared memory. On most cards, it's * 2k (or there are no mirrors at all) but on some, it's 4k.
*/
mirror_size = MIRROR_SIZE; if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue &&
check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
mirror_size = 2 * MIRROR_SIZE;
/* Do a hardware reset on the card, and set up necessary registers. * * This should be called as little as possible, because it disrupts the * token on the network (causes a RECON) and requires a significant delay. * * However, it does make sure the card is in a defined state.
*/ staticint com90xx_reset(struct net_device *dev, int really_reset)
{ struct arcnet_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr;
if (really_reset) { /* reset the card */
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
} /* clear flags & end reset */
arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
#if 0 /* don't do this until we verify that it doesn't hurt older cards! */
arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) | ENABLE16flag,
ioaddr, COM9026_REG_RW_CONFIG); #endif
/* verify that the ARCnet signature byte is present */ if (arcnet_readb(lp->mem_start, COM9026_REG_R_STATUS) != TESTvalue) { if (really_reset)
arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n"); return 1;
} /* enable extended (512-byte) packets */
arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
/* clean out all the memory to make debugging make more sense :) */ if (BUGLVL(D_DURING))
memset_io(lp->mem_start, 0x42, 2048);
/* done! return success. */ return 0;
}
staticvoid com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count)
{ struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.