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