com20020-pci.c 11 KB

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