Got rid of unnecessary casts when initializing comedi_driver.board_name
[comedi.git] / comedi / drivers / ni_atmio16d.c
1 /*
2    module/ni_atmio16d
3    hardware driver for National Instruments AT-MIO16D board
4    Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
5
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
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20  */
21 /*
22 Driver: ni_atmio16d.o
23 Description: National Instruments AT-MIO-16D
24 Author: Chris R. Baugher <baugher@enteract.com>
25 Status: unknown
26 Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d)
27 */
28 /*
29  * I must give credit here to Michal Dobes <dobes@tesnet.cz> who
30  * wrote the driver for Advantec's pcl812 boards. I used the interrupt
31  * handling code from his driver as an example for this one.
32  *
33  * Chris Baugher
34  * 5/1/2000
35  *
36  */
37
38 #include <linux/comedidev.h>
39
40 #include <linux/ioport.h>
41
42 #include "8255.h"
43
44
45 /* Configuration and Status Registers */
46 #define COM_REG_1       0x00    /* wo 16 */
47 #define STAT_REG        0x00    /* ro 16 */
48 #define COM_REG_2       0x02    /* wo 16 */
49 /* Event Strobe Registers */
50 #define START_CONVERT_REG       0x08    /* wo 16 */
51 #define START_DAQ_REG           0x0A    /* wo 16 */
52 #define AD_CLEAR_REG            0x0C    /* wo 16 */
53 #define EXT_STROBE_REG          0x0E    /* wo 16 */
54 /* Analog Output Registers */
55 #define DAC0_REG                0x10    /* wo 16 */
56 #define DAC1_REG                0x12    /* wo 16 */
57 #define INT2CLR_REG             0x14    /* wo 16 */
58 /* Analog Input Registers */
59 #define MUX_CNTR_REG            0x04    /* wo 16 */
60 #define MUX_GAIN_REG            0x06    /* wo 16 */
61 #define AD_FIFO_REG             0x16    /* ro 16 */
62 #define DMA_TC_INT_CLR_REG      0x16    /* wo 16 */
63 /* AM9513A Counter/Timer Registers */
64 #define AM9513A_DATA_REG        0x18    /* rw 16 */
65 #define AM9513A_COM_REG         0x1A    /* wo 16 */
66 #define AM9513A_STAT_REG        0x1A    /* ro 16 */
67 /* MIO-16 Digital I/O Registers */
68 #define MIO_16_DIG_IN_REG       0x1C    /* ro 16 */
69 #define MIO_16_DIG_OUT_REG      0x1C    /* wo 16 */
70 /* RTSI Switch Registers */
71 #define RTSI_SW_SHIFT_REG       0x1E    /* wo 8 */
72 #define RTSI_SW_STROBE_REG      0x1F    /* wo 8 */
73 /* DIO-24 Registers */
74 #define DIO_24_PORTA_REG        0x00    /* rw 8 */
75 #define DIO_24_PORTB_REG        0x01    /* rw 8 */
76 #define DIO_24_PORTC_REG        0x02    /* rw 8 */
77 #define DIO_24_CNFG_REG         0x03    /* wo 8 */
78
79 /* Command Register bits */
80 #define COMREG1_2SCADC          0x0001
81 #define COMREG1_1632CNT         0x0002
82 #define COMREG1_SCANEN          0x0008
83 #define COMREG1_DAQEN           0x0010
84 #define COMREG1_DMAEN           0x0020
85 #define COMREG1_CONVINTEN       0x0080
86 #define COMREG2_SCN2            0x0010
87 #define COMREG2_INTEN           0x0080
88 #define COMREG2_DOUTEN0         0x0100
89 #define COMREG2_DOUTEN1         0x0200
90 /* Status Register bits */
91 #define STAT_AD_OVERRUN         0x0100
92 #define STAT_AD_OVERFLOW        0x0200
93 #define STAT_AD_DAQPROG         0x0800
94 #define STAT_AD_CONVAVAIL       0x2000
95 #define STAT_AD_DAQSTOPINT      0x4000
96 /* AM9513A Counter/Timer defines */
97 #define CLOCK_1_MHZ             0x8B25
98 #define CLOCK_100_KHZ   0x8C25
99 #define CLOCK_10_KHZ    0x8D25
100 #define CLOCK_1_KHZ             0x8E25
101 #define CLOCK_100_HZ    0x8F25
102 /* Other miscellaneous defines */
103 #define ATMIO16D_SIZE   32      /* bus address range */
104 #define devpriv ((atmio16d_private *)dev->private)
105 #define ATMIO16D_TIMEOUT 10
106
107
108 typedef struct{
109         const char *name;
110         int has_8255;
111 }atmio16_board_t;
112 static atmio16_board_t atmio16_boards[]={
113         {
114         name:           "atmio16",
115         has_8255:       0,
116         },
117         {
118         name:           "atmio16d",
119         has_8255:       1,
120         },
121 };
122 #define n_atmio16_boards sizeof(atmio16_boards)/sizeof(atmio16_boards[0])
123
124 #define boardtype ((atmio16_board_t *)dev->board_ptr)
125
126
127 /* function prototypes */
128 static int atmio16d_attach(comedi_device *dev,comedi_devconfig *it);
129 static int atmio16d_detach(comedi_device *dev);
130 static irqreturn_t atmio16d_interrupt(int irq, void *d PT_REGS_ARG);
131 static int atmio16d_ai_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd);
132 static int atmio16d_ai_cmd(comedi_device *dev, comedi_subdevice *s);
133 static int atmio16d_ai_cancel(comedi_device *dev, comedi_subdevice *s);
134 static void reset_counters(comedi_device *dev);
135 static void reset_atmio16d(comedi_device *dev);
136
137 /* main driver struct */
138 static comedi_driver driver_atmio16d={
139         driver_name:    "atmio16",
140         module:     THIS_MODULE,
141         attach:     atmio16d_attach,
142         detach:     atmio16d_detach,
143         board_name:     &atmio16_boards[0].name,
144         num_names:      n_atmio16_boards,
145         offset:         sizeof(atmio16_board_t),
146 };
147 COMEDI_INITCLEANUP(driver_atmio16d);
148
149 /* range structs */
150 static comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
151         BIP_RANGE( 10 ),
152         BIP_RANGE( 1 ),
153         BIP_RANGE( 0.1 ),
154         BIP_RANGE( 0.02 )
155 } };
156
157 static comedi_lrange range_atmio16d_ai_5_bipolar = { 4, {
158         BIP_RANGE( 5 ),
159         BIP_RANGE( 0.5 ),
160         BIP_RANGE( 0.05 ),
161         BIP_RANGE( 0.01 )
162 } };
163
164 static comedi_lrange range_atmio16d_ai_unipolar = { 4, {
165         UNI_RANGE( 10 ),
166         UNI_RANGE( 1 ),
167         UNI_RANGE( 0.1 ),
168         UNI_RANGE( 0.02 )
169 } };
170
171
172 /* private data struct */
173 typedef struct {
174         enum { adc_diff, adc_singleended } adc_mux;
175         enum { adc_bipolar10, adc_bipolar5, adc_unipolar10 } adc_range;
176         enum { adc_2comp, adc_straight } adc_coding;
177         enum { dac_bipolar, dac_unipolar } dac0_range, dac1_range;
178         enum { dac_internal, dac_external } dac0_reference, dac1_reference;
179         enum { dac_2comp, dac_straight } dac0_coding, dac1_coding;
180         comedi_lrange *ao_range_type_list[2];
181         lsampl_t ao_readback[2];
182         unsigned int com_reg_1_state;   /* current state of command register 1 */
183         unsigned int com_reg_2_state;   /* current state of command register 2 */
184 } atmio16d_private;
185
186
187 static void reset_counters(comedi_device *dev)
188 {
189         /* Counter 2 */
190         outw(0xFFC2, dev->iobase+AM9513A_COM_REG);
191         outw(0xFF02, dev->iobase+AM9513A_COM_REG);
192         outw(0x4, dev->iobase+AM9513A_DATA_REG);
193         outw(0xFF0A, dev->iobase+AM9513A_COM_REG);
194         outw(0x3, dev->iobase+AM9513A_DATA_REG);
195         outw(0xFF42, dev->iobase+AM9513A_COM_REG);
196         outw(0xFF42, dev->iobase+AM9513A_COM_REG);
197         /* Counter 3 */
198         outw(0xFFC4, dev->iobase+AM9513A_COM_REG);
199         outw(0xFF03, dev->iobase+AM9513A_COM_REG);
200         outw(0x4, dev->iobase+AM9513A_DATA_REG);
201         outw(0xFF0B, dev->iobase+AM9513A_COM_REG);
202         outw(0x3, dev->iobase+AM9513A_DATA_REG);
203         outw(0xFF44, dev->iobase+AM9513A_COM_REG);
204         outw(0xFF44, dev->iobase+AM9513A_COM_REG);
205         /* Counter 4 */
206         outw(0xFFC8, dev->iobase+AM9513A_COM_REG);
207         outw(0xFF04, dev->iobase+AM9513A_COM_REG);
208         outw(0x4, dev->iobase+AM9513A_DATA_REG);
209         outw(0xFF0C, dev->iobase+AM9513A_COM_REG);
210         outw(0x3, dev->iobase+AM9513A_DATA_REG);
211         outw(0xFF48, dev->iobase+AM9513A_COM_REG);
212         outw(0xFF48, dev->iobase+AM9513A_COM_REG);
213         /* Counter 5 */
214         outw(0xFFD0, dev->iobase+AM9513A_COM_REG);
215         outw(0xFF05, dev->iobase+AM9513A_COM_REG);
216         outw(0x4, dev->iobase+AM9513A_DATA_REG);
217         outw(0xFF0D, dev->iobase+AM9513A_COM_REG);
218         outw(0x3, dev->iobase+AM9513A_DATA_REG);
219         outw(0xFF50, dev->iobase+AM9513A_COM_REG);
220         outw(0xFF50, dev->iobase+AM9513A_COM_REG);
221
222         outw(0, dev->iobase+AD_CLEAR_REG);
223 }
224
225 static void reset_atmio16d(comedi_device *dev)
226 {
227         int i;
228
229         /* now we need to initialize the board */
230         outw(0, dev->iobase+COM_REG_1);
231         outw(0, dev->iobase+COM_REG_2);
232         outw(0, dev->iobase+MUX_GAIN_REG);
233         /* init AM9513A timer */
234         outw(0xFFFF, dev->iobase+AM9513A_COM_REG);
235         outw(0xFFEF, dev->iobase+AM9513A_COM_REG);
236         outw(0xFF17, dev->iobase+AM9513A_COM_REG);
237         outw(0xF000, dev->iobase+AM9513A_DATA_REG);
238         for(i=1; i<=5; ++i) {
239                 outw(0xFF00+i, dev->iobase+AM9513A_COM_REG);
240                 outw(0x0004, dev->iobase+AM9513A_DATA_REG);
241                 outw(0xFF08+i, dev->iobase+AM9513A_COM_REG);
242                 outw(0x3, dev->iobase+AM9513A_DATA_REG);
243         }
244         outw(0xFF5F, dev->iobase+AM9513A_COM_REG);
245         /* timer init done */
246         outw(0, dev->iobase+AD_CLEAR_REG);
247         outw(0, dev->iobase+INT2CLR_REG);
248         /* select straight binary mode for Analog Input */
249         devpriv->com_reg_1_state |= 1;
250         outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
251         devpriv->adc_coding = adc_straight;
252         /* zero the analog outputs */
253         outw(2048, dev->iobase+DAC0_REG);
254         outw(2048, dev->iobase+DAC1_REG);
255 }
256
257 static irqreturn_t atmio16d_interrupt(int irq, void *d PT_REGS_ARG)
258 {
259         comedi_device *dev = d;
260         comedi_subdevice *s = dev->subdevices + 0;
261
262 //      printk("atmio16d_interrupt!\n");
263
264         comedi_buf_put( s->async, inw(dev->iobase+AD_FIFO_REG) );
265
266         comedi_event(dev, s, s->async->events);
267         return IRQ_HANDLED;
268 }
269
270 static int atmio16d_ai_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd)
271 {
272         int err=0, tmp;
273 #ifdef DEBUG1
274         printk("atmio16d_ai_cmdtest\n");
275 #endif
276         /* make sure triggers are valid */
277         tmp=cmd->start_src;
278         cmd->start_src &= TRIG_NOW;
279         if(!cmd->start_src || tmp!=cmd->start_src)err++;
280
281         tmp=cmd->scan_begin_src;
282         cmd->scan_begin_src &= TRIG_FOLLOW|TRIG_TIMER;
283         if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
284
285         tmp=cmd->convert_src;
286         cmd->convert_src &= TRIG_TIMER;
287         if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
288
289         tmp=cmd->scan_end_src;
290         cmd->scan_end_src &= TRIG_COUNT;
291         if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
292
293         tmp=cmd->stop_src;
294         cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
295         if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
296
297         if(err)return 1;
298
299         /* step 2: make sure trigger sources are unique and mutually compatible */
300         /* note that mutual compatiblity is not an issue here */
301         if(cmd->scan_begin_src!=TRIG_FOLLOW &&
302            cmd->scan_begin_src!=TRIG_EXT &&
303            cmd->scan_begin_src!=TRIG_TIMER)err++;
304         if(cmd->stop_src!=TRIG_COUNT &&
305            cmd->stop_src!=TRIG_NONE)err++;
306
307         if(err)return 2;
308
309
310         /* step 3: make sure arguments are trivially compatible */
311
312         if(cmd->start_arg!=0){
313                 cmd->start_arg=0;
314                 err++;
315         }
316         if(cmd->scan_begin_src==TRIG_FOLLOW){
317                 /* internal trigger */
318                 if(cmd->scan_begin_arg!=0){
319                         cmd->scan_begin_arg=0;
320                         err++;
321                 }
322         }else{
323 #if 0
324                 /* external trigger */
325                 /* should be level/edge, hi/lo specification here */
326                 if(cmd->scan_begin_arg!=0){
327                         cmd->scan_begin_arg=0;
328                         err++;
329                 }
330 #endif
331         }
332
333         if(cmd->convert_arg<10000){
334                 cmd->convert_arg=10000;
335                 err++;
336         }
337
338
339 #if 0
340         if(cmd->convert_arg>SLOWEST_TIMER){
341                 cmd->convert_arg=SLOWEST_TIMER;
342                 err++;
343         }
344 #endif
345         if(cmd->scan_end_arg!=cmd->chanlist_len){
346                 cmd->scan_end_arg=cmd->chanlist_len;
347                 err++;
348         }
349         if(cmd->stop_src==TRIG_COUNT){
350                 /* any count is allowed */
351         }else{
352                 /* TRIG_NONE */
353                 if(cmd->stop_arg!=0){
354                         cmd->stop_arg=0;
355                         err++;
356                 }
357         }
358
359         if(err)return 3;
360
361         return 0;
362 }
363
364 static int atmio16d_ai_cmd(comedi_device *dev, comedi_subdevice *s)
365 {
366         comedi_cmd *cmd = &s->async->cmd;
367         unsigned int timer, base_clock;
368         unsigned int sample_count, tmp, chan, gain;
369         int i;
370 #ifdef DEBUG1
371         printk("atmio16d_ai_cmd\n");
372 #endif
373         /* This is slowly becoming a working command interface. *
374          * It is still uber-experimental */
375
376         reset_counters(dev);
377         s->async->cur_chan      = 0;
378
379         /* check if scanning multiple channels */
380         if(cmd->chanlist_len < 2) {
381                 devpriv->com_reg_1_state &= ~COMREG1_SCANEN;
382                 outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
383         } else {
384                 devpriv->com_reg_1_state |= COMREG1_SCANEN;
385                 devpriv->com_reg_2_state |= COMREG2_SCN2;
386                 outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
387                 outw(devpriv->com_reg_2_state, dev->iobase+COM_REG_2);
388         }
389
390         /* Setup the Mux-Gain Counter */
391         for(i=0; i < cmd->chanlist_len; ++i ) {
392                 chan = CR_CHAN(cmd->chanlist[i]);
393                 gain = CR_RANGE(cmd->chanlist[i]);
394                 outw(i, dev->iobase+MUX_CNTR_REG);
395                 tmp = chan|(gain<<6);
396                 if( i == cmd->scan_end_arg-1 ) tmp |= 0x0010;   /* set LASTONE bit */
397                 outw(tmp, dev->iobase+MUX_GAIN_REG);
398         }
399
400         /* Now program the sample interval timer */
401         /* Figure out which clock to use then get an
402          * appropriate timer value */
403         if(cmd->convert_arg<65536000) {
404                 base_clock = CLOCK_1_MHZ;
405                 timer = cmd->convert_arg/1000;
406         } else if(cmd->convert_arg<655360000) {
407                 base_clock = CLOCK_100_KHZ;
408                 timer = cmd->convert_arg/10000;
409         } else if(cmd->convert_arg<=0xffffffff /* 6553600000 */ ) {
410                 base_clock = CLOCK_10_KHZ;
411                 timer = cmd->convert_arg/100000;
412         } else if(cmd->convert_arg<=0xffffffff /* 65536000000 */ ) {
413                 base_clock = CLOCK_1_KHZ;
414                 timer = cmd->convert_arg/1000000;
415         }
416         outw(0xFF03, dev->iobase+AM9513A_COM_REG);
417         outw(base_clock, dev->iobase+AM9513A_DATA_REG);
418         outw(0xFF0B, dev->iobase+AM9513A_COM_REG);
419         outw(0x2, dev->iobase+AM9513A_DATA_REG);
420         outw(0xFF44, dev->iobase+AM9513A_COM_REG);
421         outw(0xFFF3, dev->iobase+AM9513A_COM_REG);
422         outw(timer, dev->iobase+AM9513A_DATA_REG);
423         outw(0xFF24, dev->iobase+AM9513A_COM_REG);
424
425
426
427         /* Now figure out how many samples to get */
428         /* and program the sample counter */
429         sample_count = cmd->stop_arg*cmd->scan_end_arg;
430         outw(0xFF04, dev->iobase+AM9513A_COM_REG);
431         outw(0x1025, dev->iobase+AM9513A_DATA_REG);
432         outw(0xFF0C, dev->iobase+AM9513A_COM_REG);
433         if(sample_count < 65536) {
434                 /* use only Counter 4 */
435                 outw(sample_count, dev->iobase+AM9513A_DATA_REG);
436                 outw(0xFF48, dev->iobase+AM9513A_COM_REG);
437                 outw(0xFFF4, dev->iobase+AM9513A_COM_REG);
438                 outw(0xFF28, dev->iobase+AM9513A_COM_REG);
439                 devpriv->com_reg_1_state &= ~COMREG1_1632CNT;
440                 outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
441         } else {
442                 /* Counter 4 and 5 are needed */
443                 if( (tmp=sample_count&0xFFFF) ) {
444                         outw(tmp-1, dev->iobase+AM9513A_DATA_REG);
445                 } else {
446                         outw(0xFFFF, dev->iobase+AM9513A_DATA_REG);
447                 }
448                 outw(0xFF48, dev->iobase+AM9513A_COM_REG);
449                 outw(0, dev->iobase+AM9513A_DATA_REG);
450                 outw(0xFF28, dev->iobase+AM9513A_COM_REG);
451                 outw(0xFF05, dev->iobase+AM9513A_COM_REG);
452                 outw(0x25, dev->iobase+AM9513A_DATA_REG);
453                 outw(0xFF0D, dev->iobase+AM9513A_COM_REG);
454                 tmp=sample_count&0xFFFF;
455                 if( (tmp == 0) || (tmp == 1) ) {
456                         outw( (sample_count>>16)&0xFFFF, dev->iobase+AM9513A_DATA_REG);
457                 } else {
458                         outw( ((sample_count>>16)&0xFFFF)+1, dev->iobase+AM9513A_DATA_REG);
459                 }
460                 outw(0xFF70, dev->iobase+AM9513A_COM_REG);
461                 devpriv->com_reg_1_state |= COMREG1_1632CNT;
462                 outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
463         }
464
465         /* Program the scan interval timer ONLY IF SCANNING IS ENABLED */
466         /* Figure out which clock to use then get an
467          * appropriate timer value */
468         if(cmd->chanlist_len > 1) {
469                 if(cmd->scan_begin_arg<65536000) {
470                         base_clock = CLOCK_1_MHZ;
471                         timer = cmd->scan_begin_arg/1000;
472                 } else if(cmd->scan_begin_arg<655360000) {
473                         base_clock = CLOCK_100_KHZ;
474                         timer = cmd->scan_begin_arg/10000;
475                 } else if(cmd->scan_begin_arg<0xffffffff /* 6553600000 */ ) {
476                         base_clock = CLOCK_10_KHZ;
477                         timer = cmd->scan_begin_arg/100000;
478                 } else if(cmd->scan_begin_arg<0xffffffff /* 65536000000 */ ) {
479                         base_clock = CLOCK_1_KHZ;
480                         timer = cmd->scan_begin_arg/1000000;
481                 }
482                 outw(0xFF02, dev->iobase+AM9513A_COM_REG);
483                 outw(base_clock, dev->iobase+AM9513A_DATA_REG);
484                 outw(0xFF0A, dev->iobase+AM9513A_COM_REG);
485                 outw(0x2, dev->iobase+AM9513A_DATA_REG);
486                 outw(0xFF42, dev->iobase+AM9513A_COM_REG);
487                 outw(0xFFF2, dev->iobase+AM9513A_COM_REG);
488                 outw(timer, dev->iobase+AM9513A_DATA_REG);
489                 outw(0xFF22, dev->iobase+AM9513A_COM_REG);
490         }
491
492         /* Clear the A/D FIFO and reset the MUX counter */
493         outw(0, dev->iobase+AD_CLEAR_REG);
494         outw(0, dev->iobase+MUX_CNTR_REG);
495         outw(0, dev->iobase+INT2CLR_REG);
496         /* enable this acquisition operation */
497         devpriv->com_reg_1_state |= COMREG1_DAQEN;
498         outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
499         /* enable interrupts for conversion completion */
500         devpriv->com_reg_1_state |= COMREG1_CONVINTEN;
501         devpriv->com_reg_2_state |= COMREG2_INTEN;
502         outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1);
503         outw(devpriv->com_reg_2_state, dev->iobase+COM_REG_2);
504         /* apply a trigger. this starts the counters! */
505         outw(0, dev->iobase+START_DAQ_REG);
506
507         return 0;
508 }
509
510 /* This will cancel a running acquisition operation */
511 static int atmio16d_ai_cancel(comedi_device *dev, comedi_subdevice *s)
512 {
513         reset_atmio16d(dev);
514
515         return 0;
516 }
517
518 /* Mode 0 is used to get a single conversion on demand */
519 static int atmio16d_ai_insn_read(comedi_device * dev, comedi_subdevice *s,
520         comedi_insn *insn, lsampl_t *data)
521 {
522         int i, t;
523         int chan;
524         int gain;
525         int status;
526
527 #ifdef DEBUG1
528         printk("atmio16d_ai_insn_read\n");
529 #endif
530         chan = CR_CHAN(insn->chanspec);
531         gain = CR_RANGE(insn->chanspec);
532
533         /* reset the Analog input circuitry */
534         //outw( 0, dev->iobase+AD_CLEAR_REG );
535         /* reset the Analog Input MUX Counter to 0 */
536         //outw( 0, dev->iobase+MUX_CNTR_REG );
537
538         /* set the Input MUX gain */
539         outw( chan|(gain<<6), dev->iobase+MUX_GAIN_REG);
540
541         for(i=0 ; i < insn->n ; i++) {
542                 /* start the conversion */
543                 outw(0, dev->iobase+START_CONVERT_REG);
544                 /* wait for it to finish */
545                 for(t = 0; t < ATMIO16D_TIMEOUT; t++) {
546                         /* check conversion status */
547                         status=inw(dev->iobase+STAT_REG);
548 #ifdef DEBUG1
549                         printk("status=%x\n",status);
550 #endif
551                         if( status&STAT_AD_CONVAVAIL ) {
552                                 /* read the data now */
553                                 data[i] = inw( dev->iobase+AD_FIFO_REG );
554                                 /* change to two's complement if need be */
555                                 if( devpriv->adc_coding == adc_2comp ) {
556                                         data[i] ^= 0x800;
557                                 }
558                                 break;
559                         }
560                         if( status&STAT_AD_OVERFLOW ){
561                                 printk("atmio16d: a/d FIFO overflow\n");
562                                 outw(0,dev->iobase+AD_CLEAR_REG);
563
564                                 return -ETIME;
565                         }
566                 }
567                 /* end waiting, now check if it timed out */
568                 if( t == ATMIO16D_TIMEOUT ){
569                         rt_printk("atmio16d: timeout\n");
570
571                         return -ETIME;
572                 }
573         }
574
575         return i;
576 }
577
578 static int atmio16d_ao_insn_read(comedi_device *dev, comedi_subdevice *s,
579         comedi_insn *insn, lsampl_t *data)
580 {
581         int i;
582 #ifdef DEBUG1
583         printk("atmio16d_ao_insn_read\n");
584 #endif
585
586         for(i=0;i<insn->n;i++){
587                 data[i]=devpriv->ao_readback[CR_CHAN(insn->chanspec)];
588         }
589
590         return i;
591 }
592
593 static int atmio16d_ao_insn_write(comedi_device * dev, comedi_subdevice *s,
594         comedi_insn *insn, lsampl_t *data)
595 {
596         int i;
597         int chan;
598         int d;
599 #ifdef DEBUG1
600         printk("atmio16d_ao_insn_write\n");
601 #endif
602
603         chan=CR_CHAN(insn->chanspec);
604
605         for(i=0; i < insn->n; i++) {
606                 d = data[i];
607                 switch(chan){
608                 case 0:
609                         if (devpriv->dac0_coding == dac_2comp) {
610                                 d ^= 0x800;
611                         }
612                         outw(d, dev->iobase + DAC0_REG);
613                         break;
614                 case 1:
615                         if (devpriv->dac1_coding == dac_2comp) {
616                                 d ^= 0x800;
617                         }
618                         outw(d, dev->iobase + DAC1_REG);
619                         break;
620                 default:
621                         return -EINVAL;
622                 }
623                 devpriv->ao_readback[chan] = data[i];
624         }
625         return i;
626 }
627
628
629 static int atmio16d_dio_insn_bits(comedi_device *dev, comedi_subdevice *s,
630         comedi_insn *insn, lsampl_t *data)
631 {
632         if(insn->n!=2)return -EINVAL;
633
634         if(data[0]){
635                 s->state &= ~data[0];
636                 s->state |= (data[0]|data[1]);
637                 outw(s->state, dev->iobase+MIO_16_DIG_OUT_REG );
638         }
639         data[1] = inw(dev->iobase+MIO_16_DIG_IN_REG);
640
641         return 2;
642 }
643
644 static int atmio16d_dio_insn_config(comedi_device *dev, comedi_subdevice *s,
645         comedi_insn *insn, lsampl_t *data)
646 {
647         int i;
648         int mask;
649
650         for(i=0;i<insn->n;i++){
651                 mask=(CR_CHAN(insn->chanspec)<4)?0x0f:0xf0;
652                 s->io_bits &= ~mask;
653                 if(data[i])s->io_bits |= mask;
654         }
655         devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0|COMREG2_DOUTEN1);
656         if(s->io_bits&0x0f)
657                 devpriv->com_reg_2_state |= COMREG2_DOUTEN0;
658         if(s->io_bits&0xf0)
659                 devpriv->com_reg_2_state |= COMREG2_DOUTEN1;
660         outw(devpriv->com_reg_2_state, dev->iobase+COM_REG_2);
661
662         return i;
663 }
664
665
666 /*
667    options[0] - I/O port
668    options[1] - MIO irq
669                 0 == no irq
670                 N == irq N {3,4,5,6,7,9,10,11,12,14,15}
671    options[2] - DIO irq
672                 0 == no irq
673                 N == irq N {3,4,5,6,7,9}
674    options[3] - DMA1 channel
675                 0 == no DMA
676                 N == DMA N {5,6,7}
677    options[4] - DMA2 channel
678                 0 == no DMA
679                 N == DMA N {5,6,7}
680
681    options[5] - a/d mux
682         0=differential, 1=single
683    options[6] - a/d range
684         0=bipolar10, 1=bipolar5, 2=unipolar10
685
686    options[7] - dac0 range
687         0=bipolar, 1=unipolar
688    options[8] - dac0 reference
689     0=internal, 1=external
690    options[9] - dac0 coding
691         0=2's comp, 1=straight binary
692
693    options[10] - dac1 range
694    options[11] - dac1 reference
695    options[12] - dac1 coding
696  */
697
698 static int atmio16d_attach(comedi_device * dev, comedi_devconfig * it)
699 {
700         unsigned int irq;
701         unsigned long iobase;
702         int ret;
703
704         comedi_subdevice *s;
705
706         /* make sure the address range is free and allocate it */
707         iobase = it->options[0];
708         printk("comedi%d: atmio16d: 0x%04lx ", dev->minor, iobase);
709         if (!request_region(iobase, ATMIO16D_SIZE, "ni_atmio16d")) {
710                 printk("I/O port conflict\n");
711                 return -EIO;
712         }
713         dev->iobase = iobase;
714
715
716         /* board name */
717         dev->board_name = boardtype->name;
718
719         if((ret=alloc_subdevices(dev, 4))<0)
720                 return ret;
721         if((ret=alloc_private(dev,sizeof(atmio16d_private)))<0)
722                 return ret;
723
724
725         /* reset the atmio16d hardware */
726         reset_atmio16d(dev);
727
728         /* check if our interrupt is available and get it */
729         irq=it->options[1];
730         if(irq){
731                 if((ret=comedi_request_irq(irq,atmio16d_interrupt,
732                         0, "atmio16d", dev))<0)
733                 {
734                         printk("failed to allocate irq %u\n", irq);
735                         return ret;
736                 }
737                 dev->irq=irq;
738                 printk("( irq = %u )\n",irq);
739         } else {
740                 printk("( no irq )");
741         }
742
743
744         /* set device options */
745         devpriv->adc_mux = it->options[5];
746         devpriv->adc_range = it->options[6];
747
748         devpriv->dac0_range = it->options[7];
749         devpriv->dac0_reference = it->options[8];
750         devpriv->dac0_coding = it->options[9];
751         devpriv->dac1_range = it->options[10];
752         devpriv->dac1_reference = it->options[11];
753         devpriv->dac1_coding = it->options[12];
754
755
756         /* setup sub-devices */
757         s=dev->subdevices+0;
758         dev->read_subdev = s;
759         /* ai subdevice */
760         s->type=COMEDI_SUBD_AI;
761         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
762         s->n_chan=(devpriv->adc_mux? 16 : 8);
763         s->len_chanlist=16;
764         s->insn_read = atmio16d_ai_insn_read;
765         s->do_cmdtest=atmio16d_ai_cmdtest;
766         s->do_cmd=atmio16d_ai_cmd;
767         s->cancel=atmio16d_ai_cancel;
768         s->maxdata=0xfff;       /* 4095 decimal */
769         switch (devpriv->adc_range) {
770         case adc_bipolar10:
771                 s->range_table = &range_atmio16d_ai_10_bipolar;
772                 break;
773         case adc_bipolar5:
774                 s->range_table = &range_atmio16d_ai_5_bipolar;
775                 break;
776         case adc_unipolar10:
777                 s->range_table = &range_atmio16d_ai_unipolar;
778                 break;
779         }
780
781         /* ao subdevice */
782         s++;
783         s->type=COMEDI_SUBD_AO;
784         s->subdev_flags=SDF_WRITABLE;
785         s->n_chan=2;
786         s->insn_read=atmio16d_ao_insn_read;
787         s->insn_write=atmio16d_ao_insn_write;
788         s->maxdata=0xfff;       /* 4095 decimal */
789         s->range_table_list=devpriv->ao_range_type_list;
790         switch (devpriv->dac0_range) {
791         case dac_bipolar:
792                 devpriv->ao_range_type_list[0] = &range_bipolar10;
793                 break;
794         case dac_unipolar:
795                 devpriv->ao_range_type_list[0] = &range_unipolar10;
796                 break;
797         }
798         switch (devpriv->dac1_range) {
799         case dac_bipolar:
800                 devpriv->ao_range_type_list[1] = &range_bipolar10;
801                 break;
802         case dac_unipolar:
803                 devpriv->ao_range_type_list[1] = &range_unipolar10;
804                 break;
805         }
806
807
808         /* Digital I/O */
809         s++;
810         s->type=COMEDI_SUBD_DIO;
811         s->subdev_flags=SDF_WRITABLE|SDF_READABLE;
812         s->n_chan=8;
813         s->insn_bits = atmio16d_dio_insn_bits;
814         s->insn_config = atmio16d_dio_insn_config;
815         s->maxdata=1;
816         s->range_table=&range_digital;
817
818
819         /* 8255 subdevice */
820         s++;
821         if(boardtype->has_8255){
822                 subdev_8255_init(dev,s,NULL,dev->iobase);
823         }else{
824                 s->type=COMEDI_SUBD_UNUSED;
825         }
826
827 /* don't yet know how to deal with counter/timers */
828 #if 0
829         s++;
830         /* do */
831         s->type=COMEDI_SUBD_TIMER;
832         s->n_chan=0;
833         s->maxdata=0
834 #endif
835
836         printk("\n");
837
838         return 0;
839 }
840
841
842 static int atmio16d_detach(comedi_device * dev)
843 {
844         printk("comedi%d: atmio16d: remove\n", dev->minor);
845
846         if(dev->subdevices && boardtype->has_8255)
847                 subdev_8255_cleanup(dev,dev->subdevices + 3);
848
849         if(dev->irq)
850                 comedi_free_irq(dev->irq,dev);
851
852         reset_atmio16d(dev);
853
854         if(dev->iobase)
855                 release_region(dev->iobase, ATMIO16D_SIZE);
856
857         return 0;
858 }
859