com20020-pci.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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 ssize_t backplane_mode_show(struct device *dev,
  82. struct device_attribute *attr,
  83. char *buf)
  84. {
  85. struct net_device *net_dev = to_net_dev(dev);
  86. struct arcnet_local *lp = netdev_priv(net_dev);
  87. return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
  88. }
  89. static DEVICE_ATTR_RO(backplane_mode);
  90. static struct attribute *com20020_state_attrs[] = {
  91. &dev_attr_backplane_mode.attr,
  92. NULL,
  93. };
  94. static const struct attribute_group com20020_state_group = {
  95. .name = NULL,
  96. .attrs = com20020_state_attrs,
  97. };
  98. static void com20020pci_remove(struct pci_dev *pdev);
  99. static int com20020pci_probe(struct pci_dev *pdev,
  100. const struct pci_device_id *id)
  101. {
  102. struct com20020_pci_card_info *ci;
  103. struct com20020_pci_channel_map *mm;
  104. struct net_device *dev;
  105. struct arcnet_local *lp;
  106. struct com20020_priv *priv;
  107. int i, ioaddr, ret;
  108. struct resource *r;
  109. if (pci_enable_device(pdev))
  110. return -EIO;
  111. priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
  112. GFP_KERNEL);
  113. if (!priv)
  114. return -ENOMEM;
  115. ci = (struct com20020_pci_card_info *)id->driver_data;
  116. priv->ci = ci;
  117. mm = &ci->misc_map;
  118. INIT_LIST_HEAD(&priv->list_dev);
  119. if (mm->size) {
  120. ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
  121. r = devm_request_region(&pdev->dev, ioaddr, mm->size,
  122. "com20020-pci");
  123. if (!r) {
  124. pr_err("IO region %xh-%xh already allocated.\n",
  125. ioaddr, ioaddr + mm->size - 1);
  126. return -EBUSY;
  127. }
  128. priv->misc = ioaddr;
  129. }
  130. for (i = 0; i < ci->devcount; i++) {
  131. struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
  132. struct com20020_dev *card;
  133. int dev_id_mask = 0xf;
  134. dev = alloc_arcdev(device);
  135. if (!dev) {
  136. ret = -ENOMEM;
  137. goto out_port;
  138. }
  139. dev->dev_port = i;
  140. dev->netdev_ops = &com20020_netdev_ops;
  141. lp = netdev_priv(dev);
  142. arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
  143. ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
  144. r = devm_request_region(&pdev->dev, ioaddr, cm->size,
  145. "com20020-pci");
  146. if (!r) {
  147. pr_err("IO region %xh-%xh already allocated\n",
  148. ioaddr, ioaddr + cm->size - 1);
  149. ret = -EBUSY;
  150. goto out_port;
  151. }
  152. /* Dummy access after Reset
  153. * ARCNET controller needs
  154. * this access to detect bustype
  155. */
  156. arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
  157. arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
  158. SET_NETDEV_DEV(dev, &pdev->dev);
  159. dev->base_addr = ioaddr;
  160. dev->dev_addr[0] = node;
  161. dev->sysfs_groups[0] = &com20020_state_group;
  162. dev->irq = pdev->irq;
  163. lp->card_name = "PCI COM20020";
  164. lp->card_flags = ci->flags;
  165. lp->backplane = backplane;
  166. lp->clockp = clockp & 7;
  167. lp->clockm = clockm & 3;
  168. lp->timeout = timeout;
  169. lp->hw.owner = THIS_MODULE;
  170. lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
  171. if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
  172. lp->backplane = 1;
  173. /* Get the dev_id from the PLX rotary coder */
  174. if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
  175. dev_id_mask = 0x3;
  176. dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
  177. snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
  178. if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
  179. pr_err("IO address %Xh is empty!\n", ioaddr);
  180. ret = -EIO;
  181. goto out_port;
  182. }
  183. if (com20020_check(dev)) {
  184. ret = -EIO;
  185. goto out_port;
  186. }
  187. card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
  188. GFP_KERNEL);
  189. if (!card) {
  190. ret = -ENOMEM;
  191. goto out_port;
  192. }
  193. card->index = i;
  194. card->pci_priv = priv;
  195. card->tx_led.brightness_set = led_tx_set;
  196. card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
  197. GFP_KERNEL, "arc%d-%d-tx",
  198. dev->dev_id, i);
  199. card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
  200. "pci:green:tx:%d-%d",
  201. dev->dev_id, i);
  202. card->tx_led.dev = &dev->dev;
  203. card->recon_led.brightness_set = led_recon_set;
  204. card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
  205. GFP_KERNEL, "arc%d-%d-recon",
  206. dev->dev_id, i);
  207. card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
  208. "pci:red:recon:%d-%d",
  209. dev->dev_id, i);
  210. card->recon_led.dev = &dev->dev;
  211. card->dev = dev;
  212. ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
  213. if (ret)
  214. goto out_port;
  215. ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
  216. if (ret)
  217. goto out_port;
  218. dev_set_drvdata(&dev->dev, card);
  219. ret = com20020_found(dev, IRQF_SHARED);
  220. if (ret)
  221. goto out_port;
  222. devm_arcnet_led_init(dev, dev->dev_id, i);
  223. list_add(&card->list, &priv->list_dev);
  224. }
  225. pci_set_drvdata(pdev, priv);
  226. return 0;
  227. out_port:
  228. com20020pci_remove(pdev);
  229. return ret;
  230. }
  231. static void com20020pci_remove(struct pci_dev *pdev)
  232. {
  233. struct com20020_dev *card, *tmpcard;
  234. struct com20020_priv *priv;
  235. priv = pci_get_drvdata(pdev);
  236. list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
  237. struct net_device *dev = card->dev;
  238. unregister_netdev(dev);
  239. free_irq(dev->irq, dev);
  240. free_netdev(dev);
  241. }
  242. }
  243. static struct com20020_pci_card_info card_info_10mbit = {
  244. .name = "ARC-PCI",
  245. .devcount = 1,
  246. .chan_map_tbl = {
  247. {
  248. .bar = 2,
  249. .offset = 0x00,
  250. .size = 0x08,
  251. },
  252. },
  253. .flags = ARC_CAN_10MBIT,
  254. };
  255. static struct com20020_pci_card_info card_info_5mbit = {
  256. .name = "ARC-PCI",
  257. .devcount = 1,
  258. .chan_map_tbl = {
  259. {
  260. .bar = 2,
  261. .offset = 0x00,
  262. .size = 0x08,
  263. },
  264. },
  265. .flags = ARC_IS_5MBIT,
  266. };
  267. static struct com20020_pci_card_info card_info_sohard = {
  268. .name = "PLX-PCI",
  269. .devcount = 1,
  270. /* SOHARD needs PCI base addr 4 */
  271. .chan_map_tbl = {
  272. {
  273. .bar = 4,
  274. .offset = 0x00,
  275. .size = 0x08
  276. },
  277. },
  278. .flags = ARC_CAN_10MBIT,
  279. };
  280. static struct com20020_pci_card_info card_info_eae_arc1 = {
  281. .name = "EAE PLX-PCI ARC1",
  282. .devcount = 1,
  283. .chan_map_tbl = {
  284. {
  285. .bar = 2,
  286. .offset = 0x00,
  287. .size = 0x08,
  288. },
  289. },
  290. .misc_map = {
  291. .bar = 2,
  292. .offset = 0x10,
  293. .size = 0x04,
  294. },
  295. .leds = {
  296. {
  297. .green = 0x0,
  298. .red = 0x1,
  299. },
  300. },
  301. .rotary = 0x0,
  302. .flags = ARC_CAN_10MBIT,
  303. };
  304. static struct com20020_pci_card_info card_info_eae_ma1 = {
  305. .name = "EAE PLX-PCI MA1",
  306. .devcount = 2,
  307. .chan_map_tbl = {
  308. {
  309. .bar = 2,
  310. .offset = 0x00,
  311. .size = 0x08,
  312. }, {
  313. .bar = 2,
  314. .offset = 0x08,
  315. .size = 0x08,
  316. }
  317. },
  318. .misc_map = {
  319. .bar = 2,
  320. .offset = 0x10,
  321. .size = 0x04,
  322. },
  323. .leds = {
  324. {
  325. .green = 0x0,
  326. .red = 0x1,
  327. }, {
  328. .green = 0x2,
  329. .red = 0x3,
  330. },
  331. },
  332. .rotary = 0x0,
  333. .flags = ARC_CAN_10MBIT,
  334. };
  335. static struct com20020_pci_card_info card_info_eae_fb2 = {
  336. .name = "EAE PLX-PCI FB2",
  337. .devcount = 1,
  338. .chan_map_tbl = {
  339. {
  340. .bar = 2,
  341. .offset = 0x00,
  342. .size = 0x08,
  343. },
  344. },
  345. .misc_map = {
  346. .bar = 2,
  347. .offset = 0x10,
  348. .size = 0x04,
  349. },
  350. .leds = {
  351. {
  352. .green = 0x0,
  353. .red = 0x1,
  354. },
  355. },
  356. .rotary = 0x0,
  357. .flags = ARC_CAN_10MBIT,
  358. };
  359. static const struct pci_device_id com20020pci_id_table[] = {
  360. {
  361. 0x1571, 0xa001,
  362. PCI_ANY_ID, PCI_ANY_ID,
  363. 0, 0,
  364. 0,
  365. },
  366. {
  367. 0x1571, 0xa002,
  368. PCI_ANY_ID, PCI_ANY_ID,
  369. 0, 0,
  370. 0,
  371. },
  372. {
  373. 0x1571, 0xa003,
  374. PCI_ANY_ID, PCI_ANY_ID,
  375. 0, 0,
  376. 0
  377. },
  378. {
  379. 0x1571, 0xa004,
  380. PCI_ANY_ID, PCI_ANY_ID,
  381. 0, 0,
  382. 0,
  383. },
  384. {
  385. 0x1571, 0xa005,
  386. PCI_ANY_ID, PCI_ANY_ID,
  387. 0, 0,
  388. 0
  389. },
  390. {
  391. 0x1571, 0xa006,
  392. PCI_ANY_ID, PCI_ANY_ID,
  393. 0, 0,
  394. 0
  395. },
  396. {
  397. 0x1571, 0xa007,
  398. PCI_ANY_ID, PCI_ANY_ID,
  399. 0, 0,
  400. 0
  401. },
  402. {
  403. 0x1571, 0xa008,
  404. PCI_ANY_ID, PCI_ANY_ID,
  405. 0, 0,
  406. 0
  407. },
  408. {
  409. 0x1571, 0xa009,
  410. PCI_ANY_ID, PCI_ANY_ID,
  411. 0, 0,
  412. (kernel_ulong_t)&card_info_5mbit
  413. },
  414. {
  415. 0x1571, 0xa00a,
  416. PCI_ANY_ID, PCI_ANY_ID,
  417. 0, 0,
  418. (kernel_ulong_t)&card_info_5mbit
  419. },
  420. {
  421. 0x1571, 0xa00b,
  422. PCI_ANY_ID, PCI_ANY_ID,
  423. 0, 0,
  424. (kernel_ulong_t)&card_info_5mbit
  425. },
  426. {
  427. 0x1571, 0xa00c,
  428. PCI_ANY_ID, PCI_ANY_ID,
  429. 0, 0,
  430. (kernel_ulong_t)&card_info_5mbit
  431. },
  432. {
  433. 0x1571, 0xa00d,
  434. PCI_ANY_ID, PCI_ANY_ID,
  435. 0, 0,
  436. (kernel_ulong_t)&card_info_5mbit
  437. },
  438. {
  439. 0x1571, 0xa00e,
  440. PCI_ANY_ID, PCI_ANY_ID,
  441. 0, 0,
  442. (kernel_ulong_t)&card_info_5mbit
  443. },
  444. {
  445. 0x1571, 0xa201,
  446. PCI_ANY_ID, PCI_ANY_ID,
  447. 0, 0,
  448. (kernel_ulong_t)&card_info_10mbit
  449. },
  450. {
  451. 0x1571, 0xa202,
  452. PCI_ANY_ID, PCI_ANY_ID,
  453. 0, 0,
  454. (kernel_ulong_t)&card_info_10mbit
  455. },
  456. {
  457. 0x1571, 0xa203,
  458. PCI_ANY_ID, PCI_ANY_ID,
  459. 0, 0,
  460. (kernel_ulong_t)&card_info_10mbit
  461. },
  462. {
  463. 0x1571, 0xa204,
  464. PCI_ANY_ID, PCI_ANY_ID,
  465. 0, 0,
  466. (kernel_ulong_t)&card_info_10mbit
  467. },
  468. {
  469. 0x1571, 0xa205,
  470. PCI_ANY_ID, PCI_ANY_ID,
  471. 0, 0,
  472. (kernel_ulong_t)&card_info_10mbit
  473. },
  474. {
  475. 0x1571, 0xa206,
  476. PCI_ANY_ID, PCI_ANY_ID,
  477. 0, 0,
  478. (kernel_ulong_t)&card_info_10mbit
  479. },
  480. {
  481. 0x10B5, 0x9030,
  482. 0x10B5, 0x2978,
  483. 0, 0,
  484. (kernel_ulong_t)&card_info_sohard
  485. },
  486. {
  487. 0x10B5, 0x9050,
  488. 0x10B5, 0x2273,
  489. 0, 0,
  490. (kernel_ulong_t)&card_info_sohard
  491. },
  492. {
  493. 0x10B5, 0x9050,
  494. 0x10B5, 0x3263,
  495. 0, 0,
  496. (kernel_ulong_t)&card_info_eae_arc1
  497. },
  498. {
  499. 0x10B5, 0x9050,
  500. 0x10B5, 0x3292,
  501. 0, 0,
  502. (kernel_ulong_t)&card_info_eae_ma1
  503. },
  504. {
  505. 0x10B5, 0x9050,
  506. 0x10B5, 0x3294,
  507. 0, 0,
  508. (kernel_ulong_t)&card_info_eae_fb2
  509. },
  510. {
  511. 0x14BA, 0x6000,
  512. PCI_ANY_ID, PCI_ANY_ID,
  513. 0, 0,
  514. (kernel_ulong_t)&card_info_10mbit
  515. },
  516. {
  517. 0x10B5, 0x2200,
  518. PCI_ANY_ID, PCI_ANY_ID,
  519. 0, 0,
  520. (kernel_ulong_t)&card_info_10mbit
  521. },
  522. { 0, }
  523. };
  524. MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
  525. static struct pci_driver com20020pci_driver = {
  526. .name = "com20020",
  527. .id_table = com20020pci_id_table,
  528. .probe = com20020pci_probe,
  529. .remove = com20020pci_remove,
  530. };
  531. static int __init com20020pci_init(void)
  532. {
  533. if (BUGLVL(D_NORMAL))
  534. pr_info("%s\n", "COM20020 PCI support");
  535. return pci_register_driver(&com20020pci_driver);
  536. }
  537. static void __exit com20020pci_cleanup(void)
  538. {
  539. pci_unregister_driver(&com20020pci_driver);
  540. }
  541. module_init(com20020pci_init)
  542. module_exit(com20020pci_cleanup)