1 /* 2 * Linux ARCnet driver - COM20020 PCI support 3 * Contemporary Controls PCI20 and SOHARD SH-ARC PCI 4 * 5 * Written 1994-1999 by Avery Pennarun, 6 * based on an ISA version by David Woodhouse. 7 * Written 1999-2000 by Martin Mares <mj@ucw.cz>. 8 * Derived from skeleton.c by Donald Becker. 9 * 10 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) 11 * for sponsoring the further development of this driver. 12 * 13 * ********************** 14 * 15 * The original copyright of skeleton.c was as follows: 16 * 17 * skeleton.c Written 1993 by Donald Becker. 18 * Copyright 1993 United States Government as represented by the 19 * Director, National Security Agency. This software may only be used 20 * and distributed according to the terms of the GNU General Public License as 21 * modified by SRC, incorporated herein by reference. 22 * 23 * ********************** 24 * 25 * For more details, see drivers/net/arcnet.c 26 * 27 * ********************** 28 */ 29 30 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt 31 32 #include <linux/module.h> 33 #include <linux/moduleparam.h> 34 #include <linux/kernel.h> 35 #include <linux/types.h> 36 #include <linux/ioport.h> 37 #include <linux/errno.h> 38 #include <linux/netdevice.h> 39 #include <linux/init.h> 40 #include <linux/interrupt.h> 41 #include <linux/pci.h> 42 #include <linux/list.h> 43 #include <linux/io.h> 44 #include <linux/leds.h> 45 46 #include "arcdevice.h" 47 #include "com20020.h" 48 49 /* Module parameters */ 50 51 static int node; 52 static char device[9]; /* use eg. device="arc1" to change name */ 53 static int timeout = 3; 54 static int backplane; 55 static int clockp; 56 static int clockm; 57 58 module_param(node, int, 0); 59 module_param_string(device, device, sizeof(device), 0); 60 module_param(timeout, int, 0); 61 module_param(backplane, int, 0); 62 module_param(clockp, int, 0); 63 module_param(clockm, int, 0); 64 MODULE_DESCRIPTION("ARCnet COM20020 chipset PCI driver"); 65 MODULE_LICENSE("GPL"); 66 67 static void led_tx_set(struct led_classdev *led_cdev, 68 enum led_brightness value) 69 { 70 struct com20020_dev *card; 71 struct com20020_priv *priv; 72 struct com20020_pci_card_info *ci; 73 74 card = container_of(led_cdev, struct com20020_dev, tx_led); 75 76 priv = card->pci_priv; 77 ci = priv->ci; 78 79 outb(!!value, priv->misc + ci->leds[card->index].green); 80 } 81 82 static void led_recon_set(struct led_classdev *led_cdev, 83 enum led_brightness value) 84 { 85 struct com20020_dev *card; 86 struct com20020_priv *priv; 87 struct com20020_pci_card_info *ci; 88 89 card = container_of(led_cdev, struct com20020_dev, recon_led); 90 91 priv = card->pci_priv; 92 ci = priv->ci; 93 94 outb(!!value, priv->misc + ci->leds[card->index].red); 95 } 96 97 static ssize_t backplane_mode_show(struct device *dev, 98 struct device_attribute *attr, 99 char *buf) 100 { 101 struct net_device *net_dev = to_net_dev(dev); 102 struct arcnet_local *lp = netdev_priv(net_dev); 103 104 return sprintf(buf, "%s\n", lp->backplane ? "true" : "false"); 105 } 106 static DEVICE_ATTR_RO(backplane_mode); 107 108 static struct attribute *com20020_state_attrs[] = { 109 &dev_attr_backplane_mode.attr, 110 NULL, 111 }; 112 113 static const struct attribute_group com20020_state_group = { 114 .name = NULL, 115 .attrs = com20020_state_attrs, 116 }; 117 118 static void com20020pci_remove(struct pci_dev *pdev); 119 120 static int com20020pci_probe(struct pci_dev *pdev, 121 const struct pci_device_id *id) 122 { 123 struct com20020_pci_card_info *ci; 124 struct com20020_pci_channel_map *mm; 125 struct net_device *dev; 126 struct arcnet_local *lp; 127 struct com20020_priv *priv; 128 int i, ioaddr, ret; 129 struct resource *r; 130 131 ret = 0; 132 133 if (pci_enable_device(pdev)) 134 return -EIO; 135 136 priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), 137 GFP_KERNEL); 138 if (!priv) 139 return -ENOMEM; 140 141 ci = (struct com20020_pci_card_info *)id->driver_data; 142 if (!ci) 143 return -EINVAL; 144 145 priv->ci = ci; 146 mm = &ci->misc_map; 147 148 pci_set_drvdata(pdev, priv); 149 150 INIT_LIST_HEAD(&priv->list_dev); 151 152 if (mm->size) { 153 ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset; 154 r = devm_request_region(&pdev->dev, ioaddr, mm->size, 155 "com20020-pci"); 156 if (!r) { 157 pr_err("IO region %xh-%xh already allocated.\n", 158 ioaddr, ioaddr + mm->size - 1); 159 return -EBUSY; 160 } 161 priv->misc = ioaddr; 162 } 163 164 for (i = 0; i < ci->devcount; i++) { 165 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; 166 struct com20020_dev *card; 167 int dev_id_mask = 0xf; 168 169 dev = alloc_arcdev(device); 170 if (!dev) { 171 ret = -ENOMEM; 172 break; 173 } 174 dev->dev_port = i; 175 176 dev->netdev_ops = &com20020_netdev_ops; 177 178 lp = netdev_priv(dev); 179 180 arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name); 181 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset; 182 183 r = devm_request_region(&pdev->dev, ioaddr, cm->size, 184 "com20020-pci"); 185 if (!r) { 186 pr_err("IO region %xh-%xh already allocated\n", 187 ioaddr, ioaddr + cm->size - 1); 188 ret = -EBUSY; 189 goto err_free_arcdev; 190 } 191 192 /* Dummy access after Reset 193 * ARCNET controller needs 194 * this access to detect bustype 195 */ 196 arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND); 197 arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT); 198 199 SET_NETDEV_DEV(dev, &pdev->dev); 200 dev->base_addr = ioaddr; 201 arcnet_set_addr(dev, node); 202 dev->sysfs_groups[0] = &com20020_state_group; 203 dev->irq = pdev->irq; 204 lp->card_name = "PCI COM20020"; 205 lp->card_flags = ci->flags; 206 lp->backplane = backplane; 207 lp->clockp = clockp & 7; 208 lp->clockm = clockm & 3; 209 lp->timeout = timeout; 210 lp->hw.owner = THIS_MODULE; 211 212 lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1; 213 214 if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15)) 215 lp->backplane = 1; 216 217 if (ci->flags & ARC_HAS_ROTARY) { 218 /* Get the dev_id from the PLX rotary coder */ 219 if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15)) 220 dev_id_mask = 0x3; 221 dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask; 222 snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i); 223 } 224 225 if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) { 226 pr_err("IO address %Xh is empty!\n", ioaddr); 227 ret = -EIO; 228 goto err_free_arcdev; 229 } 230 if (com20020_check(dev)) { 231 ret = -EIO; 232 goto err_free_arcdev; 233 } 234 235 ret = com20020_found(dev, IRQF_SHARED); 236 if (ret) 237 goto err_free_arcdev; 238 239 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev), 240 GFP_KERNEL); 241 if (!card) { 242 ret = -ENOMEM; 243 goto err_free_arcdev; 244 } 245 246 card->index = i; 247 card->pci_priv = priv; 248 249 if (ci->flags & ARC_HAS_LED) { 250 card->tx_led.brightness_set = led_tx_set; 251 card->tx_led.default_trigger = devm_kasprintf(&pdev->dev, 252 GFP_KERNEL, "arc%d-%d-tx", 253 dev->dev_id, i); 254 card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 255 "pci:green:tx:%d-%d", 256 dev->dev_id, i); 257 258 card->tx_led.dev = &dev->dev; 259 card->recon_led.brightness_set = led_recon_set; 260 card->recon_led.default_trigger = devm_kasprintf(&pdev->dev, 261 GFP_KERNEL, "arc%d-%d-recon", 262 dev->dev_id, i); 263 card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 264 "pci:red:recon:%d-%d", 265 dev->dev_id, i); 266 card->recon_led.dev = &dev->dev; 267 268 ret = devm_led_classdev_register(&pdev->dev, &card->tx_led); 269 if (ret) 270 goto err_free_arcdev; 271 272 ret = devm_led_classdev_register(&pdev->dev, &card->recon_led); 273 if (ret) 274 goto err_free_arcdev; 275 276 dev_set_drvdata(&dev->dev, card); 277 devm_arcnet_led_init(dev, dev->dev_id, i); 278 } 279 280 card->dev = dev; 281 list_add(&card->list, &priv->list_dev); 282 continue; 283 284 err_free_arcdev: 285 free_arcdev(dev); 286 break; 287 } 288 if (ret) 289 com20020pci_remove(pdev); 290 return ret; 291 } 292 293 static void com20020pci_remove(struct pci_dev *pdev) 294 { 295 struct com20020_dev *card, *tmpcard; 296 struct com20020_priv *priv; 297 298 priv = pci_get_drvdata(pdev); 299 300 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) { 301 struct net_device *dev = card->dev; 302 303 unregister_netdev(dev); 304 free_irq(dev->irq, dev); 305 free_arcdev(dev); 306 } 307 } 308 309 static struct com20020_pci_card_info card_info_10mbit = { 310 .name = "ARC-PCI", 311 .devcount = 1, 312 .chan_map_tbl = { 313 { 314 .bar = 2, 315 .offset = 0x00, 316 .size = 0x08, 317 }, 318 }, 319 .flags = ARC_CAN_10MBIT, 320 }; 321 322 static struct com20020_pci_card_info card_info_5mbit = { 323 .name = "ARC-PCI", 324 .devcount = 1, 325 .chan_map_tbl = { 326 { 327 .bar = 2, 328 .offset = 0x00, 329 .size = 0x08, 330 }, 331 }, 332 .flags = ARC_IS_5MBIT, 333 }; 334 335 static struct com20020_pci_card_info card_info_sohard = { 336 .name = "SOHARD SH ARC-PCI", 337 .devcount = 1, 338 /* SOHARD needs PCI base addr 4 */ 339 .chan_map_tbl = { 340 { 341 .bar = 4, 342 .offset = 0x00, 343 .size = 0x08 344 }, 345 }, 346 .flags = ARC_CAN_10MBIT, 347 }; 348 349 static struct com20020_pci_card_info card_info_eae_arc1 = { 350 .name = "EAE PLX-PCI ARC1", 351 .devcount = 1, 352 .chan_map_tbl = { 353 { 354 .bar = 2, 355 .offset = 0x00, 356 .size = 0x08, 357 }, 358 }, 359 .misc_map = { 360 .bar = 2, 361 .offset = 0x10, 362 .size = 0x04, 363 }, 364 .leds = { 365 { 366 .green = 0x0, 367 .red = 0x1, 368 }, 369 }, 370 .rotary = 0x0, 371 .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT, 372 }; 373 374 static struct com20020_pci_card_info card_info_eae_ma1 = { 375 .name = "EAE PLX-PCI MA1", 376 .devcount = 2, 377 .chan_map_tbl = { 378 { 379 .bar = 2, 380 .offset = 0x00, 381 .size = 0x08, 382 }, { 383 .bar = 2, 384 .offset = 0x08, 385 .size = 0x08, 386 } 387 }, 388 .misc_map = { 389 .bar = 2, 390 .offset = 0x10, 391 .size = 0x04, 392 }, 393 .leds = { 394 { 395 .green = 0x0, 396 .red = 0x1, 397 }, { 398 .green = 0x2, 399 .red = 0x3, 400 }, 401 }, 402 .rotary = 0x0, 403 .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT, 404 }; 405 406 static struct com20020_pci_card_info card_info_eae_fb2 = { 407 .name = "EAE PLX-PCI FB2", 408 .devcount = 1, 409 .chan_map_tbl = { 410 { 411 .bar = 2, 412 .offset = 0x00, 413 .size = 0x08, 414 }, 415 }, 416 .misc_map = { 417 .bar = 2, 418 .offset = 0x10, 419 .size = 0x04, 420 }, 421 .leds = { 422 { 423 .green = 0x0, 424 .red = 0x1, 425 }, 426 }, 427 .rotary = 0x0, 428 .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT, 429 }; 430 431 static const struct pci_device_id com20020pci_id_table[] = { 432 { 433 0x1571, 0xa001, 434 PCI_ANY_ID, PCI_ANY_ID, 435 0, 0, 436 0, 437 }, 438 { 439 0x1571, 0xa002, 440 PCI_ANY_ID, PCI_ANY_ID, 441 0, 0, 442 0, 443 }, 444 { 445 0x1571, 0xa003, 446 PCI_ANY_ID, PCI_ANY_ID, 447 0, 0, 448 0 449 }, 450 { 451 0x1571, 0xa004, 452 PCI_ANY_ID, PCI_ANY_ID, 453 0, 0, 454 0, 455 }, 456 { 457 0x1571, 0xa005, 458 PCI_ANY_ID, PCI_ANY_ID, 459 0, 0, 460 0 461 }, 462 { 463 0x1571, 0xa006, 464 PCI_ANY_ID, PCI_ANY_ID, 465 0, 0, 466 0 467 }, 468 { 469 0x1571, 0xa007, 470 PCI_ANY_ID, PCI_ANY_ID, 471 0, 0, 472 0 473 }, 474 { 475 0x1571, 0xa008, 476 PCI_ANY_ID, PCI_ANY_ID, 477 0, 0, 478 0 479 }, 480 { 481 0x1571, 0xa009, 482 PCI_ANY_ID, PCI_ANY_ID, 483 0, 0, 484 (kernel_ulong_t)&card_info_5mbit 485 }, 486 { 487 0x1571, 0xa00a, 488 PCI_ANY_ID, PCI_ANY_ID, 489 0, 0, 490 (kernel_ulong_t)&card_info_5mbit 491 }, 492 { 493 0x1571, 0xa00b, 494 PCI_ANY_ID, PCI_ANY_ID, 495 0, 0, 496 (kernel_ulong_t)&card_info_5mbit 497 }, 498 { 499 0x1571, 0xa00c, 500 PCI_ANY_ID, PCI_ANY_ID, 501 0, 0, 502 (kernel_ulong_t)&card_info_5mbit 503 }, 504 { 505 0x1571, 0xa00d, 506 PCI_ANY_ID, PCI_ANY_ID, 507 0, 0, 508 (kernel_ulong_t)&card_info_5mbit 509 }, 510 { 511 0x1571, 0xa00e, 512 PCI_ANY_ID, PCI_ANY_ID, 513 0, 0, 514 (kernel_ulong_t)&card_info_5mbit 515 }, 516 { 517 0x1571, 0xa201, 518 PCI_ANY_ID, PCI_ANY_ID, 519 0, 0, 520 (kernel_ulong_t)&card_info_10mbit 521 }, 522 { 523 0x1571, 0xa202, 524 PCI_ANY_ID, PCI_ANY_ID, 525 0, 0, 526 (kernel_ulong_t)&card_info_10mbit 527 }, 528 { 529 0x1571, 0xa203, 530 PCI_ANY_ID, PCI_ANY_ID, 531 0, 0, 532 (kernel_ulong_t)&card_info_10mbit 533 }, 534 { 535 0x1571, 0xa204, 536 PCI_ANY_ID, PCI_ANY_ID, 537 0, 0, 538 (kernel_ulong_t)&card_info_10mbit 539 }, 540 { 541 0x1571, 0xa205, 542 PCI_ANY_ID, PCI_ANY_ID, 543 0, 0, 544 (kernel_ulong_t)&card_info_10mbit 545 }, 546 { 547 0x1571, 0xa206, 548 PCI_ANY_ID, PCI_ANY_ID, 549 0, 0, 550 (kernel_ulong_t)&card_info_10mbit 551 }, 552 { 553 0x10B5, 0x9030, 554 0x10B5, 0x2978, 555 0, 0, 556 (kernel_ulong_t)&card_info_sohard 557 }, 558 { 559 0x10B5, 0x9050, 560 0x10B5, 0x2273, 561 0, 0, 562 (kernel_ulong_t)&card_info_sohard 563 }, 564 { 565 0x10B5, 0x9050, 566 0x10B5, 0x3263, 567 0, 0, 568 (kernel_ulong_t)&card_info_eae_arc1 569 }, 570 { 571 0x10B5, 0x9050, 572 0x10B5, 0x3292, 573 0, 0, 574 (kernel_ulong_t)&card_info_eae_ma1 575 }, 576 { 577 0x10B5, 0x9050, 578 0x10B5, 0x3294, 579 0, 0, 580 (kernel_ulong_t)&card_info_eae_fb2 581 }, 582 { 583 0x14BA, 0x6000, 584 PCI_ANY_ID, PCI_ANY_ID, 585 0, 0, 586 (kernel_ulong_t)&card_info_10mbit 587 }, 588 { 589 0x10B5, 0x2200, 590 PCI_ANY_ID, PCI_ANY_ID, 591 0, 0, 592 (kernel_ulong_t)&card_info_10mbit 593 }, 594 { 0, } 595 }; 596 597 MODULE_DEVICE_TABLE(pci, com20020pci_id_table); 598 599 static struct pci_driver com20020pci_driver = { 600 .name = "com20020", 601 .id_table = com20020pci_id_table, 602 .probe = com20020pci_probe, 603 .remove = com20020pci_remove, 604 }; 605 606 static int __init com20020pci_init(void) 607 { 608 if (BUGLVL(D_NORMAL)) 609 pr_info("%s\n", "COM20020 PCI support"); 610 return pci_register_driver(&com20020pci_driver); 611 } 612 613 static void __exit com20020pci_cleanup(void) 614 { 615 pci_unregister_driver(&com20020pci_driver); 616 } 617 618 module_init(com20020pci_init) 619 module_exit(com20020pci_cleanup) 620