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/slab.h> 35#include <linux/errno.h> 36#include <linux/netdevice.h> 37#include <linux/init.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 lp = dev->priv; 76 77 pci_set_drvdata(pdev, dev); 78 79 // SOHARD needs PCI base addr 4 80 if (pdev->vendor==0x10B5) { 81 BUGMSG(D_NORMAL, "SOHARD\n"); 82 ioaddr = pci_resource_start(pdev, 4); 83 } 84 else { 85 BUGMSG(D_NORMAL, "Contemporary Controls\n"); 86 ioaddr = pci_resource_start(pdev, 2); 87 } 88 89 if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { 90 BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", 91 ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); 92 err = -EBUSY; 93 goto out_dev; 94 } 95 96 // Dummy access after Reset 97 // ARCNET controller needs this access to detect bustype 98 outb(0x00,ioaddr+1); 99 inb(ioaddr+1); 100 101 dev->base_addr = ioaddr; 102 dev->irq = pdev->irq; 103 dev->dev_addr[0] = node; 104 lp->card_name = "PCI COM20020"; 105 lp->card_flags = id->driver_data; 106 lp->backplane = backplane; 107 lp->clockp = clockp & 7; 108 lp->clockm = clockm & 3; 109 lp->timeout = timeout; 110 lp->hw.owner = THIS_MODULE; 111 112 if (ASTATUS() == 0xFF) { 113 BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " 114 "but seems empty!\n", ioaddr); 115 err = -EIO; 116 goto out_port; 117 } 118 if (com20020_check(dev)) { 119 err = -EIO; 120 goto out_port; 121 } 122 123 if ((err = com20020_found(dev, IRQF_SHARED)) != 0) 124 goto out_port; 125 126 return 0; 127 128out_port: 129 release_region(ioaddr, ARCNET_TOTAL_SIZE); 130out_dev: 131 free_netdev(dev); 132 return err; 133} 134 135static void __devexit com20020pci_remove(struct pci_dev *pdev) 136{ 137 struct net_device *dev = pci_get_drvdata(pdev); 138 unregister_netdev(dev); 139 free_irq(dev->irq, dev); 140 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 141 free_netdev(dev); 142} 143 144static struct pci_device_id com20020pci_id_table[] = { 145 { 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 146 { 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 147 { 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 148 { 0x1571, 0xa004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 149 { 0x1571, 0xa005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 150 { 0x1571, 0xa006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 151 { 0x1571, 0xa007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 152 { 0x1571, 0xa008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 153 { 0x1571, 0xa009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 154 { 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 155 { 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 156 { 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 157 { 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 158 { 0x1571, 0xa00e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 159 { 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 160 { 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 161 { 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 162 { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 163 { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 164 { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 165 { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 166 { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 167 { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 168 { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 169 {0,} 170}; 171 172MODULE_DEVICE_TABLE(pci, com20020pci_id_table); 173 174static struct pci_driver com20020pci_driver = { 175 .name = "com20020", 176 .id_table = com20020pci_id_table, 177 .probe = com20020pci_probe, 178 .remove = __devexit_p(com20020pci_remove), 179}; 180 181static int __init com20020pci_init(void) 182{ 183 BUGLVL(D_NORMAL) printk(VERSION); 184 return pci_register_driver(&com20020pci_driver); 185} 186 187static void __exit com20020pci_cleanup(void) 188{ 189 pci_unregister_driver(&com20020pci_driver); 190} 191 192module_init(com20020pci_init) 193module_exit(com20020pci_cleanup) 194