1d4c3a56587af3edbe5f618b20e800e9f9fde13cbBernd Porr#define DRIVER_VERSION "v2.4"
24bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
34bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
44bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/*
54bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   comedi/drivers/usbdux.c
64bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   Copyright (C) 2003-2007 Bernd Porr, Bernd.Porr@f2s.com
74bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
84bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   This program is free software; you can redistribute it and/or modify
94bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   it under the terms of the GNU General Public License as published by
104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   the Free Software Foundation; either version 2 of the License, or
114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   (at your option) any later version.
124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   This program is distributed in the hope that it will be useful,
144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   but WITHOUT ANY WARRANTY; without even the implied warranty of
154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   GNU General Public License for more details.
174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   You should have received a copy of the GNU General Public License
194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   along with this program; if not, write to the Free Software
204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr */
234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/*
244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrDriver: usbdux
254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrDescription: University of Stirling USB DAQ & INCITE Technology Limited
264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrDevices: [ITL] USB-DUX (usbdux.o)
274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrAuthor: Bernd Porr <BerndPorr@f2s.com>
286742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd PorrUpdated: 8 Dec 2008
296742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd PorrStatus: Stable
304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrConfiguration options:
314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr  You have to upload firmware with the -i option. The
324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr  firmware is usually installed under /usr/share/usb or
334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr  /usr/local/share/usb or /lib/firmware.
344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrConnection scheme for the counter at the digital port:
364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr  0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1.
374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr  The sampling rate of the counter is approximately 500Hz.
384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrPlease note that under USB2.0 the length of the channel list determines
404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrthe max sampling rate. If you sample only one channel you get 8kHz
414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrsampling rate. If you sample two channels you get 4kHz and so on.
424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr*/
434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/*
444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * I must give credit here to Chris Baugher who
454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * wrote the driver for AT-MIO-16d. I used some parts of this
464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * driver. I also must give credits to David Brownell
474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * who supported me with the USB development.
484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *
494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * Bernd Porr
504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *
514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *
524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * Revision history:
534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 0.94: D/A output should work now with any channel list combinations
544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 0.95: .owner commented out for kernel vers below 2.4.19
554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       sanity checks in ai/ao_cmd
564274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman * 0.96: trying to get it working with 2.6, moved all memory alloc to comedi's
574274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *       attach final USB IDs
584274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *       moved memory allocation completely to the corresponding comedi
594274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *       functions firmware upload is by fxload and no longer by comedi (due to
604274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *       enumeration)
614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 0.97: USB IDs received, adjusted table
624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 0.98: SMP, locking, memroy alloc: moved all usb memory alloc
634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       to the usb subsystem and moved all comedi related memory
644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       alloc to comedi.
654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       | kernel | registration | usbdux-usb | usbdux-comedi | comedi |
664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 0.99: USB 2.0: changed protocol to isochronous transfer
674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *                IRQ transfer is too buggy and too risky in 2.0
684274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *                for the high speed ISO transfer is now a working version
694274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *                available
704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 0.99b: Increased the iso transfer buffer for high sp.to 10 buffers. Some VIA
714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *        chipsets miss out IRQs. Deeper buffering is needed.
724274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman * 1.00: full USB 2.0 support for the A/D converter. Now: max 8kHz sampling
734274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman *       rate.
744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       Firmware vers 1.00 is needed for this.
754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       Two 16 bit up/down/reset counter with a sampling rate of 1kHz
764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       And loads of cleaning up, in particular streamlining the
774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *       bulk transfers.
784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 1.1:  moved EP4 transfers to EP1 to make space for a PWM output on EP4
794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 1.2:  added PWM suport via EP4
804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 2.0:  PWM seems to be stable and is not interfering with the other functions
814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * 2.1:  changed PWM API
826742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr * 2.2:  added firmware kernel request to fix an udev problem
83ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr * 2.3:  corrected a bug in bulk timeouts which were far too short
84d4c3a56587af3edbe5f618b20e800e9f9fde13cbBernd Porr * 2.4:  fixed a bug which causes the driver to hang when it ran out of data.
85d4c3a56587af3edbe5f618b20e800e9f9fde13cbBernd Porr *       Thanks to Jan-Matthias Braun and Ian to spot the bug and fix it.
864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr *
874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr */
884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
89e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* generates loads of debug info */
90e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* #define NOISY_DUX_DEBUGBUG */
914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/kernel.h>
934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/module.h>
944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/init.h>
954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/slab.h>
964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/input.h>
974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/usb.h>
984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/fcntl.h>
994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include <linux/compiler.h>
1006742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr#include <linux/firmware.h>
1014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#include "../comedidev.h"
1034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define BOARDNAME "usbdux"
1054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
106ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr/* timeout for the USB-transfer in ms*/
107ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr#define BULK_TIMEOUT 1000
1084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
109e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* constants for "firmware" upload and download */
1104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define USBDUXSUB_FIRMWARE 0xA0
1114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define VENDOR_DIR_IN  0xC0
1124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define VENDOR_DIR_OUT 0x40
1134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
114f69b0d6451679f1466381a46ac7ab671a7b5668cUwe Kleine-König/* internal addresses of the 8051 processor */
1154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define USBDUXSUB_CPUCS 0xE600
1164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
117e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
118e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * the minor device number, major is 180 only for debugging purposes and to
119e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * upload special firmware (programming the eeprom etc) which is not compatible
120e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * with the comedi framwork
121e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
1224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define USBDUXSUB_MINOR 32
1234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
124e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* max lenghth of the transfer-buffer for software upload */
1254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define TB_LEN 0x2000
1264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
127e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Input endpoint number: ISO/IRQ */
1284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define ISOINEP           6
1294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
130e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Output endpoint number: ISO/IRQ */
1314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define ISOOUTEP          2
1324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
133e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* This EP sends DUX commands to USBDUX */
1344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define COMMAND_OUT_EP     1
1354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
136e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* This EP receives the DUX commands from USBDUX */
1374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define COMMAND_IN_EP        8
1384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
139e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Output endpoint for PWM */
1404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define PWM_EP         4
1414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
142e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* 300Hz max frequ under PWM */
1434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define MIN_PWM_PERIOD  ((long)(1E9/300))
1444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
145e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Default PWM frequency */
1464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define PWM_DEFAULT_PERIOD ((long)(1E9/100))
1474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
148e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Number of channels */
1494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define NUMCHANNELS       8
1504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
151e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Size of one A/D value */
1524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SIZEADIN          ((sizeof(int16_t)))
1534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1544274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman/*
1554274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman * Size of the input-buffer IN BYTES
1564274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman * Always multiple of 8 for 8 microframes which is needed in the highspeed mode
1574274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman */
1584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SIZEINBUF         ((8*SIZEADIN))
1594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
160e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* 16 bytes. */
1614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SIZEINSNBUF       16
1624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
163e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Number of DA channels */
1644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define NUMOUTCHANNELS    8
1654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
166e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* size of one value for the D/A converter: channel and value */
1674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SIZEDAOUT          ((sizeof(int8_t)+sizeof(int16_t)))
1684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
169e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
170e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * Size of the output-buffer in bytes
171e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * Actually only the first 4 triplets are used but for the
172e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * high speed mode we need to pad it to 8 (microframes).
173e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
1744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SIZEOUTBUF         ((8*SIZEDAOUT))
1754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
176e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
177e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * Size of the buffer for the dux commands: just now max size is determined
178e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * by the analogue out + command byte + panic bytes...
179e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
1804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SIZEOFDUXBUFFER    ((8*SIZEDAOUT+2))
1814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
182e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Number of in-URBs which receive the data: min=2 */
1834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define NUMOFINBUFFERSFULL     5
1844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
185e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Number of out-URBs which send the data: min=2 */
1864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define NUMOFOUTBUFFERSFULL    5
1874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
188e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Number of in-URBs which receive the data: min=5 */
189e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* must have more buffers due to buggy USB ctr */
190e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman#define NUMOFINBUFFERSHIGH     10
1914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
192e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Number of out-URBs which send the data: min=5 */
193e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* must have more buffers due to buggy USB ctr */
194e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman#define NUMOFOUTBUFFERSHIGH    10
1954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
196e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Total number of usbdux devices */
1974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define NUMUSBDUX             16
1984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
199e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Analogue in subdevice */
2004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SUBDEV_AD             0
2014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
202e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Analogue out subdevice */
2034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SUBDEV_DA             1
2044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
205e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Digital I/O */
2064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SUBDEV_DIO            2
2074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
208e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* counter */
2094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SUBDEV_COUNTER        3
2104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
211e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* timer aka pwm output */
2124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SUBDEV_PWM            4
2134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
214e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* number of retries to get the right dux command */
2154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define RETRIES 10
2164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
217e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/**************************************************/
218e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* comedi constants */
2199ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_usbdux_ai_range = { 4, {
2200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								BIP_RANGE
2210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								(4.096),
2220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								BIP_RANGE(4.096
2230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									  / 2),
2240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								UNI_RANGE
2250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								(4.096),
2260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								UNI_RANGE(4.096
2270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									  / 2)
2280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								}
2294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr};
2304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2319ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_usbdux_ao_range = { 2, {
2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								BIP_RANGE
2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								(4.096),
2340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								UNI_RANGE
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								(4.096),
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								}
2374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr};
2384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/*
2404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * private structure of one subdevice
2414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr */
2424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
243e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
244e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * This is the structure which holds all the data of
245e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * this driver one sub device just now: A/D
246e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
247cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstruct usbduxsub {
248e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* attached? */
2494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int attached;
250e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* is it associated with a subdevice? */
2514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int probed;
252e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* pointer to the usb-device */
2534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct usb_device *usbdev;
254e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* actual number of in-buffers */
2554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int numOfInBuffers;
256e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* actual number of out-buffers */
2574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int numOfOutBuffers;
258e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* ISO-transfer handling: buffers */
2594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct urb **urbIn;
2604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct urb **urbOut;
261e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* pwm-transfer handling */
2624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct urb *urbPwm;
263e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* PWM period */
264790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int pwmPeriod;
265e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* PWM internal delay for the GPIF in the FX2 */
2664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int8_t pwmDelay;
267e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* size of the PWM buffer which holds the bit pattern */
2684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int sizePwmBuf;
269e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* input buffer for the ISO-transfer */
2704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int16_t *inBuffer;
271e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* input buffer for single insn */
2724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int16_t *insnBuffer;
273e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* output buffer for single DA outputs */
2744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int16_t *outBuffer;
275e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* interface number */
2764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ifnum;
277e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* interface structure in 2.6 */
2784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct usb_interface *interface;
279e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* comedi device for the interrupt context */
28071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *comedidev;
281e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* is it USB_SPEED_HIGH or not? */
2824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	short int high_speed;
283e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* asynchronous command is running */
2844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	short int ai_cmd_running;
2854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	short int ao_cmd_running;
286e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* pwm is running */
2874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	short int pwm_cmd_running;
28825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* continous acquisition */
2894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	short int ai_continous;
2904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	short int ao_continous;
2919d220c6b54f3d0b141846321814ec1c4e4fbdc67Uwe Kleine-König	/* number of samples to acquire */
2924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ai_sample_count;
2934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ao_sample_count;
294e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* time between samples in units of the timer */
2954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int ai_timer;
2964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int ao_timer;
297e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* counter between aquisitions */
2984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int ai_counter;
2994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int ao_counter;
300e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* interval in frames/uframes */
3014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int ai_interval;
302e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* D/A commands */
3034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int8_t *dac_commands;
304e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* commands */
3054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int8_t *dux_commands;
3064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct semaphore sem;
307cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman};
3084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
309e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
310e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * The pointer to the private usb-data of the driver is also the private data
311e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * for the comedi-device.  This has to be global as the usb subsystem needs
312e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * global variables. The other reason is that this structure must be there
313e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * _before_ any comedi command is issued. The usb subsystem must be initialised
314e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * before comedi can access it.
315e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
316cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic struct usbduxsub usbduxsub[NUMUSBDUX];
3174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
31845f4d0243525b6bc747c946937ced437b135a84dThomas Gleixnerstatic DEFINE_SEMAPHORE(start_stop_sem);
3194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
320e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
321e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * Stops the data acquision
322e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * It should be safe to call this function from any context
323e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
324cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_unlink_InURBs(struct usbduxsub *usbduxsub_tmp)
3254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
3264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i = 0;
3274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err = 0;
3284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
3294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp && usbduxsub_tmp->urbIn) {
3304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
3314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (usbduxsub_tmp->urbIn[i]) {
332e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman				/* We wait here until all transfers have been
333e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman				 * cancelled. */
3344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				usb_kill_urb(usbduxsub_tmp->urbIn[i]);
3354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
336c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_dbg(&usbduxsub_tmp->interface->dev,
337c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi: usbdux: unlinked InURB %d, err=%d\n",
3384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				i, err);
3394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
3404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
3414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return err;
3424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
3434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
3448fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/*
3458fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman * This will stop a running acquisition operation
3468fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman * Is called from within this driver from both the
3478fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman * interrupt context and from comedi
3488fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman */
349cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
3504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
3514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret = 0;
3524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
3534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!this_usbduxsub) {
354c60e55f30a4dac15db51b398c3bd94e4cfbf743aJulia Lawall		pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
3554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
3564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
357c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n");
3584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
3594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (do_unlink) {
360e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* stop aquistion */
3614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_unlink_InURBs(this_usbduxsub);
3624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
3634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
3644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ai_cmd_running = 0;
3654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
3664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return ret;
3674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
3684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
369e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
370e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * This will cancel a running acquisition operation.
371e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * This is called by comedi but never from inside the driver.
372e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
3730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ai_cancel(struct comedi_device *dev,
3740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s)
3754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
376cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub;
3774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int res = 0;
3784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
379e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* force unlink of all urbs */
3804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub = dev->private;
381c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (!this_usbduxsub)
3824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
383c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
384c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n");
385c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
386e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* prevent other CPUs from submitting new commands just now */
3874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
3884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
3894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
3904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
3914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
392e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* unlink only if the urb really has been submitted */
3934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running);
3944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
3954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return res;
3964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
3974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
398e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* analogue IN - interrupt service routine */
3994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic void usbduxsub_ai_IsocIrq(struct urb *urb)
4004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
4014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, err, n;
402cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub;
40371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *this_comedidev;
40434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
4054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
406e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the context variable points to the subdevice */
4074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_comedidev = urb->context;
408cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	/* the private structure of the subdevice is struct usbduxsub */
4094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub = this_comedidev->private;
410e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* subdevice which is the AD converter */
4114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = this_comedidev->subdevices + SUBDEV_AD;
4124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
413e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* first we test if something unusual has just happened */
4144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	switch (urb->status) {
4154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case 0:
416e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* copy the result in the transfer buffer */
4174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		memcpy(this_usbduxsub->inBuffer,
4180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       urb->transfer_buffer, SIZEINBUF);
4194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
4204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -EILSEQ:
421e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* error in the ISOchronous data */
422e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* we don't copy the data into the transfer buffer */
423e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* and recycle the last data byte */
424c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&urb->dev->dev,
425c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: usbdux: CRC error in ISO IN stream.\n",
4264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->comedidev->minor);
4274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
4294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ECONNRESET:
4314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ENOENT:
4324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ESHUTDOWN:
4334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ECONNABORTED:
434e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* happens after an unlink command */
4354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->ai_cmd_running) {
436e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* we are still running a command */
437e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* tell this comedi */
4384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_EOA;
4394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_ERROR;
4404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
441e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* stop the transfer w/o unlink */
4424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_ai_stop(this_usbduxsub, 0);
4434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
4444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
4454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	default:
447e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* a real error on the bus */
448e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* pass error to comedi if we are really running a command */
4494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->ai_cmd_running) {
450c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&urb->dev->dev,
451c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"Non-zero urb status received in ai intr "
452c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"context: %d\n", urb->status);
4534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_EOA;
4544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_ERROR;
4554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
456e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* don't do an unlink here */
4574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_ai_stop(this_usbduxsub, 0);
4584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
4594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
4604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
4614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4624274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	/*
4634274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * at this point we are reasonably sure that nothing dodgy has happened
4644274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * are we running a command?
4654274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 */
4664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (unlikely((!(this_usbduxsub->ai_cmd_running)))) {
467e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/*
468e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		 * not running a command, do not continue execution if no
469e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		 * asynchronous command is running in particular not resubmit
470e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		 */
4714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
4724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
4734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->dev = this_usbduxsub->usbdev;
4754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4768fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* resubmit the urb */
4774aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman	err = usb_submit_urb(urb, GFP_ATOMIC);
4784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (unlikely(err < 0)) {
479c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&urb->dev->dev,
480c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi_: urb resubmit failed in int-context! err=%d\n",
481c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			err);
4828fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		if (err == -EL2NSYNC)
483c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&urb->dev->dev,
484c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"buggy USB host controller or bug in IRQ "
485c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"handler!\n");
4864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->events |= COMEDI_CB_EOA;
4874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->events |= COMEDI_CB_ERROR;
4884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		comedi_event(this_usbduxsub->comedidev, s);
4898fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* don't do an unlink here */
4904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbdux_ai_stop(this_usbduxsub, 0);
4914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
4924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
4934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
4944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ai_counter--;
4958fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (likely(this_usbduxsub->ai_counter > 0))
4964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
4978fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
498e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* timer zero, transfer measurements to comedi */
4994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
5004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
501e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* test, if we transmit only a fixed number of samples */
5024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->ai_continous)) {
50325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* not continuous, fixed number of samples */
5044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_sample_count--;
505e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* all samples received? */
5064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->ai_sample_count < 0) {
507e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* prevent a resubmit next time */
5084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_ai_stop(this_usbduxsub, 0);
509e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* say comedi that the acquistion is over */
5104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_EOA;
5114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
5124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return;
5134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
5144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
515e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* get the data from the USB bus and hand it over to comedi */
5164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	n = s->async->cmd.chanlist_len;
5174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < n; i++) {
518e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* transfer data */
5194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
520efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr			err = comedi_buf_put
5210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (s->async,
5220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     le16_to_cpu(this_usbduxsub->inBuffer[i]) ^ 0x800);
5234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		} else {
524efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr			err = comedi_buf_put
5250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (s->async,
5260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     le16_to_cpu(this_usbduxsub->inBuffer[i]));
527efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr		}
528efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr		if (unlikely(err == 0)) {
529efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr			/* buffer overflow */
530efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr			usbdux_ai_stop(this_usbduxsub, 0);
531efe8d60a923ddd00de394381cb30aab5114b71a4Bernd Porr			return;
5324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
5334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
534e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* tell comedi that data is there */
535d4c3a56587af3edbe5f618b20e800e9f9fde13cbBernd Porr	s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
5364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	comedi_event(this_usbduxsub->comedidev, s);
5374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
5384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
539cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_unlink_OutURBs(struct usbduxsub *usbduxsub_tmp)
5404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
5414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i = 0;
5424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err = 0;
5434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
5444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp && usbduxsub_tmp->urbOut) {
5454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
5468fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			if (usbduxsub_tmp->urbOut[i])
5474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				usb_kill_urb(usbduxsub_tmp->urbOut[i]);
5488fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
549c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_dbg(&usbduxsub_tmp->interface->dev,
550c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi: usbdux: unlinked OutURB %d: res=%d\n",
5514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				i, err);
5524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
5534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
5544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return err;
5554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
5564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
5574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/* This will cancel a running acquisition operation
5584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * in any context.
5594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr */
560cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
5614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
5624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret = 0;
5634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
564c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (!this_usbduxsub)
5654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
566c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n");
567c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
5688fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (do_unlink)
5694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_unlink_OutURBs(this_usbduxsub);
5704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
5714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ao_cmd_running = 0;
5724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
5734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return ret;
5744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
5754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
5768fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* force unlink, is called by comedi */
5770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ao_cancel(struct comedi_device *dev,
5780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s)
5794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
580cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
5814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int res = 0;
5824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
583c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (!this_usbduxsub)
5844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
585c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
586e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* prevent other CPUs from submitting a command just now */
5874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
5884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
5894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
5904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
5914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
592e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* unlink only if it is really running */
5934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running);
5944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
5954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return res;
5964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
5974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
5984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic void usbduxsub_ao_IsocIrq(struct urb *urb)
5994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
6004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, ret;
6014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int8_t *datap;
602cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub;
60371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *this_comedidev;
60434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
6054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
606e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the context variable points to the subdevice */
6074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_comedidev = urb->context;
608cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	/* the private structure of the subdevice is struct usbduxsub */
6094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub = this_comedidev->private;
6104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
6114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = this_comedidev->subdevices + SUBDEV_DA;
6124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
6134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	switch (urb->status) {
6144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case 0:
6154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* success */
6164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
6174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
6184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ECONNRESET:
6194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ENOENT:
6204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ESHUTDOWN:
6214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ECONNABORTED:
622e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* after an unlink command, unplug, ... etc */
623e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* no unlink needed here. Already shutting down. */
6244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->ao_cmd_running) {
6254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_EOA;
6264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
6274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_ao_stop(this_usbduxsub, 0);
6284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
6294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
6304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
6314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	default:
632e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* a real error */
6334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->ao_cmd_running) {
634c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&urb->dev->dev,
635c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi_: Non-zero urb status received in ao "
636c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"intr context: %d\n", urb->status);
6374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_ERROR;
6384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_EOA;
6394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
640e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* we do an unlink if we are in the high speed mode */
6414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_ao_stop(this_usbduxsub, 0);
6424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
6434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
6444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
6454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
646e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* are we actually running? */
6478fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!(this_usbduxsub->ao_cmd_running))
6484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
6498fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
650e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* normal operation: executing a command in this subdevice */
6514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ao_counter--;
6522503a26554c7e73c544fc97f47c1d41faa88bd07Vasiliy Kulikov	if ((int)this_usbduxsub->ao_counter <= 0) {
653e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* timer zero */
6544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
6554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
65625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* handle non continous acquisition */
6574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (!(this_usbduxsub->ao_continous)) {
658e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* fixed number of samples */
6594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ao_sample_count--;
6604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (this_usbduxsub->ao_sample_count < 0) {
661e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman				/* all samples transmitted */
6624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				usbdux_ao_stop(this_usbduxsub, 0);
6634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				s->async->events |= COMEDI_CB_EOA;
6644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				comedi_event(this_usbduxsub->comedidev, s);
665e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman				/* no resubmit of the urb */
6664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				return;
6674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
6684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
669e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* transmit data to the USB bus */
6704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		((uint8_t *) (urb->transfer_buffer))[0] =
6710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    s->async->cmd.chanlist_len;
6724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		for (i = 0; i < s->async->cmd.chanlist_len; i++) {
673790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton			short temp;
6748fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			if (i >= NUMOUTCHANNELS)
6754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				break;
6768fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
677e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* pointer to the DA */
6784274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			datap =
6790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
680e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* get the data from comedi */
6814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			ret = comedi_buf_get(s->async, &temp);
6824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			datap[0] = temp;
6834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			datap[1] = temp >> 8;
6844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			datap[2] = this_usbduxsub->dac_commands[i];
685e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* printk("data[0]=%x, data[1]=%x, data[2]=%x\n", */
686e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* datap[0],datap[1],datap[2]); */
6874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (ret < 0) {
688c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				dev_err(&urb->dev->dev,
689c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman					"comedi: buffer underflow\n");
6904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				s->async->events |= COMEDI_CB_EOA;
6914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				s->async->events |= COMEDI_CB_OVERFLOW;
6924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
693e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* transmit data to comedi */
6944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_BLOCK;
6954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
6964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
6974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
6984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->transfer_buffer_length = SIZEOUTBUF;
6994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->dev = this_usbduxsub->usbdev;
7004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->status = 0;
7014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->ao_cmd_running) {
7024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->high_speed) {
703e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* uframes */
7044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			urb->interval = 8;
7054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		} else {
706e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* frames */
7074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			urb->interval = 1;
7084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
7094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		urb->number_of_packets = 1;
7104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		urb->iso_frame_desc[0].offset = 0;
7114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		urb->iso_frame_desc[0].length = SIZEOUTBUF;
7124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		urb->iso_frame_desc[0].status = 0;
7134aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		ret = usb_submit_urb(urb, GFP_ATOMIC);
7144274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		if (ret < 0) {
715c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&urb->dev->dev,
716c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi_: ao urb resubm failed in int-cont. "
717c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"ret=%d", ret);
7188fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			if (ret == EL2NSYNC)
719c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				dev_err(&urb->dev->dev,
720c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman					"buggy USB host controller or bug in "
721c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman					"IRQ handling!\n");
7228fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
7234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_EOA;
7244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			s->async->events |= COMEDI_CB_ERROR;
7254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			comedi_event(this_usbduxsub->comedidev, s);
726e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* don't do an unlink here */
7274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_ao_stop(this_usbduxsub, 0);
7284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
7294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
7304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
7314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
732cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_start(struct usbduxsub *usbduxsub)
7334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
7344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int errcode = 0;
7354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	uint8_t local_transfer_buffer[16];
7364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
7376742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	/* 7f92 to zero */
7386742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	local_transfer_buffer[0] = 0;
7396742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	errcode = usb_control_msg(usbduxsub->usbdev,
7406742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* create a pipe for a control transfer */
7416742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  usb_sndctrlpipe(usbduxsub->usbdev, 0),
7426742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* bRequest, "Firmware" */
7436742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  USBDUXSUB_FIRMWARE,
7446742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* bmRequestType */
7456742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  VENDOR_DIR_OUT,
7466742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Value */
7476742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  USBDUXSUB_CPUCS,
7486742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Index */
7496742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  0x0000,
7506742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* address of the transfer buffer */
7516742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  local_transfer_buffer,
7526742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Length */
7536742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  1,
7546742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Timeout */
755ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr				  BULK_TIMEOUT);
7566742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	if (errcode < 0) {
7576742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		dev_err(&usbduxsub->interface->dev,
7586742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr			"comedi_: control msg failed (start)\n");
7596742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		return errcode;
7604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
7614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
7624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
7634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
764cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_stop(struct usbduxsub *usbduxsub)
7654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
7664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int errcode = 0;
7674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
7684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	uint8_t local_transfer_buffer[16];
7696742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
7706742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	/* 7f92 to one */
7716742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	local_transfer_buffer[0] = 1;
7726742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	errcode = usb_control_msg(usbduxsub->usbdev,
7736742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  usb_sndctrlpipe(usbduxsub->usbdev, 0),
7746742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* bRequest, "Firmware" */
7756742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  USBDUXSUB_FIRMWARE,
7766742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* bmRequestType */
7776742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  VENDOR_DIR_OUT,
7786742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Value */
7796742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  USBDUXSUB_CPUCS,
7806742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Index */
7816742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  0x0000, local_transfer_buffer,
7826742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Length */
7836742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  1,
7846742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				  /* Timeout */
785ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr				  BULK_TIMEOUT);
7866742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	if (errcode < 0) {
7876742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		dev_err(&usbduxsub->interface->dev,
7886742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr			"comedi_: control msg failed (stop)\n");
7896742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		return errcode;
7904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
7914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
7924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
7934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
794cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_upload(struct usbduxsub *usbduxsub,
79594c1f90bb0bac8c2b75569a247b89145022c4c24Morgan Gatti			    uint8_t *local_transfer_buffer,
7968fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			    unsigned int startAddr, unsigned int len)
7974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
7984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int errcode;
7994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
8006742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	errcode = usb_control_msg(usbduxsub->usbdev,
8010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  usb_sndctrlpipe(usbduxsub->usbdev, 0),
8020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* brequest, firmware */
8030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  USBDUXSUB_FIRMWARE,
8040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* bmRequestType */
8050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  VENDOR_DIR_OUT,
8060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* value */
8070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  startAddr,
8080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* index */
8090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  0x0000,
8100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* our local safe buffer */
8110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  local_transfer_buffer,
8120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* length */
8130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  len,
8140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  /* timeout */
815ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr				  BULK_TIMEOUT);
8160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	dev_dbg(&usbduxsub->interface->dev, "comedi_: result=%d\n", errcode);
8176742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	if (errcode < 0) {
8180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		dev_err(&usbduxsub->interface->dev, "comedi_: upload failed\n");
8196742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		return errcode;
8204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
8214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
8224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
8234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
82481874ff7895f332920621104308e803434a17183Bernd Porr#define FIRMWARE_MAX_LEN 0x2000
82581874ff7895f332920621104308e803434a17183Bernd Porr
82681874ff7895f332920621104308e803434a17183Bernd Porrstatic int firmwareUpload(struct usbduxsub *usbduxsub,
82794c1f90bb0bac8c2b75569a247b89145022c4c24Morgan Gatti			  const u8 *firmwareBinary, int sizeFirmware)
8284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
8294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret;
83081874ff7895f332920621104308e803434a17183Bernd Porr	uint8_t *fwBuf;
8314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
8324274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (!firmwareBinary)
8334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
8344274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
8350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (sizeFirmware > FIRMWARE_MAX_LEN) {
83681874ff7895f332920621104308e803434a17183Bernd Porr		dev_err(&usbduxsub->interface->dev,
83794c1f90bb0bac8c2b75569a247b89145022c4c24Morgan Gatti			"usbdux firmware binary it too large for FX2.\n");
83881874ff7895f332920621104308e803434a17183Bernd Porr		return -ENOMEM;
83981874ff7895f332920621104308e803434a17183Bernd Porr	}
84081874ff7895f332920621104308e803434a17183Bernd Porr
84181874ff7895f332920621104308e803434a17183Bernd Porr	/* we generate a local buffer for the firmware */
84294002c07ff0e207a883519ccc35c0b5390b29331Julia Lawall	fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL);
84381874ff7895f332920621104308e803434a17183Bernd Porr	if (!fwBuf) {
84481874ff7895f332920621104308e803434a17183Bernd Porr		dev_err(&usbduxsub->interface->dev,
84581874ff7895f332920621104308e803434a17183Bernd Porr			"comedi_: mem alloc for firmware failed\n");
84681874ff7895f332920621104308e803434a17183Bernd Porr		return -ENOMEM;
84781874ff7895f332920621104308e803434a17183Bernd Porr	}
84881874ff7895f332920621104308e803434a17183Bernd Porr
8494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	ret = usbduxsub_stop(usbduxsub);
8504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (ret < 0) {
851c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&usbduxsub->interface->dev,
852c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi_: can not stop firmware\n");
85381874ff7895f332920621104308e803434a17183Bernd Porr		kfree(fwBuf);
8544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return ret;
8554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
85681874ff7895f332920621104308e803434a17183Bernd Porr
85781874ff7895f332920621104308e803434a17183Bernd Porr	ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware);
8584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (ret < 0) {
859c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&usbduxsub->interface->dev,
860c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi_: firmware upload failed\n");
86181874ff7895f332920621104308e803434a17183Bernd Porr		kfree(fwBuf);
8624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return ret;
8634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
8644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	ret = usbduxsub_start(usbduxsub);
8654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (ret < 0) {
866c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&usbduxsub->interface->dev,
867c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi_: can not start firmware\n");
86881874ff7895f332920621104308e803434a17183Bernd Porr		kfree(fwBuf);
8694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return ret;
8704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
87181874ff7895f332920621104308e803434a17183Bernd Porr	kfree(fwBuf);
8724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
8734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
8744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
875cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_submit_InURBs(struct usbduxsub *usbduxsub)
8764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
8774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, errFlag;
8784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
8798fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!usbduxsub)
8804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
8818fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
8824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* Submit all URBs and start the transfer on the bus */
8834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < usbduxsub->numOfInBuffers; i++) {
8848fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* in case of a resubmission after an unlink... */
8854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbIn[i]->interval = usbduxsub->ai_interval;
8864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbIn[i]->context = usbduxsub->comedidev;
8874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbIn[i]->dev = usbduxsub->usbdev;
8884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbIn[i]->status = 0;
8894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbIn[i]->transfer_flags = URB_ISO_ASAP;
890c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&usbduxsub->interface->dev,
891c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n",
892c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			usbduxsub->comedidev->minor, i,
893c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			(usbduxsub->urbIn[i]->context),
894c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			(usbduxsub->urbIn[i]->dev),
895c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			(usbduxsub->urbIn[i]->interval));
8964aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		errFlag = usb_submit_urb(usbduxsub->urbIn[i], GFP_ATOMIC);
8974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (errFlag) {
898c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&usbduxsub->interface->dev,
8994aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman				"comedi_: ai: usb_submit_urb(%d) error %d\n",
900c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				i, errFlag);
9014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return errFlag;
9024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
9034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
9044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
9054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
9064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
907cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub)
9084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
9094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, errFlag;
9104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
9114274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (!usbduxsub)
9124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
9134274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
9144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < usbduxsub->numOfOutBuffers; i++) {
915c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&usbduxsub->interface->dev,
916c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi_: submitting out-urb[%d]\n", i);
917e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* in case of a resubmission after an unlink... */
9184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbOut[i]->context = usbduxsub->comedidev;
9194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbOut[i]->dev = usbduxsub->usbdev;
9204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbOut[i]->status = 0;
9214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub->urbOut[i]->transfer_flags = URB_ISO_ASAP;
9224aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		errFlag = usb_submit_urb(usbduxsub->urbOut[i], GFP_ATOMIC);
9234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (errFlag) {
924c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&usbduxsub->interface->dev,
9254aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman				"comedi_: ao: usb_submit_urb(%d) error %d\n",
926c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				i, errFlag);
9274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return errFlag;
9284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
9294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
9304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
9314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
9324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
9330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ai_cmdtest(struct comedi_device *dev,
9340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
9354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
9364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err = 0, tmp, i;
9374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int tmpTimer;
938cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
9394274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
9404274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (!(this_usbduxsub->probed))
9414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
9424274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
943c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
944c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: usbdux_ai_cmdtest\n", dev->minor);
945c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
9464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* make sure triggers are valid */
947e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* Only immediate triggers are allowed */
9484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->start_src;
9494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->start_src &= TRIG_NOW | TRIG_INT;
9504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->start_src || tmp != cmd->start_src)
9514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
953e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* trigger should happen timed */
9544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->scan_begin_src;
955e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* start a new _scan_ with a timer */
9564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->scan_begin_src &= TRIG_TIMER;
9574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
9584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
96025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* scanning is continuous */
9614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->convert_src;
9624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->convert_src &= TRIG_NOW;
9634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->convert_src || tmp != cmd->convert_src)
9644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
966e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* issue a trigger when scan is finished and start a new scan */
9674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->scan_end_src;
9684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->scan_end_src &= TRIG_COUNT;
9694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
9704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
972e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* trigger at the end of count events or not, stop condition or not */
9734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->stop_src;
9744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
9754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->stop_src || tmp != cmd->stop_src)
9764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
9784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (err)
9794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 1;
9804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
9814274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	/*
9824274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * step 2: make sure trigger sources are unique and mutually compatible
983828684f9a6e096f9150bad523c43b75d74b9baddDirk Hohndel	 * note that mutual compatibility is not an issue here
9844274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 */
9854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_begin_src != TRIG_FOLLOW &&
9860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_EXT &&
9870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_TIMER)
9884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
9904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
9924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (err)
9934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 2;
9944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
9954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* step 3: make sure arguments are trivially compatible */
9964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->start_arg != 0) {
9974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->start_arg = 0;
9984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
9994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
10004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
10014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_begin_src == TRIG_FOLLOW) {
10024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* internal trigger */
10034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (cmd->scan_begin_arg != 0) {
10044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			cmd->scan_begin_arg = 0;
10054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			err++;
10064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
10074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
10084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
10094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_begin_src == TRIG_TIMER) {
10104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->high_speed) {
1011e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/*
1012e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			 * In high speed mode microframes are possible.
1013e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			 * However, during one microframe we can roughly
1014e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			 * sample one channel. Thus, the more channels
1015e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			 * are in the channel list the more time we need.
1016e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			 */
10174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			i = 1;
1018e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* find a power of 2 for the number of channels */
10194274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			while (i < (cmd->chanlist_len))
10204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				i = i * 2;
10214274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
10224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (cmd->scan_begin_arg < (1000000 / 8 * i)) {
10234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				cmd->scan_begin_arg = 1000000 / 8 * i;
10244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				err++;
10254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
1026e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* now calc the real sampling rate with all the
1027e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			 * rounding errors */
10284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tmpTimer =
10290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    ((unsigned int)(cmd->scan_begin_arg / 125000)) *
10300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    125000;
10314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (cmd->scan_begin_arg != tmpTimer) {
10324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				cmd->scan_begin_arg = tmpTimer;
10334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				err++;
10344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
1035e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		} else {
1036e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* full speed */
1037e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* 1kHz scans every USB frame */
10384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (cmd->scan_begin_arg < 1000000) {
10394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				cmd->scan_begin_arg = 1000000;
10404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				err++;
10414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
10424274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			/*
10434274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			 * calc the real sampling rate with the rounding errors
10444274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			 */
10454274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			tmpTimer = ((unsigned int)(cmd->scan_begin_arg /
10460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						   1000000)) * 1000000;
10474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (cmd->scan_begin_arg != tmpTimer) {
10484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				cmd->scan_begin_arg = tmpTimer;
10494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				err++;
10504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
10514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
10524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
1053e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the same argument */
10544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_end_arg != cmd->chanlist_len) {
10554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->scan_end_arg = cmd->chanlist_len;
10564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
10574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
10584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
10594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->stop_src == TRIG_COUNT) {
10604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* any count is allowed */
10614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
10624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* TRIG_NONE */
10634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (cmd->stop_arg != 0) {
10644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			cmd->stop_arg = 0;
10654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			err++;
10664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
10674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
10684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
10694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (err)
10704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 3;
10714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
10724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
10734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
10744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1075e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/*
1076e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * creates the ADC command for the MAX1271
1077e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman * range is the range value from comedi
1078e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman */
10794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic int8_t create_adc_command(unsigned int chan, int range)
10804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
10814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int8_t p = (range <= 1);
10824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int8_t r = ((range % 2) == 0);
10834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
10844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
10854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1086e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* bulk transfers to usbdux */
10874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
10884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDADCOMMANDS            0
10894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDDACOMMANDS            1
10904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDDIOCONFIGCOMMAND      2
10914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDDIOBITSCOMMAND        3
10924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDSINGLEAD              4
10934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define READCOUNTERCOMMAND        5
10944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define WRITECOUNTERCOMMAND       6
10954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDPWMON                 7
10964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#define SENDPWMOFF                8
10974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1098cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type)
10994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
11004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int result, nsent;
11014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
11024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[0] = cmd_type;
11034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#ifdef NOISY_DUX_DEBUGBUG
1104c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ",
11050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       this_usbduxsub->comedidev->minor);
11064274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	for (result = 0; result < SIZEOFDUXBUFFER; result++)
11074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		printk(" %02x", this_usbduxsub->dux_commands[result]);
11084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	printk("\n");
11094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr#endif
11104aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman	result = usb_bulk_msg(this_usbduxsub->usbdev,
11114aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			      usb_sndbulkpipe(this_usbduxsub->usbdev,
11124aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman					      COMMAND_OUT_EP),
11134aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			      this_usbduxsub->dux_commands, SIZEOFDUXBUFFER,
1114ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr			      &nsent, BULK_TIMEOUT);
11158fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (result < 0)
1116c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1117c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"could not transmit dux_command to the usb-device, "
1118c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"err=%d\n", this_usbduxsub->comedidev->minor, result);
11198fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
11204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return result;
11214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
11224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1123cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
11244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
11254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int result = (-EFAULT);
11264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int nrec;
11274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i;
11284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
11294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < RETRIES; i++) {
11304aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		result = usb_bulk_msg(this_usbduxsub->usbdev,
11314aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman				      usb_rcvbulkpipe(this_usbduxsub->usbdev,
11324aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman						      COMMAND_IN_EP),
11334aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman				      this_usbduxsub->insnBuffer, SIZEINSNBUF,
1134ea25371a78c33e276527361d3ab19393d558b2fdBernd Porr				      &nrec, BULK_TIMEOUT);
11354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (result < 0) {
1136c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1137c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"insn: USB error %d while receiving DUX command"
1138c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"\n", this_usbduxsub->comedidev->minor, result);
11394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return result;
11404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
11414274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		if (le16_to_cpu(this_usbduxsub->insnBuffer[0]) == command)
11424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return result;
11434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
11444274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	/* this is only reached if the data has been requested a couple of
11454274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * times */
1146c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: "
1147c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"wrong data returned from firmware: want cmd %d, got cmd %d.\n",
1148c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		this_usbduxsub->comedidev->minor, command,
1149c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		le16_to_cpu(this_usbduxsub->insnBuffer[0]));
11504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return -EFAULT;
11514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
11524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
11530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ai_inttrig(struct comedi_device *dev,
11540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, unsigned int trignum)
11554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
11564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret;
1157cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
11584274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (!this_usbduxsub)
11594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
11604274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
11614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
11624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
11634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
11644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
11654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
1166c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1167c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: usbdux_ai_inttrig\n", dev->minor);
11684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
11694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (trignum != 0) {
1170c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
1171c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: usbdux_ai_inttrig: invalid trignum\n",
11724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor);
11734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
11744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
11754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
11764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->ai_cmd_running)) {
11774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_cmd_running = 1;
11784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_submit_InURBs(this_usbduxsub);
11794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (ret < 0) {
1180c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1181c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi%d: usbdux_ai_inttrig: "
1182c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"urbSubmit: err=%d\n", dev->minor, ret);
11834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ai_cmd_running = 0;
11844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
11854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return ret;
11864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
11874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->inttrig = NULL;
11884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
1189c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
1190c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: ai_inttrig but acqu is already running\n",
11914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor);
11924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
11934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
11944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 1;
11954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
11964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
119734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
11984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
1199ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
12004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int chan, range;
12014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, ret;
1202cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
12034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int result;
12044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
12058fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
12064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
12078fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
1208c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1209c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: usbdux_ai_cmd\n", dev->minor);
1210c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
12118fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* block other CPUs from starting an ai_cmd */
12124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
12134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
12144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
12154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
12164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
12174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
12184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->ai_cmd_running) {
1219c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1220c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"ai_cmd not possible. Another ai_cmd is running.\n",
1221c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev->minor);
12224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
12234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EBUSY;
12244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
122525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* set current channel of the running acquisition to zero */
12264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->async->cur_chan = 0;
12274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
12284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
12294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < cmd->chanlist_len; ++i) {
12304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		chan = CR_CHAN(cmd->chanlist[i]);
12314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		range = CR_RANGE(cmd->chanlist[i]);
12324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (i >= NUMCHANNELS) {
1233c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1234c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi%d: channel list too long\n",
1235c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				dev->minor);
12364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			break;
12374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
12384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->dux_commands[i + 2] =
12390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    create_adc_command(chan, range);
12404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
12414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1242c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1243c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi %d: sending commands to the usb device: size=%u\n",
1244c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev->minor, NUMCHANNELS);
1245c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
12464274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS);
12474274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (result < 0) {
12484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
12494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return result;
12504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
12514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
12524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->high_speed) {
12538fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/*
12548fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * every channel gets a time window of 125us. Thus, if we
12558fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * sample all 8 channels we need 1ms. If we sample only one
12568fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * channel we need only 125us
12578fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 */
12584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_interval = 1;
12598fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* find a power of 2 for the interval */
12604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
12614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ai_interval =
12620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (this_usbduxsub->ai_interval) * 2;
12634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
12648fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 *
126594c1f90bb0bac8c2b75569a247b89145022c4c24Morgan Gatti							  (this_usbduxsub->
126694c1f90bb0bac8c2b75569a247b89145022c4c24Morgan Gatti							   ai_interval));
12674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
12688fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* interval always 1ms */
12694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_interval = 1;
12704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
12714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
12724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->ai_timer < 1) {
1273c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: "
1274c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"timer=%d, scan_begin_arg=%d. "
1275c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"Not properly tested by cmdtest?\n", dev->minor,
1276c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			this_usbduxsub->ai_timer, cmd->scan_begin_arg);
12774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
12784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
12794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
12804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
12814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
12824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->stop_src == TRIG_COUNT) {
1283e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* data arrives as one packet */
12844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_sample_count = cmd->stop_arg;
12854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_continous = 0;
12864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
128725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* continous acquisition */
12884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_continous = 1;
12894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_sample_count = 0;
12904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
12914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
12924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->start_src == TRIG_NOW) {
1293e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* enable this acquisition operation */
12944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ai_cmd_running = 1;
12954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_submit_InURBs(this_usbduxsub);
12964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (ret < 0) {
12974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ai_cmd_running = 0;
1298e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* fixme: unlink here?? */
12994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
13004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return ret;
13014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
13024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->inttrig = NULL;
13034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
13044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* TRIG_INT */
1305e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* don't enable the acquision operation */
1306e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* wait for an internal signal */
13074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->inttrig = usbdux_ai_inttrig;
13084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
13094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
13104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
13114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
13124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
13134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/* Mode 0 is used to get a single conversion on demand */
13140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ai_insn_read(struct comedi_device *dev,
13150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
131690035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			       struct comedi_insn *insn, unsigned int *data)
13174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
13184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i;
1319790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int one = 0;
13204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int chan, range;
13214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err;
1322cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
13234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1324c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (!this_usbduxsub)
13254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
1326c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
1327c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1328c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
13294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		dev->minor, insn->n, insn->subdev);
1330c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
13314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
13324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
13334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
13344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
13354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
13364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->ai_cmd_running) {
1337c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
1338c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: ai_insn_read not possible. "
1339c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"Async Command is running.\n", dev->minor);
13404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
13414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
13424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
13434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1344e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* sample one channel */
13454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	chan = CR_CHAN(insn->chanspec);
13464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	range = CR_RANGE(insn->chanspec);
1347e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* set command for the first channel */
13484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
13494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1350e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* adc commands */
13514274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	err = send_dux_commands(this_usbduxsub, SENDSINGLEAD);
13524274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (err < 0) {
13534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
13544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return err;
13554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
13564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
13574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < insn->n; i++) {
13584274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD);
13594274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		if (err < 0) {
13604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
13614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return 0;
13624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
13634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		one = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
13648fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		if (CR_RANGE(insn->chanspec) <= 1)
13654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			one = one ^ 0x800;
13668fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
13674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		data[i] = one;
13684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
13694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
13704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return i;
13714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
13724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1373e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/************************************/
1374e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* analog out */
13754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
13760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ao_insn_read(struct comedi_device *dev,
13770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
137890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			       struct comedi_insn *insn, unsigned int *data)
13794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
13804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i;
13814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int chan = CR_CHAN(insn->chanspec);
1382cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
13834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
13848fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
13854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
13868fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
13874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
13884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
13894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
13904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
13914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
13928fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	for (i = 0; i < insn->n; i++)
13934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		data[i] = this_usbduxsub->outBuffer[chan];
13948fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
13954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
13964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return i;
13974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
13984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
13990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ao_insn_write(struct comedi_device *dev,
14000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
140190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton				struct comedi_insn *insn, unsigned int *data)
14024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
14034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, err;
14044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int chan = CR_CHAN(insn->chanspec);
1405cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
14064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14078fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
14084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
14098fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
1410c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1411c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: ao_insn_write\n", dev->minor);
1412c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
14134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
14144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
14154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
14164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
14174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
14184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->ao_cmd_running) {
1419c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
1420c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: ao_insn_write: "
1421c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"ERROR: asynchronous ao_cmd is running\n", dev->minor);
14224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
14234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
14244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
14254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < insn->n; i++) {
1427c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
1428c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",
14294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor, chan, i, data[i]);
1430c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
1431e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* number of channels: 1 */
14324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->dux_commands[1] = 1;
1433e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* one 16 bit value */
14344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		*((int16_t *) (this_usbduxsub->dux_commands + 2)) =
14350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    cpu_to_le16(data[i]);
14364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->outBuffer[chan] = data[i];
1437e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* channel number */
14384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->dux_commands[4] = (chan << 6);
14394274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS);
14404274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		if (err < 0) {
14414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
14424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return err;
14434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
14444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
14454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
14464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return i;
14484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
14494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ao_inttrig(struct comedi_device *dev,
14510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, unsigned int trignum)
14524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
14534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret;
1454cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
14554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14568fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
14574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
14588fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
14594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
14604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
14614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
14624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
14634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
14644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (trignum != 0) {
1465c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
1466c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: usbdux_ao_inttrig: invalid trignum\n",
14674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor);
146885678d5d27cb0ea1005316f51b1b062bf4609b66Dan Carpenter		up(&this_usbduxsub->sem);
14694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
14704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
14714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->ao_cmd_running)) {
14724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_cmd_running = 1;
14734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_submit_OutURBs(this_usbduxsub);
14744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (ret < 0) {
1475c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1476c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi%d: usbdux_ao_inttrig: submitURB: "
1477c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"err=%d\n", dev->minor, ret);
14784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ao_cmd_running = 0;
14794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
14804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return ret;
14814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
14824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->inttrig = NULL;
14834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
1484c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
1485c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: ao_inttrig but acqu is already running.\n",
14864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor);
14874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
14884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
14894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 1;
14904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
14914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_ao_cmdtest(struct comedi_device *dev,
14930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
14944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
14954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err = 0, tmp;
1496cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
14974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
14988fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
14994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
15008fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
15018fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!(this_usbduxsub->probed))
15024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
15038fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
1504c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1505c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: usbdux_ao_cmdtest\n", dev->minor);
1506c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
15074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* make sure triggers are valid */
1508e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* Only immediate triggers are allowed */
15094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->start_src;
15104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->start_src &= TRIG_NOW | TRIG_INT;
15114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->start_src || tmp != cmd->start_src)
15124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1514e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* trigger should happen timed */
15154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->scan_begin_src;
1516e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* just now we scan also in the high speed mode every frame */
1517e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* this is due to ehci driver limitations */
15184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (0) {		/* (this_usbduxsub->high_speed) */
151925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* start immediately a new scan */
1520e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* the sampling rate is set by the coversion rate */
15214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->scan_begin_src &= TRIG_FOLLOW;
15224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
1523e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* start a new scan (output at once) with a timer */
15244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->scan_begin_src &= TRIG_TIMER;
15254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
15264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
15274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
152925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* scanning is continuous */
15304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->convert_src;
1531e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* we always output at 1kHz just now all channels at once */
15324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (0) {		/* (this_usbduxsub->high_speed) */
15334274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		/*
15348452c3ef79f9095eef0fa2978fc97afb13507254Weiping Pan(潘卫平)		 * in usb-2.0 only one conversion it transmitted but with 8kHz/n
15354274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		 */
15364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->convert_src &= TRIG_TIMER;
15374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
15384274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		/* all conversion events happen simultaneously with a rate of
15394274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		 * 1kHz/n */
15404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->convert_src &= TRIG_NOW;
15414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
15424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->convert_src || tmp != cmd->convert_src)
15434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1545e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* issue a trigger when scan is finished and start a new scan */
15464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->scan_end_src;
15474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->scan_end_src &= TRIG_COUNT;
15484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
15494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1551e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* trigger at the end of count events or not, stop condition or not */
15524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tmp = cmd->stop_src;
15534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
15544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!cmd->stop_src || tmp != cmd->stop_src)
15554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (err)
15584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 1;
15594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15604274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	/*
15614274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * step 2: make sure trigger sources are unique and mutually compatible
1562828684f9a6e096f9150bad523c43b75d74b9baddDirk Hohndel	 * note that mutual compatibility is not an issue here
15634274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 */
15644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_begin_src != TRIG_FOLLOW &&
15650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_EXT &&
15660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_TIMER)
15674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
15694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (err)
15724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 2;
15734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* step 3: make sure arguments are trivially compatible */
15754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->start_arg != 0) {
15774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->start_arg = 0;
15784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
15794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
15804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_begin_src == TRIG_FOLLOW) {
15824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* internal trigger */
15834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (cmd->scan_begin_arg != 0) {
15844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			cmd->scan_begin_arg = 0;
15854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			err++;
15864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
15874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
15884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
15894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_begin_src == TRIG_TIMER) {
15904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* timer */
15914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (cmd->scan_begin_arg < 1000000) {
15924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			cmd->scan_begin_arg = 1000000;
15934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			err++;
15944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
15954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
1596e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* not used now, is for later use */
15974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->convert_src == TRIG_TIMER) {
15984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (cmd->convert_arg < 125000) {
15994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			cmd->convert_arg = 125000;
16004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			err++;
16014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
16024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
16034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1604e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the same argument */
16054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->scan_end_arg != cmd->chanlist_len) {
16064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		cmd->scan_end_arg = cmd->chanlist_len;
16074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		err++;
16084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
16094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
16104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->stop_src == TRIG_COUNT) {
16114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* any count is allowed */
16124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
16134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* TRIG_NONE */
16144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (cmd->stop_arg != 0) {
16154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			cmd->stop_arg = 0;
16164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			err++;
16174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
16184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
16194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1620c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: err=%d, "
1621c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"scan_begin_src=%d, scan_begin_arg=%d, convert_src=%d, "
1622c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"convert_arg=%d\n", dev->minor, err, cmd->scan_begin_src,
1623c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		cmd->scan_begin_arg, cmd->convert_src, cmd->convert_arg);
16244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
16254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (err)
16264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 3;
16274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
16284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
16294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
16304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
163134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
16324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
1633ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
16344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	unsigned int chan, gain;
16354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, ret;
1636cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
16374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
16388fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
16394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
16408fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
16414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
16424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
16434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
16444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
16454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
1646c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1647c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: %s\n", dev->minor, __func__);
16484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
164925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* set current channel of the running acquisition to zero */
16504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->async->cur_chan = 0;
16514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < cmd->chanlist_len; ++i) {
16524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		chan = CR_CHAN(cmd->chanlist[i]);
16534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		gain = CR_RANGE(cmd->chanlist[i]);
16544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (i >= NUMOUTCHANNELS) {
1655c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1656c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi%d: %s: channel list too long\n",
1657c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				dev->minor, __func__);
16584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			break;
16594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
16604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->dac_commands[i] = (chan << 6);
1661c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
1662c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: dac command for ch %d is %x\n",
16634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor, i, this_usbduxsub->dac_commands[i]);
16644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
16654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1666e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* we count in steps of 1ms (125us) */
1667e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* 125us mode not used yet */
16684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (0) {		/* (this_usbduxsub->high_speed) */
1669e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* 125us */
1670e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* timing of the conversion itself: every 125 us */
16714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
16724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
1673e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* 1ms */
1674e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* timing of the scan: we get all channels at once */
16754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000;
1676c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
1677c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: scan_begin_src=%d, scan_begin_arg=%d, "
1678c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"convert_src=%d, convert_arg=%d\n", dev->minor,
1679c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			cmd->scan_begin_src, cmd->scan_begin_arg,
1680c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			cmd->convert_src, cmd->convert_arg);
1681c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
1682c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: ao_timer=%d (ms)\n",
16834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			dev->minor, this_usbduxsub->ao_timer);
16844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->ao_timer < 1) {
1685c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1686c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi%d: usbdux: ao_timer=%d, "
1687c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"scan_begin_arg=%d. "
1688c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"Not properly tested by cmdtest?\n",
1689c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				dev->minor, this_usbduxsub->ao_timer,
1690c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				cmd->scan_begin_arg);
16914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
16924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return -EINVAL;
16934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
16944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
16954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
16964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
16974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->stop_src == TRIG_COUNT) {
169825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* not continuous */
1699e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* counter */
1700e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* high speed also scans everything at once */
17014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (0) {	/* (this_usbduxsub->high_speed) */
17024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ao_sample_count =
17030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    (cmd->stop_arg) * (cmd->scan_end_arg);
17044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		} else {
1705e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* there's no scan as the scan has been */
1706e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* perf inside the FX2 */
1707e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* data arrives as one packet */
17084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ao_sample_count = cmd->stop_arg;
17094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
17104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_continous = 0;
17114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
171225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* continous acquisition */
17134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_continous = 1;
17144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_sample_count = 0;
17154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
17164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (cmd->start_src == TRIG_NOW) {
1718e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* enable this acquisition operation */
17194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->ao_cmd_running = 1;
17204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_submit_OutURBs(this_usbduxsub);
17214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (ret < 0) {
17224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			this_usbduxsub->ao_cmd_running = 0;
1723e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* fixme: unlink here?? */
17244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&this_usbduxsub->sem);
17254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return ret;
17264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
17274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->inttrig = NULL;
17284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
17294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* TRIG_INT */
1730e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* submit the urbs later */
1731e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* wait for an internal signal */
17324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->async->inttrig = usbdux_ao_inttrig;
17334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
17344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
17364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
17374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
17384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_dio_insn_config(struct comedi_device *dev,
17400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
174190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton				  struct comedi_insn *insn, unsigned int *data)
17424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
17434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int chan = CR_CHAN(insn->chanspec);
17444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* The input or output configuration of each digital line is
17464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	 * configured by a special insn_config instruction.  chanspec
17474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	 * contains the channel to be changed, and data[0] contains the
17484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
17494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	switch (data[0]) {
17514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_DIO_OUTPUT:
17524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->io_bits |= 1 << chan;	/* 1 means Out */
17534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
17544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_DIO_INPUT:
17554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->io_bits &= ~(1 << chan);
17564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
17574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_DIO_QUERY:
17584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		data[1] =
17590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
17604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
17614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	default:
17624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
17634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
17644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
1765e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* we don't tell the firmware here as it would take 8 frames */
1766e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* to submit the information. We do it in the insn_bits. */
17674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return insn->n;
17684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
17694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_dio_insn_bits(struct comedi_device *dev,
17710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
177290035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton				struct comedi_insn *insn, unsigned int *data)
17734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
17744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1775cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
17764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err;
17774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17788fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
17794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
17808fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
17814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (insn->n != 2)
17824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
17834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
17854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
17874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
17884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
17894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
17904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
17914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* The insn data is a mask in data[0] and the new data
17924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	 * in data[1], each channel cooresponding to a bit. */
17934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->state &= ~data[0];
17944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->state |= data[0] & data[1];
17954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[1] = s->io_bits;
17964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[2] = s->state;
17974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1798e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* This command also tells the firmware to return */
1799e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the digital input lines */
18004274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
18014274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (err < 0) {
18024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return err;
18044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18054274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
18064274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (err < 0) {
18074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return err;
18094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
18124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
18134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 2;
18144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
18154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18168fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* reads the 4 counters, only two are used just now */
18170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_counter_read(struct comedi_device *dev,
18180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
181990035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			       struct comedi_insn *insn, unsigned int *data)
18204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
1821cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
18224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int chan = insn->chanspec;
18234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err;
18244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18258fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
18264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
18274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
18294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
18314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
18334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18354274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
18364274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (err < 0) {
18374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return err;
18394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18414274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
18424274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (err < 0) {
18434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return err;
18454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	data[0] = le16_to_cpu(this_usbduxsub->insnBuffer[chan + 1]);
18484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
18494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 1;
18504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
18514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_counter_write(struct comedi_device *dev,
18530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
185490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton				struct comedi_insn *insn, unsigned int *data)
18554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
1856cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
18574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err;
18584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18598fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!this_usbduxsub)
18604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
18614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&this_usbduxsub->sem);
18634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(this_usbduxsub->probed)) {
18654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
18674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[1] = insn->chanspec;
18704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	*((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
18714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18724274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND);
18734274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (err < 0) {
18744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&this_usbduxsub->sem);
18754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return err;
18764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
18774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&this_usbduxsub->sem);
18794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 1;
18814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
18824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_counter_config(struct comedi_device *dev,
18840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 struct comedi_subdevice *s,
188590035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton				 struct comedi_insn *insn, unsigned int *data)
18864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
1887e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* nothing to do so far */
18884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 2;
18894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
18904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1891e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/***********************************/
1892e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* PWM */
18934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1894cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_unlink_PwmURBs(struct usbduxsub *usbduxsub_tmp)
18954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
18964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int err = 0;
18974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
18984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp && usbduxsub_tmp->urbPwm) {
18994398ecfac1cfe26ee63d0d4151cf9c3fa89e81d1Greg Kroah-Hartman		if (usbduxsub_tmp->urbPwm)
19004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usb_kill_urb(usbduxsub_tmp->urbPwm);
1901c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&usbduxsub_tmp->interface->dev,
1902c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi: unlinked PwmURB: res=%d\n", err);
19034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
19044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return err;
19054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
19064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/* This cancels a running acquisition operation
19084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr * in any context.
19094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr */
1910cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
19114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
19124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret = 0;
19134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1914c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (!this_usbduxsub)
19154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
1916c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
1917c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__);
19188fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (do_unlink)
19194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		ret = usbduxsub_unlink_PwmURBs(this_usbduxsub);
19208fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
19214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->pwm_cmd_running = 0;
19224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return ret;
19244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
19254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19268fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* force unlink - is called by comedi */
19270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_cancel(struct comedi_device *dev,
19280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
19294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
1930cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
19314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int res = 0;
19324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19338fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* unlink only if it is really running */
19344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
19354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1936c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev,
1937c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi %d: sending pwm off command to the usb device.\n",
19384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		dev->minor);
19394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1940c5274ab09747d0ef829f9b8f040756758e5de55cGreg Dietsche	return send_dux_commands(this_usbduxsub, SENDPWMOFF);
19414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
19424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic void usbduxsub_pwm_irq(struct urb *urb)
19444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
19454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret;
1946cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub;
194771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *this_comedidev;
194834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
19494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1950c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	/* printk(KERN_DEBUG "PWM: IRQ\n"); */
19514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
1952e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the context variable points to the subdevice */
19534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_comedidev = urb->context;
1954cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	/* the private structure of the subdevice is struct usbduxsub */
19554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub = this_comedidev->private;
19564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = this_comedidev->subdevices + SUBDEV_DA;
19584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	switch (urb->status) {
19604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case 0:
19614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		/* success */
19624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		break;
19634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ECONNRESET:
19654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ENOENT:
19664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ESHUTDOWN:
19674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case -ECONNABORTED:
19688fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/*
19698fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * after an unlink command, unplug, ... etc
19708fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * no unlink needed here. Already shutting down.
19718fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 */
19728fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		if (this_usbduxsub->pwm_cmd_running)
19734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_pwm_stop(this_usbduxsub, 0);
19748fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
19754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
19764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	default:
19788fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* a real error */
19794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (this_usbduxsub->pwm_cmd_running) {
1980c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1981c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi_: Non-zero urb status received in "
1982c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"pwm intr context: %d\n", urb->status);
19834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_pwm_stop(this_usbduxsub, 0);
19844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
19854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
19864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
19874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19888fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* are we actually running? */
19898fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!(this_usbduxsub->pwm_cmd_running))
19904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
19914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
19924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf;
19934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->dev = this_usbduxsub->usbdev;
19944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	urb->status = 0;
19954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->pwm_cmd_running) {
19964aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		ret = usb_submit_urb(urb, GFP_ATOMIC);
19974274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		if (ret < 0) {
1998c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
1999c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi_: pwm urb resubm failed in int-cont. "
2000c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"ret=%d", ret);
20018fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			if (ret == EL2NSYNC)
2002c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				dev_err(&this_usbduxsub->interface->dev,
2003c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman					"buggy USB host controller or bug in "
2004c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman					"IRQ handling!\n");
20058fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
20068fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			/* don't do an unlink here */
20074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbdux_pwm_stop(this_usbduxsub, 0);
20084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
20094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
20104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
20114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2012cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub)
20134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
20144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int errFlag;
20154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
20168fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!usbduxsub)
20174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
20188fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
2019c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n");
20204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2021c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	/* in case of a resubmission after an unlink... */
20224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usb_fill_bulk_urb(usbduxsub->urbPwm,
20230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  usbduxsub->usbdev,
20240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
20250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  usbduxsub->urbPwm->transfer_buffer,
20260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  usbduxsub->sizePwmBuf, usbduxsub_pwm_irq,
20270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  usbduxsub->comedidev);
20284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
20294aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman	errFlag = usb_submit_urb(usbduxsub->urbPwm, GFP_ATOMIC);
20304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (errFlag) {
2031c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&usbduxsub->interface->dev,
20324aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			"comedi_: usbdux: pwm: usb_submit_urb error %d\n",
2033c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			errFlag);
20344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return errFlag;
20354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
20364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
20374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
20384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
20390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_period(struct comedi_device *dev,
20400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, unsigned int period)
20414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
2042cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
20438fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	int fx2delay = 255;
20448fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
20458fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (period < MIN_PWM_PERIOD) {
2046c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&this_usbduxsub->interface->dev,
2047c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: illegal period setting for pwm.\n",
2048c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev->minor);
20494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EAGAIN;
20504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
20510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6;
20524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (fx2delay > 255) {
2053c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(&this_usbduxsub->interface->dev,
2054c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"comedi%d: period %d for pwm is too low.\n",
20550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				dev->minor, period);
20564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return -EAGAIN;
20574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
20584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
20598fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	this_usbduxsub->pwmDelay = fx2delay;
20608fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	this_usbduxsub->pwmPeriod = period;
2061c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n",
2062c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		__func__, period, fx2delay);
20634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
20644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
20654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2066e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* is called from insn so there's no need to do all the sanity checks */
20670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_start(struct comedi_device *dev,
20680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s)
20694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
20704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret, i;
2071cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
20724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2073c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n",
2074c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev->minor, __func__);
2075c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
20764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (this_usbduxsub->pwm_cmd_running) {
2077e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* already running */
20784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
20794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
20804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
20814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwmDelay);
20824274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	ret = send_dux_commands(this_usbduxsub, SENDPWMON);
20834274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (ret < 0)
20844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return ret;
20854274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
208637523e84cbf1d82fcc8237ed10818d37b951144eUwe Kleine-König	/* initialise the buffer */
20874274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	for (i = 0; i < this_usbduxsub->sizePwmBuf; i++)
20884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0;
20894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
20904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	this_usbduxsub->pwm_cmd_running = 1;
20914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	ret = usbduxsub_submit_PwmURBs(this_usbduxsub);
20924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (ret < 0) {
20934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		this_usbduxsub->pwm_cmd_running = 0;
20944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return ret;
20954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
20964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
20974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
20984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2099e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* generates the bit pattern for PWM with the optional sign bit */
21000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_pattern(struct comedi_device *dev,
21010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_subdevice *s, int channel,
21020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      unsigned int value, unsigned int sign)
21034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
2104cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
21054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i, szbuf;
21064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	char *pBuf;
21074274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	char pwm_mask;
21084274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	char sgn_mask;
21094274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	char c;
21104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21114274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (!this_usbduxsub)
21124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
21134274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman
2114e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* this is the DIO bit which carries the PWM data */
21154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	pwm_mask = (1 << channel);
2116e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* this is the DIO bit which carries the optional direction bit */
21174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	sgn_mask = (16 << channel);
2118e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* this is the buffer which will be filled with the with bit */
2119e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* pattern for one period */
21204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	szbuf = this_usbduxsub->sizePwmBuf;
21214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	pBuf = (char *)(this_usbduxsub->urbPwm->transfer_buffer);
21224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < szbuf; i++) {
21234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		c = *pBuf;
2124e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* reset bits */
21254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		c = c & (~pwm_mask);
2126e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* set the bit as long as the index is lower than the value */
21274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (i < value)
21284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			c = c | pwm_mask;
2129e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* set the optional sign bit for a relay */
21304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (!sign) {
2131e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* positive value */
21324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			c = c & (~sgn_mask);
21334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		} else {
2134e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* negative value */
21354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			c = c | sgn_mask;
21364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
21374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		*(pBuf++) = c;
21384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
21394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 1;
21404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
21414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_write(struct comedi_device *dev,
21430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s,
214490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			    struct comedi_insn *insn, unsigned int *data)
21454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
2146cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
21474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21484274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (!this_usbduxsub)
21494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
21504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21514274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if ((insn->n) != 1) {
21524274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		/*
21534274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		 * doesn't make sense to have more than one value here because
21544274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		 * it would just overwrite the PWM buffer a couple of times
21554274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		 */
21564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
21574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
21584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21594274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	/*
21604274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * the sign is set via a special INSN only, this gives us 8 bits for
21614274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * normal operation
21624274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * relay sign 0 by default
21634274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 */
21640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0);
21654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
21664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_read(struct comedi_device *x1,
21680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   struct comedi_subdevice *x2, struct comedi_insn *x3,
21690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   unsigned int *x4)
21704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
21718fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* not needed */
21724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return -EINVAL;
21734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr};
21744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
21758fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* switches on/off PWM */
21760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int usbdux_pwm_config(struct comedi_device *dev,
21770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s,
217890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			     struct comedi_insn *insn, unsigned int *data)
21794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
2180cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *this_usbduxsub = dev->private;
21814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	switch (data[0]) {
21824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_ARM:
21838fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* switch it on */
2184c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
2185c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: %s: pwm on\n", dev->minor, __func__);
21868fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/*
21878fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * if not zero the PWM is limited to a certain time which is
21888fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * not supported here
21898fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 */
21908fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		if (data[1] != 0)
21914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			return -EINVAL;
21924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return usbdux_pwm_start(dev, s);
21934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_DISARM:
2194c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
2195c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: %s: pwm off\n", dev->minor, __func__);
21964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return usbdux_pwm_cancel(dev, s);
21974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_GET_PWM_STATUS:
21988fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/*
21998fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * to check if the USB transmission has failed or in case PWM
22008fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 * was limited to n cycles to check if it has terminated
22018fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		 */
22024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		data[1] = this_usbduxsub->pwm_cmd_running;
22034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
22044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_PWM_SET_PERIOD:
2205c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_dbg(&this_usbduxsub->interface->dev,
2206c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: %s: setting period\n", dev->minor, __func__);
22078fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		return usbdux_pwm_period(dev, s, data[1]);
22084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_PWM_GET_PERIOD:
22094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		data[1] = this_usbduxsub->pwmPeriod;
22104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return 0;
22114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_PWM_SET_H_BRIDGE:
22128fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* value in the first byte and the sign in the second for a
22138fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		   relay */
22144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return usbdux_pwm_pattern(dev, s,
22158fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman					  /* the channel number */
22168fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman					  CR_CHAN(insn->chanspec),
22178fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman					  /* actual PWM data */
22188fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman					  data[1],
22198fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman					  /* just a sign */
22208fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman					  (data[2] != 0));
22214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	case INSN_CONFIG_PWM_GET_H_BRIDGE:
22228fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		/* values are not kept in this driver, nothing to return here */
22234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EINVAL;
22244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
22254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return -EINVAL;
22264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
22274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
22288fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* end of PWM */
22298fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/*****************************************************************/
22304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2231cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartmanstatic void tidy_up(struct usbduxsub *usbduxsub_tmp)
22324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
22334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i;
22344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
22358fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (!usbduxsub_tmp)
22364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
2237c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n");
22388fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
22398fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* shows the usb subsystem that the driver is down */
22404398ecfac1cfe26ee63d0d4151cf9c3fa89e81d1Greg Kroah-Hartman	if (usbduxsub_tmp->interface)
22414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usb_set_intfdata(usbduxsub_tmp->interface, NULL);
22424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
22434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp->probed = 0;
22444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
22454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp->urbIn) {
22464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub_tmp->ai_cmd_running) {
22474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub_tmp->ai_cmd_running = 0;
22484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub_unlink_InURBs(usbduxsub_tmp);
22494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
22504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
22514274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			kfree(usbduxsub_tmp->urbIn[i]->transfer_buffer);
22524274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			usbduxsub_tmp->urbIn[i]->transfer_buffer = NULL;
22534274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			usb_kill_urb(usbduxsub_tmp->urbIn[i]);
22544274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			usb_free_urb(usbduxsub_tmp->urbIn[i]);
22554274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman			usbduxsub_tmp->urbIn[i] = NULL;
22564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
22574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		kfree(usbduxsub_tmp->urbIn);
22584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub_tmp->urbIn = NULL;
22594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
22604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp->urbOut) {
22614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub_tmp->ao_cmd_running) {
22624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub_tmp->ao_cmd_running = 0;
22634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub_unlink_OutURBs(usbduxsub_tmp);
22644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
22654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
2266e4e1f289be88a75dc8b63d50ade1f9a2e6168021Ilia Mirkin			kfree(usbduxsub_tmp->urbOut[i]->transfer_buffer);
2267e4e1f289be88a75dc8b63d50ade1f9a2e6168021Ilia Mirkin			usbduxsub_tmp->urbOut[i]->transfer_buffer = NULL;
22684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			if (usbduxsub_tmp->urbOut[i]) {
22694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				usb_kill_urb(usbduxsub_tmp->urbOut[i]);
22704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				usb_free_urb(usbduxsub_tmp->urbOut[i]);
22714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr				usbduxsub_tmp->urbOut[i] = NULL;
22724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			}
22734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
22744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		kfree(usbduxsub_tmp->urbOut);
22754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub_tmp->urbOut = NULL;
22764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
22774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp->urbPwm) {
22784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub_tmp->pwm_cmd_running) {
22794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub_tmp->pwm_cmd_running = 0;
22804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub_unlink_PwmURBs(usbduxsub_tmp);
22814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
22828fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		kfree(usbduxsub_tmp->urbPwm->transfer_buffer);
22838fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman		usbduxsub_tmp->urbPwm->transfer_buffer = NULL;
22844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usb_kill_urb(usbduxsub_tmp->urbPwm);
22854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usb_free_urb(usbduxsub_tmp->urbPwm);
22864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub_tmp->urbPwm = NULL;
22874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
22888fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	kfree(usbduxsub_tmp->inBuffer);
22898fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	usbduxsub_tmp->inBuffer = NULL;
22908fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	kfree(usbduxsub_tmp->insnBuffer);
22918fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	usbduxsub_tmp->insnBuffer = NULL;
229261838261edaf621d1e8ee4ea9d7c052f7d783ca4Nicolas Kaiser	kfree(usbduxsub_tmp->outBuffer);
229361838261edaf621d1e8ee4ea9d7c052f7d783ca4Nicolas Kaiser	usbduxsub_tmp->outBuffer = NULL;
22948fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	kfree(usbduxsub_tmp->dac_commands);
22958fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	usbduxsub_tmp->dac_commands = NULL;
22968fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	kfree(usbduxsub_tmp->dux_commands);
22978fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	usbduxsub_tmp->dux_commands = NULL;
22984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp->ai_cmd_running = 0;
22994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp->ao_cmd_running = 0;
23004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp->pwm_cmd_running = 0;
23014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
23024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
23036742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porrstatic void usbdux_firmware_request_complete_handler(const struct firmware *fw,
23046742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr						     void *context)
23056742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr{
23066742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	struct usbduxsub *usbduxsub_tmp = context;
23076742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	struct usb_device *usbdev = usbduxsub_tmp->usbdev;
23086742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	int ret;
23096742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
23106742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	if (fw == NULL) {
23116742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		dev_err(&usbdev->dev,
23126742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr			"Firmware complete handler without firmware!\n");
23136742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		return;
23146742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	}
23156742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
23166742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	/*
23176742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	 * we need to upload the firmware here because fw will be
23186742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	 * freed once we've left this function
23196742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	 */
232081874ff7895f332920621104308e803434a17183Bernd Porr	ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
23216742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
23226742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	if (ret) {
23236742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		dev_err(&usbdev->dev,
23240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			"Could not upload firmware (err=%d)\n", ret);
23259ebfbd45f9d4ee9cd72529cf99e5f300eb398e67Johannes Berg		goto out;
23266742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	}
23276742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	comedi_usb_auto_config(usbdev, BOARDNAME);
23289ebfbd45f9d4ee9cd72529cf99e5f300eb398e67Johannes Berg out:
23299ebfbd45f9d4ee9cd72529cf99e5f300eb398e67Johannes Berg	release_firmware(fw);
23306742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr}
23316742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
2332e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* allocate memory for the urbs and initialise them */
23334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic int usbduxsub_probe(struct usb_interface *uinterf,
2334c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			   const struct usb_device_id *id)
23354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
23364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct usb_device *udev = interface_to_usbdev(uinterf);
2337c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	struct device *dev = &uinterf->dev;
23384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i;
23394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int index;
23406742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	int ret;
23414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2342c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(dev, "comedi_: usbdux_: "
2343c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"finding a free structure for the usb-device\n");
2344c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
23454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&start_stop_sem);
2346e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* look for a free place in the usbdux array */
23474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	index = -1;
23484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < NUMUSBDUX; i++) {
23494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (!(usbduxsub[i].probed)) {
23504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			index = i;
23514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			break;
23524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
23534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
23544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2355e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* no more space */
23564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (index == -1) {
2357c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "Too many usbdux-devices connected.\n");
23584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
23594aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -EMFILE;
23604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
2361c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(dev, "comedi_: usbdux: "
2362c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"usbduxsub[%d] is ready to connect to comedi.\n", index);
23634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
236445f4d0243525b6bc747c946937ced437b135a84dThomas Gleixner	sema_init(&(usbduxsub[index].sem), 1);
2365e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* save a pointer to the usb device */
23664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].usbdev = udev;
23674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2368e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* 2.6: save the interface itself */
23694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].interface = uinterf;
2370e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* get the interface number from the interface */
23714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
2372e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* hand the private data over to the usb subsystem */
2373e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* will be needed for disconnect */
23744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usb_set_intfdata(uinterf, &(usbduxsub[index]));
23754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2376c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
2377c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
2378e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* test if it is high speed (USB 2.0) */
23794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].high_speed =
23800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
23814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2382e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* create space for the commands of the DA converter */
23834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
23844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!usbduxsub[index].dac_commands) {
2385c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: "
2386c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"error alloc space for dac commands\n");
23874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
23884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
23894aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
23904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
2391e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* create space for the commands going to the usb device */
23924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
23934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!usbduxsub[index].dux_commands) {
2394c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: "
2395f96c377ead5ed308f0cf18b9156f86fdf207a288Nicolas Kaiser			"error alloc space for dux commands\n");
23964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
23974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
23984aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
23994bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
2400e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* create space for the in buffer and set it to zero */
24014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL);
24024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(usbduxsub[index].inBuffer)) {
2403c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: "
2404c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"could not alloc space for inBuffer\n");
24054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
24064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
24074aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
24084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
2409e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* create space of the instruction buffer */
24104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
24114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(usbduxsub[index].insnBuffer)) {
2412c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: "
2413c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"could not alloc space for insnBuffer\n");
24144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
24154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
24164aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
24174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
2418e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* create space for the outbuffer */
24194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
24204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(usbduxsub[index].outBuffer)) {
2421c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: "
2422c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"could not alloc space for outBuffer\n");
24234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
24244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
24254aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
24264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
24278fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* setting to alternate setting 3: enabling iso ep and bulk ep. */
24284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	i = usb_set_interface(usbduxsub[index].usbdev,
24298fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman			      usbduxsub[index].ifnum, 3);
24304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (i < 0) {
2431c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux%d: "
2432c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"could not set alternate setting 3 in high speed.\n",
2433c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			index);
24344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
24354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
24364aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENODEV;
24374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
24388fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (usbduxsub[index].high_speed)
24394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH;
24408fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	else
24414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL;
24428fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
24434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].urbIn =
24440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers,
24450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
24464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(usbduxsub[index].urbIn)) {
2447c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: Could not alloc. urbIn array\n");
24484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
24494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
24504aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
24514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
24524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) {
2453e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* one frame: 1ms */
24544aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		usbduxsub[index].urbIn[i] = usb_alloc_urb(1, GFP_KERNEL);
24554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub[index].urbIn[i] == NULL) {
2456c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(dev, "comedi_: usbdux%d: "
2457c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"Could not alloc. urb(%d)\n", index, i);
24584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tidy_up(&(usbduxsub[index]));
24594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&start_stop_sem);
24604aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			return -ENOMEM;
24614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
24624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->dev = usbduxsub[index].usbdev;
2463e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* will be filled later with a pointer to the comedi-device */
2464e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* and ONLY then the urb should be submitted */
24654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->context = NULL;
24664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->pipe =
24670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
24684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP;
24694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->transfer_buffer =
24700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    kzalloc(SIZEINBUF, GFP_KERNEL);
24714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) {
2472c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(dev, "comedi_: usbdux%d: "
2473c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"could not alloc. transb.\n", index);
24744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tidy_up(&(usbduxsub[index]));
24754bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&start_stop_sem);
24764aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			return -ENOMEM;
24774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
24784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->complete = usbduxsub_ai_IsocIrq;
24794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->number_of_packets = 1;
24804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->transfer_buffer_length = SIZEINBUF;
24814bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->iso_frame_desc[0].offset = 0;
24824bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbIn[i]->iso_frame_desc[0].length = SIZEINBUF;
24834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
24844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
24858fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	/* out */
24868fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	if (usbduxsub[index].high_speed)
24874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
24888fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman	else
24894bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL;
24908fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman
24914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].urbOut =
24920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers,
24930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
24944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!(usbduxsub[index].urbOut)) {
2495c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(dev, "comedi_: usbdux: "
2496c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"Could not alloc. urbOut array\n");
24974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		tidy_up(&(usbduxsub[index]));
24984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
24994aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		return -ENOMEM;
25004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
25014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) {
2502e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* one frame: 1ms */
25034aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		usbduxsub[index].urbOut[i] = usb_alloc_urb(1, GFP_KERNEL);
25044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub[index].urbOut[i] == NULL) {
2505c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(dev, "comedi_: usbdux%d: "
2506c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"Could not alloc. urb(%d)\n", index, i);
25074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tidy_up(&(usbduxsub[index]));
25084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&start_stop_sem);
25094aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			return -ENOMEM;
25104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
25114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->dev = usbduxsub[index].usbdev;
2512e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* will be filled later with a pointer to the comedi-device */
2513e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* and ONLY then the urb should be submitted */
25144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->context = NULL;
25154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->pipe =
25160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
25174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP;
25184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->transfer_buffer =
25190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    kzalloc(SIZEOUTBUF, GFP_KERNEL);
25204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) {
2521c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(dev, "comedi_: usbdux%d: "
2522c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"could not alloc. transb.\n", index);
25234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tidy_up(&(usbduxsub[index]));
25244bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&start_stop_sem);
25254aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			return -ENOMEM;
25264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
25274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->complete = usbduxsub_ao_IsocIrq;
25284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->number_of_packets = 1;
25294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->transfer_buffer_length = SIZEOUTBUF;
25304bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0;
25314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbOut[i]->iso_frame_desc[0].length =
25320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    SIZEOUTBUF;
25334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub[index].high_speed) {
2534e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* uframes */
25354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub[index].urbOut[i]->interval = 8;
25364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		} else {
2537e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman			/* frames */
25384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			usbduxsub[index].urbOut[i]->interval = 1;
25394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
25404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
25414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2542e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* pwm */
25434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub[index].high_speed) {
25444274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		/* max bulk ep size in high speed */
25454274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman		usbduxsub[index].sizePwmBuf = 512;
25464aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman		usbduxsub[index].urbPwm = usb_alloc_urb(0, GFP_KERNEL);
25474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (usbduxsub[index].urbPwm == NULL) {
2548c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(dev, "comedi_: usbdux%d: "
2549c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"Could not alloc. pwm urb\n", index);
25504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tidy_up(&(usbduxsub[index]));
25514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&start_stop_sem);
25524aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			return -ENOMEM;
25534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
25544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbPwm->transfer_buffer =
25550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL);
25564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if (!(usbduxsub[index].urbPwm->transfer_buffer)) {
2557c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			dev_err(dev, "comedi_: usbdux%d: "
2558c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman				"could not alloc. transb. for pwm\n", index);
25594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			tidy_up(&(usbduxsub[index]));
25604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			up(&start_stop_sem);
25614aa3a8232158abeea939ec12770fdfcf2987b3c4Greg Kroah-Hartman			return -ENOMEM;
25624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
25634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
25644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].urbPwm = NULL;
25654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbduxsub[index].sizePwmBuf = 0;
25664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
25674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
25684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].ai_cmd_running = 0;
25694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].ao_cmd_running = 0;
25704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].pwm_cmd_running = 0;
25714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2572e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* we've reached the bottom of the function */
25734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub[index].probed = 1;
25744bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&start_stop_sem);
25756742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
25766742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	ret = request_firmware_nowait(THIS_MODULE,
25776742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				      FW_ACTION_HOTPLUG,
257881874ff7895f332920621104308e803434a17183Bernd Porr				      "usbdux_firmware.bin",
25796742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				      &udev->dev,
25809ebfbd45f9d4ee9cd72529cf99e5f300eb398e67Johannes Berg				      GFP_KERNEL,
25816742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				      usbduxsub + index,
25826742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr				      usbdux_firmware_request_complete_handler);
25836742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
25846742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	if (ret) {
25856742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		dev_err(dev, "Could not load firmware (err=%d)\n", ret);
25866742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr		return ret;
25876742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	}
25886742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr
2589c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_info(dev, "comedi_: usbdux%d "
2590c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		 "has been successfully initialised.\n", index);
2591e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* success */
25924bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
25934bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
25944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
25954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic void usbduxsub_disconnect(struct usb_interface *intf)
25964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
2597cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
25984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	struct usb_device *udev = interface_to_usbdev(intf);
25994398ecfac1cfe26ee63d0d4151cf9c3fa89e81d1Greg Kroah-Hartman
26004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!usbduxsub_tmp) {
2601c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&intf->dev,
2602c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi_: disconnect called with null pointer.\n");
26034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
26044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (usbduxsub_tmp->usbdev != udev) {
26060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
26074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return;
26084bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26096742c0af2ef2d8ff70e379ebf8a8541190ff44e6Bernd Porr	comedi_usb_auto_unconfig(udev);
26104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&start_stop_sem);
26114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&usbduxsub_tmp->sem);
26124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	tidy_up(usbduxsub_tmp);
26134bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&usbduxsub_tmp->sem);
26144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&start_stop_sem);
2615c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
26164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
26174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
26188fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* is called when comedi-config is called */
26190707bb04be89b18ee83b5a997e36cc585f0b988dBill Pembertonstatic int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
26204bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
26214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int ret;
26224bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int index;
26234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	int i;
2624cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *udev;
2625c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
262634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
26274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	dev->private = NULL;
26284bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
26294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&start_stop_sem);
26304274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	/* find a valid device which has been detected by the probe function of
26314274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	 * the usb */
26324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	index = -1;
26334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	for (i = 0; i < NUMUSBDUX; i++) {
26344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
26354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			index = i;
26364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr			break;
26374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		}
26384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26394bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
26404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (index < 0) {
2641c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no "
2642c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		       "usbdux devs connected to the usb bus.\n", dev->minor);
26434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
26444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -ENODEV;
26454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2647c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	udev = &usbduxsub[index];
2648c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	down(&udev->sem);
2649e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* pointer back to the corresponding comedi device */
2650c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	udev->comedidev = dev;
26514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2652e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* trying to upload the firmware into the chip */
26534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (comedi_aux_data(it->options, 0) &&
26540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
265581874ff7895f332920621104308e803434a17183Bernd Porr		firmwareUpload(udev, comedi_aux_data(it->options, 0),
265681874ff7895f332920621104308e803434a17183Bernd Porr			       it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
26574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
26594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	dev->board_name = BOARDNAME;
26604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
26614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	/* set number of subdevices */
2662c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (udev->high_speed) {
2663e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* with pwm */
26644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		dev->n_subdevices = 5;
26654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	} else {
2666e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* without pwm */
26674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		dev->n_subdevices = 4;
26684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2670e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* allocate space for the subdevices */
26714274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	ret = alloc_subdevices(dev, dev->n_subdevices);
26724274ea02d728f3732433782919b32895555df3caGreg Kroah-Hartman	if (ret < 0) {
2673c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev_err(&udev->interface->dev,
2674c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman			"comedi%d: error alloc space for subdev\n", dev->minor);
267585678d5d27cb0ea1005316f51b1b062bf4609b66Dan Carpenter		up(&udev->sem);
26764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		up(&start_stop_sem);
26774bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return ret;
26784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
26794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2680c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_info(&udev->interface->dev,
26810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 "comedi%d: usb-device %d is attached to comedi.\n",
26820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 dev->minor, index);
2683e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* private structure is also simply the usb-structure */
2684c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev->private = udev;
26854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2686e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the first subdevice is the A/D converter */
26874bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = dev->subdevices + SUBDEV_AD;
2688e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the URBs get the comedi subdevice */
2689e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* which is responsible for reading */
2690e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* this is the subdevice which reads data */
26914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	dev->read_subdev = s;
2692e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the subdevice receives as private structure the */
2693e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* usb-structure */
26944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->private = NULL;
2695e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* analog input */
26964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->type = COMEDI_SUBD_AI;
2697e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* readable and ref is to ground */
26984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
2699e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* 8 channels */
27004bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->n_chan = 8;
2701e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* length of the channellist */
27024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->len_chanlist = 8;
2703e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* callback functions */
27044bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_read = usbdux_ai_insn_read;
27054bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->do_cmdtest = usbdux_ai_cmdtest;
27064bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->do_cmd = usbdux_ai_cmd;
27074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->cancel = usbdux_ai_cancel;
2708e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* max value from the A/D converter (12bit) */
27094bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->maxdata = 0xfff;
2710e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* range table to convert to physical units */
27114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->range_table = (&range_usbdux_ai_range);
27124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2713e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* analog out */
27144bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = dev->subdevices + SUBDEV_DA;
2715e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* analog out */
27164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->type = COMEDI_SUBD_AO;
2717e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* backward pointer */
27184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	dev->write_subdev = s;
2719e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* the subdevice receives as private structure the */
2720e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* usb-structure */
27214bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->private = NULL;
2722e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* are writable */
27234bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
2724e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* 4 channels */
27254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->n_chan = 4;
2726e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* length of the channellist */
27274bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->len_chanlist = 4;
2728e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* 12 bit resolution */
27294bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->maxdata = 0x0fff;
2730e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* bipolar range */
27314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->range_table = (&range_usbdux_ao_range);
2732e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* callback */
27334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->do_cmdtest = usbdux_ao_cmdtest;
27344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->do_cmd = usbdux_ao_cmd;
27354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->cancel = usbdux_ao_cancel;
27364bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_read = usbdux_ao_insn_read;
27374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_write = usbdux_ao_insn_write;
27384bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2739e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* digital I/O */
27404bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = dev->subdevices + SUBDEV_DIO;
27414bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->type = COMEDI_SUBD_DIO;
27424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
27434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->n_chan = 8;
27444bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->maxdata = 1;
27454bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->range_table = (&range_digital);
27464bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_bits = usbdux_dio_insn_bits;
27474bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_config = usbdux_dio_insn_config;
2748e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* we don't use it */
27494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->private = NULL;
27504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2751e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* counter */
27524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s = dev->subdevices + SUBDEV_COUNTER;
27534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->type = COMEDI_SUBD_COUNTER;
27544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
27554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->n_chan = 4;
27564bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->maxdata = 0xFFFF;
27574bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_read = usbdux_counter_read;
27584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_write = usbdux_counter_write;
27594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	s->insn_config = usbdux_counter_config;
27604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2761c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	if (udev->high_speed) {
2762e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* timer / pwm */
27634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s = dev->subdevices + SUBDEV_PWM;
27644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->type = COMEDI_SUBD_PWM;
27654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
27664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->n_chan = 8;
2767e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman		/* this defines the max duty cycle resolution */
2768c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		s->maxdata = udev->sizePwmBuf;
27694bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->insn_write = usbdux_pwm_write;
27704bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->insn_read = usbdux_pwm_read;
27714bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		s->insn_config = usbdux_pwm_config;
27724bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
27734bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
2774e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* finally decide that it's attached */
2775c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	udev->attached = 1;
27764bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2777c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	up(&udev->sem);
27784bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
27794bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&start_stop_sem);
27804bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2781c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
2782c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		 dev->minor);
27834bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
27844bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
27854bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
27864bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
278771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int usbdux_detach(struct comedi_device *dev)
27884bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
2789cc92fca7bad65adee79c241a72082bacbfec6c3eGreg Kroah-Hartman	struct usbduxsub *usbduxsub_tmp;
27904bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
27914bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!dev) {
2792c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		printk(KERN_ERR
27930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi?: usbdux: detach without dev variable...\n");
27944bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
27954bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
27964bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
27974bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp = dev->private;
27984bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	if (!usbduxsub_tmp) {
2799c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		printk(KERN_ERR
28000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi?: usbdux: detach without ptr to usbduxsub[]\n");
28014bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr		return -EFAULT;
28024bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	}
28034bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2804c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n",
2805c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		dev->minor);
2806c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman
28074bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	down(&usbduxsub_tmp->sem);
2808e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* Don't allow detach to free the private structure */
2809e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman	/* It's one entry of of usbduxsub[] */
28104bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	dev->private = NULL;
28114bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp->attached = 0;
28124bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usbduxsub_tmp->comedidev = NULL;
2813c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman	dev_dbg(&usbduxsub_tmp->interface->dev,
2814c0e0c26e6b877d91af0477cd965ddad4835d2905Greg Kroah-Hartman		"comedi%d: detach: successfully removed\n", dev->minor);
28154bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	up(&usbduxsub_tmp->sem);
28164bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
28174bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
28184bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
28194bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr/* main driver struct */
2820139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_usbdux = {
28210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.driver_name = "usbdux",
28220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.module = THIS_MODULE,
28230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.attach = usbdux_attach,
28240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.detach = usbdux_detach,
28254bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr};
28264bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
28278fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* Table with the USB-devices: just now only testing IDs */
2828a457732b836b970c82c7ba35b4cfc938c9c543f9Németh Mártonstatic const struct usb_device_id usbduxsub_table[] = {
28290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	{USB_DEVICE(0x13d8, 0x0001)},
28300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	{USB_DEVICE(0x13d8, 0x0002)},
28314bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	{}			/* Terminating entry */
28324bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr};
28334bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
28344bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrMODULE_DEVICE_TABLE(usb, usbduxsub_table);
28354bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
28368fa07567bf5d824537839e6984a571daeed2c7fcGreg Kroah-Hartman/* The usbduxsub-driver */
28374bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrstatic struct usb_driver usbduxsub_driver = {
28380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.name = BOARDNAME,
28390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.probe = usbduxsub_probe,
28400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.disconnect = usbduxsub_disconnect,
28410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.id_table = usbduxsub_table,
28424bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr};
28434bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2844e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* Can't use the nice macro as I have also to initialise the USB */
2845e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* subsystem: */
2846e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* registering the usb-system _and_ the comedi-driver */
28471b9fb14eb21f86519ce35a2e770a29cd768386a2Mariusz Kozlowskistatic int __init init_usbdux(void)
28484bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
28494bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	printk(KERN_INFO KBUILD_MODNAME ": "
28504bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	       DRIVER_VERSION ":" DRIVER_DESC "\n");
28514bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usb_register(&usbduxsub_driver);
28524bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	comedi_driver_register(&driver_usbdux);
28534bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	return 0;
28544bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
28554bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
2856e54fb9c184a250fc80c48110ae42068bb0237a13Greg Kroah-Hartman/* deregistering the comedi driver and the usb-subsystem */
28571b9fb14eb21f86519ce35a2e770a29cd768386a2Mariusz Kozlowskistatic void __exit exit_usbdux(void)
28584bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr{
28594bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	comedi_driver_unregister(&driver_usbdux);
28604bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr	usb_deregister(&usbduxsub_driver);
28614bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr}
28624bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
28634bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrmodule_init(init_usbdux);
28644bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porrmodule_exit(exit_usbdux);
28654bf21fa4dabaa8803906c6548496fcf12b15b10fBernd Porr
28664bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrMODULE_AUTHOR(DRIVER_AUTHOR);
28674bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrMODULE_DESCRIPTION(DRIVER_DESC);
28684bf21fa4dabaa8803906c6548496fcf12b15b10fBernd PorrMODULE_LICENSE("GPL");
2869