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 if (!card->tx_led.default_trigger) { 255 ret = -ENOMEM; 256 goto err_free_arcdev; 257 } 258 card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 259 "pci:green:tx:%d-%d", 260 dev->dev_id, i); 261 if (!card->tx_led.name) { 262 ret = -ENOMEM; 263 goto err_free_arcdev; 264 } 265 card->tx_led.dev = &dev->dev; 266 card->recon_led.brightness_set = led_recon_set; 267 card->recon_led.default_trigger = devm_kasprintf(&pdev->dev, 268 GFP_KERNEL, "arc%d-%d-recon", 269 dev->dev_id, i); 270 if (!card->recon_led.default_trigger) { 271 ret = -ENOMEM; 272 goto err_free_arcdev; 273 } 274 card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 275 "pci:red:recon:%d-%d", 276 dev->dev_id, i); 277 if (!card->recon_led.name) { 278 ret = -ENOMEM; 279 goto err_free_arcdev; 280 } 281 card->recon_led.dev = &dev->dev; 282 283 ret = devm_led_classdev_register(&pdev->dev, &card->tx_led); 284 if (ret) 285 goto err_free_arcdev; 286 287 ret = devm_led_classdev_register(&pdev->dev, &card->recon_led); 288 if (ret) 289 goto err_free_arcdev; 290 291 dev_set_drvdata(&dev->dev, card); 292 devm_arcnet_led_init(dev, dev->dev_id, i); 293 } 294 295 card->dev = dev; 296 list_add(&card->list, &priv->list_dev); 297 continue; 298 299 err_free_arcdev: 300 free_arcdev(dev); 301 break; 302 } 303 if (ret) 304 com20020pci_remove(pdev); 305 return ret; 306 } 307 308 static void com20020pci_remove(struct pci_dev *pdev) 309 { 310 struct com20020_dev *card, *tmpcard; 311 struct com20020_priv *priv; 312 313 priv = pci_get_drvdata(pdev); 314 315 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) { 316 struct net_device *dev = card->dev; 317 318 unregister_netdev(dev); 319 free_irq(dev->irq, dev); 320 free_arcdev(dev); 321 } 322 } 323 324 static struct com20020_pci_card_info card_info_10mbit = { 325 .name = "ARC-PCI", 326 .devcount = 1, 327 .chan_map_tbl = { 328 { 329 .bar = 2, 330 .offset = 0x00, 331 .size = 0x08, 332 }, 333 }, 334 .flags = ARC_CAN_10MBIT, 335 }; 336 337 static struct com20020_pci_card_info card_info_5mbit = { 338 .name = "ARC-PCI", 339 .devcount = 1, 340 .chan_map_tbl = { 341 { 342 .bar = 2, 343 .offset = 0x00, 344 .size = 0x08, 345 }, 346 }, 347 .flags = ARC_IS_5MBIT, 348 }; 349 350 static struct com20020_pci_card_info card_info_sohard = { 351 .name = "SOHARD SH ARC-PCI", 352 .devcount = 1, 353 /* SOHARD needs PCI base addr 4 */ 354 .chan_map_tbl = { 355 { 356 .bar = 4, 357 .offset = 0x00, 358 .size = 0x08 359 }, 360 }, 361 .flags = ARC_CAN_10MBIT, 362 }; 363 364 static struct com20020_pci_card_info card_info_eae_arc1 = { 365 .name = "EAE PLX-PCI ARC1", 366 .devcount = 1, 367 .chan_map_tbl = { 368 { 369 .bar = 2, 370 .offset = 0x00, 371 .size = 0x08, 372 }, 373 }, 374 .misc_map = { 375 .bar = 2, 376 .offset = 0x10, 377 .size = 0x04, 378 }, 379 .leds = { 380 { 381 .green = 0x0, 382 .red = 0x1, 383 }, 384 }, 385 .rotary = 0x0, 386 .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT, 387 }; 388 389 static struct com20020_pci_card_info card_info_eae_ma1 = { 390 .name = "EAE PLX-PCI MA1", 391 .devcount = 2, 392 .chan_map_tbl = { 393 { 394 .bar = 2, 395 .offset = 0x00, 396 .size = 0x08, 397 }, { 398 .bar = 2, 399 .offset = 0x08, 400 .size = 0x08, 401 } 402 }, 403 .misc_map = { 404 .bar = 2, 405 .offset = 0x10, 406 .size = 0x04, 407 }, 408 .leds = { 409 { 410 .green = 0x0, 411 .red = 0x1, 412 }, { 413 .green = 0x2, 414 .red = 0x3, 415 }, 416 }, 417 .rotary = 0x0, 418 .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT, 419 }; 420 421 static struct com20020_pci_card_info card_info_eae_fb2 = { 422 .name = "EAE PLX-PCI FB2", 423 .devcount = 1, 424 .chan_map_tbl = { 425 { 426 .bar = 2, 427 .offset = 0x00, 428 .size = 0x08, 429 }, 430 }, 431 .misc_map = { 432 .bar = 2, 433 .offset = 0x10, 434 .size = 0x04, 435 }, 436 .leds = { 437 { 438 .green = 0x0, 439 .red = 0x1, 440 }, 441 }, 442 .rotary = 0x0, 443 .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT, 444 }; 445 446 static const struct pci_device_id com20020pci_id_table[] = { 447 { 448 0x1571, 0xa001, 449 PCI_ANY_ID, PCI_ANY_ID, 450 0, 0, 451 0, 452 }, 453 { 454 0x1571, 0xa002, 455 PCI_ANY_ID, PCI_ANY_ID, 456 0, 0, 457 0, 458 }, 459 { 460 0x1571, 0xa003, 461 PCI_ANY_ID, PCI_ANY_ID, 462 0, 0, 463 0 464 }, 465 { 466 0x1571, 0xa004, 467 PCI_ANY_ID, PCI_ANY_ID, 468 0, 0, 469 0, 470 }, 471 { 472 0x1571, 0xa005, 473 PCI_ANY_ID, PCI_ANY_ID, 474 0, 0, 475 0 476 }, 477 { 478 0x1571, 0xa006, 479 PCI_ANY_ID, PCI_ANY_ID, 480 0, 0, 481 0 482 }, 483 { 484 0x1571, 0xa007, 485 PCI_ANY_ID, PCI_ANY_ID, 486 0, 0, 487 0 488 }, 489 { 490 0x1571, 0xa008, 491 PCI_ANY_ID, PCI_ANY_ID, 492 0, 0, 493 0 494 }, 495 { 496 0x1571, 0xa009, 497 PCI_ANY_ID, PCI_ANY_ID, 498 0, 0, 499 (kernel_ulong_t)&card_info_5mbit 500 }, 501 { 502 0x1571, 0xa00a, 503 PCI_ANY_ID, PCI_ANY_ID, 504 0, 0, 505 (kernel_ulong_t)&card_info_5mbit 506 }, 507 { 508 0x1571, 0xa00b, 509 PCI_ANY_ID, PCI_ANY_ID, 510 0, 0, 511 (kernel_ulong_t)&card_info_5mbit 512 }, 513 { 514 0x1571, 0xa00c, 515 PCI_ANY_ID, PCI_ANY_ID, 516 0, 0, 517 (kernel_ulong_t)&card_info_5mbit 518 }, 519 { 520 0x1571, 0xa00d, 521 PCI_ANY_ID, PCI_ANY_ID, 522 0, 0, 523 (kernel_ulong_t)&card_info_5mbit 524 }, 525 { 526 0x1571, 0xa00e, 527 PCI_ANY_ID, PCI_ANY_ID, 528 0, 0, 529 (kernel_ulong_t)&card_info_5mbit 530 }, 531 { 532 0x1571, 0xa201, 533 PCI_ANY_ID, PCI_ANY_ID, 534 0, 0, 535 (kernel_ulong_t)&card_info_10mbit 536 }, 537 { 538 0x1571, 0xa202, 539 PCI_ANY_ID, PCI_ANY_ID, 540 0, 0, 541 (kernel_ulong_t)&card_info_10mbit 542 }, 543 { 544 0x1571, 0xa203, 545 PCI_ANY_ID, PCI_ANY_ID, 546 0, 0, 547 (kernel_ulong_t)&card_info_10mbit 548 }, 549 { 550 0x1571, 0xa204, 551 PCI_ANY_ID, PCI_ANY_ID, 552 0, 0, 553 (kernel_ulong_t)&card_info_10mbit 554 }, 555 { 556 0x1571, 0xa205, 557 PCI_ANY_ID, PCI_ANY_ID, 558 0, 0, 559 (kernel_ulong_t)&card_info_10mbit 560 }, 561 { 562 0x1571, 0xa206, 563 PCI_ANY_ID, PCI_ANY_ID, 564 0, 0, 565 (kernel_ulong_t)&card_info_10mbit 566 }, 567 { 568 0x10B5, 0x9030, 569 0x10B5, 0x2978, 570 0, 0, 571 (kernel_ulong_t)&card_info_sohard 572 }, 573 { 574 0x10B5, 0x9050, 575 0x10B5, 0x2273, 576 0, 0, 577 (kernel_ulong_t)&card_info_sohard 578 }, 579 { 580 0x10B5, 0x9050, 581 0x10B5, 0x3263, 582 0, 0, 583 (kernel_ulong_t)&card_info_eae_arc1 584 }, 585 { 586 0x10B5, 0x9050, 587 0x10B5, 0x3292, 588 0, 0, 589 (kernel_ulong_t)&card_info_eae_ma1 590 }, 591 { 592 0x10B5, 0x9050, 593 0x10B5, 0x3294, 594 0, 0, 595 (kernel_ulong_t)&card_info_eae_fb2 596 }, 597 { 598 0x14BA, 0x6000, 599 PCI_ANY_ID, PCI_ANY_ID, 600 0, 0, 601 (kernel_ulong_t)&card_info_10mbit 602 }, 603 { 604 0x10B5, 0x2200, 605 PCI_ANY_ID, PCI_ANY_ID, 606 0, 0, 607 (kernel_ulong_t)&card_info_10mbit 608 }, 609 { 0, } 610 }; 611 612 MODULE_DEVICE_TABLE(pci, com20020pci_id_table); 613 614 static struct pci_driver com20020pci_driver = { 615 .name = "com20020", 616 .id_table = com20020pci_id_table, 617 .probe = com20020pci_probe, 618 .remove = com20020pci_remove, 619 }; 620 621 static int __init com20020pci_init(void) 622 { 623 if (BUGLVL(D_NORMAL)) 624 pr_info("%s\n", "COM20020 PCI support"); 625 return pci_register_driver(&com20020pci_driver); 626 } 627 628 static void __exit com20020pci_cleanup(void) 629 { 630 pci_unregister_driver(&com20020pci_driver); 631 } 632 633 module_init(com20020pci_init) 634 module_exit(com20020pci_cleanup) 635