PageRenderTime 429ms CodeModel.GetById 101ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/staging/comedi/drivers/dmm32at.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 1081 lines | 644 code | 168 blank | 269 comment | 149 complexity | 0b13c4be6207851859d9461c3a825d65 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1. /*
  2. comedi/drivers/dmm32at.c
  3. Diamond Systems mm32at code for a Comedi driver
  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: dmm32at
  20. Description: Diamond Systems mm32at driver.
  21. Devices:
  22. Author: Perry J. Piplani <perry.j.piplani@nasa.gov>
  23. Updated: Fri Jun 4 09:13:24 CDT 2004
  24. Status: experimental
  25. This driver is for the Diamond Systems MM-32-AT board
  26. http://www.diamondsystems.com/products/diamondmm32at It is being used
  27. on serveral projects inside NASA, without problems so far. For analog
  28. input commands, TRIG_EXT is not yet supported at all..
  29. Configuration Options:
  30. comedi_config /dev/comedi0 dmm32at baseaddr,irq
  31. */
  32. #include <linux/interrupt.h>
  33. #include "../comedidev.h"
  34. #include <linux/ioport.h>
  35. /* Board register addresses */
  36. #define DMM32AT_MEMSIZE 0x10
  37. #define DMM32AT_CONV 0x00
  38. #define DMM32AT_AILSB 0x00
  39. #define DMM32AT_AUXDOUT 0x01
  40. #define DMM32AT_AIMSB 0x01
  41. #define DMM32AT_AILOW 0x02
  42. #define DMM32AT_AIHIGH 0x03
  43. #define DMM32AT_DACLSB 0x04
  44. #define DMM32AT_DACSTAT 0x04
  45. #define DMM32AT_DACMSB 0x05
  46. #define DMM32AT_FIFOCNTRL 0x07
  47. #define DMM32AT_FIFOSTAT 0x07
  48. #define DMM32AT_CNTRL 0x08
  49. #define DMM32AT_AISTAT 0x08
  50. #define DMM32AT_INTCLOCK 0x09
  51. #define DMM32AT_CNTRDIO 0x0a
  52. #define DMM32AT_AICONF 0x0b
  53. #define DMM32AT_AIRBACK 0x0b
  54. #define DMM32AT_CLK1 0x0d
  55. #define DMM32AT_CLK2 0x0e
  56. #define DMM32AT_CLKCT 0x0f
  57. #define DMM32AT_DIOA 0x0c
  58. #define DMM32AT_DIOB 0x0d
  59. #define DMM32AT_DIOC 0x0e
  60. #define DMM32AT_DIOCONF 0x0f
  61. #define dmm_inb(cdev, reg) inb((cdev->iobase)+reg)
  62. #define dmm_outb(cdev, reg, valu) outb(valu, (cdev->iobase)+reg)
  63. /* Board register values. */
  64. /* DMM32AT_DACSTAT 0x04 */
  65. #define DMM32AT_DACBUSY 0x80
  66. /* DMM32AT_FIFOCNTRL 0x07 */
  67. #define DMM32AT_FIFORESET 0x02
  68. #define DMM32AT_SCANENABLE 0x04
  69. /* DMM32AT_CNTRL 0x08 */
  70. #define DMM32AT_RESET 0x20
  71. #define DMM32AT_INTRESET 0x08
  72. #define DMM32AT_CLKACC 0x00
  73. #define DMM32AT_DIOACC 0x01
  74. /* DMM32AT_AISTAT 0x08 */
  75. #define DMM32AT_STATUS 0x80
  76. /* DMM32AT_INTCLOCK 0x09 */
  77. #define DMM32AT_ADINT 0x80
  78. #define DMM32AT_CLKSEL 0x03
  79. /* DMM32AT_CNTRDIO 0x0a */
  80. #define DMM32AT_FREQ12 0x80
  81. /* DMM32AT_AICONF 0x0b */
  82. #define DMM32AT_RANGE_U10 0x0c
  83. #define DMM32AT_RANGE_U5 0x0d
  84. #define DMM32AT_RANGE_B10 0x08
  85. #define DMM32AT_RANGE_B5 0x00
  86. #define DMM32AT_SCINT_20 0x00
  87. #define DMM32AT_SCINT_15 0x10
  88. #define DMM32AT_SCINT_10 0x20
  89. #define DMM32AT_SCINT_5 0x30
  90. /* DMM32AT_CLKCT 0x0f */
  91. #define DMM32AT_CLKCT1 0x56 /* mode3 counter 1 - write low byte only */
  92. #define DMM32AT_CLKCT2 0xb6 /* mode3 counter 2 - write high and low byte */
  93. /* DMM32AT_DIOCONF 0x0f */
  94. #define DMM32AT_DIENABLE 0x80
  95. #define DMM32AT_DIRA 0x10
  96. #define DMM32AT_DIRB 0x02
  97. #define DMM32AT_DIRCL 0x01
  98. #define DMM32AT_DIRCH 0x08
  99. /* board AI ranges in comedi structure */
  100. static const struct comedi_lrange dmm32at_airanges = {
  101. 4,
  102. {
  103. UNI_RANGE(10),
  104. UNI_RANGE(5),
  105. BIP_RANGE(10),
  106. BIP_RANGE(5),
  107. }
  108. };
  109. /* register values for above ranges */
  110. static const unsigned char dmm32at_rangebits[] = {
  111. DMM32AT_RANGE_U10,
  112. DMM32AT_RANGE_U5,
  113. DMM32AT_RANGE_B10,
  114. DMM32AT_RANGE_B5,
  115. };
  116. /* only one of these ranges is valid, as set by a jumper on the
  117. * board. The application should only use the range set by the jumper
  118. */
  119. static const struct comedi_lrange dmm32at_aoranges = {
  120. 4,
  121. {
  122. UNI_RANGE(10),
  123. UNI_RANGE(5),
  124. BIP_RANGE(10),
  125. BIP_RANGE(5),
  126. }
  127. };
  128. /*
  129. * Board descriptions for two imaginary boards. Describing the
  130. * boards in this way is optional, and completely driver-dependent.
  131. * Some drivers use arrays such as this, other do not.
  132. */
  133. struct dmm32at_board {
  134. const char *name;
  135. int ai_chans;
  136. int ai_bits;
  137. const struct comedi_lrange *ai_ranges;
  138. int ao_chans;
  139. int ao_bits;
  140. const struct comedi_lrange *ao_ranges;
  141. int have_dio;
  142. int dio_chans;
  143. };
  144. static const struct dmm32at_board dmm32at_boards[] = {
  145. {
  146. .name = "dmm32at",
  147. .ai_chans = 32,
  148. .ai_bits = 16,
  149. .ai_ranges = &dmm32at_airanges,
  150. .ao_chans = 4,
  151. .ao_bits = 12,
  152. .ao_ranges = &dmm32at_aoranges,
  153. .have_dio = 1,
  154. .dio_chans = 24,
  155. },
  156. };
  157. /*
  158. * Useful for shorthand access to the particular board structure
  159. */
  160. #define thisboard ((const struct dmm32at_board *)dev->board_ptr)
  161. /* this structure is for data unique to this hardware driver. If
  162. * several hardware drivers keep similar information in this structure,
  163. * feel free to suggest moving the variable to the struct comedi_device struct.
  164. */
  165. struct dmm32at_private {
  166. int data;
  167. int ai_inuse;
  168. unsigned int ai_scans_left;
  169. /* Used for AO readback */
  170. unsigned int ao_readback[4];
  171. unsigned char dio_config;
  172. };
  173. /*
  174. * most drivers define the following macro to make it easy to
  175. * access the private structure.
  176. */
  177. #define devpriv ((struct dmm32at_private *)dev->private)
  178. /*
  179. * The struct comedi_driver structure tells the Comedi core module
  180. * which functions to call to configure/deconfigure (attach/detach)
  181. * the board, and also about the kernel module that contains
  182. * the device code.
  183. */
  184. static int dmm32at_attach(struct comedi_device *dev,
  185. struct comedi_devconfig *it);
  186. static int dmm32at_detach(struct comedi_device *dev);
  187. static struct comedi_driver driver_dmm32at = {
  188. .driver_name = "dmm32at",
  189. .module = THIS_MODULE,
  190. .attach = dmm32at_attach,
  191. .detach = dmm32at_detach,
  192. /* It is not necessary to implement the following members if you are
  193. * writing a driver for a ISA PnP or PCI card */
  194. /* Most drivers will support multiple types of boards by
  195. * having an array of board structures. These were defined
  196. * in dmm32at_boards[] above. Note that the element 'name'
  197. * was first in the structure -- Comedi uses this fact to
  198. * extract the name of the board without knowing any details
  199. * about the structure except for its length.
  200. * When a device is attached (by comedi_config), the name
  201. * of the device is given to Comedi, and Comedi tries to
  202. * match it by going through the list of board names. If
  203. * there is a match, the address of the pointer is put
  204. * into dev->board_ptr and driver->attach() is called.
  205. *
  206. * Note that these are not necessary if you can determine
  207. * the type of board in software. ISA PnP, PCI, and PCMCIA
  208. * devices are such boards.
  209. */
  210. .board_name = &dmm32at_boards[0].name,
  211. .offset = sizeof(struct dmm32at_board),
  212. .num_names = ARRAY_SIZE(dmm32at_boards),
  213. };
  214. /* prototypes for driver functions below */
  215. static int dmm32at_ai_rinsn(struct comedi_device *dev,
  216. struct comedi_subdevice *s,
  217. struct comedi_insn *insn, unsigned int *data);
  218. static int dmm32at_ao_winsn(struct comedi_device *dev,
  219. struct comedi_subdevice *s,
  220. struct comedi_insn *insn, unsigned int *data);
  221. static int dmm32at_ao_rinsn(struct comedi_device *dev,
  222. struct comedi_subdevice *s,
  223. struct comedi_insn *insn, unsigned int *data);
  224. static int dmm32at_dio_insn_bits(struct comedi_device *dev,
  225. struct comedi_subdevice *s,
  226. struct comedi_insn *insn, unsigned int *data);
  227. static int dmm32at_dio_insn_config(struct comedi_device *dev,
  228. struct comedi_subdevice *s,
  229. struct comedi_insn *insn,
  230. unsigned int *data);
  231. static int dmm32at_ai_cmdtest(struct comedi_device *dev,
  232. struct comedi_subdevice *s,
  233. struct comedi_cmd *cmd);
  234. static int dmm32at_ai_cmd(struct comedi_device *dev,
  235. struct comedi_subdevice *s);
  236. static int dmm32at_ai_cancel(struct comedi_device *dev,
  237. struct comedi_subdevice *s);
  238. static int dmm32at_ns_to_timer(unsigned int *ns, int round);
  239. static irqreturn_t dmm32at_isr(int irq, void *d);
  240. void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec);
  241. /*
  242. * Attach is called by the Comedi core to configure the driver
  243. * for a particular board. If you specified a board_name array
  244. * in the driver structure, dev->board_ptr contains that
  245. * address.
  246. */
  247. static int dmm32at_attach(struct comedi_device *dev,
  248. struct comedi_devconfig *it)
  249. {
  250. int ret;
  251. struct comedi_subdevice *s;
  252. unsigned char aihi, ailo, fifostat, aistat, intstat, airback;
  253. unsigned long iobase;
  254. unsigned int irq;
  255. iobase = it->options[0];
  256. irq = it->options[1];
  257. printk(KERN_INFO "comedi%d: dmm32at: attaching\n", dev->minor);
  258. printk(KERN_DEBUG "dmm32at: probing at address 0x%04lx, irq %u\n",
  259. iobase, irq);
  260. /* register address space */
  261. if (!request_region(iobase, DMM32AT_MEMSIZE, thisboard->name)) {
  262. printk(KERN_ERR "comedi%d: dmm32at: I/O port conflict\n",
  263. dev->minor);
  264. return -EIO;
  265. }
  266. dev->iobase = iobase;
  267. /* the following just makes sure the board is there and gets
  268. it to a known state */
  269. /* reset the board */
  270. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_RESET);
  271. /* allow a millisecond to reset */
  272. udelay(1000);
  273. /* zero scan and fifo control */
  274. dmm_outb(dev, DMM32AT_FIFOCNTRL, 0x0);
  275. /* zero interrupt and clock control */
  276. dmm_outb(dev, DMM32AT_INTCLOCK, 0x0);
  277. /* write a test channel range, the high 3 bits should drop */
  278. dmm_outb(dev, DMM32AT_AILOW, 0x80);
  279. dmm_outb(dev, DMM32AT_AIHIGH, 0xff);
  280. /* set the range at 10v unipolar */
  281. dmm_outb(dev, DMM32AT_AICONF, DMM32AT_RANGE_U10);
  282. /* should take 10 us to settle, here's a hundred */
  283. udelay(100);
  284. /* read back the values */
  285. ailo = dmm_inb(dev, DMM32AT_AILOW);
  286. aihi = dmm_inb(dev, DMM32AT_AIHIGH);
  287. fifostat = dmm_inb(dev, DMM32AT_FIFOSTAT);
  288. aistat = dmm_inb(dev, DMM32AT_AISTAT);
  289. intstat = dmm_inb(dev, DMM32AT_INTCLOCK);
  290. airback = dmm_inb(dev, DMM32AT_AIRBACK);
  291. printk(KERN_DEBUG "dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n",
  292. ailo, aihi, fifostat);
  293. printk(KERN_DEBUG
  294. "dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n",
  295. aistat, intstat, airback);
  296. if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) ||
  297. (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) {
  298. printk(KERN_ERR "dmmat32: board detection failed\n");
  299. return -EIO;
  300. }
  301. /* board is there, register interrupt */
  302. if (irq) {
  303. ret = request_irq(irq, dmm32at_isr, 0, thisboard->name, dev);
  304. if (ret < 0) {
  305. printk(KERN_ERR "dmm32at: irq conflict\n");
  306. return ret;
  307. }
  308. dev->irq = irq;
  309. }
  310. /*
  311. * If you can probe the device to determine what device in a series
  312. * it is, this is the place to do it. Otherwise, dev->board_ptr
  313. * should already be initialized.
  314. */
  315. /* dev->board_ptr = dmm32at_probe(dev); */
  316. /*
  317. * Initialize dev->board_name. Note that we can use the "thisboard"
  318. * macro now, since we just initialized it in the last line.
  319. */
  320. dev->board_name = thisboard->name;
  321. /*
  322. * Allocate the private structure area. alloc_private() is a
  323. * convenient macro defined in comedidev.h.
  324. */
  325. if (alloc_private(dev, sizeof(struct dmm32at_private)) < 0)
  326. return -ENOMEM;
  327. /*
  328. * Allocate the subdevice structures. alloc_subdevice() is a
  329. * convenient macro defined in comedidev.h.
  330. */
  331. if (alloc_subdevices(dev, 3) < 0)
  332. return -ENOMEM;
  333. s = dev->subdevices + 0;
  334. dev->read_subdev = s;
  335. /* analog input subdevice */
  336. s->type = COMEDI_SUBD_AI;
  337. /* we support single-ended (ground) and differential */
  338. s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
  339. s->n_chan = thisboard->ai_chans;
  340. s->maxdata = (1 << thisboard->ai_bits) - 1;
  341. s->range_table = thisboard->ai_ranges;
  342. s->len_chanlist = 32; /* This is the maximum chanlist length that
  343. the board can handle */
  344. s->insn_read = dmm32at_ai_rinsn;
  345. s->do_cmd = dmm32at_ai_cmd;
  346. s->do_cmdtest = dmm32at_ai_cmdtest;
  347. s->cancel = dmm32at_ai_cancel;
  348. s = dev->subdevices + 1;
  349. /* analog output subdevice */
  350. s->type = COMEDI_SUBD_AO;
  351. s->subdev_flags = SDF_WRITABLE;
  352. s->n_chan = thisboard->ao_chans;
  353. s->maxdata = (1 << thisboard->ao_bits) - 1;
  354. s->range_table = thisboard->ao_ranges;
  355. s->insn_write = dmm32at_ao_winsn;
  356. s->insn_read = dmm32at_ao_rinsn;
  357. s = dev->subdevices + 2;
  358. /* digital i/o subdevice */
  359. if (thisboard->have_dio) {
  360. /* get access to the DIO regs */
  361. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
  362. /* set the DIO's to the defualt input setting */
  363. devpriv->dio_config = DMM32AT_DIRA | DMM32AT_DIRB |
  364. DMM32AT_DIRCL | DMM32AT_DIRCH | DMM32AT_DIENABLE;
  365. dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config);
  366. /* set up the subdevice */
  367. s->type = COMEDI_SUBD_DIO;
  368. s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
  369. s->n_chan = thisboard->dio_chans;
  370. s->maxdata = 1;
  371. s->state = 0;
  372. s->range_table = &range_digital;
  373. s->insn_bits = dmm32at_dio_insn_bits;
  374. s->insn_config = dmm32at_dio_insn_config;
  375. } else {
  376. s->type = COMEDI_SUBD_UNUSED;
  377. }
  378. /* success */
  379. printk(KERN_INFO "comedi%d: dmm32at: attached\n", dev->minor);
  380. return 1;
  381. }
  382. /*
  383. * _detach is called to deconfigure a device. It should deallocate
  384. * resources.
  385. * This function is also called when _attach() fails, so it should be
  386. * careful not to release resources that were not necessarily
  387. * allocated by _attach(). dev->private and dev->subdevices are
  388. * deallocated automatically by the core.
  389. */
  390. static int dmm32at_detach(struct comedi_device *dev)
  391. {
  392. printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor);
  393. if (dev->irq)
  394. free_irq(dev->irq, dev);
  395. if (dev->iobase)
  396. release_region(dev->iobase, DMM32AT_MEMSIZE);
  397. return 0;
  398. }
  399. /*
  400. * "instructions" read/write data in "one-shot" or "software-triggered"
  401. * mode.
  402. */
  403. static int dmm32at_ai_rinsn(struct comedi_device *dev,
  404. struct comedi_subdevice *s,
  405. struct comedi_insn *insn, unsigned int *data)
  406. {
  407. int n, i;
  408. unsigned int d;
  409. unsigned char status;
  410. unsigned short msb, lsb;
  411. unsigned char chan;
  412. int range;
  413. /* get the channel and range number */
  414. chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1);
  415. range = CR_RANGE(insn->chanspec);
  416. /* printk("channel=0x%02x, range=%d\n",chan,range); */
  417. /* zero scan and fifo control and reset fifo */
  418. dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET);
  419. /* write the ai channel range regs */
  420. dmm_outb(dev, DMM32AT_AILOW, chan);
  421. dmm_outb(dev, DMM32AT_AIHIGH, chan);
  422. /* set the range bits */
  423. dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]);
  424. /* wait for circuit to settle */
  425. for (i = 0; i < 40000; i++) {
  426. status = dmm_inb(dev, DMM32AT_AIRBACK);
  427. if ((status & DMM32AT_STATUS) == 0)
  428. break;
  429. }
  430. if (i == 40000) {
  431. printk(KERN_WARNING "dmm32at: timeout\n");
  432. return -ETIMEDOUT;
  433. }
  434. /* convert n samples */
  435. for (n = 0; n < insn->n; n++) {
  436. /* trigger conversion */
  437. dmm_outb(dev, DMM32AT_CONV, 0xff);
  438. /* wait for conversion to end */
  439. for (i = 0; i < 40000; i++) {
  440. status = dmm_inb(dev, DMM32AT_AISTAT);
  441. if ((status & DMM32AT_STATUS) == 0)
  442. break;
  443. }
  444. if (i == 40000) {
  445. printk(KERN_WARNING "dmm32at: timeout\n");
  446. return -ETIMEDOUT;
  447. }
  448. /* read data */
  449. lsb = dmm_inb(dev, DMM32AT_AILSB);
  450. msb = dmm_inb(dev, DMM32AT_AIMSB);
  451. /* invert sign bit to make range unsigned, this is an
  452. idiosyncrasy of the diamond board, it return
  453. conversions as a signed value, i.e. -32768 to
  454. 32767, flipping the bit and interpreting it as
  455. signed gives you a range of 0 to 65535 which is
  456. used by comedi */
  457. d = ((msb ^ 0x0080) << 8) + lsb;
  458. data[n] = d;
  459. }
  460. /* return the number of samples read/written */
  461. return n;
  462. }
  463. static int dmm32at_ai_cmdtest(struct comedi_device *dev,
  464. struct comedi_subdevice *s,
  465. struct comedi_cmd *cmd)
  466. {
  467. int err = 0;
  468. int tmp;
  469. int start_chan, gain, i;
  470. /* printk("dmmat32 in command test\n"); */
  471. /* cmdtest tests a particular command to see if it is valid.
  472. * Using the cmdtest ioctl, a user can create a valid cmd
  473. * and then have it executes by the cmd ioctl.
  474. *
  475. * cmdtest returns 1,2,3,4 or 0, depending on which tests
  476. * the command passes. */
  477. /* step 1: make sure trigger sources are trivially valid */
  478. tmp = cmd->start_src;
  479. cmd->start_src &= TRIG_NOW;
  480. if (!cmd->start_src || tmp != cmd->start_src)
  481. err++;
  482. tmp = cmd->scan_begin_src;
  483. cmd->scan_begin_src &= TRIG_TIMER /*| TRIG_EXT */ ;
  484. if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
  485. err++;
  486. tmp = cmd->convert_src;
  487. cmd->convert_src &= TRIG_TIMER /*| TRIG_EXT */ ;
  488. if (!cmd->convert_src || tmp != cmd->convert_src)
  489. err++;
  490. tmp = cmd->scan_end_src;
  491. cmd->scan_end_src &= TRIG_COUNT;
  492. if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
  493. err++;
  494. tmp = cmd->stop_src;
  495. cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
  496. if (!cmd->stop_src || tmp != cmd->stop_src)
  497. err++;
  498. if (err)
  499. return 1;
  500. /* step 2: make sure trigger sources are unique and mutually
  501. * compatible */
  502. /* note that mutual compatibility is not an issue here */
  503. if (cmd->scan_begin_src != TRIG_TIMER &&
  504. cmd->scan_begin_src != TRIG_EXT)
  505. err++;
  506. if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
  507. err++;
  508. if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
  509. err++;
  510. if (err)
  511. return 2;
  512. /* step 3: make sure arguments are trivially compatible */
  513. if (cmd->start_arg != 0) {
  514. cmd->start_arg = 0;
  515. err++;
  516. }
  517. #define MAX_SCAN_SPEED 1000000 /* in nanoseconds */
  518. #define MIN_SCAN_SPEED 1000000000 /* in nanoseconds */
  519. if (cmd->scan_begin_src == TRIG_TIMER) {
  520. if (cmd->scan_begin_arg < MAX_SCAN_SPEED) {
  521. cmd->scan_begin_arg = MAX_SCAN_SPEED;
  522. err++;
  523. }
  524. if (cmd->scan_begin_arg > MIN_SCAN_SPEED) {
  525. cmd->scan_begin_arg = MIN_SCAN_SPEED;
  526. err++;
  527. }
  528. } else {
  529. /* external trigger */
  530. /* should be level/edge, hi/lo specification here */
  531. /* should specify multiple external triggers */
  532. if (cmd->scan_begin_arg > 9) {
  533. cmd->scan_begin_arg = 9;
  534. err++;
  535. }
  536. }
  537. if (cmd->convert_src == TRIG_TIMER) {
  538. if (cmd->convert_arg >= 17500)
  539. cmd->convert_arg = 20000;
  540. else if (cmd->convert_arg >= 12500)
  541. cmd->convert_arg = 15000;
  542. else if (cmd->convert_arg >= 7500)
  543. cmd->convert_arg = 10000;
  544. else
  545. cmd->convert_arg = 5000;
  546. } else {
  547. /* external trigger */
  548. /* see above */
  549. if (cmd->convert_arg > 9) {
  550. cmd->convert_arg = 9;
  551. err++;
  552. }
  553. }
  554. if (cmd->scan_end_arg != cmd->chanlist_len) {
  555. cmd->scan_end_arg = cmd->chanlist_len;
  556. err++;
  557. }
  558. if (cmd->stop_src == TRIG_COUNT) {
  559. if (cmd->stop_arg > 0xfffffff0) {
  560. cmd->stop_arg = 0xfffffff0;
  561. err++;
  562. }
  563. if (cmd->stop_arg == 0) {
  564. cmd->stop_arg = 1;
  565. err++;
  566. }
  567. } else {
  568. /* TRIG_NONE */
  569. if (cmd->stop_arg != 0) {
  570. cmd->stop_arg = 0;
  571. err++;
  572. }
  573. }
  574. if (err)
  575. return 3;
  576. /* step 4: fix up any arguments */
  577. if (cmd->scan_begin_src == TRIG_TIMER) {
  578. tmp = cmd->scan_begin_arg;
  579. dmm32at_ns_to_timer(&cmd->scan_begin_arg,
  580. cmd->flags & TRIG_ROUND_MASK);
  581. if (tmp != cmd->scan_begin_arg)
  582. err++;
  583. }
  584. if (cmd->convert_src == TRIG_TIMER) {
  585. tmp = cmd->convert_arg;
  586. dmm32at_ns_to_timer(&cmd->convert_arg,
  587. cmd->flags & TRIG_ROUND_MASK);
  588. if (tmp != cmd->convert_arg)
  589. err++;
  590. if (cmd->scan_begin_src == TRIG_TIMER &&
  591. cmd->scan_begin_arg <
  592. cmd->convert_arg * cmd->scan_end_arg) {
  593. cmd->scan_begin_arg =
  594. cmd->convert_arg * cmd->scan_end_arg;
  595. err++;
  596. }
  597. }
  598. if (err)
  599. return 4;
  600. /* step 5 check the channel list, the channel list for this
  601. board must be consecutive and gains must be the same */
  602. if (cmd->chanlist) {
  603. gain = CR_RANGE(cmd->chanlist[0]);
  604. start_chan = CR_CHAN(cmd->chanlist[0]);
  605. for (i = 1; i < cmd->chanlist_len; i++) {
  606. if (CR_CHAN(cmd->chanlist[i]) !=
  607. (start_chan + i) % s->n_chan) {
  608. comedi_error(dev,
  609. "entries in chanlist must be consecutive channels, counting upwards\n");
  610. err++;
  611. }
  612. if (CR_RANGE(cmd->chanlist[i]) != gain) {
  613. comedi_error(dev,
  614. "entries in chanlist must all have the same gain\n");
  615. err++;
  616. }
  617. }
  618. }
  619. if (err)
  620. return 5;
  621. return 0;
  622. }
  623. static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
  624. {
  625. struct comedi_cmd *cmd = &s->async->cmd;
  626. int i, range;
  627. unsigned char chanlo, chanhi, status;
  628. if (!cmd->chanlist)
  629. return -EINVAL;
  630. /* get the channel list and range */
  631. chanlo = CR_CHAN(cmd->chanlist[0]) & (s->n_chan - 1);
  632. chanhi = chanlo + cmd->chanlist_len - 1;
  633. if (chanhi >= s->n_chan)
  634. return -EINVAL;
  635. range = CR_RANGE(cmd->chanlist[0]);
  636. /* reset fifo */
  637. dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET);
  638. /* set scan enable */
  639. dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_SCANENABLE);
  640. /* write the ai channel range regs */
  641. dmm_outb(dev, DMM32AT_AILOW, chanlo);
  642. dmm_outb(dev, DMM32AT_AIHIGH, chanhi);
  643. /* set the range bits */
  644. dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]);
  645. /* reset the interrupt just in case */
  646. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET);
  647. if (cmd->stop_src == TRIG_COUNT)
  648. devpriv->ai_scans_left = cmd->stop_arg;
  649. else { /* TRIG_NONE */
  650. devpriv->ai_scans_left = 0xffffffff; /* indicates TRIG_NONE to
  651. * isr */
  652. }
  653. /* wait for circuit to settle */
  654. for (i = 0; i < 40000; i++) {
  655. status = dmm_inb(dev, DMM32AT_AIRBACK);
  656. if ((status & DMM32AT_STATUS) == 0)
  657. break;
  658. }
  659. if (i == 40000) {
  660. printk(KERN_WARNING "dmm32at: timeout\n");
  661. return -ETIMEDOUT;
  662. }
  663. if (devpriv->ai_scans_left > 1) {
  664. /* start the clock and enable the interrupts */
  665. dmm32at_setaitimer(dev, cmd->scan_begin_arg);
  666. } else {
  667. /* start the interrups and initiate a single scan */
  668. dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT);
  669. dmm_outb(dev, DMM32AT_CONV, 0xff);
  670. }
  671. /* printk("dmmat32 in command\n"); */
  672. /* for(i=0;i<cmd->chanlist_len;i++) */
  673. /* comedi_buf_put(s->async,i*100); */
  674. /* s->async->events |= COMEDI_CB_EOA; */
  675. /* comedi_event(dev, s); */
  676. return 0;
  677. }
  678. static int dmm32at_ai_cancel(struct comedi_device *dev,
  679. struct comedi_subdevice *s)
  680. {
  681. devpriv->ai_scans_left = 1;
  682. return 0;
  683. }
  684. static irqreturn_t dmm32at_isr(int irq, void *d)
  685. {
  686. unsigned char intstat;
  687. unsigned int samp;
  688. unsigned short msb, lsb;
  689. int i;
  690. struct comedi_device *dev = d;
  691. if (!dev->attached) {
  692. comedi_error(dev, "spurious interrupt");
  693. return IRQ_HANDLED;
  694. }
  695. intstat = dmm_inb(dev, DMM32AT_INTCLOCK);
  696. if (intstat & DMM32AT_ADINT) {
  697. struct comedi_subdevice *s = dev->read_subdev;
  698. struct comedi_cmd *cmd = &s->async->cmd;
  699. for (i = 0; i < cmd->chanlist_len; i++) {
  700. /* read data */
  701. lsb = dmm_inb(dev, DMM32AT_AILSB);
  702. msb = dmm_inb(dev, DMM32AT_AIMSB);
  703. /* invert sign bit to make range unsigned */
  704. samp = ((msb ^ 0x0080) << 8) + lsb;
  705. comedi_buf_put(s->async, samp);
  706. }
  707. if (devpriv->ai_scans_left != 0xffffffff) { /* TRIG_COUNT */
  708. devpriv->ai_scans_left--;
  709. if (devpriv->ai_scans_left == 0) {
  710. /* disable further interrupts and clocks */
  711. dmm_outb(dev, DMM32AT_INTCLOCK, 0x0);
  712. /* set the buffer to be flushed with an EOF */
  713. s->async->events |= COMEDI_CB_EOA;
  714. }
  715. }
  716. /* flush the buffer */
  717. comedi_event(dev, s);
  718. }
  719. /* reset the interrupt */
  720. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET);
  721. return IRQ_HANDLED;
  722. }
  723. /* This function doesn't require a particular form, this is just
  724. * what happens to be used in some of the drivers. It should
  725. * convert ns nanoseconds to a counter value suitable for programming
  726. * the device. Also, it should adjust ns so that it cooresponds to
  727. * the actual time that the device will use. */
  728. static int dmm32at_ns_to_timer(unsigned int *ns, int round)
  729. {
  730. /* trivial timer */
  731. /* if your timing is done through two cascaded timers, the
  732. * i8253_cascade_ns_to_timer() function in 8253.h can be
  733. * very helpful. There are also i8254_load() and i8254_mm_load()
  734. * which can be used to load values into the ubiquitous 8254 counters
  735. */
  736. return *ns;
  737. }
  738. static int dmm32at_ao_winsn(struct comedi_device *dev,
  739. struct comedi_subdevice *s,
  740. struct comedi_insn *insn, unsigned int *data)
  741. {
  742. int i;
  743. int chan = CR_CHAN(insn->chanspec);
  744. unsigned char hi, lo, status;
  745. /* Writing a list of values to an AO channel is probably not
  746. * very useful, but that's how the interface is defined. */
  747. for (i = 0; i < insn->n; i++) {
  748. devpriv->ao_readback[chan] = data[i];
  749. /* get the low byte */
  750. lo = data[i] & 0x00ff;
  751. /* high byte also contains channel number */
  752. hi = (data[i] >> 8) + chan * (1 << 6);
  753. /* printk("writing 0x%02x 0x%02x\n",hi,lo); */
  754. /* write the low and high values to the board */
  755. dmm_outb(dev, DMM32AT_DACLSB, lo);
  756. dmm_outb(dev, DMM32AT_DACMSB, hi);
  757. /* wait for circuit to settle */
  758. for (i = 0; i < 40000; i++) {
  759. status = dmm_inb(dev, DMM32AT_DACSTAT);
  760. if ((status & DMM32AT_DACBUSY) == 0)
  761. break;
  762. }
  763. if (i == 40000) {
  764. printk(KERN_WARNING "dmm32at: timeout\n");
  765. return -ETIMEDOUT;
  766. }
  767. /* dummy read to update trigger the output */
  768. status = dmm_inb(dev, DMM32AT_DACMSB);
  769. }
  770. /* return the number of samples read/written */
  771. return i;
  772. }
  773. /* AO subdevices should have a read insn as well as a write insn.
  774. * Usually this means copying a value stored in devpriv. */
  775. static int dmm32at_ao_rinsn(struct comedi_device *dev,
  776. struct comedi_subdevice *s,
  777. struct comedi_insn *insn, unsigned int *data)
  778. {
  779. int i;
  780. int chan = CR_CHAN(insn->chanspec);
  781. for (i = 0; i < insn->n; i++)
  782. data[i] = devpriv->ao_readback[chan];
  783. return i;
  784. }
  785. /* DIO devices are slightly special. Although it is possible to
  786. * implement the insn_read/insn_write interface, it is much more
  787. * useful to applications if you implement the insn_bits interface.
  788. * This allows packed reading/writing of the DIO channels. The
  789. * comedi core can convert between insn_bits and insn_read/write */
  790. static int dmm32at_dio_insn_bits(struct comedi_device *dev,
  791. struct comedi_subdevice *s,
  792. struct comedi_insn *insn, unsigned int *data)
  793. {
  794. unsigned char diobits;
  795. if (insn->n != 2)
  796. return -EINVAL;
  797. /* The insn data is a mask in data[0] and the new data
  798. * in data[1], each channel cooresponding to a bit. */
  799. if (data[0]) {
  800. s->state &= ~data[0];
  801. s->state |= data[0] & data[1];
  802. /* Write out the new digital output lines */
  803. /* outw(s->state,dev->iobase + DMM32AT_DIO); */
  804. }
  805. /* get access to the DIO regs */
  806. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
  807. /* if either part of dio is set for output */
  808. if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) ||
  809. ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) {
  810. diobits = (s->state & 0x00ff0000) >> 16;
  811. dmm_outb(dev, DMM32AT_DIOC, diobits);
  812. }
  813. if ((devpriv->dio_config & DMM32AT_DIRB) == 0) {
  814. diobits = (s->state & 0x0000ff00) >> 8;
  815. dmm_outb(dev, DMM32AT_DIOB, diobits);
  816. }
  817. if ((devpriv->dio_config & DMM32AT_DIRA) == 0) {
  818. diobits = (s->state & 0x000000ff);
  819. dmm_outb(dev, DMM32AT_DIOA, diobits);
  820. }
  821. /* now read the state back in */
  822. s->state = dmm_inb(dev, DMM32AT_DIOC);
  823. s->state <<= 8;
  824. s->state |= dmm_inb(dev, DMM32AT_DIOB);
  825. s->state <<= 8;
  826. s->state |= dmm_inb(dev, DMM32AT_DIOA);
  827. data[1] = s->state;
  828. /* on return, data[1] contains the value of the digital
  829. * input and output lines. */
  830. /* data[1]=inw(dev->iobase + DMM32AT_DIO); */
  831. /* or we could just return the software copy of the output values if
  832. * it was a purely digital output subdevice */
  833. /* data[1]=s->state; */
  834. return 2;
  835. }
  836. static int dmm32at_dio_insn_config(struct comedi_device *dev,
  837. struct comedi_subdevice *s,
  838. struct comedi_insn *insn, unsigned int *data)
  839. {
  840. unsigned char chanbit;
  841. int chan = CR_CHAN(insn->chanspec);
  842. if (insn->n != 1)
  843. return -EINVAL;
  844. if (chan < 8)
  845. chanbit = DMM32AT_DIRA;
  846. else if (chan < 16)
  847. chanbit = DMM32AT_DIRB;
  848. else if (chan < 20)
  849. chanbit = DMM32AT_DIRCL;
  850. else
  851. chanbit = DMM32AT_DIRCH;
  852. /* The input or output configuration of each digital line is
  853. * configured by a special insn_config instruction. chanspec
  854. * contains the channel to be changed, and data[0] contains the
  855. * value COMEDI_INPUT or COMEDI_OUTPUT. */
  856. /* if output clear the bit, otherwise set it */
  857. if (data[0] == COMEDI_OUTPUT)
  858. devpriv->dio_config &= ~chanbit;
  859. else
  860. devpriv->dio_config |= chanbit;
  861. /* get access to the DIO regs */
  862. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
  863. /* set the DIO's to the new configuration setting */
  864. dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config);
  865. return 1;
  866. }
  867. void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
  868. {
  869. unsigned char lo1, lo2, hi2;
  870. unsigned short both2;
  871. /* based on 10mhz clock */
  872. lo1 = 200;
  873. both2 = nansec / 20000;
  874. hi2 = (both2 & 0xff00) >> 8;
  875. lo2 = both2 & 0x00ff;
  876. /* set the counter frequency to 10mhz */
  877. dmm_outb(dev, DMM32AT_CNTRDIO, 0);
  878. /* get access to the clock regs */
  879. dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_CLKACC);
  880. /* write the counter 1 control word and low byte to counter */
  881. dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT1);
  882. dmm_outb(dev, DMM32AT_CLK1, lo1);
  883. /* write the counter 2 control word and low byte then to counter */
  884. dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT2);
  885. dmm_outb(dev, DMM32AT_CLK2, lo2);
  886. dmm_outb(dev, DMM32AT_CLK2, hi2);
  887. /* enable the ai conversion interrupt and the clock to start scans */
  888. dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT | DMM32AT_CLKSEL);
  889. }
  890. /*
  891. * A convenient macro that defines init_module() and cleanup_module(),
  892. * as necessary.
  893. */
  894. static int __init driver_dmm32at_init_module(void)
  895. {
  896. return comedi_driver_register(&driver_dmm32at);
  897. }
  898. static void __exit driver_dmm32at_cleanup_module(void)
  899. {
  900. comedi_driver_unregister(&driver_dmm32at);
  901. }
  902. module_init(driver_dmm32at_init_module);
  903. module_exit(driver_dmm32at_cleanup_module);
  904. MODULE_AUTHOR("Comedi http://www.comedi.org");
  905. MODULE_DESCRIPTION("Comedi low-level driver");
  906. MODULE_LICENSE("GPL");