com20020-pci.c 13 KB

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