com90io.c (11825B)
1/* 2 * Linux ARCnet driver - COM90xx chipset (IO-mapped buffers) 3 * 4 * Written 1997 by David Woodhouse. 5 * Written 1994-1999 by Avery Pennarun. 6 * Written 1999-2000 by Martin Mares <mj@ucw.cz>. 7 * Derived from skeleton.c by Donald Becker. 8 * 9 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) 10 * for sponsoring the further development of this driver. 11 * 12 * ********************** 13 * 14 * The original copyright of skeleton.c was as follows: 15 * 16 * skeleton.c Written 1993 by Donald Becker. 17 * Copyright 1993 United States Government as represented by the 18 * Director, National Security Agency. This software may only be used 19 * and distributed according to the terms of the GNU General Public License as 20 * modified by SRC, incorporated herein by reference. 21 * 22 * ********************** 23 * 24 * For more details, see drivers/net/arcnet.c 25 * 26 * ********************** 27 */ 28 29#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt 30 31#include <linux/kernel.h> 32#include <linux/module.h> 33#include <linux/moduleparam.h> 34#include <linux/ioport.h> 35#include <linux/delay.h> 36#include <linux/netdevice.h> 37#include <linux/memblock.h> 38#include <linux/init.h> 39#include <linux/interrupt.h> 40#include <linux/io.h> 41 42#include "arcdevice.h" 43#include "com9026.h" 44 45/* Internal function declarations */ 46 47static int com90io_found(struct net_device *dev); 48static void com90io_command(struct net_device *dev, int command); 49static int com90io_status(struct net_device *dev); 50static void com90io_setmask(struct net_device *dev, int mask); 51static int com90io_reset(struct net_device *dev, int really_reset); 52static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, 53 void *buf, int count); 54static void com90io_copy_from_card(struct net_device *dev, int bufnum, 55 int offset, void *buf, int count); 56 57/* Handy defines for ARCnet specific stuff */ 58 59/* The number of low I/O ports used by the card. */ 60#define ARCNET_TOTAL_SIZE 16 61 62/**************************************************************************** 63 * * 64 * IO-mapped operation routines * 65 * * 66 ****************************************************************************/ 67 68#undef ONE_AT_A_TIME_TX 69#undef ONE_AT_A_TIME_RX 70 71static u_char get_buffer_byte(struct net_device *dev, unsigned offset) 72{ 73 int ioaddr = dev->base_addr; 74 75 arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI); 76 arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO); 77 78 return arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA); 79} 80 81#ifdef ONE_AT_A_TIME_TX 82static void put_buffer_byte(struct net_device *dev, unsigned offset, 83 u_char datum) 84{ 85 int ioaddr = dev->base_addr; 86 87 arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI); 88 arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO); 89 90 arcnet_outb(datum, ioaddr, COM9026_REG_RW_MEMDATA); 91} 92 93#endif 94 95static void get_whole_buffer(struct net_device *dev, unsigned offset, 96 unsigned length, char *dest) 97{ 98 int ioaddr = dev->base_addr; 99 100 arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI); 101 arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO); 102 103 while (length--) 104#ifdef ONE_AT_A_TIME_RX 105 *(dest++) = get_buffer_byte(dev, offset++); 106#else 107 *(dest++) = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA); 108#endif 109} 110 111static void put_whole_buffer(struct net_device *dev, unsigned offset, 112 unsigned length, char *dest) 113{ 114 int ioaddr = dev->base_addr; 115 116 arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI); 117 arcnet_outb(offset & 0xff, ioaddr,COM9026_REG_W_ADDR_LO); 118 119 while (length--) 120#ifdef ONE_AT_A_TIME_TX 121 put_buffer_byte(dev, offset++, *(dest++)); 122#else 123 arcnet_outb(*(dest++), ioaddr, COM9026_REG_RW_MEMDATA); 124#endif 125} 126 127/* We cannot probe for an IO mapped card either, although we can check that 128 * it's where we were told it was, and even autoirq 129 */ 130static int __init com90io_probe(struct net_device *dev) 131{ 132 int ioaddr = dev->base_addr, status; 133 unsigned long airqmask; 134 135 if (BUGLVL(D_NORMAL)) { 136 pr_info("%s\n", "COM90xx IO-mapped mode support (by David Woodhouse et el.)"); 137 pr_info("E-mail me if you actually test this driver, please!\n"); 138 } 139 140 if (!ioaddr) { 141 arc_printk(D_NORMAL, dev, "No autoprobe for IO mapped cards; you must specify the base address!\n"); 142 return -ENODEV; 143 } 144 if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) { 145 arc_printk(D_INIT_REASONS, dev, "IO request_region %x-%x failed\n", 146 ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); 147 return -ENXIO; 148 } 149 if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) { 150 arc_printk(D_INIT_REASONS, dev, "IO address %x empty\n", 151 ioaddr); 152 goto err_out; 153 } 154 arcnet_inb(ioaddr, COM9026_REG_R_RESET); 155 mdelay(RESETtime); 156 157 status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 158 159 if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { 160 arc_printk(D_INIT_REASONS, dev, "Status invalid (%Xh)\n", 161 status); 162 goto err_out; 163 } 164 arc_printk(D_INIT_REASONS, dev, "Status after reset: %X\n", status); 165 166 arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear, 167 ioaddr, COM9026_REG_W_COMMAND); 168 169 arc_printk(D_INIT_REASONS, dev, "Status after reset acknowledged: %X\n", 170 status); 171 172 status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 173 174 if (status & RESETflag) { 175 arc_printk(D_INIT_REASONS, dev, "Eternal reset (status=%Xh)\n", 176 status); 177 goto err_out; 178 } 179 arcnet_outb((0x16 | IOMAPflag) & ~ENABLE16flag, 180 ioaddr, COM9026_REG_RW_CONFIG); 181 182 /* Read first loc'n of memory */ 183 184 arcnet_outb(AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI); 185 arcnet_outb(0, ioaddr, COM9026_REG_W_ADDR_LO); 186 187 status = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA); 188 if (status != 0xd1) { 189 arc_printk(D_INIT_REASONS, dev, "Signature byte not found (%Xh instead).\n", 190 status); 191 goto err_out; 192 } 193 if (!dev->irq) { 194 /* if we do this, we're sure to get an IRQ since the 195 * card has just reset and the NORXflag is on until 196 * we tell it to start receiving. 197 */ 198 199 airqmask = probe_irq_on(); 200 arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK); 201 udelay(1); 202 arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK); 203 dev->irq = probe_irq_off(airqmask); 204 205 if ((int)dev->irq <= 0) { 206 arc_printk(D_INIT_REASONS, dev, "Autoprobe IRQ failed\n"); 207 goto err_out; 208 } 209 } 210 release_region(ioaddr, ARCNET_TOTAL_SIZE); /* end of probing */ 211 return com90io_found(dev); 212 213err_out: 214 release_region(ioaddr, ARCNET_TOTAL_SIZE); 215 return -ENODEV; 216} 217 218/* Set up the struct net_device associated with this card. Called after 219 * probing succeeds. 220 */ 221static int __init com90io_found(struct net_device *dev) 222{ 223 struct arcnet_local *lp; 224 int ioaddr = dev->base_addr; 225 int err; 226 227 /* Reserve the irq */ 228 if (request_irq(dev->irq, arcnet_interrupt, 0, 229 "arcnet (COM90xx-IO)", dev)) { 230 arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq); 231 return -ENODEV; 232 } 233 /* Reserve the I/O region */ 234 if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, 235 "arcnet (COM90xx-IO)")) { 236 free_irq(dev->irq, dev); 237 return -EBUSY; 238 } 239 240 lp = netdev_priv(dev); 241 lp->card_name = "COM90xx I/O"; 242 lp->hw.command = com90io_command; 243 lp->hw.status = com90io_status; 244 lp->hw.intmask = com90io_setmask; 245 lp->hw.reset = com90io_reset; 246 lp->hw.owner = THIS_MODULE; 247 lp->hw.copy_to_card = com90io_copy_to_card; 248 lp->hw.copy_from_card = com90io_copy_from_card; 249 250 lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; 251 arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG); 252 253 /* get and check the station ID from offset 1 in shmem */ 254 255 arcnet_set_addr(dev, get_buffer_byte(dev, 1)); 256 257 err = register_netdev(dev); 258 if (err) { 259 arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag, 260 ioaddr, COM9026_REG_RW_CONFIG); 261 free_irq(dev->irq, dev); 262 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 263 return err; 264 } 265 266 arc_printk(D_NORMAL, dev, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", 267 dev->dev_addr[0], dev->base_addr, dev->irq); 268 269 return 0; 270} 271 272/* Do a hardware reset on the card, and set up necessary registers. 273 * 274 * This should be called as little as possible, because it disrupts the 275 * token on the network (causes a RECON) and requires a significant delay. 276 * 277 * However, it does make sure the card is in a defined state. 278 */ 279static int com90io_reset(struct net_device *dev, int really_reset) 280{ 281 struct arcnet_local *lp = netdev_priv(dev); 282 short ioaddr = dev->base_addr; 283 284 arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n", 285 dev->name, arcnet_inb(ioaddr, COM9026_REG_R_STATUS)); 286 287 if (really_reset) { 288 /* reset the card */ 289 arcnet_inb(ioaddr, COM9026_REG_R_RESET); 290 mdelay(RESETtime); 291 } 292 /* Set the thing to IO-mapped, 8-bit mode */ 293 lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag; 294 arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG); 295 296 arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND); 297 /* clear flags & end reset */ 298 arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND); 299 300 /* verify that the ARCnet signature byte is present */ 301 if (get_buffer_byte(dev, 0) != TESTvalue) { 302 arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n"); 303 return 1; 304 } 305 /* enable extended (512-byte) packets */ 306 arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND); 307 /* done! return success. */ 308 return 0; 309} 310 311static void com90io_command(struct net_device *dev, int cmd) 312{ 313 short ioaddr = dev->base_addr; 314 315 arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND); 316} 317 318static int com90io_status(struct net_device *dev) 319{ 320 short ioaddr = dev->base_addr; 321 322 return arcnet_inb(ioaddr, COM9026_REG_R_STATUS); 323} 324 325static void com90io_setmask(struct net_device *dev, int mask) 326{ 327 short ioaddr = dev->base_addr; 328 329 arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK); 330} 331 332static void com90io_copy_to_card(struct net_device *dev, int bufnum, 333 int offset, void *buf, int count) 334{ 335 TIME(dev, "put_whole_buffer", count, 336 put_whole_buffer(dev, bufnum * 512 + offset, count, buf)); 337} 338 339static void com90io_copy_from_card(struct net_device *dev, int bufnum, 340 int offset, void *buf, int count) 341{ 342 TIME(dev, "get_whole_buffer", count, 343 get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); 344} 345 346static int io; /* use the insmod io= irq= shmem= options */ 347static int irq; 348static char device[9]; /* use eg. device=arc1 to change name */ 349 350module_param_hw(io, int, ioport, 0); 351module_param_hw(irq, int, irq, 0); 352module_param_string(device, device, sizeof(device), 0); 353MODULE_LICENSE("GPL"); 354 355#ifndef MODULE 356static int __init com90io_setup(char *s) 357{ 358 int ints[4]; 359 360 s = get_options(s, 4, ints); 361 if (!ints[0]) 362 return 0; 363 switch (ints[0]) { 364 default: /* ERROR */ 365 pr_err("Too many arguments\n"); 366 fallthrough; 367 case 2: /* IRQ */ 368 irq = ints[2]; 369 fallthrough; 370 case 1: /* IO address */ 371 io = ints[1]; 372 } 373 if (*s) 374 snprintf(device, sizeof(device), "%s", s); 375 return 1; 376} 377__setup("com90io=", com90io_setup); 378#endif 379 380static struct net_device *my_dev; 381 382static int __init com90io_init(void) 383{ 384 struct net_device *dev; 385 int err; 386 387 dev = alloc_arcdev(device); 388 if (!dev) 389 return -ENOMEM; 390 391 dev->base_addr = io; 392 dev->irq = irq; 393 if (dev->irq == 2) 394 dev->irq = 9; 395 396 err = com90io_probe(dev); 397 398 if (err) { 399 free_arcdev(dev); 400 return err; 401 } 402 403 my_dev = dev; 404 return 0; 405} 406 407static void __exit com90io_exit(void) 408{ 409 struct net_device *dev = my_dev; 410 int ioaddr = dev->base_addr; 411 412 unregister_netdev(dev); 413 414 /* In case the old driver is loaded later, 415 * set the thing back to MMAP mode 416 */ 417 arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag, 418 ioaddr, COM9026_REG_RW_CONFIG); 419 420 free_irq(dev->irq, dev); 421 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 422 free_arcdev(dev); 423} 424 425module_init(com90io_init) 426module_exit(com90io_exit)