parport_serial.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Support for common PCI multi-I/O cards (which is most of them)
  3.  *
  4.  * Copyright (C) 2001  Tim Waugh <twaugh@redhat.com>
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License
  8.  * as published by the Free Software Foundation; either version
  9.  * 2 of the License, or (at your option) any later version.
  10.  *
  11.  *
  12.  * Multi-function PCI cards are supposed to present separate logical
  13.  * devices on the bus.  A common thing to do seems to be to just use
  14.  * one logical device with lots of base address registers for both
  15.  * parallel ports and serial ports.  This driver is for dealing with
  16.  * that.
  17.  *
  18.  */
  19. #include <linux/types.h>
  20. #include <linux/module.h>
  21. #include <linux/init.h>
  22. #include <linux/pci.h>
  23. #include <linux/parport.h>
  24. #include <linux/parport_pc.h>
  25. #include <linux/serial.h>
  26. #include <linux/serialP.h>
  27. #include <linux/list.h>
  28. #include <asm/serial.h>
  29. enum parport_pc_pci_cards {
  30. titan_110l = 0,
  31. titan_210l,
  32. avlab_1s1p,
  33. avlab_1s1p_650,
  34. avlab_1s1p_850,
  35. avlab_1s2p,
  36. avlab_1s2p_650,
  37. avlab_1s2p_850,
  38. avlab_2s1p,
  39. avlab_2s1p_650,
  40. avlab_2s1p_850,
  41. siig_1s1p_10x,
  42. siig_2s1p_10x,
  43. siig_2p1s_20x,
  44. siig_1s1p_20x,
  45. siig_2s1p_20x,
  46. };
  47. /* each element directly indexed from enum list, above */
  48. static struct parport_pc_pci {
  49. int numports;
  50. struct { /* BAR (base address registers) numbers in the config
  51.                     space header */
  52. int lo;
  53. int hi; /* -1 if not there, >6 for offset-method (max
  54.                            BAR is 6) */
  55. } addr[4];
  56. /* If set, this is called immediately after pci_enable_device.
  57.  * If it returns non-zero, no probing will take place and the
  58.  * ports will not be used. */
  59. int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma);
  60. /* If set, this is called after probing for ports.  If 'failed'
  61.  * is non-zero we couldn't use any of the ports. */
  62. void (*postinit_hook) (struct pci_dev *pdev, int failed);
  63. } cards[] __devinitdata = {
  64. /* titan_110l */ { 1, { { 3, -1 }, } },
  65. /* titan_210l */ { 1, { { 3, -1 }, } },
  66. /* avlab_1s1p     */ { 1, { { 1, 2}, } },
  67. /* avlab_1s1p_650 */ { 1, { { 1, 2}, } },
  68. /* avlab_1s1p_850 */ { 1, { { 1, 2}, } },
  69. /* avlab_1s2p     */ { 2, { { 1, 2}, { 3, 4 },} },
  70. /* avlab_1s2p_650 */ { 2, { { 1, 2}, { 3, 4 },} },
  71. /* avlab_1s2p_850 */ { 2, { { 1, 2}, { 3, 4 },} },
  72. /* avlab_2s1p     */ { 1, { { 2, 3}, } },
  73. /* avlab_2s1p_650 */ { 1, { { 2, 3}, } },
  74. /* avlab_2s1p_850 */ { 1, { { 2, 3}, } },
  75. /* siig_1s1p_10x */ { 1, { { 3, 4 }, } },
  76. /* siig_2s1p_10x */ { 1, { { 4, 5 }, } },
  77. /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } },
  78. /* siig_1s1p_20x */ { 1, { { 1, 2 }, } },
  79. /* siig_2s1p_20x */ { 1, { { 2, 3 }, } },
  80. };
  81. static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = {
  82. /* PCI cards */
  83. { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
  84.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },
  85. { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
  86.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
  87. /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
  88. { 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p},
  89. { 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650},
  90. { 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850},
  91. { 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p},
  92. { 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650},
  93. { 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850},
  94. { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p},
  95. { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650},
  96. { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850},
  97. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
  98.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
  99. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
  100.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
  101. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
  102.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
  103. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
  104.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
  105. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
  106.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
  107. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
  108.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
  109. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
  110.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
  111. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
  112.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
  113. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
  114.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
  115. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
  116.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
  117. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
  118.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
  119. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
  120.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
  121. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
  122.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
  123. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
  124.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
  125. { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
  126.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
  127. { 0, } /* terminate list */
  128. };
  129. MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
  130. struct pci_board_no_ids {
  131. int flags;
  132. int num_ports;
  133. int base_baud;
  134. int uart_offset;
  135. int reg_shift;
  136. int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board,
  137. int enable);
  138. int first_uart_offset;
  139. };
  140. static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
  141. {
  142. return pci_siig10x_fn(dev, NULL, enable);
  143. }
  144. static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
  145. {
  146. return pci_siig20x_fn(dev, NULL, enable);
  147. }
  148. static struct pci_board_no_ids pci_boards[] __devinitdata = {
  149. /*
  150.  * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
  151.  * Offset to get to next UART's registers,
  152.  * Register shift to use for memory-mapped I/O,
  153.  * Initialization function, first UART offset
  154.  */
  155. // Cards not tested are marked n/t
  156. // If you have one of these cards and it works for you, please tell me..
  157. /* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
  158. /* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
  159. /* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
  160. /* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
  161. /* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
  162. /* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
  163. /* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
  164. /* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
  165. /* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
  166. /* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
  167. /* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
  168. /* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn },
  169. /* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn },
  170. /* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
  171. /* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
  172. /* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
  173. };
  174. struct parport_serial_private {
  175. int num_ser;
  176. int line[20];
  177. struct pci_board_no_ids ser;
  178. int num_par;
  179. struct parport *port[PARPORT_MAX];
  180. };
  181. static int __devinit get_pci_port (struct pci_dev *dev,
  182.    struct pci_board_no_ids *board,
  183.    struct serial_struct *req,
  184.    int idx)
  185. {
  186. unsigned long port;
  187. int base_idx;
  188. int max_port;
  189. int offset;
  190. base_idx = SPCI_FL_GET_BASE(board->flags);
  191. if (board->flags & SPCI_FL_BASE_TABLE)
  192. base_idx += idx;
  193. if (board->flags & SPCI_FL_REGION_SZ_CAP) {
  194. max_port = pci_resource_len(dev, base_idx) / 8;
  195. if (idx >= max_port)
  196. return 1;
  197. }
  198. offset = board->first_uart_offset;
  199. /* Timedia/SUNIX uses a mixture of BARs and offsets */
  200. /* Ugh, this is ugly as all hell --- TYT */
  201. if(dev->vendor == PCI_VENDOR_ID_TIMEDIA )  /* 0x1409 */
  202. switch(idx) {
  203. case 0: base_idx=0;
  204. break;
  205. case 1: base_idx=0; offset=8;
  206. break;
  207. case 2: base_idx=1; 
  208. break;
  209. case 3: base_idx=1; offset=8;
  210. break;
  211. case 4: /* BAR 2*/
  212. case 5: /* BAR 3 */
  213. case 6: /* BAR 4*/
  214. case 7: base_idx=idx-2; /* BAR 5*/
  215. }
  216.   
  217. port =  pci_resource_start(dev, base_idx) + offset;
  218. if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
  219. port += idx * (board->uart_offset ? board->uart_offset : 8);
  220. if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) {
  221. int high_bits_offset = ((sizeof(long)-sizeof(int))*8);
  222. req->port = port;
  223. if (high_bits_offset)
  224. req->port_high = port >> high_bits_offset;
  225. else
  226. req->port_high = 0;
  227. return 0;
  228. }
  229. req->io_type = SERIAL_IO_MEM;
  230. req->iomem_base = ioremap(port, board->uart_offset);
  231. req->iomem_reg_shift = board->reg_shift;
  232. req->port = 0;
  233. return req->iomem_base ? 0 : 1;
  234. }
  235. /* Register the serial port(s) of a PCI card. */
  236. static int __devinit serial_register (struct pci_dev *dev,
  237.       const struct pci_device_id *id)
  238. {
  239. struct pci_board_no_ids *board = &pci_boards[id->driver_data];
  240. struct parport_serial_private *priv = pci_get_drvdata (dev);
  241. struct serial_struct serial_req;
  242. int base_baud;
  243. int k;
  244. int success = 0;
  245. priv->ser = *board;
  246. if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
  247. return 1;
  248. base_baud = board->base_baud;
  249. if (!base_baud)
  250. base_baud = BASE_BAUD;
  251. memset (&serial_req, 0, sizeof (serial_req));
  252. for (k = 0; k < board->num_ports; k++) {
  253. int line;
  254. serial_req.irq = dev->irq;
  255. if (get_pci_port (dev, board, &serial_req, k))
  256. break;
  257. serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
  258. serial_req.baud_base = base_baud;
  259. line = register_serial (&serial_req);
  260. if (line < 0) {
  261. printk (KERN_DEBUG
  262. "parport_serial: register_serial failedn");
  263. continue;
  264. }
  265. priv->line[priv->num_ser++] = line;
  266. success = 1;
  267. }
  268. return success ? 0 : 1;
  269. }
  270. /* Register the parallel port(s) of a PCI card. */
  271. static int __devinit parport_register (struct pci_dev *dev,
  272.        const struct pci_device_id *id)
  273. {
  274. struct parport_serial_private *priv = pci_get_drvdata (dev);
  275. int i = id->driver_data, n;
  276. int success = 0;
  277. if (cards[i].preinit_hook &&
  278.     cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
  279. return -ENODEV;
  280. for (n = 0; n < cards[i].numports; n++) {
  281. struct parport *port;
  282. int lo = cards[i].addr[n].lo;
  283. int hi = cards[i].addr[n].hi;
  284. unsigned long io_lo, io_hi;
  285. io_lo = pci_resource_start (dev, lo);
  286. io_hi = 0;
  287. if ((hi >= 0) && (hi <= 6))
  288. io_hi = pci_resource_start (dev, hi);
  289. else if (hi > 6)
  290. io_lo += hi; /* Reinterpret the meaning of
  291.                                         "hi" as an offset (see SYBA
  292.                                         def.) */
  293. /* TODO: test if sharing interrupts works */
  294. printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
  295. "I/O at %#lx(%#lx)n",
  296. parport_serial_pci_tbl[i].vendor,
  297. parport_serial_pci_tbl[i].device, io_lo, io_hi);
  298. port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
  299.       PARPORT_DMA_NONE, dev);
  300. if (port) {
  301. priv->port[priv->num_par++] = port;
  302. success = 1;
  303. }
  304. }
  305. if (cards[i].postinit_hook)
  306. cards[i].postinit_hook (dev, !success);
  307. return success ? 0 : 1;
  308. }
  309. static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
  310.        const struct pci_device_id *id)
  311. {
  312. struct parport_serial_private *priv;
  313. int err;
  314. priv = kmalloc (sizeof *priv, GFP_KERNEL);
  315. if (!priv)
  316. return -ENOMEM;
  317. priv->num_ser = priv->num_par = 0;
  318. pci_set_drvdata (dev, priv);
  319. err = pci_enable_device (dev);
  320. if (err) {
  321. pci_set_drvdata (dev, NULL);
  322. kfree (priv);
  323. return err;
  324. }
  325. if (parport_register (dev, id)) {
  326. pci_set_drvdata (dev, NULL);
  327. kfree (priv);
  328. return -ENODEV;
  329. }
  330. if (serial_register (dev, id)) {
  331. int i;
  332. for (i = 0; i < priv->num_par; i++)
  333. parport_pc_unregister_port (priv->port[i]);
  334. pci_set_drvdata (dev, NULL);
  335. kfree (priv);
  336. return -ENODEV;
  337. }
  338. return 0;
  339. }
  340. static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
  341. {
  342. struct parport_serial_private *priv = pci_get_drvdata (dev);
  343. int i;
  344. // Serial ports
  345. for (i = 0; i < priv->num_ser; i++) {
  346. unregister_serial (priv->line[i]);
  347. if (priv->ser.init_fn)
  348. (priv->ser.init_fn) (dev, &priv->ser, 0);
  349. }
  350. pci_set_drvdata (dev, NULL);
  351. // Parallel ports
  352. for (i = 0; i < priv->num_par; i++)
  353. parport_pc_unregister_port (priv->port[i]);
  354. kfree (priv);
  355. return;
  356. }
  357. static struct pci_driver parport_serial_pci_driver = {
  358. name: "parport_serial",
  359. id_table: parport_serial_pci_tbl,
  360. probe: parport_serial_pci_probe,
  361. remove: __devexit_p(parport_serial_pci_remove),
  362. };
  363. static int __init parport_serial_init (void)
  364. {
  365. return pci_module_init (&parport_serial_pci_driver);
  366. }
  367. static void __exit parport_serial_exit (void)
  368. {
  369. pci_unregister_driver (&parport_serial_pci_driver);
  370. return;
  371. }
  372. MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>");
  373. MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
  374. MODULE_LICENSE("GPL");
  375. module_init(parport_serial_init);
  376. module_exit(parport_serial_exit);