fixing end of scan events in some drivers
[comedi.git] / comedi / drivers / ni_pcidio.c
1 /*
2     comedi/drivers/ni_pcidio.c
3     driver for National Instruments PCI-DIO-96/PCI-6508
4                National Instruments PCI-DIO-32HS
5                National Instruments PCI-6503
6
7     COMEDI - Linux Control and Measurement Device Interface
8     Copyright (C) 1999,2002 David A. Schleef <ds@schleef.org>
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25 /*
26 Driver: ni_pcidio.o
27 Description: National Instruments PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503
28 Author: ds
29 Status: works
30 Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533,
31   PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
32   PXI-6503, PCI-6534, PCI-6533
33 Updated: Sun, 21 Apr 2002 21:03:38 -0700
34
35 The DIO-96 appears as four 8255 subdevices.  See the 8255
36 driver notes for details.
37
38 The DIO32HS board appears as one subdevice, with 32 channels.
39 Each channel is individually I/O configurable.  The channel order
40 is 0=A0, 1=A1, 2=A2, ... 8=B0, 16=C0, 24=D0.  The driver only
41 supports simple digital I/O; no handshaking is supported.
42
43 DMA mostly works for the PCI-DIO32HS, but only in timed input mode.
44
45 This driver could be easily modified to support AT-MIO32HS and
46 AT-MIO96.
47 */
48
49 /*
50    This driver is for both the NI PCI-DIO-32HS and the PCI-DIO-96,
51    which have very different architectures.  But, since the '96 is
52    so simple, it is included here.
53
54    Manuals (available from ftp://ftp.natinst.com/support/manuals)
55
56         320938c.pdf     PCI-DIO-96/PXI-6508/PCI-6503 User Manual
57         321464b.pdf     AT/PCI-DIO-32HS User Manual
58         341329A.pdf     PCI-6533 Register-Level Programmer Manual
59         341330A.pdf     DAQ-DIO Technical Reference Manual
60
61  */
62
63 #define USE_DMA
64 #define DEBUG 1
65 #define DEBUG_FLAGS
66
67 #include <linux/kernel.h>
68 #include <linux/module.h>
69 #include <linux/comedidev.h>
70 #include <linux/errno.h>
71 #include <linux/ioport.h>
72 #include <linux/slab.h>
73 #include <linux/delay.h>
74 #include <linux/irq.h>
75 #include <linux/init.h>
76
77 #include <asm/io.h>
78 #include "mite.h"
79 #include "8255.h"
80
81
82 #undef DPRINTK
83 #ifdef DEBUG
84 #define DPRINTK(format, args...)        printk(format, ## args)
85 #else
86 #define DPRINTK(format, args...)
87 #endif
88
89 #define PCI_VENDOR_ID_NATINST   0x1093
90
91 #define PCI_DIO_SIZE 4096
92 #define PCI_MITE_SIZE 4096
93
94 /* defines for the PCI-DIO-96 */
95
96 #define NIDIO_8255_BASE(x)      ((x)*4)
97 #define NIDIO_A 0
98 #define NIDIO_B 4
99 #define NIDIO_C 8
100 #define NIDIO_D 12
101
102 /* defines for the PCI-DIO-32HS */
103
104 #define Window_Address                  4       /* W */
105 #define Interrupt_And_Window_Status     4       /* R */
106   #define IntStatus1                            (1<<0)
107   #define IntStatus2                            (1<<1)
108   #define WindowAddressStatus_mask              0x7c
109
110 #define Master_DMA_And_Interrupt_Control 5      /* W */
111   #define InterruptLine(x)                      ((x)&3)
112   #define OpenInt                               (1<<2)
113 #define Group_Status                    5       /* R */
114   #define DataLeft                              (1<<0)
115   #define Req                                   (1<<2)
116   #define StopTrig                              (1<<3)
117
118 #define Group_1_Flags                   6       /* R */
119 #define Group_2_Flags                   7       /* R */
120   #define TransferReady                         (1<<0)
121   #define CountExpired                          (1<<1)
122   #define Waited                                (1<<5)
123   #define PrimaryTC                             (1<<6)
124   #define SecondaryTC                           (1<<7)
125   //#define SerialRose
126   //#define ReqRose
127   //#define Paused
128
129 #define Group_1_First_Clear             6       /* W */
130 #define Group_2_First_Clear             7       /* W */
131   #define ClearWaited                           (1<<3)
132   #define ClearPrimaryTC                        (1<<4)
133   #define ClearSecondaryTC                      (1<<5)
134   #define DMAReset                              (1<<6)
135   #define FIFOReset                             (1<<7)
136   #define ClearAll                              0xf8
137
138 #define Group_1_FIFO                    8       /* W */
139 #define Group_2_FIFO                    12      /* W */
140
141 #define Transfer_Count                  20
142 #define Chip_ID_D                       24
143 #define Chip_ID_I                       25
144 #define Chip_ID_O                       26
145 #define Chip_Version                    27
146 #define Port_IO(x)                      (28+(x))
147 #define Port_Pin_Directions(x)          (32+(x))
148 #define Port_Pin_Mask(x)                (36+(x))
149 #define Port_Pin_Polarities(x)          (40+(x))
150
151 #define Master_Clock_Routing            45
152   #define RTSIClocking(x)                       (((x)&3)<<4)
153
154 #define Group_1_Second_Clear            46      /* W */
155 #define Group_2_Second_Clear            47      /* W */
156   #define ClearExpired                          (1<<0)
157
158 #define Port_Pattern(x)                 (48+(x))
159
160 #define Data_Path                       64
161   #define FIFOEnableA           (1<<0)
162   #define FIFOEnableB           (1<<1)
163   #define FIFOEnableC           (1<<2)
164   #define FIFOEnableD           (1<<3)
165   #define Funneling(x)          (((x)&3)<<4)
166   #define GroupDirection        (1<<7)
167
168 #define Protocol_Register_1             65
169 #define OpMode                          Protocol_Register_1
170   #define RunMode(x)            ((x)&7)
171   #define Numbered              (1<<3)
172
173 #define Protocol_Register_2             66
174 #define ClockReg                        Protocol_Register_2
175   #define ClockLine(x)          (((x)&3)<<5)
176   #define InvertStopTrig        (1<<7)
177
178 #define Protocol_Register_3             67
179 #define Sequence                        Protocol_Register_3
180
181 #define Protocol_Register_14            68 /* 16 bit */
182 #define ClockSpeed                      Protocol_Register_14
183
184 #define Protocol_Register_4             70
185 #define ReqReg                          Protocol_Register_4
186   #define ReqConditioning(x)    (((x)&7)<<3)
187
188 #define Protocol_Register_5             71
189 #define BlockMode                       Protocol_Register_5
190
191 #define FIFO_Control                    72
192   #define ReadyLevel(x)         ((x)&7)
193
194 #define Protocol_Register_6             73
195 #define LinePolarities                  Protocol_Register_6
196   #define InvertAck             (1<<0)
197   #define InvertReq             (1<<1)
198   #define InvertClock           (1<<2)
199   #define InvertSerial          (1<<3)
200   #define OpenAck               (1<<4)
201   #define OpenClock             (1<<5)
202
203 #define Protocol_Register_7             74
204 #define AckSer                          Protocol_Register_7
205   #define AckLine(x)            (((x)&3)<<2)
206   #define ExchangePins          (1<<7)
207
208 #define Interrupt_Control               75
209   /* bits same as flags */
210
211 #define DMA_Line_Control                76
212   #define DMAChannel(x)         ((x)&0xf)
213
214 #define Transfer_Size_Control           77
215   #define TransferWidth(x)      ((x)&3)
216   #define TransferLength(x)     (((x)&3)<<3)
217   #define RequireRLevel         (1<<5)
218
219 #define Protocol_Register_15            79
220 #define DAQOptions                      Protocol_Register_15
221   #define StartSource(x)                        ((x)&0x3)
222   #define InvertStart                           (1<<2)
223   #define StopSource(x)                         (((x)&0x3)<<3)
224   #define ReqStart                              (1<<6)
225   #define PreStart                              (1<<7)
226
227 #define Pattern_Detection               81
228   #define DetectionMethod                       (1<<0)
229   #define InvertMatch                           (1<<1)
230   #define IE_Pattern_Detection                  (1<<2)
231
232 #define Protocol_Register_9             82
233 #define ReqDelay                        Protocol_Register_9
234
235 #define Protocol_Register_10            83
236 #define ReqNotDelay                     Protocol_Register_10
237
238 #define Protocol_Register_11            84
239 #define AckDelay                        Protocol_Register_11
240
241 #define Protocol_Register_12            85
242 #define AckNotDelay                     Protocol_Register_12
243
244 #define Protocol_Register_13            86
245 #define Data1Delay                      Protocol_Register_13
246
247 #define Protocol_Register_8             88 /* 32 bit */
248 #define StartDelay                      Protocol_Register_8
249
250
251 #define TIMER_BASE 50           /* nanoseconds */
252
253 #ifdef USE_DMA
254 #define IntEn (CountExpired|Waited|PrimaryTC|SecondaryTC)
255 #else
256 #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
257 #endif
258
259 static int nidio_attach(comedi_device *dev,comedi_devconfig *it);
260 static int nidio_detach(comedi_device *dev);
261 static comedi_driver driver_pcidio={
262         driver_name:    "ni_pcidio",
263         module:         THIS_MODULE,
264         attach:         nidio_attach,
265         detach:         nidio_detach,
266 };
267 COMEDI_INITCLEANUP(driver_pcidio);
268
269 typedef struct{
270         int dev_id;
271         char *name;
272         int n_8255;
273         int is_diodaq;
274 }nidio_board;
275 static nidio_board nidio_boards[]={
276         {
277         dev_id:         0x1150,
278         name:           "pci-dio-32hs",
279         n_8255:         0,
280         is_diodaq:      1,
281         },
282         {
283         dev_id:         0x1320,
284         name:           "pxi-6533",
285         n_8255:         0,
286         is_diodaq:      1,
287         },
288         {
289         dev_id:         0x12b0,
290         name:           "pci-6534",
291         n_8255:         0,
292         is_diodaq:      1,
293         },
294         {
295         dev_id:         0x0160,
296         name:           "pci-dio-96",
297         n_8255:         4,
298         is_diodaq:      0,
299         },
300         {
301         dev_id:         0x1630,
302         name:           "pci-dio-96b",
303         n_8255:         4,
304         is_diodaq:      0,
305         },
306         {
307         dev_id:         0x13c0,
308         name:           "pxi-6508",
309         n_8255:         4,
310         is_diodaq:      0,
311         },
312         {
313         dev_id:         0x0400,
314         name:           "pci-6503",
315         n_8255:         1,
316         is_diodaq:      0,
317         },
318         {
319         dev_id:         0x1250,
320         name:           "pci-6503b",
321         n_8255:         1,
322         is_diodaq:      0,
323         },
324         {
325         dev_id:         0x17d0,
326         name:           "pci-6503x",
327         n_8255:         1,
328         is_diodaq:      0,
329         },
330         {
331         dev_id:         0x1800,
332         name:           "pxi-6503",
333         n_8255:         1,
334         is_diodaq:      0,
335         },
336 };
337 #define n_nidio_boards (sizeof(nidio_boards)/sizeof(nidio_boards[0]))
338 #define this_board ((nidio_board *)dev->board_ptr)
339
340 static struct pci_device_id ni_pcidio_pci_table[] __devinitdata = {
341         { PCI_VENDOR_ID_NATINST, 0x1150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
342         { PCI_VENDOR_ID_NATINST, 0x1320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
343         { PCI_VENDOR_ID_NATINST, 0x0160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
344         { PCI_VENDOR_ID_NATINST, 0x1630, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
345         { PCI_VENDOR_ID_NATINST, 0x13c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
346         { PCI_VENDOR_ID_NATINST, 0x0400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
347         { PCI_VENDOR_ID_NATINST, 0x1250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
348         { PCI_VENDOR_ID_NATINST, 0x17d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
349         { PCI_VENDOR_ID_NATINST, 0x1800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
350         { 0 }
351 };
352 MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
353
354 typedef struct{
355         struct mite_struct *mite;
356         int boardtype;
357         int dio;
358 }nidio96_private;
359 #define devpriv ((nidio96_private *)dev->private)
360
361 static int ni_pcidio_cmdtest(comedi_device *dev,comedi_subdevice *s,
362                                   comedi_cmd *cmd);
363 static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s);
364 static int ni_pcidio_inttrig(comedi_device *dev, comedi_subdevice *s,
365         unsigned int trignum);
366 static int nidio_find_device(comedi_device *dev,int bus,int slot);
367 static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode);
368 static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s);
369
370 #ifdef DEBUG_FLAGS
371 static void ni_pcidio_print_flags(unsigned int flags);
372 static void ni_pcidio_print_status(unsigned int status);
373 #else
374 #define ni_pcidio_print_flags(x)
375 #define ni_pcidio_print_status(x)
376 #endif
377
378 static int nidio96_8255_cb(int dir,int port,int data,unsigned long iobase)
379 {
380         if(dir){
381                 writeb(data,iobase+port);
382                 return 0;
383         }else{
384                 return readb(iobase+port);
385         }
386 }
387
388 static void nidio_interrupt(int irq, void *d, struct pt_regs *regs)
389 {
390         comedi_device *dev=d;
391         comedi_subdevice *s = dev->subdevices;
392         comedi_async *async = s->async;
393         struct mite_struct *mite = devpriv->mite;
394         //int i, j;
395         long int AuxData = 0;
396         sampl_t data1 = 0;
397         sampl_t data2 = 0;
398         int flags;
399         int status;
400         int work = 0;
401         unsigned int m_status;
402
403         status = readb(dev->iobase+Interrupt_And_Window_Status);
404         flags = readb(dev->iobase+Group_1_Flags);
405         m_status = readl(mite->mite_io_addr + MITE_CHSR + CHAN_OFFSET(1));
406
407         //interrupcions parasites
408         if(dev->attached == 0){
409                 comedi_error(dev,"premature interrupt");
410                 async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;
411         }
412
413         DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x,m_status=0x%08x\n",
414                 status,flags,m_status);
415         ni_pcidio_print_flags(flags);
416         ni_pcidio_print_status(status);
417 #ifdef MITE_DEBUG
418         mite_print_chsr(m_status);
419 #endif
420         //printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,1));
421         //mite_dump_regs(mite);
422
423         //printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf);
424         //printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096));
425
426         if(m_status & CHSR_INT){
427                 if(m_status & CHSR_LINKC){
428                         unsigned int count;
429
430                         writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(1));
431                         count = le32_to_cpu(mite->ring[mite->current_link].count);
432
433                         /* XXX need to byteswap */
434
435                         async->buf_write_count += count;
436                         async->buf_write_ptr += count;
437                         if(async->buf_write_ptr >= async->data_len){
438                                 async->buf_write_ptr -= async->data_len;
439                         }
440                         mite->current_link++;
441                         if(mite->current_link >= mite->n_links){
442                                 mite->current_link=0;
443                         }
444                 }
445                 if(m_status & CHSR_DONE){
446                         writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR +
447                                 CHAN_OFFSET(1));
448                 }
449                 if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY | CHSR_DRQ1)){
450                         DPRINTK("unknown mite interrupt, disabling IRQ\n");
451                         writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR +
452                                 CHAN_OFFSET(1));
453                         disable_irq(dev->irq);
454                 }
455                 async->events |= COMEDI_CB_BLOCK;
456         }
457
458         while(status&DataLeft){
459                 work++;
460                 if(work>20){
461                         DPRINTK("too much work in interrupt\n");
462                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
463                         break;
464                 }
465
466                 flags &= IntEn;
467
468                 if(flags & TransferReady){
469                         //DPRINTK("TransferReady\n");
470                         while(flags & TransferReady){
471                                 work++;
472                                 if(work>100){
473                                         DPRINTK("too much work in interrupt\n");
474                                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
475                                         goto out;
476                                 }
477                                 AuxData = readl(dev->iobase+Group_1_FIFO);
478                                 data1 = AuxData & 0xffff;
479                                 data2 = (AuxData & 0xffff0000) >> 16;
480                                 comedi_buf_put(async,data1);
481                                 comedi_buf_put(async,data2);
482                                 //DPRINTK("read:%d, %d\n",data1,data2);
483                                 flags = readb(dev->iobase+Group_1_Flags);
484                         }
485                         //DPRINTK("buf_int_count: %d\n",async->buf_int_count);
486                         //DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",IntEn,flags,status);
487                         //ni_pcidio_print_flags(flags);
488                         //ni_pcidio_print_status(status);
489                         async->events |= COMEDI_CB_BLOCK;
490                 }
491
492                 if(flags & CountExpired){
493                         DPRINTK("CountExpired\n");
494                         writeb(ClearExpired,dev->iobase+Group_1_Second_Clear);
495                         async->events |= COMEDI_CB_EOA;
496
497                         writeb(0x00,dev->iobase+OpMode);
498                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
499 #ifdef USE_DMA
500                         mite_dma_disarm(mite);
501                         writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR +
502                                 CHAN_OFFSET(1));
503 #endif
504                         break;
505                 }else if(flags & Waited){
506                         DPRINTK("Waited\n");
507                         writeb(ClearWaited,dev->iobase+Group_1_First_Clear);
508                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
509                         async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
510 #ifdef USE_DMA
511                         mite_dma_disarm(mite);
512                         writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR +
513                                 CHAN_OFFSET(1));
514 #endif
515                         break;
516                 }else if(flags & PrimaryTC){
517                         DPRINTK("PrimaryTC\n");
518                         writeb(ClearPrimaryTC,dev->iobase+Group_1_First_Clear);
519                         async->events |= COMEDI_CB_EOA;
520                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
521                 }else if(flags & SecondaryTC){
522                         DPRINTK("SecondaryTC\n");
523                         writeb(ClearSecondaryTC,dev->iobase+Group_1_First_Clear);
524                         async->events |= COMEDI_CB_EOA;
525                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
526                 }
527 #if 0
528                 else{
529                         printk("ni_pcidio: unknown interrupt\n");
530                         async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;
531                         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
532                 }
533 #endif
534                 flags = readb(dev->iobase+Group_1_Flags);
535                 status = readb(dev->iobase+Interrupt_And_Window_Status);
536                 //DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,status=0x%02x\n",
537                 //      IntEn,flags,status);
538                 //ni_pcidio_print_flags(flags);
539                 //ni_pcidio_print_status(status);
540         }
541
542 out:
543         comedi_event(dev,s,async->events);
544             
545 #if unused
546         if(!tag){
547                 writeb(0x03,dev->iobase+Master_DMA_And_Interrupt_Control);
548         }
549 #endif
550
551 }
552
553 #ifdef DEBUG_FLAGS
554 static char *flags_strings[] = {
555         "TransferReady", "CountExpired", "2", "3",
556         "4", "Waited", "PrimaryTC", "SecondaryTC",
557 };
558 static void ni_pcidio_print_flags(unsigned int flags)
559 {
560         int i;
561
562         printk("group_1_flags:");
563         for(i=7;i>=0;i--){
564                 if(flags&(1<<i)){
565                         printk(" %s",flags_strings[i]);
566                 }
567         }
568         printk("\n");
569 }
570 static char *status_strings[] = {
571         "DataLeft1", "Reserved1", "Req1", "StopTrig1",
572         "DataLeft2", "Reserved2", "Req2", "StopTrig2",
573 };
574 static void ni_pcidio_print_status(unsigned int flags)
575 {
576         int i;
577
578         printk("group_status:");
579         for(i=7;i>=0;i--){
580                 if(flags&(1<<i)){
581                         printk(" %s",status_strings[i]);
582                 }
583         }
584         printk("\n");
585 }
586 #endif
587
588 #ifdef unused
589 static void debug_int(comedi_device *dev)
590 {
591         int a,b;
592         static int n_int = 0;
593         struct timeval tv;
594
595         do_gettimeofday(&tv);
596         a=readb(dev->iobase+Group_Status);
597         b=readb(dev->iobase+Group_1_Flags);
598
599         if(n_int < 10){
600                 DPRINTK("status 0x%02x flags 0x%02x time %06d\n",a,b,(int)tv.tv_usec);
601         }
602
603         while(b&1){
604                 writew(0xff,dev->iobase+Group_1_FIFO);
605                 b=readb(dev->iobase+Group_1_Flags);
606         }
607
608         b=readb(dev->iobase+Group_1_Flags);
609
610         if(n_int < 10){
611                 DPRINTK("new status 0x%02x\n",b);
612                 n_int++;
613         }
614 }
615 #endif
616
617
618 static int ni_pcidio_insn_config(comedi_device *dev,comedi_subdevice *s,
619         comedi_insn *insn,lsampl_t *data)
620 {
621         if(insn->n!=1)return -EINVAL;
622         switch(data[0]){
623         case COMEDI_OUTPUT:
624                 s->io_bits |= 1<<CR_CHAN(insn->chanspec);
625                 break;
626         case COMEDI_INPUT:
627                 s->io_bits &= ~(1<<CR_CHAN(insn->chanspec));
628                 break;
629         default:
630                 return -EINVAL;
631         }
632         writel(s->io_bits,dev->iobase+Port_Pin_Directions(0));
633
634         return 1;
635 }
636
637 static int ni_pcidio_insn_bits(comedi_device *dev,comedi_subdevice *s,
638         comedi_insn *insn,lsampl_t *data)
639 {
640         if(insn->n!=2)return -EINVAL;
641         if(data[0]){
642                 s->state &= ~data[0];
643                 s->state |= (data[0]&data[1]);
644                 writel(s->state,dev->iobase+Port_IO(0));
645         }
646         data[1] = readl(dev->iobase+Port_IO(0));
647
648         return 2;
649 }
650
651 static int ni_pcidio_cmdtest(comedi_device *dev,comedi_subdevice *s,
652         comedi_cmd *cmd)
653 {
654         int err=0;
655         int tmp;
656
657         /* step 1: make sure trigger sources are trivially valid */
658
659         tmp=cmd->start_src;
660         cmd->start_src &= TRIG_NOW|TRIG_INT;
661         if(!cmd->start_src || tmp!=cmd->start_src)err++;
662
663         tmp=cmd->scan_begin_src;
664         cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT;
665         if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
666
667         tmp=cmd->convert_src;
668         cmd->convert_src &= TRIG_NOW;
669         if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
670
671         tmp=cmd->scan_end_src;
672         cmd->scan_end_src &= TRIG_COUNT;
673         if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
674
675         tmp=cmd->stop_src;
676         cmd->stop_src &= TRIG_COUNT;
677         if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
678
679         if(err)return 1;
680
681         /* step 2: make sure trigger sources are unique and mutually compatible */
682
683         /* note that mutual compatiblity is not an issue here */
684         if(cmd->start_src!=TRIG_NOW &&
685            cmd->start_src!=TRIG_INT)err++;
686         if(cmd->scan_begin_src!=TRIG_TIMER &&
687            cmd->scan_begin_src!=TRIG_EXT)err++;
688
689         if(err)return 2;
690
691         /* step 3: make sure arguments are trivially compatible */
692
693         if(cmd->start_arg!=0){
694                 /* same for both TRIG_INT and TRIG_NOW */
695                 cmd->start_arg=0;
696                 err++;
697         }
698
699 #define MAX_SPEED       (TIMER_BASE)    /* in nanoseconds */
700
701         if(cmd->scan_begin_src==TRIG_TIMER){
702                 if(cmd->scan_begin_arg<MAX_SPEED){
703                         cmd->scan_begin_arg=MAX_SPEED;
704                         err++;
705                 }
706                 /* no minumum speed */
707         }else{
708                 /* TRIG_EXT */
709                 /* should be level/edge, hi/lo specification here */
710                 if(cmd->scan_begin_arg!=0){
711                         cmd->scan_begin_arg=0;
712                         err++;
713                 }
714         }
715         if(cmd->convert_arg!=0){
716                 cmd->convert_arg = 0;
717                 err++;
718         }
719
720         if(cmd->scan_end_arg!=cmd->chanlist_len){
721                 cmd->scan_end_arg=cmd->chanlist_len;
722                 err++;
723         }
724         if(cmd->stop_src==TRIG_COUNT){
725                 /* no limit */
726         }else{
727                 /* TRIG_NONE */
728                 if(cmd->stop_arg!=0){
729                         cmd->stop_arg=0;
730                         err++;
731                 }
732         }
733
734         if(err)return 3;
735
736         /* step 4: fix up any arguments */
737         
738         if(cmd->scan_begin_src == TRIG_TIMER){
739                 tmp = cmd->scan_begin_arg;
740                 ni_pcidio_ns_to_timer(&cmd->scan_begin_arg,
741                         cmd->flags&TRIG_ROUND_MASK);
742                 if(tmp!=cmd->scan_begin_arg)err++;
743         }
744
745         if(err)return 4;
746
747         return 0;
748 }
749
750
751 static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode)
752 {
753         int divider, base;
754
755         base = TIMER_BASE;
756
757         switch(round_mode){
758         case TRIG_ROUND_NEAREST:
759         default:
760                 divider = (*nanosec + base/2)/base;
761                 break;
762         case TRIG_ROUND_DOWN:
763                 divider = (*nanosec)/base;
764                 break;
765         case TRIG_ROUND_UP:
766                 divider = (*nanosec + base - 1)/base;
767                 break;
768         }
769
770         *nanosec = base * divider;
771         return divider;
772 }
773
774
775 static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s)
776 {
777         comedi_cmd *cmd = &s->async->cmd;
778
779         /* XXX configure ports for input*/
780         writel(0x0000,dev->iobase+Port_Pin_Directions(0));
781
782         if(0){
783                 /* enable fifos A B C D */
784                 writeb(0x0f,dev->iobase+Data_Path);
785
786                 /* set transfer width a 32 bits*/
787                 writeb(TransferWidth(0) | TransferLength(0),
788                         dev->iobase+Transfer_Size_Control);
789         }else{
790                 writeb(0x03,dev->iobase+Data_Path);
791                 writeb(TransferWidth(3) | TransferLength(0),
792                         dev->iobase+Transfer_Size_Control);
793         }
794
795         /* protocol configuration */
796         if(cmd->scan_begin_src == TRIG_TIMER){
797                 /* page 4-5, "input with internal REQs" */
798                 writeb(  0 ,dev->iobase+OpMode);
799                 writeb(0x00,dev->iobase+ClockReg);
800                 writeb(  1 ,dev->iobase+Sequence);
801                 writeb(0x04,dev->iobase+ReqReg);
802                 writeb(  4 ,dev->iobase+BlockMode);
803                 writeb(  3 ,dev->iobase+LinePolarities);
804                 writeb(0xc0,dev->iobase+AckSer);
805                 writel(ni_pcidio_ns_to_timer(&cmd->scan_begin_arg,
806                         TRIG_ROUND_NEAREST),dev->iobase+StartDelay);
807                 writeb(  1 ,dev->iobase+ReqDelay);
808                 writeb(  1 ,dev->iobase+ReqNotDelay);
809                 writeb(  1 ,dev->iobase+AckDelay);
810                 writeb(0x0b,dev->iobase+AckNotDelay);
811                 writeb(0x01,dev->iobase+Data1Delay);
812                 /* manual, page 4-5: ClockSpeed comment is incorrectly listed
813                 * on DAQOptions */
814                 writew(0   ,dev->iobase+ClockSpeed);
815                 writeb(0   ,dev->iobase+DAQOptions);
816         }else{
817                 /* TRIG_EXT */
818                 /* page 4-5, "input with external REQs" */
819                 writeb(  0 ,dev->iobase+OpMode);
820                 writeb(0x00,dev->iobase+ClockReg);
821                 writeb(  0 ,dev->iobase+Sequence);
822                 writeb(0x00,dev->iobase+ReqReg);
823                 writeb(  4 ,dev->iobase+BlockMode);
824                 writeb(  0 ,dev->iobase+LinePolarities);
825                 writeb(0x00,dev->iobase+AckSer);
826                 writel(  1 ,dev->iobase+StartDelay);
827                 writeb(  1 ,dev->iobase+ReqDelay);
828                 writeb(  1 ,dev->iobase+ReqNotDelay);
829                 writeb(  1 ,dev->iobase+AckDelay);
830                 writeb(0x0C,dev->iobase+AckNotDelay);
831                 writeb(0x10,dev->iobase+Data1Delay);
832                 writew(  0 ,dev->iobase+ClockSpeed);
833                 writeb(0x60,dev->iobase+DAQOptions);
834         }
835
836         if(cmd->stop_src == TRIG_COUNT){
837                 writel(cmd->stop_arg,dev->iobase+Transfer_Count);
838         }else{
839                 /* XXX */
840         }
841
842 #ifdef USE_DMA
843         writeb(0x05,dev->iobase+DMA_Line_Control);
844         writeb(0x30,dev->iobase+Group_1_First_Clear);
845
846         setup_mite_dma(dev,s);
847 #else
848         writeb(0x00,dev->iobase+DMA_Line_Control);
849 #endif
850   
851         /* clear and enable interrupts */
852         writeb(0xff,dev->iobase+Group_1_First_Clear);
853         //writeb(ClearExpired,dev->iobase+Group_1_Second_Clear);
854
855         writeb(IntEn,dev->iobase+Interrupt_Control);
856         writeb(0x03,dev->iobase+Master_DMA_And_Interrupt_Control);
857
858         if(cmd->start_src == TRIG_NOW){
859                 /* start */
860                 writeb(Numbered | RunMode(7),dev->iobase+OpMode);
861                 s->async->inttrig = NULL;
862         }else{
863                 /* TRIG_INT */
864                 s->async->inttrig = ni_pcidio_inttrig;
865         }
866
867         DPRINTK("ni_pcidio: command started\n");
868         return 0;
869 }
870
871
872 static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s)
873 {
874         struct mite_struct *mite = devpriv->mite;
875
876         mite->current_link = 0;
877
878         mite->dir = COMEDI_INPUT;
879         mite->chan = 1;
880
881         mite_prep_dma(mite);
882
883         mite_dma_arm(mite);
884 }
885
886
887 static int ni_pcidio_inttrig(comedi_device *dev, comedi_subdevice *s,
888         unsigned int trignum)
889 {
890         if(trignum!=0)return -EINVAL;
891
892         writeb(Numbered | RunMode(7),dev->iobase+OpMode);
893         s->async->inttrig = NULL;
894
895         return 1;
896 }
897
898
899 static int ni_pcidio_cancel(comedi_device *dev, comedi_subdevice *s)
900 {
901         writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
902
903         return 0;
904 }
905
906
907 static int ni_pcidio_alloc(comedi_device *dev, comedi_subdevice *s,
908         unsigned long new_size)
909 {
910         int ret;
911
912         ret = mite_buf_alloc(devpriv->mite, s->async, new_size);
913         if(ret<0)return ret;
914
915         memset(s->async->prealloc_buf, 0xaa, s->async->prealloc_bufsz);
916
917         return 0;
918 }
919
920
921 static int nidio_attach(comedi_device *dev,comedi_devconfig *it)
922 {
923         comedi_subdevice *s;
924         int i;
925         int ret;
926         
927         printk("comedi%d: nidio:",dev->minor);
928
929         if((ret=alloc_private(dev,sizeof(nidio96_private)))<0)
930                 return ret;
931         
932         ret=nidio_find_device(dev,it->options[0],it->options[1]);
933         if(ret<0)return ret;
934
935         ret = mite_setup(devpriv->mite);
936         if(ret < 0)
937         {
938                 printk("error setting up mite\n");
939                 return ret;
940         }
941         dev->iobase = mite_iobase(devpriv->mite);
942
943         dev->board_name=this_board->name;
944         dev->irq=mite_irq(devpriv->mite);
945         printk(" %s",dev->board_name);
946
947         if(!this_board->is_diodaq){
948                 dev->n_subdevices=this_board->n_8255;
949         }else{
950                 dev->n_subdevices=1;
951         }
952         if((ret=alloc_subdevices(dev))<0)
953                 return ret;
954
955         if(!this_board->is_diodaq){
956                 for(i=0;i<this_board->n_8255;i++){
957                         subdev_8255_init(dev,dev->subdevices+i,
958                                 nidio96_8255_cb,(unsigned long)(dev->iobase+NIDIO_8255_BASE(i)));
959                 }
960         }else{
961
962                 printk(" rev=%d",readb(dev->iobase+Chip_Version));
963         
964                 s=dev->subdevices+0;
965
966                 dev->read_subdev = s;
967                 s->type=COMEDI_SUBD_DIO;
968                 s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_RT;
969                 s->n_chan=32;
970                 s->range_table=&range_digital;
971                 s->maxdata=1;
972                 s->insn_config = ni_pcidio_insn_config;
973                 s->insn_bits = ni_pcidio_insn_bits;
974                 s->do_cmd = ni_pcidio_cmd;
975                 s->do_cmdtest = ni_pcidio_cmdtest;
976                 s->cancel = ni_pcidio_cancel;
977                 s->len_chanlist=32;             /* XXX */
978                 s->buf_alloc = ni_pcidio_alloc;
979
980                 writel(0,dev->iobase+Port_IO(0));
981                 writel(0,dev->iobase+Port_Pin_Directions(0));
982                 writel(0,dev->iobase+Port_Pin_Mask(0));
983
984                 /* disable interrupts on board */
985                 writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
986
987                 ret=comedi_request_irq(dev->irq,nidio_interrupt,SA_SHIRQ,"ni_pcidio",dev);
988                 if(ret<0){
989                         dev->irq=0;
990                         printk(" irq not available");
991                 }
992         }
993
994         devpriv->mite->chan = 1;
995
996         printk("\n");
997
998         return 0;
999 }
1000
1001 static int nidio_detach(comedi_device *dev)
1002 {
1003         int i;
1004
1005         if(this_board && !this_board->is_diodaq){
1006                 for(i=0;i<this_board->n_8255;i++){
1007                         subdev_8255_cleanup(dev,dev->subdevices+i);
1008                 }
1009         }
1010
1011         if(dev->irq)
1012                 comedi_free_irq(dev->irq,dev);
1013
1014         if(devpriv && devpriv->mite)
1015                 mite_unsetup(devpriv->mite);
1016
1017         return 0;
1018 }
1019
1020
1021 static int nidio_find_device(comedi_device *dev,int bus,int slot)
1022 {
1023         struct mite_struct *mite;
1024         int i;
1025         
1026         for(mite=mite_devices;mite;mite=mite->next){
1027                 if(mite->used)continue;
1028                 if(bus || slot){
1029                         if(bus!=(mite->pcidev->bus->number<<8) ||
1030                            slot!=PCI_SLOT(mite->pcidev->devfn))
1031                                 continue;
1032                 }
1033                 for(i=0;i<n_nidio_boards;i++){
1034                         if(mite_device_id(mite)==nidio_boards[i].dev_id){
1035                                 dev->board_ptr=nidio_boards+i;
1036                                 devpriv->mite=mite;
1037
1038                                 return 0;
1039                         }
1040                 }
1041         }
1042         printk("no device found\n");
1043         mite_list_devices();
1044         return -EIO;
1045 }
1046