/drivers/staging/comedi/drivers/ni_mio_cs.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 459 lines · 324 code · 80 blank · 55 comment · 20 complexity · 401d1fb124ce67bbb8ab3e03594246ca MD5 · raw file

  1. /*
  2. comedi/drivers/ni_mio_cs.c
  3. Hardware driver for NI PCMCIA MIO E series cards
  4. COMEDI - Linux Control and Measurement Device Interface
  5. Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. /*
  19. Driver: ni_mio_cs
  20. Description: National Instruments DAQCard E series
  21. Author: ds
  22. Status: works
  23. Devices: [National Instruments] DAQCard-AI-16XE-50 (ni_mio_cs),
  24. DAQCard-AI-16E-4, DAQCard-6062E, DAQCard-6024E, DAQCard-6036E
  25. Updated: Thu Oct 23 19:43:17 CDT 2003
  26. See the notes in the ni_atmio.o driver.
  27. */
  28. /*
  29. The real guts of the driver is in ni_mio_common.c, which is
  30. included by all the E series drivers.
  31. References for specifications:
  32. 341080a.pdf DAQCard E Series Register Level Programmer Manual
  33. */
  34. #include "../comedidev.h"
  35. #include <linux/delay.h>
  36. #include "ni_stc.h"
  37. #include "8255.h"
  38. #include <pcmcia/cistpl.h>
  39. #include <pcmcia/ds.h>
  40. #undef DEBUG
  41. #define ATMIO 1
  42. #undef PCIMIO
  43. /*
  44. * AT specific setup
  45. */
  46. #define NI_SIZE 0x20
  47. #define MAX_N_CALDACS 32
  48. static const struct ni_board_struct ni_boards[] = {
  49. {.device_id = 0x010d,
  50. .name = "DAQCard-ai-16xe-50",
  51. .n_adchan = 16,
  52. .adbits = 16,
  53. .ai_fifo_depth = 1024,
  54. .alwaysdither = 0,
  55. .gainlkup = ai_gain_8,
  56. .ai_speed = 5000,
  57. .n_aochan = 0,
  58. .aobits = 0,
  59. .ao_fifo_depth = 0,
  60. .ao_unipolar = 0,
  61. .num_p0_dio_channels = 8,
  62. .has_8255 = 0,
  63. .caldac = {dac8800, dac8043},
  64. },
  65. {.device_id = 0x010c,
  66. .name = "DAQCard-ai-16e-4",
  67. .n_adchan = 16,
  68. .adbits = 12,
  69. .ai_fifo_depth = 1024,
  70. .alwaysdither = 0,
  71. .gainlkup = ai_gain_16,
  72. .ai_speed = 4000,
  73. .n_aochan = 0,
  74. .aobits = 0,
  75. .ao_fifo_depth = 0,
  76. .ao_unipolar = 0,
  77. .num_p0_dio_channels = 8,
  78. .has_8255 = 0,
  79. .caldac = {mb88341}, /* verified */
  80. },
  81. {.device_id = 0x02c4,
  82. .name = "DAQCard-6062E",
  83. .n_adchan = 16,
  84. .adbits = 12,
  85. .ai_fifo_depth = 8192,
  86. .alwaysdither = 0,
  87. .gainlkup = ai_gain_16,
  88. .ai_speed = 2000,
  89. .n_aochan = 2,
  90. .aobits = 12,
  91. .ao_fifo_depth = 2048,
  92. .ao_range_table = &range_bipolar10,
  93. .ao_unipolar = 0,
  94. .ao_speed = 1176,
  95. .num_p0_dio_channels = 8,
  96. .has_8255 = 0,
  97. .caldac = {ad8804_debug}, /* verified */
  98. },
  99. {.device_id = 0x075e,
  100. .name = "DAQCard-6024E", /* specs incorrect! */
  101. .n_adchan = 16,
  102. .adbits = 12,
  103. .ai_fifo_depth = 1024,
  104. .alwaysdither = 0,
  105. .gainlkup = ai_gain_4,
  106. .ai_speed = 5000,
  107. .n_aochan = 2,
  108. .aobits = 12,
  109. .ao_fifo_depth = 0,
  110. .ao_range_table = &range_bipolar10,
  111. .ao_unipolar = 0,
  112. .ao_speed = 1000000,
  113. .num_p0_dio_channels = 8,
  114. .has_8255 = 0,
  115. .caldac = {ad8804_debug},
  116. },
  117. {.device_id = 0x0245,
  118. .name = "DAQCard-6036E", /* specs incorrect! */
  119. .n_adchan = 16,
  120. .adbits = 16,
  121. .ai_fifo_depth = 1024,
  122. .alwaysdither = 1,
  123. .gainlkup = ai_gain_4,
  124. .ai_speed = 5000,
  125. .n_aochan = 2,
  126. .aobits = 16,
  127. .ao_fifo_depth = 0,
  128. .ao_range_table = &range_bipolar10,
  129. .ao_unipolar = 0,
  130. .ao_speed = 1000000,
  131. .num_p0_dio_channels = 8,
  132. .has_8255 = 0,
  133. .caldac = {ad8804_debug},
  134. },
  135. #if 0
  136. {.device_id = 0x0000, /* unknown */
  137. .name = "DAQCard-6715",
  138. .n_adchan = 0,
  139. .n_aochan = 8,
  140. .aobits = 12,
  141. .ao_671x = 8192,
  142. .num_p0_dio_channels = 8,
  143. .caldac = {mb88341, mb88341},
  144. },
  145. #endif
  146. /* N.B. Update ni_mio_cs_ids[] when entries added above. */
  147. };
  148. #define interrupt_pin(a) 0
  149. #define IRQ_POLARITY 1
  150. #define NI_E_IRQ_FLAGS IRQF_SHARED
  151. struct ni_private {
  152. struct pcmcia_device *link;
  153. NI_PRIVATE_COMMON};
  154. #define devpriv ((struct ni_private *)dev->private)
  155. /* How we access registers */
  156. #define ni_writel(a, b) (outl((a), (b)+dev->iobase))
  157. #define ni_readl(a) (inl((a)+dev->iobase))
  158. #define ni_writew(a, b) (outw((a), (b)+dev->iobase))
  159. #define ni_readw(a) (inw((a)+dev->iobase))
  160. #define ni_writeb(a, b) (outb((a), (b)+dev->iobase))
  161. #define ni_readb(a) (inb((a)+dev->iobase))
  162. /* How we access windowed registers */
  163. /* We automatically take advantage of STC registers that can be
  164. * read/written directly in the I/O space of the board. The
  165. * DAQCard devices map the low 8 STC registers to iobase+addr*2. */
  166. static void mio_cs_win_out(struct comedi_device *dev, uint16_t data, int addr)
  167. {
  168. unsigned long flags;
  169. spin_lock_irqsave(&devpriv->window_lock, flags);
  170. if (addr < 8) {
  171. ni_writew(data, addr * 2);
  172. } else {
  173. ni_writew(addr, Window_Address);
  174. ni_writew(data, Window_Data);
  175. }
  176. spin_unlock_irqrestore(&devpriv->window_lock, flags);
  177. }
  178. static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr)
  179. {
  180. unsigned long flags;
  181. uint16_t ret;
  182. spin_lock_irqsave(&devpriv->window_lock, flags);
  183. if (addr < 8) {
  184. ret = ni_readw(addr * 2);
  185. } else {
  186. ni_writew(addr, Window_Address);
  187. ret = ni_readw(Window_Data);
  188. }
  189. spin_unlock_irqrestore(&devpriv->window_lock, flags);
  190. return ret;
  191. }
  192. static int mio_cs_attach(struct comedi_device *dev,
  193. struct comedi_devconfig *it);
  194. static int mio_cs_detach(struct comedi_device *dev);
  195. static struct comedi_driver driver_ni_mio_cs = {
  196. .driver_name = "ni_mio_cs",
  197. .module = THIS_MODULE,
  198. .attach = mio_cs_attach,
  199. .detach = mio_cs_detach,
  200. };
  201. #include "ni_mio_common.c"
  202. static int ni_getboardtype(struct comedi_device *dev,
  203. struct pcmcia_device *link);
  204. /* clean up allocated resources */
  205. /* called when driver is removed */
  206. static int mio_cs_detach(struct comedi_device *dev)
  207. {
  208. mio_common_detach(dev);
  209. /* PCMCIA layer frees the IO region */
  210. if (dev->irq)
  211. free_irq(dev->irq, dev);
  212. return 0;
  213. }
  214. static void mio_cs_config(struct pcmcia_device *link);
  215. static void cs_release(struct pcmcia_device *link);
  216. static void cs_detach(struct pcmcia_device *);
  217. static struct pcmcia_device *cur_dev = NULL;
  218. static int cs_attach(struct pcmcia_device *link)
  219. {
  220. cur_dev = link;
  221. mio_cs_config(link);
  222. return 0;
  223. }
  224. static void cs_release(struct pcmcia_device *link)
  225. {
  226. pcmcia_disable_device(link);
  227. }
  228. static void cs_detach(struct pcmcia_device *link)
  229. {
  230. DPRINTK("cs_detach(link=%p)\n", link);
  231. cs_release(link);
  232. }
  233. static int mio_cs_suspend(struct pcmcia_device *link)
  234. {
  235. DPRINTK("pm suspend\n");
  236. return 0;
  237. }
  238. static int mio_cs_resume(struct pcmcia_device *link)
  239. {
  240. DPRINTK("pm resume\n");
  241. return 0;
  242. }
  243. static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
  244. {
  245. int base, ret;
  246. p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
  247. p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
  248. for (base = 0x000; base < 0x400; base += 0x20) {
  249. p_dev->resource[0]->start = base;
  250. ret = pcmcia_request_io(p_dev);
  251. if (!ret)
  252. return 0;
  253. }
  254. return -ENODEV;
  255. }
  256. static void mio_cs_config(struct pcmcia_device *link)
  257. {
  258. int ret;
  259. DPRINTK("mio_cs_config(link=%p)\n", link);
  260. link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
  261. ret = pcmcia_loop_config(link, mio_pcmcia_config_loop, NULL);
  262. if (ret) {
  263. dev_warn(&link->dev, "no configuration found\n");
  264. return;
  265. }
  266. if (!link->irq)
  267. dev_info(&link->dev, "no IRQ available\n");
  268. ret = pcmcia_enable_device(link);
  269. }
  270. static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it)
  271. {
  272. struct pcmcia_device *link;
  273. unsigned int irq;
  274. int ret;
  275. DPRINTK("mio_cs_attach(dev=%p,it=%p)\n", dev, it);
  276. link = cur_dev; /* XXX hack */
  277. if (!link)
  278. return -EIO;
  279. dev->driver = &driver_ni_mio_cs;
  280. dev->iobase = link->resource[0]->start;
  281. irq = link->irq;
  282. printk("comedi%d: %s: DAQCard: io 0x%04lx, irq %u, ",
  283. dev->minor, dev->driver->driver_name, dev->iobase, irq);
  284. #if 0
  285. {
  286. int i;
  287. printk(" board fingerprint:");
  288. for (i = 0; i < 32; i += 2) {
  289. printk(" %04x %02x", inw(dev->iobase + i),
  290. inb(dev->iobase + i + 1));
  291. }
  292. printk("\n");
  293. printk(" board fingerprint (windowed):");
  294. for (i = 0; i < 10; i++)
  295. printk(" 0x%04x", win_in(i));
  296. printk("\n");
  297. }
  298. #endif
  299. dev->board_ptr = ni_boards + ni_getboardtype(dev, link);
  300. printk(" %s", boardtype.name);
  301. dev->board_name = boardtype.name;
  302. ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
  303. "ni_mio_cs", dev);
  304. if (ret < 0) {
  305. printk(" irq not available\n");
  306. return -EINVAL;
  307. }
  308. dev->irq = irq;
  309. /* allocate private area */
  310. ret = ni_alloc_private(dev);
  311. if (ret < 0)
  312. return ret;
  313. devpriv->stc_writew = &mio_cs_win_out;
  314. devpriv->stc_readw = &mio_cs_win_in;
  315. devpriv->stc_writel = &win_out2;
  316. devpriv->stc_readl = &win_in2;
  317. ret = ni_E_init(dev, it);
  318. if (ret < 0)
  319. return ret;
  320. return 0;
  321. }
  322. static int ni_getboardtype(struct comedi_device *dev,
  323. struct pcmcia_device *link)
  324. {
  325. int i;
  326. for (i = 0; i < n_ni_boards; i++) {
  327. if (ni_boards[i].device_id == link->card_id)
  328. return i;
  329. }
  330. printk("unknown board 0x%04x -- pretend it is a ", link->card_id);
  331. return 0;
  332. }
  333. #ifdef MODULE
  334. static const struct pcmcia_device_id ni_mio_cs_ids[] = {
  335. PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d), /* DAQCard-ai-16xe-50 */
  336. PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c), /* DAQCard-ai-16e-4 */
  337. PCMCIA_DEVICE_MANF_CARD(0x010b, 0x02c4), /* DAQCard-6062E */
  338. PCMCIA_DEVICE_MANF_CARD(0x010b, 0x075e), /* DAQCard-6024E */
  339. PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0245), /* DAQCard-6036E */
  340. PCMCIA_DEVICE_NULL
  341. };
  342. MODULE_DEVICE_TABLE(pcmcia, ni_mio_cs_ids);
  343. MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
  344. MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series");
  345. MODULE_LICENSE("GPL");
  346. struct pcmcia_driver ni_mio_cs_driver = {
  347. .probe = &cs_attach,
  348. .remove = &cs_detach,
  349. .suspend = &mio_cs_suspend,
  350. .resume = &mio_cs_resume,
  351. .id_table = ni_mio_cs_ids,
  352. .owner = THIS_MODULE,
  353. .name = "ni_mio_cs",
  354. };
  355. int init_module(void)
  356. {
  357. pcmcia_register_driver(&ni_mio_cs_driver);
  358. comedi_driver_register(&driver_ni_mio_cs);
  359. return 0;
  360. }
  361. void cleanup_module(void)
  362. {
  363. pcmcia_unregister_driver(&ni_mio_cs_driver);
  364. #if 0
  365. while (cur_dev != NULL)
  366. cs_detach(cur_dev->handle);
  367. #endif
  368. comedi_driver_unregister(&driver_ni_mio_cs);
  369. }
  370. #endif