Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Linux ARCnet driver - COM20020 PCI support
0003  * Contemporary Controls PCI20 and SOHARD SH-ARC PCI
0004  *
0005  * Written 1994-1999 by Avery Pennarun,
0006  *    based on an ISA version by David Woodhouse.
0007  * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
0008  * Derived from skeleton.c by Donald Becker.
0009  *
0010  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
0011  *  for sponsoring the further development of this driver.
0012  *
0013  * **********************
0014  *
0015  * The original copyright of skeleton.c was as follows:
0016  *
0017  * skeleton.c Written 1993 by Donald Becker.
0018  * Copyright 1993 United States Government as represented by the
0019  * Director, National Security Agency.  This software may only be used
0020  * and distributed according to the terms of the GNU General Public License as
0021  * modified by SRC, incorporated herein by reference.
0022  *
0023  * **********************
0024  *
0025  * For more details, see drivers/net/arcnet.c
0026  *
0027  * **********************
0028  */
0029 
0030 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
0031 
0032 #include <linux/module.h>
0033 #include <linux/moduleparam.h>
0034 #include <linux/kernel.h>
0035 #include <linux/types.h>
0036 #include <linux/ioport.h>
0037 #include <linux/errno.h>
0038 #include <linux/netdevice.h>
0039 #include <linux/init.h>
0040 #include <linux/interrupt.h>
0041 #include <linux/pci.h>
0042 #include <linux/list.h>
0043 #include <linux/io.h>
0044 #include <linux/leds.h>
0045 
0046 #include "arcdevice.h"
0047 #include "com20020.h"
0048 
0049 /* Module parameters */
0050 
0051 static int node;
0052 static char device[9];      /* use eg. device="arc1" to change name */
0053 static int timeout = 3;
0054 static int backplane;
0055 static int clockp;
0056 static int clockm;
0057 
0058 module_param(node, int, 0);
0059 module_param_string(device, device, sizeof(device), 0);
0060 module_param(timeout, int, 0);
0061 module_param(backplane, int, 0);
0062 module_param(clockp, int, 0);
0063 module_param(clockm, int, 0);
0064 MODULE_LICENSE("GPL");
0065 
0066 static void led_tx_set(struct led_classdev *led_cdev,
0067                  enum led_brightness value)
0068 {
0069     struct com20020_dev *card;
0070     struct com20020_priv *priv;
0071     struct com20020_pci_card_info *ci;
0072 
0073     card = container_of(led_cdev, struct com20020_dev, tx_led);
0074 
0075     priv = card->pci_priv;
0076     ci = priv->ci;
0077 
0078     outb(!!value, priv->misc + ci->leds[card->index].green);
0079 }
0080 
0081 static void led_recon_set(struct led_classdev *led_cdev,
0082                  enum led_brightness value)
0083 {
0084     struct com20020_dev *card;
0085     struct com20020_priv *priv;
0086     struct com20020_pci_card_info *ci;
0087 
0088     card = container_of(led_cdev, struct com20020_dev, recon_led);
0089 
0090     priv = card->pci_priv;
0091     ci = priv->ci;
0092 
0093     outb(!!value, priv->misc + ci->leds[card->index].red);
0094 }
0095 
0096 static ssize_t backplane_mode_show(struct device *dev,
0097                    struct device_attribute *attr,
0098                    char *buf)
0099 {
0100     struct net_device *net_dev = to_net_dev(dev);
0101     struct arcnet_local *lp = netdev_priv(net_dev);
0102 
0103     return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
0104 }
0105 static DEVICE_ATTR_RO(backplane_mode);
0106 
0107 static struct attribute *com20020_state_attrs[] = {
0108     &dev_attr_backplane_mode.attr,
0109     NULL,
0110 };
0111 
0112 static const struct attribute_group com20020_state_group = {
0113     .name = NULL,
0114     .attrs = com20020_state_attrs,
0115 };
0116 
0117 static void com20020pci_remove(struct pci_dev *pdev);
0118 
0119 static int com20020pci_probe(struct pci_dev *pdev,
0120                  const struct pci_device_id *id)
0121 {
0122     struct com20020_pci_card_info *ci;
0123     struct com20020_pci_channel_map *mm;
0124     struct net_device *dev;
0125     struct arcnet_local *lp;
0126     struct com20020_priv *priv;
0127     int i, ioaddr, ret;
0128     struct resource *r;
0129 
0130     ret = 0;
0131 
0132     if (pci_enable_device(pdev))
0133         return -EIO;
0134 
0135     priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
0136                 GFP_KERNEL);
0137     if (!priv)
0138         return -ENOMEM;
0139 
0140     ci = (struct com20020_pci_card_info *)id->driver_data;
0141     if (!ci)
0142         return -EINVAL;
0143 
0144     priv->ci = ci;
0145     mm = &ci->misc_map;
0146 
0147     pci_set_drvdata(pdev, priv);
0148 
0149     INIT_LIST_HEAD(&priv->list_dev);
0150 
0151     if (mm->size) {
0152         ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
0153         r = devm_request_region(&pdev->dev, ioaddr, mm->size,
0154                     "com20020-pci");
0155         if (!r) {
0156             pr_err("IO region %xh-%xh already allocated.\n",
0157                    ioaddr, ioaddr + mm->size - 1);
0158             return -EBUSY;
0159         }
0160         priv->misc = ioaddr;
0161     }
0162 
0163     for (i = 0; i < ci->devcount; i++) {
0164         struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
0165         struct com20020_dev *card;
0166         int dev_id_mask = 0xf;
0167 
0168         dev = alloc_arcdev(device);
0169         if (!dev) {
0170             ret = -ENOMEM;
0171             break;
0172         }
0173         dev->dev_port = i;
0174 
0175         dev->netdev_ops = &com20020_netdev_ops;
0176 
0177         lp = netdev_priv(dev);
0178 
0179         arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
0180         ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
0181 
0182         r = devm_request_region(&pdev->dev, ioaddr, cm->size,
0183                     "com20020-pci");
0184         if (!r) {
0185             pr_err("IO region %xh-%xh already allocated\n",
0186                    ioaddr, ioaddr + cm->size - 1);
0187             ret = -EBUSY;
0188             goto err_free_arcdev;
0189         }
0190 
0191         /* Dummy access after Reset
0192          * ARCNET controller needs
0193          * this access to detect bustype
0194          */
0195         arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
0196         arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
0197 
0198         SET_NETDEV_DEV(dev, &pdev->dev);
0199         dev->base_addr = ioaddr;
0200         arcnet_set_addr(dev, node);
0201         dev->sysfs_groups[0] = &com20020_state_group;
0202         dev->irq = pdev->irq;
0203         lp->card_name = "PCI COM20020";
0204         lp->card_flags = ci->flags;
0205         lp->backplane = backplane;
0206         lp->clockp = clockp & 7;
0207         lp->clockm = clockm & 3;
0208         lp->timeout = timeout;
0209         lp->hw.owner = THIS_MODULE;
0210 
0211         lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
0212 
0213         if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
0214             lp->backplane = 1;
0215 
0216         /* Get the dev_id from the PLX rotary coder */
0217         if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
0218             dev_id_mask = 0x3;
0219         dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
0220 
0221         snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
0222 
0223         if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
0224             pr_err("IO address %Xh is empty!\n", ioaddr);
0225             ret = -EIO;
0226             goto err_free_arcdev;
0227         }
0228         if (com20020_check(dev)) {
0229             ret = -EIO;
0230             goto err_free_arcdev;
0231         }
0232 
0233         card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
0234                     GFP_KERNEL);
0235         if (!card) {
0236             ret = -ENOMEM;
0237             goto err_free_arcdev;
0238         }
0239 
0240         card->index = i;
0241         card->pci_priv = priv;
0242         card->tx_led.brightness_set = led_tx_set;
0243         card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
0244                         GFP_KERNEL, "arc%d-%d-tx",
0245                         dev->dev_id, i);
0246         card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0247                         "pci:green:tx:%d-%d",
0248                         dev->dev_id, i);
0249 
0250         card->tx_led.dev = &dev->dev;
0251         card->recon_led.brightness_set = led_recon_set;
0252         card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
0253                         GFP_KERNEL, "arc%d-%d-recon",
0254                         dev->dev_id, i);
0255         card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0256                         "pci:red:recon:%d-%d",
0257                         dev->dev_id, i);
0258         card->recon_led.dev = &dev->dev;
0259         card->dev = dev;
0260 
0261         ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
0262         if (ret)
0263             goto err_free_arcdev;
0264 
0265         ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
0266         if (ret)
0267             goto err_free_arcdev;
0268 
0269         dev_set_drvdata(&dev->dev, card);
0270 
0271         ret = com20020_found(dev, IRQF_SHARED);
0272         if (ret)
0273             goto err_free_arcdev;
0274 
0275         devm_arcnet_led_init(dev, dev->dev_id, i);
0276 
0277         list_add(&card->list, &priv->list_dev);
0278         continue;
0279 
0280 err_free_arcdev:
0281         free_arcdev(dev);
0282         break;
0283     }
0284     if (ret)
0285         com20020pci_remove(pdev);
0286     return ret;
0287 }
0288 
0289 static void com20020pci_remove(struct pci_dev *pdev)
0290 {
0291     struct com20020_dev *card, *tmpcard;
0292     struct com20020_priv *priv;
0293 
0294     priv = pci_get_drvdata(pdev);
0295 
0296     list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
0297         struct net_device *dev = card->dev;
0298 
0299         unregister_netdev(dev);
0300         free_irq(dev->irq, dev);
0301         free_arcdev(dev);
0302     }
0303 }
0304 
0305 static struct com20020_pci_card_info card_info_10mbit = {
0306     .name = "ARC-PCI",
0307     .devcount = 1,
0308     .chan_map_tbl = {
0309         {
0310             .bar = 2,
0311             .offset = 0x00,
0312             .size = 0x08,
0313         },
0314     },
0315     .flags = ARC_CAN_10MBIT,
0316 };
0317 
0318 static struct com20020_pci_card_info card_info_5mbit = {
0319     .name = "ARC-PCI",
0320     .devcount = 1,
0321     .chan_map_tbl = {
0322         {
0323             .bar = 2,
0324             .offset = 0x00,
0325             .size = 0x08,
0326         },
0327     },
0328     .flags = ARC_IS_5MBIT,
0329 };
0330 
0331 static struct com20020_pci_card_info card_info_sohard = {
0332     .name = "PLX-PCI",
0333     .devcount = 1,
0334     /* SOHARD needs PCI base addr 4 */
0335     .chan_map_tbl = {
0336         {
0337             .bar = 4,
0338             .offset = 0x00,
0339             .size = 0x08
0340         },
0341     },
0342     .flags = ARC_CAN_10MBIT,
0343 };
0344 
0345 static struct com20020_pci_card_info card_info_eae_arc1 = {
0346     .name = "EAE PLX-PCI ARC1",
0347     .devcount = 1,
0348     .chan_map_tbl = {
0349         {
0350             .bar = 2,
0351             .offset = 0x00,
0352             .size = 0x08,
0353         },
0354     },
0355     .misc_map = {
0356         .bar = 2,
0357         .offset = 0x10,
0358         .size = 0x04,
0359     },
0360     .leds = {
0361         {
0362             .green = 0x0,
0363             .red = 0x1,
0364         },
0365     },
0366     .rotary = 0x0,
0367     .flags = ARC_CAN_10MBIT,
0368 };
0369 
0370 static struct com20020_pci_card_info card_info_eae_ma1 = {
0371     .name = "EAE PLX-PCI MA1",
0372     .devcount = 2,
0373     .chan_map_tbl = {
0374         {
0375             .bar = 2,
0376             .offset = 0x00,
0377             .size = 0x08,
0378         }, {
0379             .bar = 2,
0380             .offset = 0x08,
0381             .size = 0x08,
0382         }
0383     },
0384     .misc_map = {
0385         .bar = 2,
0386         .offset = 0x10,
0387         .size = 0x04,
0388     },
0389     .leds = {
0390         {
0391             .green = 0x0,
0392             .red = 0x1,
0393         }, {
0394             .green = 0x2,
0395             .red = 0x3,
0396         },
0397     },
0398     .rotary = 0x0,
0399     .flags = ARC_CAN_10MBIT,
0400 };
0401 
0402 static struct com20020_pci_card_info card_info_eae_fb2 = {
0403     .name = "EAE PLX-PCI FB2",
0404     .devcount = 1,
0405     .chan_map_tbl = {
0406         {
0407             .bar = 2,
0408             .offset = 0x00,
0409             .size = 0x08,
0410         },
0411     },
0412     .misc_map = {
0413         .bar = 2,
0414         .offset = 0x10,
0415         .size = 0x04,
0416     },
0417     .leds = {
0418         {
0419             .green = 0x0,
0420             .red = 0x1,
0421         },
0422     },
0423     .rotary = 0x0,
0424     .flags = ARC_CAN_10MBIT,
0425 };
0426 
0427 static const struct pci_device_id com20020pci_id_table[] = {
0428     {
0429         0x1571, 0xa001,
0430         PCI_ANY_ID, PCI_ANY_ID,
0431         0, 0,
0432         0,
0433     },
0434     {
0435         0x1571, 0xa002,
0436         PCI_ANY_ID, PCI_ANY_ID,
0437         0, 0,
0438         0,
0439     },
0440     {
0441         0x1571, 0xa003,
0442         PCI_ANY_ID, PCI_ANY_ID,
0443         0, 0,
0444         0
0445     },
0446     {
0447         0x1571, 0xa004,
0448         PCI_ANY_ID, PCI_ANY_ID,
0449         0, 0,
0450         0,
0451     },
0452     {
0453         0x1571, 0xa005,
0454         PCI_ANY_ID, PCI_ANY_ID,
0455         0, 0,
0456         0
0457     },
0458     {
0459         0x1571, 0xa006,
0460         PCI_ANY_ID, PCI_ANY_ID,
0461         0, 0,
0462         0
0463     },
0464     {
0465         0x1571, 0xa007,
0466         PCI_ANY_ID, PCI_ANY_ID,
0467         0, 0,
0468         0
0469     },
0470     {
0471         0x1571, 0xa008,
0472         PCI_ANY_ID, PCI_ANY_ID,
0473         0, 0,
0474         0
0475     },
0476     {
0477         0x1571, 0xa009,
0478         PCI_ANY_ID, PCI_ANY_ID,
0479         0, 0,
0480         (kernel_ulong_t)&card_info_5mbit
0481     },
0482     {
0483         0x1571, 0xa00a,
0484         PCI_ANY_ID, PCI_ANY_ID,
0485         0, 0,
0486         (kernel_ulong_t)&card_info_5mbit
0487     },
0488     {
0489         0x1571, 0xa00b,
0490         PCI_ANY_ID, PCI_ANY_ID,
0491         0, 0,
0492         (kernel_ulong_t)&card_info_5mbit
0493     },
0494     {
0495         0x1571, 0xa00c,
0496         PCI_ANY_ID, PCI_ANY_ID,
0497         0, 0,
0498         (kernel_ulong_t)&card_info_5mbit
0499     },
0500     {
0501         0x1571, 0xa00d,
0502         PCI_ANY_ID, PCI_ANY_ID,
0503         0, 0,
0504         (kernel_ulong_t)&card_info_5mbit
0505     },
0506     {
0507         0x1571, 0xa00e,
0508         PCI_ANY_ID, PCI_ANY_ID,
0509         0, 0,
0510         (kernel_ulong_t)&card_info_5mbit
0511     },
0512     {
0513         0x1571, 0xa201,
0514         PCI_ANY_ID, PCI_ANY_ID,
0515         0, 0,
0516         (kernel_ulong_t)&card_info_10mbit
0517     },
0518     {
0519         0x1571, 0xa202,
0520         PCI_ANY_ID, PCI_ANY_ID,
0521         0, 0,
0522         (kernel_ulong_t)&card_info_10mbit
0523     },
0524     {
0525         0x1571, 0xa203,
0526         PCI_ANY_ID, PCI_ANY_ID,
0527         0, 0,
0528         (kernel_ulong_t)&card_info_10mbit
0529     },
0530     {
0531         0x1571, 0xa204,
0532         PCI_ANY_ID, PCI_ANY_ID,
0533         0, 0,
0534         (kernel_ulong_t)&card_info_10mbit
0535     },
0536     {
0537         0x1571, 0xa205,
0538         PCI_ANY_ID, PCI_ANY_ID,
0539         0, 0,
0540         (kernel_ulong_t)&card_info_10mbit
0541     },
0542     {
0543         0x1571, 0xa206,
0544         PCI_ANY_ID, PCI_ANY_ID,
0545         0, 0,
0546         (kernel_ulong_t)&card_info_10mbit
0547     },
0548     {
0549         0x10B5, 0x9030,
0550         0x10B5, 0x2978,
0551         0, 0,
0552         (kernel_ulong_t)&card_info_sohard
0553     },
0554     {
0555         0x10B5, 0x9050,
0556         0x10B5, 0x2273,
0557         0, 0,
0558         (kernel_ulong_t)&card_info_sohard
0559     },
0560     {
0561         0x10B5, 0x9050,
0562         0x10B5, 0x3263,
0563         0, 0,
0564         (kernel_ulong_t)&card_info_eae_arc1
0565     },
0566     {
0567         0x10B5, 0x9050,
0568         0x10B5, 0x3292,
0569         0, 0,
0570         (kernel_ulong_t)&card_info_eae_ma1
0571     },
0572     {
0573         0x10B5, 0x9050,
0574         0x10B5, 0x3294,
0575         0, 0,
0576         (kernel_ulong_t)&card_info_eae_fb2
0577     },
0578     {
0579         0x14BA, 0x6000,
0580         PCI_ANY_ID, PCI_ANY_ID,
0581         0, 0,
0582         (kernel_ulong_t)&card_info_10mbit
0583     },
0584     {
0585         0x10B5, 0x2200,
0586         PCI_ANY_ID, PCI_ANY_ID,
0587         0, 0,
0588         (kernel_ulong_t)&card_info_10mbit
0589     },
0590     { 0, }
0591 };
0592 
0593 MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
0594 
0595 static struct pci_driver com20020pci_driver = {
0596     .name       = "com20020",
0597     .id_table   = com20020pci_id_table,
0598     .probe      = com20020pci_probe,
0599     .remove     = com20020pci_remove,
0600 };
0601 
0602 static int __init com20020pci_init(void)
0603 {
0604     if (BUGLVL(D_NORMAL))
0605         pr_info("%s\n", "COM20020 PCI support");
0606     return pci_register_driver(&com20020pci_driver);
0607 }
0608 
0609 static void __exit com20020pci_cleanup(void)
0610 {
0611     pci_unregister_driver(&com20020pci_driver);
0612 }
0613 
0614 module_init(com20020pci_init)
0615 module_exit(com20020pci_cleanup)