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