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