com20020-pci.c 13 KB

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