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