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#include <linux/module.h> 30#include <linux/moduleparam.h> 31#include <linux/kernel.h> 32#include <linux/types.h> 33#include <linux/ioport.h> 34#include <linux/errno.h> 35#include <linux/netdevice.h> 36#include <linux/init.h> 37#include <linux/interrupt.h> 38#include <linux/pci.h> 39#include <linux/arcdevice.h> 40#include <linux/com20020.h> 41 42#include <asm/io.h> 43 44 45#define VERSION "arcnet: COM20020 PCI support\n" 46 47/* Module parameters */ 48 49static int node; 50static char device[9]; /* use eg. device="arc1" to change name */ 51static int timeout = 3; 52static int backplane; 53static int clockp; 54static int clockm; 55 56module_param(node, int, 0); 57module_param_string(device, device, sizeof(device), 0); 58module_param(timeout, int, 0); 59module_param(backplane, int, 0); 60module_param(clockp, int, 0); 61module_param(clockm, int, 0); 62MODULE_LICENSE("GPL"); 63 64static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 65{ 66 struct net_device *dev; 67 struct arcnet_local *lp; 68 int ioaddr, err; 69 70 if (pci_enable_device(pdev)) 71 return -EIO; 72 dev = alloc_arcdev(device); 73 if (!dev) 74 return -ENOMEM; 75 76 dev->netdev_ops = &com20020_netdev_ops; 77 78 lp = netdev_priv(dev); 79 80 pci_set_drvdata(pdev, dev); 81 82 // SOHARD needs PCI base addr 4 83 if (pdev->vendor==0x10B5) { 84 BUGMSG(D_NORMAL, "SOHARD\n"); 85 ioaddr = pci_resource_start(pdev, 4); 86 } 87 else { 88 BUGMSG(D_NORMAL, "Contemporary Controls\n"); 89 ioaddr = pci_resource_start(pdev, 2); 90 } 91 92 if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { 93 BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", 94 ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); 95 err = -EBUSY; 96 goto out_dev; 97 } 98 99 // Dummy access after Reset 100 // ARCNET controller needs this access to detect bustype 101 outb(0x00,ioaddr+1); 102 inb(ioaddr+1); 103 104 dev->base_addr = ioaddr; 105 dev->irq = pdev->irq; 106 dev->dev_addr[0] = node; 107 lp->card_name = "PCI COM20020"; 108 lp->card_flags = id->driver_data; 109 lp->backplane = backplane; 110 lp->clockp = clockp & 7; 111 lp->clockm = clockm & 3; 112 lp->timeout = timeout; 113 lp->hw.owner = THIS_MODULE; 114 115 if (ASTATUS() == 0xFF) { 116 BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " 117 "but seems empty!\n", ioaddr); 118 err = -EIO; 119 goto out_port; 120 } 121 if (com20020_check(dev)) { 122 err = -EIO; 123 goto out_port; 124 } 125 126 if ((err = com20020_found(dev, IRQF_SHARED)) != 0) 127 goto out_port; 128 129 return 0; 130 131out_port: 132 release_region(ioaddr, ARCNET_TOTAL_SIZE); 133out_dev: 134 free_netdev(dev); 135 return err; 136} 137 138static void __devexit com20020pci_remove(struct pci_dev *pdev) 139{ 140 struct net_device *dev = pci_get_drvdata(pdev); 141 unregister_netdev(dev); 142 free_irq(dev->irq, dev); 143 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 144 free_netdev(dev); 145} 146 147static DEFINE_PCI_DEVICE_TABLE(com20020pci_id_table) = { 148 { 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 149 { 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 150 { 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 151 { 0x1571, 0xa004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 152 { 0x1571, 0xa005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 153 { 0x1571, 0xa006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 154 { 0x1571, 0xa007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 155 { 0x1571, 0xa008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 156 { 0x1571, 0xa009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 157 { 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 158 { 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 159 { 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 160 { 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 161 { 0x1571, 0xa00e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 162 { 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 163 { 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 164 { 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 165 { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 166 { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 167 { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 168 { 0x10B5, 0x9030, 0x10B5, 0x2978, 0, 0, ARC_CAN_10MBIT }, 169 { 0x10B5, 0x9050, 0x10B5, 0x2273, 0, 0, ARC_CAN_10MBIT }, 170 { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 171 { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 172 {0,} 173}; 174 175MODULE_DEVICE_TABLE(pci, com20020pci_id_table); 176 177static struct pci_driver com20020pci_driver = { 178 .name = "com20020", 179 .id_table = com20020pci_id_table, 180 .probe = com20020pci_probe, 181 .remove = __devexit_p(com20020pci_remove), 182}; 183 184static int __init com20020pci_init(void) 185{ 186 BUGLVL(D_NORMAL) printk(VERSION); 187 return pci_register_driver(&com20020pci_driver); 188} 189 190static void __exit com20020pci_cleanup(void) 191{ 192 pci_unregister_driver(&com20020pci_driver); 193} 194 195module_init(com20020pci_init) 196module_exit(com20020pci_cleanup) 197