PageRenderTime 23ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/comedi/drivers/adq12b.c

https://github.com/dmitriy103/bravo_kernel-2.6.35
C | 405 lines | 200 code | 55 blank | 150 comment | 23 complexity | fe840a98d375d35cf8c15954a4c00265 MD5 | raw file
  1. /*
  2. comedi/drivers/adq12b.c
  3. driver for MicroAxial ADQ12-B data acquisition and control card
  4. COMEDI - Linux Control and Measurement Device Interface
  5. Copyright (C) 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: adq12b
  20. Description: driver for MicroAxial ADQ12-B data acquisition and control card
  21. Devices: [MicroAxial] ADQ12-B (adq12b)
  22. Author: jeremy theler <thelerg@ib.cnea.gov.ar>
  23. Updated: Thu, 21 Feb 2008 02:56:27 -0300
  24. Status: works
  25. Driver for the acquisition card ADQ12-B (without any add-on).
  26. - Analog input is subdevice 0 (16 channels single-ended or 8 differential)
  27. - Digital input is subdevice 1 (5 channels)
  28. - Digital output is subdevice 1 (8 channels)
  29. - The PACER is not supported in this version
  30. If you do not specify any options, they will default to
  31. # comedi_config /dev/comedi0 adq12b 0x300,0,0
  32. option 1: I/O base address. The following table is provided as a help
  33. of the hardware jumpers.
  34. address jumper JADR
  35. 0x300 1 (factory default)
  36. 0x320 2
  37. 0x340 3
  38. 0x360 4
  39. 0x380 5
  40. 0x3A0 6
  41. option 2: unipolar/bipolar ADC selection: 0 -> bipolar, 1 -> unipolar
  42. selection comedi_config option JUB
  43. bipolar 0 2-3 (factory default)
  44. unipolar 1 1-2
  45. option 3: single-ended/differential AI selection: 0 -> SE, 1 -> differential
  46. selection comedi_config option JCHA JCHB
  47. single-ended 0 1-2 1-2 (factory default)
  48. differential 1 2-3 2-3
  49. written by jeremy theler <thelerg@ib.cnea.gov.ar>
  50. instituto balseiro
  51. comision nacional de energia atomica
  52. universidad nacional de cuyo
  53. argentina
  54. 21-feb-2008
  55. + changed supported devices string (missused the [] and ())
  56. 13-oct-2007
  57. + first try
  58. */
  59. #include "../comedidev.h"
  60. /* address scheme (page 2.17 of the manual) */
  61. #define ADQ12B_SIZE 16
  62. #define ADQ12B_CTREG 0x00
  63. #define ADQ12B_STINR 0x00
  64. #define ADQ12B_OUTBR 0x04
  65. #define ADQ12B_ADLOW 0x08
  66. #define ADQ12B_ADHIG 0x09
  67. #define ADQ12B_CONT0 0x0c
  68. #define ADQ12B_CONT1 0x0d
  69. #define ADQ12B_CONT2 0x0e
  70. #define ADQ12B_COWORD 0x0f
  71. /* mask of the bit at STINR to check end of conversion */
  72. #define ADQ12B_EOC 0x20
  73. #define TIMEOUT 20
  74. /* available ranges through the PGA gains */
  75. static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, {
  76. BIP_RANGE(5),
  77. BIP_RANGE(2),
  78. BIP_RANGE(1),
  79. BIP_RANGE(0.5)
  80. }
  81. };
  82. static const struct comedi_lrange range_adq12b_ai_unipolar = { 4, {
  83. UNI_RANGE(5),
  84. UNI_RANGE(2),
  85. UNI_RANGE(1),
  86. UNI_RANGE
  87. (0.5)
  88. }
  89. };
  90. struct adq12b_board {
  91. const char *name;
  92. int ai_se_chans;
  93. int ai_diff_chans;
  94. int ai_bits;
  95. int di_chans;
  96. int do_chans;
  97. };
  98. static const struct adq12b_board adq12b_boards[] = {
  99. {
  100. .name = "adq12b",
  101. .ai_se_chans = 16,
  102. .ai_diff_chans = 8,
  103. .ai_bits = 12,
  104. .di_chans = 5,
  105. .do_chans = 8}
  106. /* potentially, more adq-based deviced will be added */
  107. /*,
  108. .name = "adq12b",
  109. .ai_chans = 16, // this is just for reference, hardcoded again later
  110. .ai_bits = 12,
  111. .di_chans = 8,
  112. .do_chans = 5
  113. }*/
  114. };
  115. #define thisboard ((const struct adq12b_board *)dev->board_ptr)
  116. struct adq12b_private {
  117. int unipolar; /* option 2 of comedi_config (1 is iobase) */
  118. int differential; /* option 3 of comedi_config */
  119. int last_channel;
  120. int last_range;
  121. unsigned int digital_state;
  122. };
  123. #define devpriv ((struct adq12b_private *)dev->private)
  124. /*
  125. * The struct comedi_driver structure tells the Comedi core module
  126. * which functions to call to configure/deconfigure (attach/detach)
  127. * the board, and also about the kernel module that contains
  128. * the device code.
  129. */
  130. static int adq12b_attach(struct comedi_device *dev,
  131. struct comedi_devconfig *it);
  132. static int adq12b_detach(struct comedi_device *dev);
  133. static struct comedi_driver driver_adq12b = {
  134. .driver_name = "adq12b",
  135. .module = THIS_MODULE,
  136. .attach = adq12b_attach,
  137. .detach = adq12b_detach,
  138. .board_name = &adq12b_boards[0].name,
  139. .offset = sizeof(struct adq12b_board),
  140. .num_names = ARRAY_SIZE(adq12b_boards),
  141. };
  142. static int adq12b_ai_rinsn(struct comedi_device *dev,
  143. struct comedi_subdevice *s, struct comedi_insn *insn,
  144. unsigned int *data);
  145. static int adq12b_di_insn_bits(struct comedi_device *dev,
  146. struct comedi_subdevice *s,
  147. struct comedi_insn *insn, unsigned int *data);
  148. static int adq12b_do_insn_bits(struct comedi_device *dev,
  149. struct comedi_subdevice *s,
  150. struct comedi_insn *insn, unsigned int *data);
  151. /*
  152. * Attach is called by the Comedi core to configure the driver
  153. * for a particular board. If you specified a board_name array
  154. * in the driver structure, dev->board_ptr contains that
  155. * address.
  156. */
  157. static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
  158. {
  159. struct comedi_subdevice *s;
  160. unsigned long iobase;
  161. int unipolar, differential;
  162. iobase = it->options[0];
  163. unipolar = it->options[1];
  164. differential = it->options[2];
  165. printk(KERN_INFO "comedi%d: adq12b called with options base=0x%03lx, "
  166. "%s and %s\n", dev->minor, iobase,
  167. (unipolar == 1) ? "unipolar" : "bipolar",
  168. (differential == 1) ? "differential" : "single-ended");
  169. /* if no address was specified, try the default 0x300 */
  170. if (iobase == 0) {
  171. printk(KERN_WARNING "comedi%d: adq12b warning: I/O base "
  172. "address not specified. Trying the default 0x300.\n",
  173. dev->minor);
  174. iobase = 0x300;
  175. }
  176. printk("comedi%d: adq12b: 0x%04lx ", dev->minor, iobase);
  177. if (!request_region(iobase, ADQ12B_SIZE, "adq12b")) {
  178. printk("I/O port conflict\n");
  179. return -EIO;
  180. }
  181. dev->iobase = iobase;
  182. /*
  183. * Initialize dev->board_name. Note that we can use the "thisboard"
  184. * macro now, since we just initialized it in the last line.
  185. */
  186. dev->board_name = thisboard->name;
  187. /*
  188. * Allocate the private structure area. alloc_private() is a
  189. * convenient macro defined in comedidev.h.
  190. */
  191. if (alloc_private(dev, sizeof(struct adq12b_private)) < 0)
  192. return -ENOMEM;
  193. /* fill in devpriv structure */
  194. devpriv->unipolar = unipolar;
  195. devpriv->differential = differential;
  196. devpriv->digital_state = 0;
  197. /* initialize channel and range to -1 so we make sure we always write
  198. at least once to the CTREG in the instruction */
  199. devpriv->last_channel = -1;
  200. devpriv->last_range = -1;
  201. /*
  202. * Allocate the subdevice structures. alloc_subdevice() is a
  203. * convenient macro defined in comedidev.h.
  204. */
  205. if (alloc_subdevices(dev, 3) < 0)
  206. return -ENOMEM;
  207. s = dev->subdevices + 0;
  208. /* analog input subdevice */
  209. s->type = COMEDI_SUBD_AI;
  210. if (differential) {
  211. s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
  212. s->n_chan = thisboard->ai_diff_chans;
  213. } else {
  214. s->subdev_flags = SDF_READABLE | SDF_GROUND;
  215. s->n_chan = thisboard->ai_se_chans;
  216. }
  217. if (unipolar)
  218. s->range_table = &range_adq12b_ai_unipolar;
  219. else
  220. s->range_table = &range_adq12b_ai_bipolar;
  221. s->maxdata = (1 << thisboard->ai_bits) - 1;
  222. s->len_chanlist = 4; /* This is the maximum chanlist length that
  223. the board can handle */
  224. s->insn_read = adq12b_ai_rinsn;
  225. s = dev->subdevices + 1;
  226. /* digital input subdevice */
  227. s->type = COMEDI_SUBD_DI;
  228. s->subdev_flags = SDF_READABLE;
  229. s->n_chan = thisboard->di_chans;
  230. s->maxdata = 1;
  231. s->range_table = &range_digital;
  232. s->insn_bits = adq12b_di_insn_bits;
  233. s = dev->subdevices + 2;
  234. /* digital output subdevice */
  235. s->type = COMEDI_SUBD_DO;
  236. s->subdev_flags = SDF_WRITABLE;
  237. s->n_chan = thisboard->do_chans;
  238. s->maxdata = 1;
  239. s->range_table = &range_digital;
  240. s->insn_bits = adq12b_do_insn_bits;
  241. printk(KERN_INFO "attached\n");
  242. return 0;
  243. }
  244. /*
  245. * _detach is called to deconfigure a device. It should deallocate
  246. * resources.
  247. * This function is also called when _attach() fails, so it should be
  248. * careful not to release resources that were not necessarily
  249. * allocated by _attach(). dev->private and dev->subdevices are
  250. * deallocated automatically by the core.
  251. */
  252. static int adq12b_detach(struct comedi_device *dev)
  253. {
  254. if (dev->iobase)
  255. release_region(dev->iobase, ADQ12B_SIZE);
  256. kfree(devpriv);
  257. printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor);
  258. return 0;
  259. }
  260. /*
  261. * "instructions" read/write data in "one-shot" or "software-triggered"
  262. * mode.
  263. */
  264. static int adq12b_ai_rinsn(struct comedi_device *dev,
  265. struct comedi_subdevice *s, struct comedi_insn *insn,
  266. unsigned int *data)
  267. {
  268. int n, i;
  269. int range, channel;
  270. unsigned char hi, lo, status;
  271. /* change channel and range only if it is different from the previous */
  272. range = CR_RANGE(insn->chanspec);
  273. channel = CR_CHAN(insn->chanspec);
  274. if (channel != devpriv->last_channel || range != devpriv->last_range) {
  275. outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
  276. udelay(50); /* wait for the mux to settle */
  277. }
  278. /* trigger conversion */
  279. status = inb(dev->iobase + ADQ12B_ADLOW);
  280. /* convert n samples */
  281. for (n = 0; n < insn->n; n++) {
  282. /* wait for end of convertion */
  283. i = 0;
  284. do {
  285. /* udelay(1); */
  286. status = inb(dev->iobase + ADQ12B_STINR);
  287. status = status & ADQ12B_EOC;
  288. } while (status == 0 && ++i < TIMEOUT);
  289. /* } while (++i < 10); */
  290. /* read data */
  291. hi = inb(dev->iobase + ADQ12B_ADHIG);
  292. lo = inb(dev->iobase + ADQ12B_ADLOW);
  293. /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
  294. channel, range, status, hi, lo); */
  295. data[n] = (hi << 8) | lo;
  296. }
  297. /* return the number of samples read/written */
  298. return n;
  299. }
  300. static int adq12b_di_insn_bits(struct comedi_device *dev,
  301. struct comedi_subdevice *s,
  302. struct comedi_insn *insn, unsigned int *data)
  303. {
  304. /* only bits 0-4 have information about digital inputs */
  305. data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
  306. return 2;
  307. }
  308. static int adq12b_do_insn_bits(struct comedi_device *dev,
  309. struct comedi_subdevice *s,
  310. struct comedi_insn *insn, unsigned int *data)
  311. {
  312. int channel;
  313. for (channel = 0; channel < 8; channel++)
  314. if (((data[0] >> channel) & 0x01) != 0)
  315. outb((((data[1] >> channel) & 0x01) << 3) | channel,
  316. dev->iobase + ADQ12B_OUTBR);
  317. /* store information to retrieve when asked for reading */
  318. if (data[0]) {
  319. devpriv->digital_state &= ~data[0];
  320. devpriv->digital_state |= (data[0] & data[1]);
  321. }
  322. data[1] = devpriv->digital_state;
  323. return 2;
  324. }
  325. /*
  326. * A convenient macro that defines init_module() and cleanup_module(),
  327. * as necessary.
  328. */
  329. COMEDI_INITCLEANUP(driver_adq12b);