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 49 static int node; 50 static char device[9]; /* use eg. device="arc1" to change name */ 51 static int timeout = 3; 52 static int backplane; 53 static int clockp; 54 static int clockm; 55 56 module_param(node, int, 0); 57 module_param_string(device, device, sizeof(device), 0); 58 module_param(timeout, int, 0); 59 module_param(backplane, int, 0); 60 module_param(clockp, int, 0); 61 module_param(clockm, int, 0); 62 MODULE_LICENSE("GPL"); 63 64 static 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 128 out_port: 129 release_region(ioaddr, ARCNET_TOTAL_SIZE); 130 out_dev: 131 free_netdev(dev); 132 return err; 133 } 134 135 static 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 144 static 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 172 MODULE_DEVICE_TABLE(pci, com20020pci_id_table); 173 174 static 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 181 static int __init com20020pci_init(void) 182 { 183 BUGLVL(D_NORMAL) printk(VERSION); 184 return pci_register_driver(&com20020pci_driver); 185 } 186 187 static void __exit com20020pci_cleanup(void) 188 { 189 pci_unregister_driver(&com20020pci_driver); 190 } 191 192 module_init(com20020pci_init) 193 module_exit(com20020pci_cleanup) 194