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 45 #include "arcdevice.h" 46 #include "com20020.h" 47 48 /* Module parameters */ 49 50 static int node; 51 static char device[9]; /* use eg. device="arc1" to change name */ 52 static int timeout = 3; 53 static int backplane; 54 static int clockp; 55 static int clockm; 56 57 module_param(node, int, 0); 58 module_param_string(device, device, sizeof(device), 0); 59 module_param(timeout, int, 0); 60 module_param(backplane, int, 0); 61 module_param(clockp, int, 0); 62 module_param(clockm, int, 0); 63 MODULE_LICENSE("GPL"); 64 65 static void com20020pci_remove(struct pci_dev *pdev); 66 67 static int com20020pci_probe(struct pci_dev *pdev, 68 const struct pci_device_id *id) 69 { 70 struct com20020_pci_card_info *ci; 71 struct net_device *dev; 72 struct arcnet_local *lp; 73 struct com20020_priv *priv; 74 int i, ioaddr, ret; 75 struct resource *r; 76 77 if (pci_enable_device(pdev)) 78 return -EIO; 79 80 priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), 81 GFP_KERNEL); 82 if (!priv) 83 return -ENOMEM; 84 85 ci = (struct com20020_pci_card_info *)id->driver_data; 86 priv->ci = ci; 87 88 INIT_LIST_HEAD(&priv->list_dev); 89 90 for (i = 0; i < ci->devcount; i++) { 91 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; 92 struct com20020_dev *card; 93 94 dev = alloc_arcdev(device); 95 if (!dev) { 96 ret = -ENOMEM; 97 goto out_port; 98 } 99 100 dev->netdev_ops = &com20020_netdev_ops; 101 102 lp = netdev_priv(dev); 103 104 arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name); 105 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset; 106 107 r = devm_request_region(&pdev->dev, ioaddr, cm->size, 108 "com20020-pci"); 109 if (!r) { 110 pr_err("IO region %xh-%xh already allocated\n", 111 ioaddr, ioaddr + cm->size - 1); 112 ret = -EBUSY; 113 goto out_port; 114 } 115 116 /* Dummy access after Reset 117 * ARCNET controller needs 118 * this access to detect bustype 119 */ 120 arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND); 121 arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT); 122 123 dev->base_addr = ioaddr; 124 dev->dev_addr[0] = node; 125 dev->irq = pdev->irq; 126 lp->card_name = "PCI COM20020"; 127 lp->card_flags = ci->flags; 128 lp->backplane = backplane; 129 lp->clockp = clockp & 7; 130 lp->clockm = clockm & 3; 131 lp->timeout = timeout; 132 lp->hw.owner = THIS_MODULE; 133 134 if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) { 135 pr_err("IO address %Xh is empty!\n", ioaddr); 136 ret = -EIO; 137 goto out_port; 138 } 139 if (com20020_check(dev)) { 140 ret = -EIO; 141 goto out_port; 142 } 143 144 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev), 145 GFP_KERNEL); 146 if (!card) 147 return -ENOMEM; 148 149 card->index = i; 150 card->pci_priv = priv; 151 card->dev = dev; 152 153 dev_set_drvdata(&dev->dev, card); 154 155 ret = com20020_found(dev, IRQF_SHARED); 156 if (ret) 157 goto out_port; 158 159 list_add(&card->list, &priv->list_dev); 160 } 161 162 pci_set_drvdata(pdev, priv); 163 164 return 0; 165 166 out_port: 167 com20020pci_remove(pdev); 168 return ret; 169 } 170 171 static void com20020pci_remove(struct pci_dev *pdev) 172 { 173 struct com20020_dev *card, *tmpcard; 174 struct com20020_priv *priv; 175 176 priv = pci_get_drvdata(pdev); 177 178 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) { 179 struct net_device *dev = card->dev; 180 181 unregister_netdev(dev); 182 free_irq(dev->irq, dev); 183 free_netdev(dev); 184 } 185 } 186 187 static struct com20020_pci_card_info card_info_10mbit = { 188 .name = "ARC-PCI", 189 .devcount = 1, 190 .chan_map_tbl = { 191 { 192 .bar = 2, 193 .offset = 0x00, 194 .size = 0x08, 195 }, 196 }, 197 .flags = ARC_CAN_10MBIT, 198 }; 199 200 static struct com20020_pci_card_info card_info_5mbit = { 201 .name = "ARC-PCI", 202 .devcount = 1, 203 .chan_map_tbl = { 204 { 205 .bar = 2, 206 .offset = 0x00, 207 .size = 0x08, 208 }, 209 }, 210 .flags = ARC_IS_5MBIT, 211 }; 212 213 static struct com20020_pci_card_info card_info_sohard = { 214 .name = "PLX-PCI", 215 .devcount = 1, 216 /* SOHARD needs PCI base addr 4 */ 217 .chan_map_tbl = { 218 { 219 .bar = 4, 220 .offset = 0x00, 221 .size = 0x08 222 }, 223 }, 224 .flags = ARC_CAN_10MBIT, 225 }; 226 227 static struct com20020_pci_card_info card_info_eae_arc1 = { 228 .name = "EAE PLX-PCI ARC1", 229 .devcount = 1, 230 .chan_map_tbl = { 231 { 232 .bar = 2, 233 .offset = 0x00, 234 .size = 0x08, 235 }, 236 }, 237 .flags = ARC_CAN_10MBIT, 238 }; 239 240 static struct com20020_pci_card_info card_info_eae_ma1 = { 241 .name = "EAE PLX-PCI MA1", 242 .devcount = 2, 243 .chan_map_tbl = { 244 { 245 .bar = 2, 246 .offset = 0x00, 247 .size = 0x08, 248 }, { 249 .bar = 2, 250 .offset = 0x08, 251 .size = 0x08, 252 } 253 }, 254 .flags = ARC_CAN_10MBIT, 255 }; 256 257 static const struct pci_device_id com20020pci_id_table[] = { 258 { 259 0x1571, 0xa001, 260 PCI_ANY_ID, PCI_ANY_ID, 261 0, 0, 262 0, 263 }, 264 { 265 0x1571, 0xa002, 266 PCI_ANY_ID, PCI_ANY_ID, 267 0, 0, 268 0, 269 }, 270 { 271 0x1571, 0xa003, 272 PCI_ANY_ID, PCI_ANY_ID, 273 0, 0, 274 0 275 }, 276 { 277 0x1571, 0xa004, 278 PCI_ANY_ID, PCI_ANY_ID, 279 0, 0, 280 0, 281 }, 282 { 283 0x1571, 0xa005, 284 PCI_ANY_ID, PCI_ANY_ID, 285 0, 0, 286 0 287 }, 288 { 289 0x1571, 0xa006, 290 PCI_ANY_ID, PCI_ANY_ID, 291 0, 0, 292 0 293 }, 294 { 295 0x1571, 0xa007, 296 PCI_ANY_ID, PCI_ANY_ID, 297 0, 0, 298 0 299 }, 300 { 301 0x1571, 0xa008, 302 PCI_ANY_ID, PCI_ANY_ID, 303 0, 0, 304 0 305 }, 306 { 307 0x1571, 0xa009, 308 PCI_ANY_ID, PCI_ANY_ID, 309 0, 0, 310 (kernel_ulong_t)&card_info_5mbit 311 }, 312 { 313 0x1571, 0xa00a, 314 PCI_ANY_ID, PCI_ANY_ID, 315 0, 0, 316 (kernel_ulong_t)&card_info_5mbit 317 }, 318 { 319 0x1571, 0xa00b, 320 PCI_ANY_ID, PCI_ANY_ID, 321 0, 0, 322 (kernel_ulong_t)&card_info_5mbit 323 }, 324 { 325 0x1571, 0xa00c, 326 PCI_ANY_ID, PCI_ANY_ID, 327 0, 0, 328 (kernel_ulong_t)&card_info_5mbit 329 }, 330 { 331 0x1571, 0xa00d, 332 PCI_ANY_ID, PCI_ANY_ID, 333 0, 0, 334 (kernel_ulong_t)&card_info_5mbit 335 }, 336 { 337 0x1571, 0xa00e, 338 PCI_ANY_ID, PCI_ANY_ID, 339 0, 0, 340 (kernel_ulong_t)&card_info_5mbit 341 }, 342 { 343 0x1571, 0xa201, 344 PCI_ANY_ID, PCI_ANY_ID, 345 0, 0, 346 (kernel_ulong_t)&card_info_10mbit 347 }, 348 { 349 0x1571, 0xa202, 350 PCI_ANY_ID, PCI_ANY_ID, 351 0, 0, 352 (kernel_ulong_t)&card_info_10mbit 353 }, 354 { 355 0x1571, 0xa203, 356 PCI_ANY_ID, PCI_ANY_ID, 357 0, 0, 358 (kernel_ulong_t)&card_info_10mbit 359 }, 360 { 361 0x1571, 0xa204, 362 PCI_ANY_ID, PCI_ANY_ID, 363 0, 0, 364 (kernel_ulong_t)&card_info_10mbit 365 }, 366 { 367 0x1571, 0xa205, 368 PCI_ANY_ID, PCI_ANY_ID, 369 0, 0, 370 (kernel_ulong_t)&card_info_10mbit 371 }, 372 { 373 0x1571, 0xa206, 374 PCI_ANY_ID, PCI_ANY_ID, 375 0, 0, 376 (kernel_ulong_t)&card_info_10mbit 377 }, 378 { 379 0x10B5, 0x9030, 380 0x10B5, 0x2978, 381 0, 0, 382 (kernel_ulong_t)&card_info_sohard 383 }, 384 { 385 0x10B5, 0x9050, 386 0x10B5, 0x2273, 387 0, 0, 388 (kernel_ulong_t)&card_info_sohard 389 }, 390 { 391 0x10B5, 0x9050, 392 0x10B5, 0x3263, 393 0, 0, 394 (kernel_ulong_t)&card_info_eae_arc1 395 }, 396 { 397 0x10B5, 0x9050, 398 0x10B5, 0x3292, 399 0, 0, 400 (kernel_ulong_t)&card_info_eae_ma1 401 }, 402 { 403 0x14BA, 0x6000, 404 PCI_ANY_ID, PCI_ANY_ID, 405 0, 0, 406 (kernel_ulong_t)&card_info_10mbit 407 }, 408 { 409 0x10B5, 0x2200, 410 PCI_ANY_ID, PCI_ANY_ID, 411 0, 0, 412 (kernel_ulong_t)&card_info_10mbit 413 }, 414 { 0, } 415 }; 416 417 MODULE_DEVICE_TABLE(pci, com20020pci_id_table); 418 419 static struct pci_driver com20020pci_driver = { 420 .name = "com20020", 421 .id_table = com20020pci_id_table, 422 .probe = com20020pci_probe, 423 .remove = com20020pci_remove, 424 }; 425 426 static int __init com20020pci_init(void) 427 { 428 if (BUGLVL(D_NORMAL)) 429 pr_info("%s\n", "COM20020 PCI support"); 430 return pci_register_driver(&com20020pci_driver); 431 } 432 433 static void __exit com20020pci_cleanup(void) 434 { 435 pci_unregister_driver(&com20020pci_driver); 436 } 437 438 module_init(com20020pci_init) 439 module_exit(com20020pci_cleanup) 440