com20020-pci.c 12 KB

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