18d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
28d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   comedi/drivers/dt282x.c
38d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   Hardware driver for Data Translation DT2821 series
48d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
58d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   COMEDI - Linux Control and Measurement Device Interface
68d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
78d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
88d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   This program is free software; you can redistribute it and/or modify
98d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   it under the terms of the GNU General Public License as published by
108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   the Free Software Foundation; either version 2 of the License, or
118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   (at your option) any later version.
128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   This program is distributed in the hope that it will be useful,
148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   but WITHOUT ANY WARRANTY; without even the implied warranty of
158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   GNU General Public License for more details.
178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   You should have received a copy of the GNU General Public License
198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   along with this program; if not, write to the Free Software
208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
248d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefDriver: dt282x
258d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefDescription: Data Translation DT2821 series (including DT-EZ)
268d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefAuthor: ds
278d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefDevices: [Data Translation] DT2821 (dt2821),
288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f),
298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g),
308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  DT2823 (dt2823),
318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),
328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
348d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefStatus: complete
358d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefUpdated: Wed, 22 Aug 2001 17:11:34 -0700
368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
378d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefConfiguration options:
388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [0] - I/O port base address
398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [1] - IRQ
408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [2] - DMA 1
418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [3] - DMA 2
428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [4] - AI jumpered for 0=single ended, 1=differential
438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [5] - AI jumpered for 0=straight binary, 1=2's complement
448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [6] - AO 0 jumpered for 0=straight binary, 1=2's complement
458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [7] - AO 1 jumpered for 0=straight binary, 1=2's complement
468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
4818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4=[-2.5,2.5]
498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
5018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4=[-2.5,2.5]
518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
528d3d823c74a4c967b4a02e6466c6727ad21422a0David SchleefNotes:
538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  - AO commands might be broken.
548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef  - If you try to run a command on both the AI and AO subdevices
558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef    simultaneously, bad things will happen.  The driver needs to
568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef    be fixed to check for this situation and return an error.
578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef*/
588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#include "../comedidev.h"
608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
615a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#include <linux/ioport.h>
638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#include <linux/interrupt.h>
64845d131e2b363717d8ac8db2c6b4417de8cf10b5Greg Kroah-Hartman#include <linux/io.h>
658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#include <asm/dma.h>
668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#include "comedi_fc.h"
678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DEBUG
698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_TIMEOUT		100	/* 500 us */
718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_SIZE 0x10
728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *    Registers in the DT282x
758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADCSR	0x00	/* A/D Control/Status             */
788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_CHANCSR	0x02	/* Channel Control/Status */
798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADDAT	0x04	/* A/D data                       */
808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACSR	0x06	/* D/A Control/Status             */
818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DADAT	0x08	/* D/A data                       */
828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DIODAT	0x0a	/* digital data                   */
838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_SUPCSR	0x0c	/* Supervisor Control/Status      */
848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_TMRCTR	0x0e	/* Timer/Counter          */
858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *  At power up, some registers are in a well-known state.  The
888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *  masks and values are as follows:
898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADCSR_MASK 0xfff0
928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADCSR_VAL 0x7c00
938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_CHANCSR_MASK 0xf0f0
958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_CHANCSR_VAL 0x70f0
968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACSR_MASK 0x7c93
988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACSR_VAL 0x7c90
998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_SUPCSR_MASK 0xf8ff
1018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_SUPCSR_VAL 0x0000
1028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_TMRCTR_MASK 0xff00
1048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_TMRCTR_VAL 0xf000
1058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
1078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *    Bit fields of each register
1088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
1098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/* ADCSR */
1118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADERR	0x8000	/* (R)   1 for A/D error  */
1138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADCLK	0x0200	/* (R/W) A/D clock enable */
1148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x7c00           read as 1's            */
1158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_MUXBUSY	0x0100	/* (R)   multiplexer busy */
1168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADDONE	0x0080	/* (R)   A/D done         */
1178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_IADDONE	0x0040	/* (R/W) interrupt on A/D done    */
1188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x0030           gain select            */
1198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x000f           channel select         */
1208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/* CHANCSR */
1228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_LLE	0x8000	/* (R/W) Load List Enable */
1248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x7000           read as 1's            */
1258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x0f00     (R)   present address        */
1268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x00f0           read as 1's            */
1278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/*      0x000f     (R)   number of entries - 1  */
1288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/* DACSR */
1308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DAERR	0x8000	/* (R)   D/A error                */
1328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_YSEL	0x0200	/* (R/W) DAC 1 select             */
1338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_SSEL	0x0100	/* (R/W) single channel select    */
1348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACRDY	0x0080	/* (R)   DAC ready                */
1358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_IDARDY	0x0040	/* (R/W) interrupt on DAC ready   */
1368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACLK	0x0020	/* (R/W) D/A clock enable */
1378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_HBOE	0x0002	/* (R/W) DIO high byte output enable      */
1388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_LBOE	0x0001	/* (R/W) DIO low byte output enable       */
1398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/* SUPCSR */
1418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DMAD	0x8000	/* (R)   DMA done                 */
1438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ERRINTEN	0x4000	/* (R/W) interrupt on error               */
1448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_CLRDMADNE 0x2000	/* (W)   clear DMA done                   */
1458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DDMA	0x1000	/* (R/W) dual DMA                 */
1468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DS1	0x0800	/* (R/W) DMA select 1                     */
1478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DS0	0x0400	/* (R/W) DMA select 0                     */
1488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_BUFFB	0x0200	/* (R/W) buffer B selected                */
1498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_SCDN	0x0100	/* (R)   scan done                        */
1508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACON	0x0080	/* (W)   DAC single conversion            */
1518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_ADCINIT	0x0040	/* (W)   A/D initialize                   */
1528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_DACINIT	0x0020	/* (W)   D/A initialize                   */
1538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_PRLD	0x0010	/* (W)   preload multiplexer              */
1548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_STRIG	0x0008	/* (W)   software trigger         */
1558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_XTRIG	0x0004	/* (R/W) external trigger enable  */
1568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_XCLK	0x0002	/* (R/W) external clock enable            */
1578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define DT2821_BDINIT	0x0001	/* (W)   initialize board         */
1588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
15918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherstatic const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
16018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4, {
16118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-10, 10),
16218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-5, 5),
16318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-2.5, 2.5),
16418e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-1.25, 1.25)
16518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	}
1668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
1670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
16818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherstatic const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
16918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4, {
17018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 10),
17118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 5),
17218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 2.5),
17318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 1.25)
17418e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	}
1758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
1760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
17718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherstatic const struct comedi_lrange range_dt282x_ai_5_bipolar = {
17818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4, {
17918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-5, 5),
18018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-2.5, 2.5),
18118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-1.25, 1.25),
18218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-0.625, 0.625)
18318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	}
1848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
1850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
18618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherstatic const struct comedi_lrange range_dt282x_ai_5_unipolar = {
18718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4, {
18818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 5),
18918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 2.5),
19018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 1.25),
19118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 0.625),
19218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	}
1938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
1940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
19518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherstatic const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
19618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4, {
19718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-10, 10),
19818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-1, 1),
19918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-0.1, 0.1),
20018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(-0.02, 0.02)
20118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	}
2028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
2030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
20418e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherstatic const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
20518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	4, {
20618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 10),
20718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 1),
20818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 0.1),
20918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		RANGE(0, 0.02)
21018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	}
2118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
2128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
21398484c1ae621eb784c4b2a7dd6c76a069bad6214Bill Pembertonstruct dt282x_board {
2148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	const char *name;
2158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int adbits;
2168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int adchan_se;
2178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int adchan_di;
2188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int ai_speed;
2198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int ispgl;
2208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int dachan;
2218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int dabits;
22298484c1ae621eb784c4b2a7dd6c76a069bad6214Bill Pemberton};
2238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
22498484c1ae621eb784c4b2a7dd6c76a069bad6214Bill Pembertonstatic const struct dt282x_board boardtypes[] = {
22568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2821",
22668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
22768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
22868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
22968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 20000,
23068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
23168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
23268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
23468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2821-f",
23568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
23668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
23768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
23868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 6500,
23968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
24068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
24168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
2420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
24368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2821-g",
24468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
24568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
24668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
24768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 4000,
24868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
24968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
25068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
2510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
25268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2823",
25368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 16,
25468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 0,
25568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 4,
25668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
25768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
25868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
25968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 16,
2600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
26168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2824-pgh",
2620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .adbits = 12,
2630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .adchan_se = 16,
2640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .adchan_di = 8,
2650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_speed = 20000,
2660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ispgl = 0,
2670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dachan = 0,
2680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dabits = 0,
2690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
27068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2824-pgl",
27168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
27268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
27368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
27468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 20000,
27568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 1,
27668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 0,
27768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 0,
2780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
27968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2825",
28068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
28168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
28268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
28368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 20000,
28468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 1,
28568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
28668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
2870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
28868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2827",
28968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 16,
29068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 0,
29168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 4,
29268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
29368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
29468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
29568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
2960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
29768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2828",
29868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
29968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 4,
30068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 0,
30168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
30268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
30368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
30468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
3050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
30668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt2829",
30768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 16,
30868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 8,
30968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 0,
31068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 33250,
31168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
31268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
31368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 16,
3140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
31568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt21-ez",
31668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
31768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
31868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
31968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
32068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
32168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 2,
32268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 12,
3230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
32468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt23-ez",
32568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 16,
32668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
32768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
32868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
32968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
33068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 0,
33168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 0,
3320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
33368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt24-ez",
33468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
33568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
33668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
33768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
33868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 0,
33968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 0,
34068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 0,
3410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
34268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	{.name = "dt24-ez-pgl",
34368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adbits = 12,
34468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_se = 16,
34568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .adchan_di = 8,
34668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ai_speed = 10000,
34768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .ispgl = 1,
34868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dachan = 0,
34968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	 .dabits = 0,
3500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 },
3518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
3528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
35318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board))
35498484c1ae621eb784c4b2a7dd6c76a069bad6214Bill Pemberton#define this_board ((const struct dt282x_board *)dev->board_ptr)
3558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
35668b08cdad78c79fc87df52f8c8d4adf60ec5d7fcBill Pembertonstruct dt282x_private {
3578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int ad_2scomp;		/* we have 2's comp jumper set  */
3588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int da0_2scomp;		/* same, for DAC0               */
3598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int da1_2scomp;		/* same, for DAC1               */
3608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
3619ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton	const struct comedi_lrange *darangelist[2];
3628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
363790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	short ao[2];
3648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
3658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	volatile int dacsr;	/* software copies of registers */
3668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	volatile int adcsr;
3678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	volatile int supcsr;
3688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
3698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	volatile int ntrig;
3708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	volatile int nread;
3718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
3728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	struct {
3738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		int chan;
3748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		short *buf;	/* DMA buffer */
3758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		volatile int size;	/* size of current transfer */
3768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} dma[2];
3778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int dma_maxsize;	/* max size of DMA transfer (in bytes) */
3788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int usedma;		/* driver uses DMA              */
3798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	volatile int current_dma_index;
3808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int dma_dir;
38168b08cdad78c79fc87df52f8c8d4adf60ec5d7fcBill Pemberton};
3828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
38368b08cdad78c79fc87df52f8c8d4adf60ec5d7fcBill Pemberton#define devpriv ((struct dt282x_private *)dev->private)
38498484c1ae621eb784c4b2a7dd6c76a069bad6214Bill Pemberton#define boardtype (*(const struct dt282x_board *)dev->board_ptr)
3858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
3868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
3878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *    Some useless abstractions
3888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
3898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define chan_to_DAC(a)	((a)&1)
390f7cbd7aad063b2a4b7aff6a743b2b00015ce3c3eBill Pemberton#define update_dacsr(a)	outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR)
391f7cbd7aad063b2a4b7aff6a743b2b00015ce3c3eBill Pemberton#define update_adcsr(a)	outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR)
3928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
3938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
39418e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher#define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR)
3958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
3968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
3978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *    danger! macro abuse... a is the expression to wait on, and b is
3988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      the statement(s) to execute if it doesn't happen.
3998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
40018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher#define wait_for(a, b)						\
40118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	do {							\
40218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		int _i;						\
40318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		for (_i = 0; _i < DT2821_TIMEOUT; _i++) {	\
40418e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			if (a) {				\
40518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher				_i = 0;				\
40618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher				break;				\
40718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			}					\
40818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			udelay(5);				\
40918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		}						\
41018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		if (_i)						\
41118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			b					\
41218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	} while (0)
4138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_attach(struct comedi_device *dev,
4150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_devconfig *it);
416da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_detach(struct comedi_device *dev);
417139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_dt282x = {
41868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "dt282x",
41968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
42068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = dt282x_attach,
42168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = dt282x_detach,
42268c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.board_name = &boardtypes[0].name,
42368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.num_names = n_boardtypes,
42468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.offset = sizeof(struct dt282x_board),
4258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
4268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4277114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_dt282x_init_module(void)
4287114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
4297114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_dt282x);
4307114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
4317114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
4327114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_dt282x_cleanup_module(void)
4337114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
4347114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_dt282x);
4357114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
4367114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
4377114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_dt282x_init_module);
4387114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_dt282x_cleanup_module);
4398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
440da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void free_resources(struct comedi_device *dev);
441da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int prep_ai_dma(struct comedi_device *dev, int chan, int size);
442da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int prep_ao_dma(struct comedi_device *dev, int chan, int size);
4430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ai_cancel(struct comedi_device *dev,
4440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s);
4450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ao_cancel(struct comedi_device *dev,
4460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s);
4478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleefstatic int dt282x_ns_to_timer(int *nanosec, int round_mode);
448da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void dt282x_disable_dma(struct comedi_device *dev);
4498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
450da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
4518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
452da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void dt282x_munge(struct comedi_device *dev, short *buf,
4530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 unsigned int nbytes)
4548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
4558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned int i;
4568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned short mask = (1 << boardtype.adbits) - 1;
4578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned short sign = 1 << (boardtype.adbits - 1);
4588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int n;
4598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
46018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	if (devpriv->ad_2scomp)
4618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		sign = 1 << (boardtype.adbits - 1);
46218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	else
4638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		sign = 0;
4648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (nbytes % 2)
4668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		comedi_error(dev, "bug! odd number of bytes from dma xfer");
4678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	n = nbytes / 2;
46818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	for (i = 0; i < n; i++)
4698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		buf[i] = (buf[i] & mask) ^ sign;
4708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
4718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
472da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void dt282x_ao_dma_interrupt(struct comedi_device *dev)
4738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
4748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	void *ptr;
4758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int size;
4768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int i;
47734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = dev->subdevices + 1;
4788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_CLRDMADNE);
4808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!s->async->prealloc_buf) {
48218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR "async->data disappeared.  dang!\n");
4838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return;
4848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
4858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	i = devpriv->current_dma_index;
4878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	ptr = devpriv->dma[i].buf;
4888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	disable_dma(devpriv->dma[i].chan);
4908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->current_dma_index = 1 - i;
4928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
4938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
4948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (size == 0) {
49518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR "dt282x: AO underrun\n");
4968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dt282x_ao_cancel(dev, s);
4978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->async->events |= COMEDI_CB_OVERFLOW;
4988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return;
4998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
5008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	prep_ao_dma(dev, i, size);
5018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return;
5028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
5038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
504da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void dt282x_ai_dma_interrupt(struct comedi_device *dev)
5058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
5068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	void *ptr;
5078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int size;
5088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int i;
5098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int ret;
51034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = dev->subdevices;
5118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_CLRDMADNE);
5138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!s->async->prealloc_buf) {
51518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR "async->data disappeared.  dang!\n");
5168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return;
5178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
5188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	i = devpriv->current_dma_index;
5208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	ptr = devpriv->dma[i].buf;
5218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	size = devpriv->dma[i].size;
5228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	disable_dma(devpriv->dma[i].chan);
5248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->current_dma_index = 1 - i;
5268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_munge(dev, ptr, size);
5288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	ret = cfc_write_array_to_buffer(s, ptr, size);
5298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (ret != size) {
5308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dt282x_ai_cancel(dev, s);
5318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return;
5328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
5338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->nread -= size / 2;
5348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (devpriv->nread < 0) {
53618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_INFO "dt282x: off by one\n");
5378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->nread = 0;
5388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
5398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!devpriv->nread) {
5408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dt282x_ai_cancel(dev, s);
5418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->async->events |= COMEDI_CB_EOA;
5428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return;
5438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
5448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#if 0
5458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* clear the dual dma flag, making this the last dma segment */
5468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* XXX probably wrong */
5478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!devpriv->ntrig) {
5488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->supcsr &= ~(DT2821_DDMA);
5498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		update_supcsr(0);
5508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
5518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#endif
5528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* restart the channel */
5538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	prep_ai_dma(dev, i, 0);
5548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
5558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
556da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
5578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
5588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int dma_chan;
5598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned long dma_ptr;
5608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned long flags;
5618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!devpriv->ntrig)
5638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 0;
5648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (n == 0)
5668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		n = devpriv->dma_maxsize;
5678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (n > devpriv->ntrig * 2)
5688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		n = devpriv->ntrig * 2;
5698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->ntrig -= n / 2;
5708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma[dma_index].size = n;
5728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dma_chan = devpriv->dma[dma_index].chan;
5738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
5748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	set_dma_mode(dma_chan, DMA_MODE_READ);
5768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	flags = claim_dma_lock();
5778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	clear_dma_ff(dma_chan);
5788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	set_dma_addr(dma_chan, dma_ptr);
5798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	set_dma_count(dma_chan, n);
5808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	release_dma_lock(flags);
5818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	enable_dma(dma_chan);
5838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return n;
5858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
5868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
587da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
5888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
5898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int dma_chan;
5908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned long dma_ptr;
5918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned long flags;
5928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma[dma_index].size = n;
5948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dma_chan = devpriv->dma[dma_index].chan;
5958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
5968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
5978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	set_dma_mode(dma_chan, DMA_MODE_WRITE);
5988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	flags = claim_dma_lock();
5998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	clear_dma_ff(dma_chan);
6008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	set_dma_addr(dma_chan, dma_ptr);
6018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	set_dma_count(dma_chan, n);
6028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	release_dma_lock(flags);
6038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	enable_dma(dma_chan);
6058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return n;
6078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
6088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
60970265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t dt282x_interrupt(int irq, void *d)
6108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
61171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = d;
61234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
61334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s_ao;
6148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned int supcsr, adcsr, dacsr;
6158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int handled = 0;
6168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!dev->attached) {
6188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		comedi_error(dev, "spurious interrupt");
6198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return IRQ_HANDLED;
6208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
6218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s = dev->subdevices + 0;
6238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s_ao = dev->subdevices + 1;
6248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	adcsr = inw(dev->iobase + DT2821_ADCSR);
6258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dacsr = inw(dev->iobase + DT2821_DACSR);
6268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	supcsr = inw(dev->iobase + DT2821_SUPCSR);
6278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (supcsr & DT2821_DMAD) {
6288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->dma_dir == DMA_MODE_READ)
6298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			dt282x_ai_dma_interrupt(dev);
6308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		else
6318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			dt282x_ao_dma_interrupt(dev);
6328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		handled = 1;
6338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
6348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (adcsr & DT2821_ADERR) {
6358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->nread != 0) {
6368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			comedi_error(dev, "A/D error");
6378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			dt282x_ai_cancel(dev, s);
6388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			s->async->events |= COMEDI_CB_ERROR;
6398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
6408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		handled = 1;
6418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
6428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (dacsr & DT2821_DAERR) {
6438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#if 0
6448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		static int warn = 5;
6458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (--warn <= 0) {
6468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			disable_irq(dev->irq);
64718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			printk(KERN_INFO "disabling irq\n");
6488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
6498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#endif
6508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		comedi_error(dev, "D/A error");
6518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dt282x_ao_cancel(dev, s_ao);
6528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->async->events |= COMEDI_CB_ERROR;
6538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		handled = 1;
6548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
6558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#if 0
6568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (adcsr & DT2821_ADDONE) {
6578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		int ret;
658790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		short data;
6598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		data = (short)inw(dev->iobase + DT2821_ADDAT);
6618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		data &= (1 << boardtype.adbits) - 1;
66218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher
66318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		if (devpriv->ad_2scomp)
6648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			data ^= 1 << (boardtype.adbits - 1);
6658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		ret = comedi_buf_put(s->async, data);
66618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher
66718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		if (ret == 0)
6688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			s->async->events |= COMEDI_CB_OVERFLOW;
6698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->nread--;
6718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (!devpriv->nread) {
6728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			s->async->events |= COMEDI_CB_EOA;
6738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		} else {
6748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			if (supcsr & DT2821_SCDN)
6758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef				update_supcsr(DT2821_STRIG);
6768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
6778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		handled = 1;
6788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
6798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#endif
6808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	comedi_event(dev, s);
68118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	/* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
68218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		adcsr, dacsr, supcsr); */
6838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return IRQ_RETVAL(handled);
6848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
6858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
686da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void dt282x_load_changain(struct comedi_device *dev, int n,
6870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 unsigned int *chanlist)
6888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
6898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned int i;
6908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned int chan, range;
6918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
6928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
6938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	for (i = 0; i < n; i++) {
6948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		chan = CR_CHAN(chanlist[i]);
6958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		range = CR_RANGE(chanlist[i]);
6968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		update_adcsr((range << 4) | (chan));
6978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
6988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(n - 1, dev->iobase + DT2821_CHANCSR);
6998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
7008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
7028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *    Performs a single A/D conversion.
7038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      - Put channel/gain into channel-gain list
7048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      - preload multiplexer
7058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      - trigger conversion and wait for it to finish
7068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
7070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ai_insn_read(struct comedi_device *dev,
7080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
7090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
7108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
7118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int i;
7128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* XXX should we really be enabling the ad clock here? */
7148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->adcsr = DT2821_ADCLK;
7158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_adcsr(0);
7168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_load_changain(dev, 1, &insn->chanspec);
7188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_PRLD);
7200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
7218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	for (i = 0; i < insn->n; i++) {
7238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		update_supcsr(DT2821_STRIG);
7248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		wait_for(ad_done(), comedi_error(dev, "timeout\n");
7250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 return -ETIME;);
7268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		data[i] =
7280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    inw(dev->iobase +
7298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
7308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->ad_2scomp)
7318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			data[i] ^= (1 << (boardtype.adbits - 1));
7328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
7338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return i;
7358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
7368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ai_cmdtest(struct comedi_device *dev,
7380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
7398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
7408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int err = 0;
7418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int tmp;
7428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* step 1: make sure trigger sources are trivially valid */
7448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->start_src;
7468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->start_src &= TRIG_NOW;
7478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->start_src || tmp != cmd->start_src)
7488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->scan_begin_src;
7518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
7528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
7538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->convert_src;
7568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->convert_src &= TRIG_TIMER;
7578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->convert_src || tmp != cmd->convert_src)
7588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->scan_end_src;
7618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->scan_end_src &= TRIG_COUNT;
7628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
7638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->stop_src;
7668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
7678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->stop_src || tmp != cmd->stop_src)
7688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
7718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 1;
7728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
77318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	/*
77418e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	 * step 2: make sure trigger sources are unique
77518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	 * and mutually compatible
77618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	 */
7778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
778828684f9a6e096f9150bad523c43b75d74b9baddDirk Hohndel	/* note that mutual compatibility is not an issue here */
7798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->scan_begin_src != TRIG_FOLLOW &&
7800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_EXT)
7818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
7838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
7868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 2;
7878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* step 3: make sure arguments are trivially compatible */
7898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
7908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->start_arg != 0) {
7918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->start_arg = 0;
7928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
7938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
7948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->scan_begin_src == TRIG_FOLLOW) {
7958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* internal trigger */
7968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (cmd->scan_begin_arg != 0) {
7978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			cmd->scan_begin_arg = 0;
7988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			err++;
7998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
8008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
8018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* external trigger */
8028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* should be level/edge, hi/lo specification here */
8038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (cmd->scan_begin_arg != 0) {
8048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			cmd->scan_begin_arg = 0;
8058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			err++;
8068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
8078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->convert_arg < 4000) {
8098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* XXX board dependent */
8108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->convert_arg = 4000;
8118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
8128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#define SLOWEST_TIMER	(250*(1<<15)*255)
8148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->convert_arg > SLOWEST_TIMER) {
8158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->convert_arg = SLOWEST_TIMER;
8168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
8178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->convert_arg < this_board->ai_speed) {
8198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->convert_arg = this_board->ai_speed;
8208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
8218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->scan_end_arg != cmd->chanlist_len) {
8238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->scan_end_arg = cmd->chanlist_len;
8248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
8258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->stop_src == TRIG_COUNT) {
8278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* any count is allowed */
8288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
8298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* TRIG_NONE */
8308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (cmd->stop_arg != 0) {
8318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			cmd->stop_arg = 0;
8328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			err++;
8338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
8348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
8378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 3;
8388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* step 4: fix up any arguments */
8408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->convert_arg;
8428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
8438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (tmp != cmd->convert_arg)
8448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
8458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
8478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 4;
8488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
8508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
8518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
852da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
8538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
854ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
8558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int timer;
8568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (devpriv->usedma == 0) {
8588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		comedi_error(dev,
85918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			     "driver requires 2 dma channels"
86018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher						" to execute command");
8618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EIO;
8628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_disable_dma(dev);
8658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->convert_arg < this_board->ai_speed)
8678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->convert_arg = this_board->ai_speed;
8688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
8698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(timer, dev->iobase + DT2821_TMRCTR);
8708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->scan_begin_src == TRIG_FOLLOW) {
8728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* internal trigger */
8738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
8748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
8758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* external trigger */
8768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
8778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
8798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
8818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->nread = devpriv->ntrig;
8828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma_dir = DMA_MODE_READ;
8848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->current_dma_index = 0;
8858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	prep_ai_dma(dev, 0, 0);
8868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (devpriv->ntrig) {
8878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		prep_ai_dma(dev, 1, 0);
8888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->supcsr |= DT2821_DDMA;
8898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		update_supcsr(0);
8908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
8918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->adcsr = 0;
8938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
8958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
8978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_adcsr(0);
8988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
8998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_PRLD);
9000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
9018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->scan_begin_src == TRIG_FOLLOW) {
9038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		update_supcsr(DT2821_STRIG);
9048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
9058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->supcsr |= DT2821_XTRIG;
9068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		update_supcsr(0);
9078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
9088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
9108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
9118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
912da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void dt282x_disable_dma(struct comedi_device *dev)
9138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
9148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (devpriv->usedma) {
9158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		disable_dma(devpriv->dma[0].chan);
9168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		disable_dma(devpriv->dma[1].chan);
9178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
9188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
9198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ai_cancel(struct comedi_device *dev,
9210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s)
9228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
9238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_disable_dma(dev);
9248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->adcsr = 0;
9268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_adcsr(0);
9278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->supcsr = 0;
9298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_ADCINIT);
9308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
9328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
9338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleefstatic int dt282x_ns_to_timer(int *nanosec, int round_mode)
9358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
9368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int prescale, base, divider;
9378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	for (prescale = 0; prescale < 16; prescale++) {
9398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (prescale == 1)
9408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			continue;
9418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		base = 250 * (1 << prescale);
9428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		switch (round_mode) {
9438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		case TRIG_ROUND_NEAREST:
9448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		default:
9458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			divider = (*nanosec + base / 2) / base;
9468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			break;
9478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		case TRIG_ROUND_DOWN:
9488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			divider = (*nanosec) / base;
9498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			break;
9508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		case TRIG_ROUND_UP:
9518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			divider = (*nanosec + base - 1) / base;
9528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			break;
9538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
9548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (divider < 256) {
9558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			*nanosec = divider * base;
9568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			return (prescale << 8) | (255 - divider);
9578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
9588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
9598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	base = 250 * (1 << 15);
9608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	divider = 255;
9618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	*nanosec = divider * base;
9628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return (15 << 8) | (255 - divider);
9638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
9648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
9668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *    Analog output routine.  Selects single channel conversion,
9678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      selects correct channel, converts from 2's compliment to
9688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      offset binary if necessary, loads the data into the DAC
9698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef *      data register, and performs the conversion.
9708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
9710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ao_insn_read(struct comedi_device *dev,
9720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
9730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
9748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
9758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
9768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 1;
9788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
9798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ao_insn_write(struct comedi_device *dev,
9810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
9820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
9838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
984790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	short d;
9858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned int chan;
9868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	chan = CR_CHAN(insn->chanspec);
9888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	d = data[0];
9898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	d &= (1 << boardtype.dabits) - 1;
9908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->ao[chan] = d;
9918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dacsr |= DT2821_SSEL;
9938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
9948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (chan) {
9958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* select channel */
9968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->dacsr |= DT2821_YSEL;
9978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->da0_2scomp)
9988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			d ^= (1 << (boardtype.dabits - 1));
9998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
10008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->dacsr &= ~DT2821_YSEL;
10018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->da1_2scomp)
10028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			d ^= (1 << (boardtype.dabits - 1));
10038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
10048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_dacsr(0);
10068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(d, dev->iobase + DT2821_DADAT);
10088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_DACON);
10108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 1;
10128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
10138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ao_cmdtest(struct comedi_device *dev,
10150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
10168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
10178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int err = 0;
10188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int tmp;
10198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* step 1: make sure trigger sources are trivially valid */
10218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->start_src;
10238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->start_src &= TRIG_INT;
10248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->start_src || tmp != cmd->start_src)
10258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->scan_begin_src;
10288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->scan_begin_src &= TRIG_TIMER;
10298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
10308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->convert_src;
10338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->convert_src &= TRIG_NOW;
10348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->convert_src || tmp != cmd->convert_src)
10358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->scan_end_src;
10388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->scan_end_src &= TRIG_COUNT;
10398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
10408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->stop_src;
10438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	cmd->stop_src &= TRIG_NONE;
10448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!cmd->stop_src || tmp != cmd->stop_src)
10458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
10488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 1;
10498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
105018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	/*
105118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	 * step 2: make sure trigger sources are unique
105218e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	 * and mutually compatible
105318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	 */
10548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1055828684f9a6e096f9150bad523c43b75d74b9baddDirk Hohndel	/* note that mutual compatibility is not an issue here */
10568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
10578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
10608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 2;
10618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* step 3: make sure arguments are trivially compatible */
10638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->start_arg != 0) {
10658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->start_arg = 0;
10668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
106818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	if (cmd->scan_begin_arg < 5000 /* XXX unknown */) {
10698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->scan_begin_arg = 5000;
10708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
10728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->convert_arg != 0) {
10738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->convert_arg = 0;
10748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
10768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->scan_end_arg > 2) {
10778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* XXX chanlist stuff? */
10788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		cmd->scan_end_arg = 2;
10798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
10808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
10818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (cmd->stop_src == TRIG_COUNT) {
10828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* any count is allowed */
10838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
10848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* TRIG_NONE */
10858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (cmd->stop_arg != 0) {
10868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			cmd->stop_arg = 0;
10878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			err++;
10888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
10898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
10908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
10928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 3;
10938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* step 4: fix up any arguments */
10958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
10968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	tmp = cmd->scan_begin_arg;
10978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
10988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (tmp != cmd->scan_begin_arg)
10998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		err++;
11008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (err)
11028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 4;
11038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
11058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
11078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ao_inttrig(struct comedi_device *dev,
11090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, unsigned int x)
11108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
11118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int size;
11128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (x != 0)
11148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EINVAL;
11158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
11170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  devpriv->dma_maxsize);
11188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (size == 0) {
111918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR "dt282x: AO underrun\n");
11208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EPIPE;
11218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
11228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	prep_ao_dma(dev, 0, size);
11238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
11250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  devpriv->dma_maxsize);
11268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (size == 0) {
112718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR "dt282x: AO underrun\n");
11288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EPIPE;
11298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
11308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	prep_ao_dma(dev, 1, size);
11318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_STRIG);
11338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->async->inttrig = NULL;
11348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 1;
11368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
11378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1138da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
11398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
11408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int timer;
1141ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
11428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (devpriv->usedma == 0) {
11448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		comedi_error(dev,
114518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			     "driver requires 2 dma channels"
114618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher						" to execute command");
11478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EIO;
11488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
11498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_disable_dma(dev);
11518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
11538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
11548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
11568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->nread = devpriv->ntrig;
11578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma_dir = DMA_MODE_WRITE;
11598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->current_dma_index = 0;
11608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
11628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(timer, dev->iobase + DT2821_TMRCTR);
11638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
11658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_dacsr(0);
11668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->async->inttrig = dt282x_ao_inttrig;
11688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
11708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
11718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_ao_cancel(struct comedi_device *dev,
11730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s)
11748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
11758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dt282x_disable_dma(dev);
11768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dacsr = 0;
11788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_dacsr(0);
11798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->supcsr = 0;
11818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	update_supcsr(DT2821_DACINIT);
11828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
11848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
11858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_dio_insn_bits(struct comedi_device *dev,
11870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
11880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
11898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
11908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (data[0]) {
11918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->state &= ~data[0];
11928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->state |= (data[0] & data[1]);
11938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		outw(s->state, dev->iobase + DT2821_DIODAT);
11958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
11968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	data[1] = inw(dev->iobase + DT2821_DIODAT);
11978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
11988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 2;
11998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
12008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt282x_dio_insn_config(struct comedi_device *dev,
12020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
12030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
12048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
12058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int mask;
12068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
12088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (data[0])
12098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->io_bits |= mask;
12108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	else
12118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->io_bits &= ~mask;
12128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (s->io_bits & 0x00ff)
12148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->dacsr |= DT2821_LBOE;
12158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	else
12168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->dacsr &= ~DT2821_LBOE;
12178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (s->io_bits & 0xff00)
12188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->dacsr |= DT2821_HBOE;
12198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	else
12208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->dacsr &= ~DT2821_HBOE;
12218d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
12238d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 1;
12258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
12268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12279ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange *const ai_range_table[] = {
12288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_dt282x_ai_lo_bipolar,
12298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_dt282x_ai_lo_unipolar,
12308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_dt282x_ai_5_bipolar,
12318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_dt282x_ai_5_unipolar
12328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
12330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
12349ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange *const ai_range_pgl_table[] = {
12358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_dt282x_ai_hi_bipolar,
12368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_dt282x_ai_hi_unipolar
12378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
12380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
12399ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
12408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
12418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (ispgl) {
12428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (x < 0 || x >= 2)
12438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			x = 0;
12448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return ai_range_pgl_table[x];
12458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
12468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (x < 0 || x >= 4)
12478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			x = 0;
12488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return ai_range_table[x];
12498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
12508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
12510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
12529ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange *const ao_range_table[] = {
12538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_bipolar10,
12548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_unipolar10,
12558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_bipolar5,
12568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_unipolar5,
12578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	&range_bipolar2_5
12588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
12590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
12609ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange *opt_ao_range_lkup(int x)
12618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
12628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (x < 0 || x >= 5)
12638d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		x = 0;
12648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return ao_range_table[x];
12658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
12668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
126718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcherenum {  /* i/o base, irq, dma channels */
126818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
12698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	opt_diff,		/* differential */
12708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	opt_ai_twos, opt_ao0_twos, opt_ao1_twos,	/* twos comp */
12718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	opt_ai_range, opt_ao0_range, opt_ao1_range,	/* range */
12728d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef};
12738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef/*
12758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   options:
12768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   0	i/o base
12778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   1	irq
12788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   2	dma1
12798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   3	dma2
12808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   4	0=single ended, 1=differential
12818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   5	ai 0=straight binary, 1=2's comp
12828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   6	ao0 0=straight binary, 1=2's comp
12838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   7	ao1 0=straight binary, 1=2's comp
12848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   8	ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
12858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   9	ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
12868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef   10	ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
12878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef */
1288da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
12898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
12908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int i, irq;
12918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int ret;
129234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
12938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	unsigned long iobase;
12948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dev->board_name = this_board->name;
12968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
12978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	iobase = it->options[opt_iobase];
12988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!iobase)
12998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		iobase = 0x240;
13008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
130118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
13028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
130318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_INFO " I/O port conflict\n");
13048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EBUSY;
13058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
13068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dev->iobase = iobase;
13078d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
13098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	i = inw(dev->iobase + DT2821_ADCSR);
13108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#ifdef DEBUG
131118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
13120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       inw(dev->iobase + DT2821_ADCSR),
13130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       inw(dev->iobase + DT2821_CHANCSR),
13140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       inw(dev->iobase + DT2821_DACSR),
13150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       inw(dev->iobase + DT2821_SUPCSR),
13160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       inw(dev->iobase + DT2821_TMRCTR));
13178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#endif
13188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
13200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     != DT2821_ADCSR_VAL) ||
13210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
13220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     != DT2821_CHANCSR_VAL) ||
13230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
13240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     != DT2821_DACSR_VAL) ||
13250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
13260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     != DT2821_SUPCSR_VAL) ||
13270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
13280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     != DT2821_TMRCTR_VAL)) {
132918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR " board not found");
13308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EIO;
13318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
13328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* should do board test */
13338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	irq = it->options[opt_irq];
13358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#if 0
13368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (irq < 0) {
13378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		unsigned long flags;
13388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		int irqs;
13398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13408d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		save_flags(flags);
13418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		sti();
13428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		irqs = probe_irq_on();
13438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* trigger interrupt */
13458d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13465f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(100);
13478d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13488d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		irq = probe_irq_off(irqs);
13498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		restore_flags(flags);
135018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		if (0 /* error */)
135118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			printk(KERN_ERR " error probing irq (bad)");
13528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
13538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#endif
13548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (irq > 0) {
135518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_INFO " ( irq = %d )", irq);
13565f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
13578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (ret < 0) {
135818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher			printk(KERN_ERR " failed to get irq\n");
13598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			return -EIO;
13608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		}
13618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dev->irq = irq;
13628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else if (irq == 0) {
136318e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_INFO " (no irq)");
13648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
13658d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#if 0
136618e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_INFO " (probe returned multiple irqs--bad)");
13678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#else
136818e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_INFO " (irq probe not implemented)");
13698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef#endif
13708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
13718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1372c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	ret = alloc_private(dev, sizeof(struct dt282x_private));
1373c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (ret < 0)
13748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return ret;
13758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	ret = dt282x_grab_dma(dev, it->options[opt_dma1],
13770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      it->options[opt_dma2]);
13788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (ret < 0)
13798d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return ret;
13808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1381c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	ret = alloc_subdevices(dev, 3);
1382c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (ret < 0)
13838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return ret;
13848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s = dev->subdevices + 0;
13868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
13878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	dev->read_subdev = s;
13888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* ai subdevice */
13898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->type = COMEDI_SUBD_AI;
13908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
13910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
13928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->n_chan =
13930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
13948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->insn_read = dt282x_ai_insn_read;
13958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->do_cmdtest = dt282x_ai_cmdtest;
13968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->do_cmd = dt282x_ai_cmd;
13978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->cancel = dt282x_ai_cancel;
13988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->maxdata = (1 << boardtype.adbits) - 1;
13998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->len_chanlist = 16;
14008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->range_table =
14010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
14028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->ad_2scomp = it->options[opt_ai_twos];
14038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s++;
1405c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton
1406c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	s->n_chan = boardtype.dachan;
1407c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (s->n_chan) {
14088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		/* ao subsystem */
14098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->type = COMEDI_SUBD_AO;
14108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dev->write_subdev = s;
14118d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
14128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->insn_read = dt282x_ao_insn_read;
14138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->insn_write = dt282x_ao_insn_write;
14148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->do_cmdtest = dt282x_ao_cmdtest;
14158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->do_cmd = dt282x_ao_cmd;
14168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->cancel = dt282x_ao_cancel;
14178d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->maxdata = (1 << boardtype.dabits) - 1;
14188d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->len_chanlist = 2;
14198d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->range_table_list = devpriv->darangelist;
14208d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->darangelist[0] =
14210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    opt_ao_range_lkup(it->options[opt_ao0_range]);
14228d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->darangelist[1] =
14230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    opt_ao_range_lkup(it->options[opt_ao1_range]);
14248d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->da0_2scomp = it->options[opt_ao0_twos];
14258d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		devpriv->da1_2scomp = it->options[opt_ao1_twos];
14268d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	} else {
14278d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		s->type = COMEDI_SUBD_UNUSED;
14288d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
14298d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14308d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s++;
14318d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	/* dio subsystem */
14328d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->type = COMEDI_SUBD_DIO;
14338d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
14348d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->n_chan = 16;
14358d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->insn_bits = dt282x_dio_insn_bits;
14368d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->insn_config = dt282x_dio_insn_config;
14378d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->maxdata = 1;
14388d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	s->range_table = &range_digital;
14398d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
144018e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	printk(KERN_INFO "\n");
14418d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14428d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
14438d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
14448d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1445da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void free_resources(struct comedi_device *dev)
14468d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
144718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	if (dev->irq)
14485f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		free_irq(dev->irq, dev);
14498d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (dev->iobase)
14508d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		release_region(dev->iobase, DT2821_SIZE);
14518d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (dev->private) {
14528d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->dma[0].chan)
14538d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			free_dma(devpriv->dma[0].chan);
14548d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->dma[1].chan)
14558d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			free_dma(devpriv->dma[1].chan);
14568d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->dma[0].buf)
14578d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			free_page((unsigned long)devpriv->dma[0].buf);
14588d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		if (devpriv->dma[1].buf)
14598d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef			free_page((unsigned long)devpriv->dma[1].buf);
14608d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
14618d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
14628d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1463da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_detach(struct comedi_device *dev)
14648d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
146518e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor);
14668d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14678d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	free_resources(dev);
14688d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14698d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
14708d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
14718d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
1472da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
14738d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef{
14748d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	int ret;
14758d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14768d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->usedma = 0;
14778d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14788d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!dma1 && !dma2) {
147918e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR " (no dma)");
14808d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return 0;
14818d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
14828d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14838d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
14848d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EINVAL;
14858d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14868d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (dma2 < dma1) {
14878d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		int i;
14888d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		i = dma1;
14898d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dma1 = dma2;
14908d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		dma2 = i;
14918d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
14928d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14938d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	ret = request_dma(dma1, "dt282x A");
14948d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (ret)
14958d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EBUSY;
14968d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma[0].chan = dma1;
14978d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
14988d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	ret = request_dma(dma2, "dt282x B");
14998d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (ret)
15008d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -EBUSY;
15018d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma[1].chan = dma2;
15028d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
15038d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma_maxsize = PAGE_SIZE;
15048d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
15058d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
15068d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
150718e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher		printk(KERN_ERR " can't get DMA memory");
15088d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef		return -ENOMEM;
15098d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	}
15108d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
151118e7e78e945527d9cb570a17f0835815f1794c2fIain Churcher	printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
15128d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
15138d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	devpriv->usedma = 1;
15148d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef
15158d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef	return 0;
15168d3d823c74a4c967b4a02e6466c6727ad21422a0David Schleef}
151790f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
151890f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
151990f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
152090f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
1521