162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Linux ARCnet driver - COM90xx chipset (IO-mapped buffers) 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Written 1997 by David Woodhouse. 562306a36Sopenharmony_ci * Written 1994-1999 by Avery Pennarun. 662306a36Sopenharmony_ci * Written 1999-2000 by Martin Mares <mj@ucw.cz>. 762306a36Sopenharmony_ci * Derived from skeleton.c by Donald Becker. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) 1062306a36Sopenharmony_ci * for sponsoring the further development of this driver. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * ********************** 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The original copyright of skeleton.c was as follows: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * skeleton.c Written 1993 by Donald Becker. 1762306a36Sopenharmony_ci * Copyright 1993 United States Government as represented by the 1862306a36Sopenharmony_ci * Director, National Security Agency. This software may only be used 1962306a36Sopenharmony_ci * and distributed according to the terms of the GNU General Public License as 2062306a36Sopenharmony_ci * modified by SRC, incorporated herein by reference. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * ********************** 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * For more details, see drivers/net/arcnet.c 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * ********************** 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/kernel.h> 3262306a36Sopenharmony_ci#include <linux/module.h> 3362306a36Sopenharmony_ci#include <linux/moduleparam.h> 3462306a36Sopenharmony_ci#include <linux/ioport.h> 3562306a36Sopenharmony_ci#include <linux/delay.h> 3662306a36Sopenharmony_ci#include <linux/netdevice.h> 3762306a36Sopenharmony_ci#include <linux/memblock.h> 3862306a36Sopenharmony_ci#include <linux/init.h> 3962306a36Sopenharmony_ci#include <linux/interrupt.h> 4062306a36Sopenharmony_ci#include <linux/io.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "arcdevice.h" 4362306a36Sopenharmony_ci#include "com9026.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Internal function declarations */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int com90io_found(struct net_device *dev); 4862306a36Sopenharmony_cistatic void com90io_command(struct net_device *dev, int command); 4962306a36Sopenharmony_cistatic int com90io_status(struct net_device *dev); 5062306a36Sopenharmony_cistatic void com90io_setmask(struct net_device *dev, int mask); 5162306a36Sopenharmony_cistatic int com90io_reset(struct net_device *dev, int really_reset); 5262306a36Sopenharmony_cistatic void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, 5362306a36Sopenharmony_ci void *buf, int count); 5462306a36Sopenharmony_cistatic void com90io_copy_from_card(struct net_device *dev, int bufnum, 5562306a36Sopenharmony_ci int offset, void *buf, int count); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Handy defines for ARCnet specific stuff */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* The number of low I/O ports used by the card. */ 6062306a36Sopenharmony_ci#define ARCNET_TOTAL_SIZE 16 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/**************************************************************************** 6362306a36Sopenharmony_ci * * 6462306a36Sopenharmony_ci * IO-mapped operation routines * 6562306a36Sopenharmony_ci * * 6662306a36Sopenharmony_ci ****************************************************************************/ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#undef ONE_AT_A_TIME_TX 6962306a36Sopenharmony_ci#undef ONE_AT_A_TIME_RX 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic u_char get_buffer_byte(struct net_device *dev, unsigned offset) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci int ioaddr = dev->base_addr; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI); 7662306a36Sopenharmony_ci arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#ifdef ONE_AT_A_TIME_TX 8262306a36Sopenharmony_cistatic void put_buffer_byte(struct net_device *dev, unsigned offset, 8362306a36Sopenharmony_ci u_char datum) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci int ioaddr = dev->base_addr; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI); 8862306a36Sopenharmony_ci arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci arcnet_outb(datum, ioaddr, COM9026_REG_RW_MEMDATA); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#endif 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void get_whole_buffer(struct net_device *dev, unsigned offset, 9662306a36Sopenharmony_ci unsigned length, char *dest) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci int ioaddr = dev->base_addr; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI); 10162306a36Sopenharmony_ci arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci while (length--) 10462306a36Sopenharmony_ci#ifdef ONE_AT_A_TIME_RX 10562306a36Sopenharmony_ci *(dest++) = get_buffer_byte(dev, offset++); 10662306a36Sopenharmony_ci#else 10762306a36Sopenharmony_ci *(dest++) = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA); 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void put_whole_buffer(struct net_device *dev, unsigned offset, 11262306a36Sopenharmony_ci unsigned length, char *dest) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci int ioaddr = dev->base_addr; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI); 11762306a36Sopenharmony_ci arcnet_outb(offset & 0xff, ioaddr,COM9026_REG_W_ADDR_LO); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci while (length--) 12062306a36Sopenharmony_ci#ifdef ONE_AT_A_TIME_TX 12162306a36Sopenharmony_ci put_buffer_byte(dev, offset++, *(dest++)); 12262306a36Sopenharmony_ci#else 12362306a36Sopenharmony_ci arcnet_outb(*(dest++), ioaddr, COM9026_REG_RW_MEMDATA); 12462306a36Sopenharmony_ci#endif 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* We cannot probe for an IO mapped card either, although we can check that 12862306a36Sopenharmony_ci * it's where we were told it was, and even autoirq 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_cistatic int __init com90io_probe(struct net_device *dev) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci int ioaddr = dev->base_addr, status; 13362306a36Sopenharmony_ci unsigned long airqmask; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (BUGLVL(D_NORMAL)) { 13662306a36Sopenharmony_ci pr_info("%s\n", "COM90xx IO-mapped mode support (by David Woodhouse et el.)"); 13762306a36Sopenharmony_ci pr_info("E-mail me if you actually test this driver, please!\n"); 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (!ioaddr) { 14162306a36Sopenharmony_ci arc_printk(D_NORMAL, dev, "No autoprobe for IO mapped cards; you must specify the base address!\n"); 14262306a36Sopenharmony_ci return -ENODEV; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) { 14562306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "IO request_region %x-%x failed\n", 14662306a36Sopenharmony_ci ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); 14762306a36Sopenharmony_ci return -ENXIO; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) { 15062306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "IO address %x empty\n", 15162306a36Sopenharmony_ci ioaddr); 15262306a36Sopenharmony_ci goto err_out; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_RESET); 15562306a36Sopenharmony_ci mdelay(RESETtime); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { 16062306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "Status invalid (%Xh)\n", 16162306a36Sopenharmony_ci status); 16262306a36Sopenharmony_ci goto err_out; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "Status after reset: %X\n", status); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear, 16762306a36Sopenharmony_ci ioaddr, COM9026_REG_W_COMMAND); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "Status after reset acknowledged: %X\n", 17062306a36Sopenharmony_ci status); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (status & RESETflag) { 17562306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "Eternal reset (status=%Xh)\n", 17662306a36Sopenharmony_ci status); 17762306a36Sopenharmony_ci goto err_out; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci arcnet_outb((0x16 | IOMAPflag) & ~ENABLE16flag, 18062306a36Sopenharmony_ci ioaddr, COM9026_REG_RW_CONFIG); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Read first loc'n of memory */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci arcnet_outb(AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI); 18562306a36Sopenharmony_ci arcnet_outb(0, ioaddr, COM9026_REG_W_ADDR_LO); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci status = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA); 18862306a36Sopenharmony_ci if (status != 0xd1) { 18962306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "Signature byte not found (%Xh instead).\n", 19062306a36Sopenharmony_ci status); 19162306a36Sopenharmony_ci goto err_out; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci if (!dev->irq) { 19462306a36Sopenharmony_ci /* if we do this, we're sure to get an IRQ since the 19562306a36Sopenharmony_ci * card has just reset and the NORXflag is on until 19662306a36Sopenharmony_ci * we tell it to start receiving. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci airqmask = probe_irq_on(); 20062306a36Sopenharmony_ci arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK); 20162306a36Sopenharmony_ci udelay(1); 20262306a36Sopenharmony_ci arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK); 20362306a36Sopenharmony_ci dev->irq = probe_irq_off(airqmask); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if ((int)dev->irq <= 0) { 20662306a36Sopenharmony_ci arc_printk(D_INIT_REASONS, dev, "Autoprobe IRQ failed\n"); 20762306a36Sopenharmony_ci goto err_out; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci release_region(ioaddr, ARCNET_TOTAL_SIZE); /* end of probing */ 21162306a36Sopenharmony_ci return com90io_found(dev); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cierr_out: 21462306a36Sopenharmony_ci release_region(ioaddr, ARCNET_TOTAL_SIZE); 21562306a36Sopenharmony_ci return -ENODEV; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* Set up the struct net_device associated with this card. Called after 21962306a36Sopenharmony_ci * probing succeeds. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic int __init com90io_found(struct net_device *dev) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct arcnet_local *lp; 22462306a36Sopenharmony_ci int ioaddr = dev->base_addr; 22562306a36Sopenharmony_ci int err; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Reserve the irq */ 22862306a36Sopenharmony_ci if (request_irq(dev->irq, arcnet_interrupt, 0, 22962306a36Sopenharmony_ci "arcnet (COM90xx-IO)", dev)) { 23062306a36Sopenharmony_ci arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq); 23162306a36Sopenharmony_ci return -ENODEV; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci /* Reserve the I/O region */ 23462306a36Sopenharmony_ci if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, 23562306a36Sopenharmony_ci "arcnet (COM90xx-IO)")) { 23662306a36Sopenharmony_ci free_irq(dev->irq, dev); 23762306a36Sopenharmony_ci return -EBUSY; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci lp = netdev_priv(dev); 24162306a36Sopenharmony_ci lp->card_name = "COM90xx I/O"; 24262306a36Sopenharmony_ci lp->hw.command = com90io_command; 24362306a36Sopenharmony_ci lp->hw.status = com90io_status; 24462306a36Sopenharmony_ci lp->hw.intmask = com90io_setmask; 24562306a36Sopenharmony_ci lp->hw.reset = com90io_reset; 24662306a36Sopenharmony_ci lp->hw.owner = THIS_MODULE; 24762306a36Sopenharmony_ci lp->hw.copy_to_card = com90io_copy_to_card; 24862306a36Sopenharmony_ci lp->hw.copy_from_card = com90io_copy_from_card; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; 25162306a36Sopenharmony_ci arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* get and check the station ID from offset 1 in shmem */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci arcnet_set_addr(dev, get_buffer_byte(dev, 1)); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci err = register_netdev(dev); 25862306a36Sopenharmony_ci if (err) { 25962306a36Sopenharmony_ci arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag, 26062306a36Sopenharmony_ci ioaddr, COM9026_REG_RW_CONFIG); 26162306a36Sopenharmony_ci free_irq(dev->irq, dev); 26262306a36Sopenharmony_ci release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 26362306a36Sopenharmony_ci return err; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci arc_printk(D_NORMAL, dev, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", 26762306a36Sopenharmony_ci dev->dev_addr[0], dev->base_addr, dev->irq); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* Do a hardware reset on the card, and set up necessary registers. 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * This should be called as little as possible, because it disrupts the 27562306a36Sopenharmony_ci * token on the network (causes a RECON) and requires a significant delay. 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * However, it does make sure the card is in a defined state. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic int com90io_reset(struct net_device *dev, int really_reset) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct arcnet_local *lp = netdev_priv(dev); 28262306a36Sopenharmony_ci short ioaddr = dev->base_addr; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n", 28562306a36Sopenharmony_ci dev->name, arcnet_inb(ioaddr, COM9026_REG_R_STATUS)); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (really_reset) { 28862306a36Sopenharmony_ci /* reset the card */ 28962306a36Sopenharmony_ci arcnet_inb(ioaddr, COM9026_REG_R_RESET); 29062306a36Sopenharmony_ci mdelay(RESETtime); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci /* Set the thing to IO-mapped, 8-bit mode */ 29362306a36Sopenharmony_ci lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag; 29462306a36Sopenharmony_ci arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND); 29762306a36Sopenharmony_ci /* clear flags & end reset */ 29862306a36Sopenharmony_ci arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* verify that the ARCnet signature byte is present */ 30162306a36Sopenharmony_ci if (get_buffer_byte(dev, 0) != TESTvalue) { 30262306a36Sopenharmony_ci arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n"); 30362306a36Sopenharmony_ci return 1; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci /* enable extended (512-byte) packets */ 30662306a36Sopenharmony_ci arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND); 30762306a36Sopenharmony_ci /* done! return success. */ 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void com90io_command(struct net_device *dev, int cmd) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci short ioaddr = dev->base_addr; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int com90io_status(struct net_device *dev) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci short ioaddr = dev->base_addr; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void com90io_setmask(struct net_device *dev, int mask) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci short ioaddr = dev->base_addr; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic void com90io_copy_to_card(struct net_device *dev, int bufnum, 33362306a36Sopenharmony_ci int offset, void *buf, int count) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci TIME(dev, "put_whole_buffer", count, 33662306a36Sopenharmony_ci put_whole_buffer(dev, bufnum * 512 + offset, count, buf)); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void com90io_copy_from_card(struct net_device *dev, int bufnum, 34062306a36Sopenharmony_ci int offset, void *buf, int count) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci TIME(dev, "get_whole_buffer", count, 34362306a36Sopenharmony_ci get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int io; /* use the insmod io= irq= shmem= options */ 34762306a36Sopenharmony_cistatic int irq; 34862306a36Sopenharmony_cistatic char device[9]; /* use eg. device=arc1 to change name */ 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cimodule_param_hw(io, int, ioport, 0); 35162306a36Sopenharmony_cimodule_param_hw(irq, int, irq, 0); 35262306a36Sopenharmony_cimodule_param_string(device, device, sizeof(device), 0); 35362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci#ifndef MODULE 35662306a36Sopenharmony_cistatic int __init com90io_setup(char *s) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int ints[4]; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci s = get_options(s, 4, ints); 36162306a36Sopenharmony_ci if (!ints[0]) 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci switch (ints[0]) { 36462306a36Sopenharmony_ci default: /* ERROR */ 36562306a36Sopenharmony_ci pr_err("Too many arguments\n"); 36662306a36Sopenharmony_ci fallthrough; 36762306a36Sopenharmony_ci case 2: /* IRQ */ 36862306a36Sopenharmony_ci irq = ints[2]; 36962306a36Sopenharmony_ci fallthrough; 37062306a36Sopenharmony_ci case 1: /* IO address */ 37162306a36Sopenharmony_ci io = ints[1]; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci if (*s) 37462306a36Sopenharmony_ci snprintf(device, sizeof(device), "%s", s); 37562306a36Sopenharmony_ci return 1; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci__setup("com90io=", com90io_setup); 37862306a36Sopenharmony_ci#endif 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic struct net_device *my_dev; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int __init com90io_init(void) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct net_device *dev; 38562306a36Sopenharmony_ci int err; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci dev = alloc_arcdev(device); 38862306a36Sopenharmony_ci if (!dev) 38962306a36Sopenharmony_ci return -ENOMEM; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci dev->base_addr = io; 39262306a36Sopenharmony_ci dev->irq = irq; 39362306a36Sopenharmony_ci if (dev->irq == 2) 39462306a36Sopenharmony_ci dev->irq = 9; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci err = com90io_probe(dev); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (err) { 39962306a36Sopenharmony_ci free_arcdev(dev); 40062306a36Sopenharmony_ci return err; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci my_dev = dev; 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void __exit com90io_exit(void) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct net_device *dev = my_dev; 41062306a36Sopenharmony_ci int ioaddr = dev->base_addr; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci unregister_netdev(dev); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* In case the old driver is loaded later, 41562306a36Sopenharmony_ci * set the thing back to MMAP mode 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag, 41862306a36Sopenharmony_ci ioaddr, COM9026_REG_RW_CONFIG); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci free_irq(dev->irq, dev); 42162306a36Sopenharmony_ci release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 42262306a36Sopenharmony_ci free_arcdev(dev); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cimodule_init(com90io_init) 42662306a36Sopenharmony_cimodule_exit(com90io_exit) 427