RTXI 1.3
comedi/comedi/drivers/usbduxfast.c
Go to the documentation of this file.
00001 #define DRIVER_VERSION "v1.0"
00002 #define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
00003 #define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com"
00004 /*
00005    comedi/drivers/usbduxfast.c
00006    Copyright (C) 2004 Bernd Porr, Bernd.Porr@f2s.com
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 /*
00024 Driver: usbduxfast
00025 Description: ITL USB-DUXfast
00026 Devices: [ITL] USB-DUX (usbduxfast.o)
00027 Author: Bernd Porr <BerndPorr@f2s.com>
00028 Updated: 08 Dec 2008
00029 Status: stable
00030 */
00031 
00032 /*
00033  * I must give credit here to Chris Baugher who
00034  * wrote the driver for AT-MIO-16d. I used some parts of this
00035  * driver. I also must give credits to David Brownell
00036  * who supported me with the USB development.
00037  *
00038  * Bernd Porr
00039  *
00040  *
00041  * Revision history:
00042  * 0.9: Dropping the first data packet which seems to be from the last transfer.
00043  *      Buffer overflows in the FX2 are handed over to comedi.
00044  * 0.92: Dropping now 4 packets. The quad buffer has to be emptied.
00045  *       Added insn command basically for testing. Sample rate is 1MHz/16ch=62.5kHz
00046  * 0.99: Ian Abbott pointed out a bug which has been corrected. Thanks!
00047  * 0.99a: added external trigger.
00048  * 1.00: added firmware kernel request to the driver which fixed
00049  *       udev coldplug problem
00050  */
00051 
00052 #include <linux/kernel.h>
00053 #include <linux/firmware.h>
00054 #include <linux/module.h>
00055 #include <linux/init.h>
00056 #include <linux/slab.h>
00057 #include <linux/input.h>
00058 #include <linux/usb.h>
00059 #include <linux/smp_lock.h>
00060 #include <linux/fcntl.h>
00061 #include <linux/compiler.h>
00062 #include "comedi_fc.h"
00063 #include <linux/comedidev.h>
00064 #include <linux/usb.h>
00065 
00066 // (un)comment this if you want to have debug info.
00067 //#define CONFIG_COMEDI_DEBUG
00068 #undef  CONFIG_COMEDI_DEBUG
00069 
00070 #define BOARDNAME "usbduxfast"
00071 
00072 // timeout for the USB-transfer
00073 #define EZTIMEOUT 30
00074 
00075 // constants for "firmware" upload and download
00076 #define USBDUXFASTSUB_FIRMWARE 0xA0
00077 #define VENDOR_DIR_IN  0xC0
00078 #define VENDOR_DIR_OUT 0x40
00079 
00080 // internal adresses of the 8051 processor
00081 #define USBDUXFASTSUB_CPUCS 0xE600
00082 
00083 // max lenghth of the transfer-buffer for software upload
00084 #define TB_LEN 0x2000
00085 
00086 // Input endpoint number
00087 #define BULKINEP           6
00088 
00089 // Endpoint for the A/D channellist: bulk OUT
00090 #define CHANNELLISTEP     4
00091 
00092 // Number of channels
00093 #define NUMCHANNELS       32
00094 
00095 // size of the waveform descriptor
00096 #define WAVESIZE          0x20
00097 
00098 // Size of one A/D value
00099 #define SIZEADIN          ((sizeof(int16_t)))
00100 
00101 // Size of the input-buffer IN BYTES
00102 #define SIZEINBUF         512
00103 
00104 // 16 bytes.
00105 #define SIZEINSNBUF       512
00106 
00107 // Size of the buffer for the dux commands
00108 #define SIZEOFDUXBUFFER    256  // bytes
00109 
00110 // Number of in-URBs which receive the data: min=5
00111 #define NUMOFINBUFFERSHIGH     10
00112 
00113 // Total number of usbduxfast devices
00114 #define NUMUSBDUXFAST             16
00115 
00116 // Number of subdevices
00117 #define N_SUBDEVICES          1
00118 
00119 // Analogue in subdevice
00120 #define SUBDEV_AD             0
00121 
00122 // min delay steps for more than one channel
00123 // basically when the mux gives up. ;-)
00124 #define MIN_SAMPLING_PERIOD 9   // steps at 30MHz in the FX2
00125 
00126 // Max number of 1/30MHz delay steps:
00127 #define MAX_SAMPLING_PERIOD 500
00128 
00129 // Number of received packets to ignore before we start handing data over to comedi.
00130 // It's quad buffering and we have to ignore 4 packets.
00131 #define PACKETS_TO_IGNORE 4
00132 
00134 // comedi constants
00135 static const comedi_lrange range_usbduxfast_ai_range = { 2, {
00136                         BIP_RANGE(0.75),
00137                         BIP_RANGE(0.5),
00138         }
00139 };
00140 
00141 /*
00142  * private structure of one subdevice
00143  */
00144 
00145 // This is the structure which holds all the data of this driver
00146 // one sub device just now: A/D
00147 typedef struct {
00148         // attached?
00149         int attached;
00150         // is it associated with a subdevice?
00151         int probed;
00152         // pointer to the usb-device
00153         struct usb_device *usbdev;
00154         // BULK-transfer handling: urb
00155         struct urb *urbIn;
00156         int8_t *transfer_buffer;
00157         // input buffer for single insn
00158         int16_t *insnBuffer;
00159         // interface number
00160         int ifnum;
00161 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
00162         // interface structure in 2.6
00163         struct usb_interface *interface;
00164 #endif
00165         // comedi device for the interrupt context
00166         comedi_device *comedidev;
00167         // asynchronous command is running
00168         short int ai_cmd_running;
00169         // continous aquisition
00170         short int ai_continous;
00171         // number of samples to aquire
00172         long int ai_sample_count;
00173         // commands
00174         uint8_t *dux_commands;
00175         // counter which ignores the first buffers
00176         int ignore;
00177         struct semaphore sem;
00178 } usbduxfastsub_t;
00179 
00180 // The pointer to the private usb-data of the driver
00181 // is also the private data for the comedi-device.
00182 // This has to be global as the usb subsystem needs
00183 // global variables. The other reason is that this
00184 // structure must be there _before_ any comedi
00185 // command is issued. The usb subsystem must be
00186 // initialised before comedi can access it.
00187 static usbduxfastsub_t usbduxfastsub[NUMUSBDUXFAST];
00188 
00189 static DECLARE_MUTEX(start_stop_sem);
00190 
00191 // bulk transfers to usbduxfast
00192 
00193 #define SENDADCOMMANDS            0
00194 #define SENDINITEP6               1
00195 
00196 static int send_dux_commands(usbduxfastsub_t * this_usbduxfastsub, int cmd_type)
00197 {
00198         int result, nsent;
00199         this_usbduxfastsub->dux_commands[0] = cmd_type;
00200 #ifdef CONFIG_COMEDI_DEBUG
00201         int i;
00202         printk("comedi%d: usbduxfast: dux_commands: ",
00203                 this_usbduxfastsub->comedidev->minor);
00204         for (i = 0; i < SIZEOFDUXBUFFER; i++) {
00205                 printk(" %02x", this_usbduxfastsub->dux_commands[i]);
00206         }
00207         printk("\n");
00208 #endif
00209         result = USB_BULK_MSG(this_usbduxfastsub->usbdev,
00210                 usb_sndbulkpipe(this_usbduxfastsub->usbdev,
00211                         CHANNELLISTEP),
00212                 this_usbduxfastsub->dux_commands,
00213                 SIZEOFDUXBUFFER, &nsent, 10000);
00214         if (result < 0) {
00215                 printk("comedi%d: could not transmit dux_commands to the usb-device, err=%d\n", this_usbduxfastsub->comedidev->minor, result);
00216         }
00217         return result;
00218 }
00219 
00220 // Stops the data acquision
00221 // It should be safe to call this function from any context
00222 static int usbduxfastsub_unlink_InURBs(usbduxfastsub_t * usbduxfastsub_tmp)
00223 {
00224         int j = 0;
00225         int err = 0;
00226 
00227         if (usbduxfastsub_tmp && usbduxfastsub_tmp->urbIn) {
00228                 usbduxfastsub_tmp->ai_cmd_running = 0;
00229 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
00230                 j = usb_unlink_urb(usbduxfastsub_tmp->urbIn);
00231                 if (j < 0) {
00232                         err = j;
00233                 }
00234 #else
00235                 // waits until a running transfer is over
00236                 usb_kill_urb(usbduxfastsub_tmp->urbIn);
00237                 j = 0;
00238 #endif
00239         }
00240 #ifdef CONFIG_COMEDI_DEBUG
00241         printk("comedi: usbduxfast: unlinked InURB: res=%d\n", j);
00242 #endif
00243         return err;
00244 }
00245 
00246 /* This will stop a running acquisition operation */
00247 // Is called from within this driver from both the
00248 // interrupt context and from comedi
00249 static int usbduxfast_ai_stop(usbduxfastsub_t * this_usbduxfastsub,
00250         int do_unlink)
00251 {
00252         int ret = 0;
00253 
00254         if (!this_usbduxfastsub) {
00255                 printk("comedi?: usbduxfast_ai_stop: this_usbduxfastsub=NULL!\n");
00256                 return -EFAULT;
00257         }
00258 #ifdef CONFIG_COMEDI_DEBUG
00259         printk("comedi: usbduxfast_ai_stop\n");
00260 #endif
00261 
00262         this_usbduxfastsub->ai_cmd_running = 0;
00263 
00264         if (do_unlink) {
00265                 // stop aquistion
00266                 ret = usbduxfastsub_unlink_InURBs(this_usbduxfastsub);
00267         }
00268 
00269         return ret;
00270 }
00271 
00272 // This will cancel a running acquisition operation.
00273 // This is called by comedi but never from inside the
00274 // driver.
00275 static int usbduxfast_ai_cancel(comedi_device * dev, comedi_subdevice * s)
00276 {
00277         usbduxfastsub_t *this_usbduxfastsub;
00278         int res = 0;
00279 
00280         // force unlink of all urbs
00281 #ifdef CONFIG_COMEDI_DEBUG
00282         printk("comedi: usbduxfast_ai_cancel\n");
00283 #endif
00284         this_usbduxfastsub = dev->private;
00285         if (!this_usbduxfastsub) {
00286                 printk("comedi: usbduxfast_ai_cancel: this_usbduxfastsub=NULL\n");
00287                 return -EFAULT;
00288         }
00289         down(&this_usbduxfastsub->sem);
00290         if (!(this_usbduxfastsub->probed)) {
00291                 up(&this_usbduxfastsub->sem);
00292                 return -ENODEV;
00293         }
00294         // unlink
00295         res = usbduxfast_ai_stop(this_usbduxfastsub, 1);
00296         up(&this_usbduxfastsub->sem);
00297 
00298         return res;
00299 }
00300 
00301 // analogue IN
00302 // interrupt service routine
00303 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
00304 static void usbduxfastsub_ai_Irq(struct urb *urb)
00305 #else
00306 static void usbduxfastsub_ai_Irq(struct urb *urb PT_REGS_ARG)
00307 #endif
00308 {
00309         int n, err;
00310         usbduxfastsub_t *this_usbduxfastsub;
00311         comedi_device *this_comedidev;
00312         comedi_subdevice *s;
00313         uint16_t *p;
00314 
00315         // sanity checks
00316         // is the urb there?
00317         if (!urb) {
00318                 printk("comedi_: usbduxfast_: ao int-handler called with urb=NULL!\n");
00319                 return;
00320         }
00321         // the context variable points to the subdevice
00322         this_comedidev = urb->context;
00323         if (!this_comedidev) {
00324                 printk("comedi_: usbduxfast_: urb context is a NULL pointer!\n");
00325                 return;
00326         }
00327         // the private structure of the subdevice is usbduxfastsub_t
00328         this_usbduxfastsub = this_comedidev->private;
00329         if (!this_usbduxfastsub) {
00330                 printk("comedi_: usbduxfast_: private of comedi subdev is a NULL pointer!\n");
00331                 return;
00332         }
00333         // are we running a command?
00334         if (unlikely(!(this_usbduxfastsub->ai_cmd_running))) {
00335                 // not running a command
00336                 // do not continue execution if no asynchronous command is running
00337                 // in particular not resubmit
00338                 return;
00339         }
00340 
00341         if (unlikely(!(this_usbduxfastsub->attached))) {
00342                 // no comedi device there
00343                 return;
00344         }
00345         // subdevice which is the AD converter
00346         s = this_comedidev->subdevices + SUBDEV_AD;
00347 
00348         // first we test if something unusual has just happened
00349         switch (urb->status) {
00350         case 0:
00351                 break;
00352 
00353                 // happens after an unlink command or when the device is plugged out
00354         case -ECONNRESET:
00355         case -ENOENT:
00356         case -ESHUTDOWN:
00357         case -ECONNABORTED:
00358                 // tell this comedi
00359                 s->async->events |= COMEDI_CB_EOA;
00360                 s->async->events |= COMEDI_CB_ERROR;
00361                 comedi_event(this_usbduxfastsub->comedidev, s);
00362                 // stop the transfer w/o unlink
00363                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
00364                 return;
00365 
00366         default:
00367                 printk("comedi%d: usbduxfast: non-zero urb status received in ai intr context: %d\n", this_usbduxfastsub->comedidev->minor, urb->status);
00368                 s->async->events |= COMEDI_CB_EOA;
00369                 s->async->events |= COMEDI_CB_ERROR;
00370                 comedi_event(this_usbduxfastsub->comedidev, s);
00371                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
00372                 return;
00373         }
00374 
00375         p = urb->transfer_buffer;
00376         if (!this_usbduxfastsub->ignore) {
00377                 if (!(this_usbduxfastsub->ai_continous)) {
00378                         // not continous, fixed number of samples
00379                         n = urb->actual_length / sizeof(uint16_t);
00380                         if (unlikely(this_usbduxfastsub->ai_sample_count < n)) {
00381                                 // we have send only a fraction of the bytes received
00382                                 cfc_write_array_to_buffer(s,
00383                                         urb->transfer_buffer,
00384                                         this_usbduxfastsub->ai_sample_count *
00385                                         sizeof(uint16_t));
00386                                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
00387                                 // say comedi that the acquistion is over
00388                                 s->async->events |= COMEDI_CB_EOA;
00389                                 comedi_event(this_usbduxfastsub->comedidev, s);
00390                                 return;
00391                         }
00392                         this_usbduxfastsub->ai_sample_count -= n;
00393                 }
00394                 // write the full buffer to comedi
00395                 err = cfc_write_array_to_buffer(s,
00396                                                 urb->transfer_buffer, urb->actual_length);
00397 
00398                 if (unlikely(err == 0)) {
00399                         /* buffer overflow */
00400                         usbduxfast_ai_stop(this_usbduxfastsub, 0);
00401                         return;
00402                 }
00403 
00404                 // tell comedi that data is there
00405                 comedi_event(this_usbduxfastsub->comedidev, s);
00406 
00407         } else {
00408                 // ignore this packet
00409                 this_usbduxfastsub->ignore--;
00410         }
00411 
00412         // command is still running
00413         // resubmit urb for BULK transfer
00414         urb->dev = this_usbduxfastsub->usbdev;
00415         urb->status = 0;
00416         if ((err = USB_SUBMIT_URB(urb)) < 0) {
00417                 printk("comedi%d: usbduxfast: urb resubm failed: %d",
00418                         this_usbduxfastsub->comedidev->minor, err);
00419                 s->async->events |= COMEDI_CB_EOA;
00420                 s->async->events |= COMEDI_CB_ERROR;
00421                 comedi_event(this_usbduxfastsub->comedidev, s);
00422                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
00423         }
00424 }
00425 
00426 static int usbduxfastsub_start(usbduxfastsub_t * usbduxfastsub)
00427 {
00428         int errcode = 0;
00429         unsigned char local_transfer_buffer[16];
00430 
00431         // 7f92 to zero
00432         local_transfer_buffer[0] = 0;
00433         errcode = USB_CONTROL_MSG(usbduxfastsub->usbdev,
00434                                   // create a pipe for a control transfer
00435                                   usb_sndctrlpipe(usbduxfastsub->usbdev, 0),
00436                                   // bRequest, "Firmware"
00437                                   USBDUXFASTSUB_FIRMWARE,
00438                                   // bmRequestType
00439                                   VENDOR_DIR_OUT,
00440                                   // Value
00441                                   USBDUXFASTSUB_CPUCS,
00442                                   // Index
00443                                   0x0000,
00444                                   // address of the transfer buffer
00445                                   local_transfer_buffer,
00446                                   // Length
00447                                   1,
00448                                   // Timeout
00449                                   EZTIMEOUT);
00450         if (errcode < 0) {
00451                 printk("comedi_: usbduxfast_: control msg failed (start)\n");
00452                 return errcode;
00453         }
00454         return 0;
00455 }
00456 
00457 static int usbduxfastsub_stop(usbduxfastsub_t * usbduxfastsub)
00458 {
00459         int errcode = 0;
00460 
00461         unsigned char local_transfer_buffer[16];
00462         // 7f92 to one
00463         local_transfer_buffer[0] = 1;
00464         errcode = USB_CONTROL_MSG
00465                 (usbduxfastsub->usbdev,
00466                  usb_sndctrlpipe(usbduxfastsub->usbdev, 0),
00467                  // bRequest, "Firmware"
00468                  USBDUXFASTSUB_FIRMWARE,
00469                  // bmRequestType
00470                  VENDOR_DIR_OUT,
00471                  // Value
00472                  USBDUXFASTSUB_CPUCS,
00473                  // Index
00474                  0x0000, local_transfer_buffer,
00475                  // Length
00476                  1,
00477                  // Timeout
00478                  EZTIMEOUT);
00479         if (errcode < 0) {
00480                 printk("comedi_: usbduxfast: control msg failed (stop)\n");
00481                 return errcode;
00482         }
00483         return 0;
00484 }
00485 
00486 static int usbduxfastsub_upload(usbduxfastsub_t * usbduxfastsub,
00487         unsigned char *local_transfer_buffer,
00488         unsigned int startAddr, unsigned int len)
00489 {
00490         int errcode;
00491 
00492         errcode = USB_CONTROL_MSG
00493                 (usbduxfastsub->usbdev,
00494                  usb_sndctrlpipe(usbduxfastsub->usbdev, 0),
00495                  // brequest, firmware
00496                  USBDUXFASTSUB_FIRMWARE,
00497                  // bmRequestType
00498                  VENDOR_DIR_OUT,
00499                  // value
00500                  startAddr,
00501                  // index
00502                  0x0000,
00503                  // our local safe buffer
00504                  local_transfer_buffer,
00505                  // length
00506                  len,
00507                  // timeout
00508                  EZTIMEOUT);
00509         if (errcode < 0) {
00510                 printk("comedi_: usbduxfast: uppload failed\n");
00511                 return errcode;
00512         }
00513         return 0;
00514 }
00515 
00516 int firmwareUpload(usbduxfastsub_t * usbduxfastsub,
00517         unsigned char *firmwareBinary, int sizeFirmware)
00518 {
00519         int ret;
00520 
00521         if (!firmwareBinary) {
00522                 return 0;
00523         }
00524         ret = usbduxfastsub_stop(usbduxfastsub);
00525         if (ret < 0) {
00526                 printk("comedi_: usbduxfast: can not stop firmware\n");
00527                 return ret;
00528         }
00529         ret = usbduxfastsub_upload(usbduxfastsub,
00530                 firmwareBinary, 0, sizeFirmware);
00531         if (ret < 0) {
00532                 printk("comedi_: usbduxfast: firmware upload failed\n");
00533                 return ret;
00534         }
00535         ret = usbduxfastsub_start(usbduxfastsub);
00536         if (ret < 0) {
00537                 printk("comedi_: usbduxfast: can not start firmware\n");
00538                 return ret;
00539         }
00540         return 0;
00541 }
00542 
00543 int usbduxfastsub_submit_InURBs(usbduxfastsub_t * usbduxfastsub)
00544 {
00545         int errFlag;
00546 
00547         if (!usbduxfastsub) {
00548                 return -EFAULT;
00549         }
00550         usb_fill_bulk_urb(usbduxfastsub->urbIn,
00551                 usbduxfastsub->usbdev,
00552                 usb_rcvbulkpipe(usbduxfastsub->usbdev, BULKINEP),
00553                 usbduxfastsub->transfer_buffer,
00554                 SIZEINBUF, usbduxfastsub_ai_Irq, usbduxfastsub->comedidev);
00555 
00556 #ifdef CONFIG_COMEDI_DEBUG
00557         printk("comedi%d: usbduxfast: submitting in-urb: %x,%x\n",
00558                 usbduxfastsub->comedidev->minor,
00559                 (int)(usbduxfastsub->urbIn->context),
00560                 (int)(usbduxfastsub->urbIn->dev));
00561 #endif
00562         errFlag = USB_SUBMIT_URB(usbduxfastsub->urbIn);
00563         if (errFlag) {
00564                 printk("comedi_: usbduxfast: ai: ");
00565                 printk("USB_SUBMIT_URB");
00566                 printk(" error %d\n", errFlag);
00567                 return errFlag;
00568         }
00569         return 0;
00570 }
00571 
00572 static int usbduxfast_ai_cmdtest(comedi_device * dev,
00573         comedi_subdevice * s, comedi_cmd * cmd)
00574 {
00575         int err = 0, stop_mask = 0;
00576         long int steps, tmp = 0;
00577         int minSamplPer;
00578         usbduxfastsub_t *this_usbduxfastsub = dev->private;
00579         if (!(this_usbduxfastsub->probed)) {
00580                 return -ENODEV;
00581         }
00582 #ifdef CONFIG_COMEDI_DEBUG
00583         printk("comedi%d: usbduxfast_ai_cmdtest\n", dev->minor);
00584         printk("comedi%d: usbduxfast: convert_arg=%u scan_begin_arg=%u\n",
00585                 dev->minor, cmd->convert_arg, cmd->scan_begin_arg);
00586 #endif
00587         /* step 1: make sure trigger sources are trivially valid */
00588 
00589         tmp = cmd->start_src;
00590         cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT;
00591         if (!cmd->start_src || tmp != cmd->start_src)
00592                 err++;
00593 
00594         tmp = cmd->scan_begin_src;
00595         cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
00596         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
00597                 err++;
00598 
00599         tmp = cmd->convert_src;
00600         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
00601         if (!cmd->convert_src || tmp != cmd->convert_src)
00602                 err++;
00603 
00604         tmp = cmd->scan_end_src;
00605         cmd->scan_end_src &= TRIG_COUNT;
00606         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
00607                 err++;
00608 
00609         tmp = cmd->stop_src;
00610         stop_mask = TRIG_COUNT | TRIG_NONE;
00611         cmd->stop_src &= stop_mask;
00612         if (!cmd->stop_src || tmp != cmd->stop_src)
00613                 err++;
00614 
00615         if (err)
00616                 return 1;
00617 
00618         /* step 2: make sure trigger sources are unique and mutually compatible */
00619 
00620         if (cmd->start_src != TRIG_NOW &&
00621                 cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT)
00622                 err++;
00623         if (cmd->scan_begin_src != TRIG_TIMER &&
00624                 cmd->scan_begin_src != TRIG_FOLLOW &&
00625                 cmd->scan_begin_src != TRIG_EXT)
00626                 err++;
00627         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
00628                 err++;
00629         if (cmd->stop_src != TRIG_COUNT &&
00630                 cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
00631                 err++;
00632 
00633         // can't have external stop and start triggers at once
00634         if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
00635                 err++;
00636 
00637         if (err)
00638                 return 2;
00639 
00640         /* step 3: make sure arguments are trivially compatible */
00641 
00642         if (cmd->start_src == TRIG_NOW && cmd->start_arg != 0) {
00643                 cmd->start_arg = 0;
00644                 err++;
00645         }
00646 
00647         if (!cmd->chanlist_len) {
00648                 err++;
00649         }
00650         if (cmd->scan_end_arg != cmd->chanlist_len) {
00651                 cmd->scan_end_arg = cmd->chanlist_len;
00652                 err++;
00653         }
00654 
00655         if (cmd->chanlist_len == 1) {
00656                 minSamplPer = 1;
00657         } else {
00658                 minSamplPer = MIN_SAMPLING_PERIOD;
00659         }
00660 
00661         if (cmd->convert_src == TRIG_TIMER) {
00662                 steps = cmd->convert_arg * 30;
00663                 if (steps < (minSamplPer * 1000)) {
00664                         steps = minSamplPer * 1000;
00665                 }
00666                 if (steps > (MAX_SAMPLING_PERIOD * 1000)) {
00667                         steps = MAX_SAMPLING_PERIOD * 1000;
00668                 }
00669                 // calc arg again
00670                 tmp = steps / 30;
00671                 if (cmd->convert_arg != tmp) {
00672                         cmd->convert_arg = tmp;
00673                         err++;
00674                 }
00675         }
00676 
00677         if (cmd->scan_begin_src == TRIG_TIMER) {
00678                 err++;
00679         }
00680         // stop source
00681         switch (cmd->stop_src) {
00682         case TRIG_COUNT:
00683                 if (!cmd->stop_arg) {
00684                         cmd->stop_arg = 1;
00685                         err++;
00686                 }
00687                 break;
00688         case TRIG_NONE:
00689                 if (cmd->stop_arg != 0) {
00690                         cmd->stop_arg = 0;
00691                         err++;
00692                 }
00693                 break;
00694                 // TRIG_EXT doesn't care since it doesn't trigger off a numbered channel
00695         default:
00696                 break;
00697         }
00698 
00699         if (err)
00700                 return 3;
00701 
00702         /* step 4: fix up any arguments */
00703 
00704         return 0;
00705 
00706 }
00707 
00708 static int usbduxfast_ai_inttrig(comedi_device * dev,
00709         comedi_subdevice * s, unsigned int trignum)
00710 {
00711         int ret;
00712         usbduxfastsub_t *this_usbduxfastsub = dev->private;
00713         if (!this_usbduxfastsub) {
00714                 return -EFAULT;
00715         }
00716         down(&this_usbduxfastsub->sem);
00717         if (!(this_usbduxfastsub->probed)) {
00718                 up(&this_usbduxfastsub->sem);
00719                 return -ENODEV;
00720         }
00721 #ifdef CONFIG_COMEDI_DEBUG
00722         printk("comedi%d: usbduxfast_ai_inttrig\n", dev->minor);
00723 #endif
00724 
00725         if (trignum != 0) {
00726                 printk("comedi%d: usbduxfast_ai_inttrig: invalid trignum\n",
00727                         dev->minor);
00728                 up(&this_usbduxfastsub->sem);
00729                 return -EINVAL;
00730         }
00731         if (!(this_usbduxfastsub->ai_cmd_running)) {
00732                 this_usbduxfastsub->ai_cmd_running = 1;
00733                 ret = usbduxfastsub_submit_InURBs(this_usbduxfastsub);
00734                 if (ret < 0) {
00735                         printk("comedi%d: usbduxfast_ai_inttrig: urbSubmit: err=%d\n", dev->minor, ret);
00736                         this_usbduxfastsub->ai_cmd_running = 0;
00737                         up(&this_usbduxfastsub->sem);
00738                         return ret;
00739                 }
00740                 s->async->inttrig = NULL;
00741         } else {
00742                 printk("comedi%d: ai_inttrig but acqu is already running\n",
00743                         dev->minor);
00744         }
00745         up(&this_usbduxfastsub->sem);
00746         return 1;
00747 }
00748 
00749 // offsets for the GPIF bytes
00750 // the first byte is the command byte
00751 #define LENBASE 1+0x00
00752 #define OPBASE  1+0x08
00753 #define OUTBASE 1+0x10
00754 #define LOGBASE 1+0x18
00755 
00756 static int usbduxfast_ai_cmd(comedi_device * dev, comedi_subdevice * s)
00757 {
00758         comedi_cmd *cmd = &s->async->cmd;
00759         unsigned int chan, gain, rngmask = 0xff;
00760         int i, j, ret;
00761         usbduxfastsub_t *this_usbduxfastsub = dev->private;
00762         int result;
00763         long steps, steps_tmp;
00764 
00765 #ifdef CONFIG_COMEDI_DEBUG
00766         printk("comedi%d: usbduxfast_ai_cmd\n", dev->minor);
00767 #endif
00768         if (!this_usbduxfastsub) {
00769                 return -EFAULT;
00770         }
00771         down(&this_usbduxfastsub->sem);
00772         if (!(this_usbduxfastsub->probed)) {
00773                 up(&this_usbduxfastsub->sem);
00774                 return -ENODEV;
00775         }
00776         if (this_usbduxfastsub->ai_cmd_running) {
00777                 printk("comedi%d: ai_cmd not possible. Another ai_cmd is running.\n", dev->minor);
00778                 up(&this_usbduxfastsub->sem);
00779                 return -EBUSY;
00780         }
00781         // set current channel of the running aquisition to zero
00782         s->async->cur_chan = 0;
00783 
00784         // ignore the first buffers from the device if there is an error condition
00785         this_usbduxfastsub->ignore = PACKETS_TO_IGNORE;
00786 
00787         if (cmd->chanlist_len > 0) {
00788                 gain = CR_RANGE(cmd->chanlist[0]);
00789                 for (i = 0; i < cmd->chanlist_len; ++i) {
00790                         chan = CR_CHAN(cmd->chanlist[i]);
00791                         if (chan != i) {
00792                                 printk("comedi%d: cmd is accepting only consecutive channels.\n", dev->minor);
00793                                 up(&this_usbduxfastsub->sem);
00794                                 return -EINVAL;
00795                         }
00796                         if ((gain != CR_RANGE(cmd->chanlist[i]))
00797                                 && (cmd->chanlist_len > 3)) {
00798                                 printk("comedi%d: the gain must be the same for all channels.\n", dev->minor);
00799                                 up(&this_usbduxfastsub->sem);
00800                                 return -EINVAL;
00801                         }
00802                         if (i >= NUMCHANNELS) {
00803                                 printk("comedi%d: channel list too long\n",
00804                                         dev->minor);
00805                                 break;
00806                         }
00807                 }
00808         }
00809         steps = 0;
00810         if (cmd->scan_begin_src == TRIG_TIMER) {
00811                 printk("comedi%d: usbduxfast: scan_begin_src==TRIG_TIMER not valid.\n", dev->minor);
00812                 up(&this_usbduxfastsub->sem);
00813                 return -EINVAL;
00814         }
00815         if (cmd->convert_src == TRIG_TIMER) {
00816                 steps = (cmd->convert_arg * 30) / 1000;
00817         }
00818         if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) {
00819                 printk("comedi%d: usbduxfast: ai_cmd: steps=%ld, scan_begin_arg=%d. Not properly tested by cmdtest?\n", dev->minor, steps, cmd->scan_begin_arg);
00820                 up(&this_usbduxfastsub->sem);
00821                 return -EINVAL;
00822         }
00823         if (steps > MAX_SAMPLING_PERIOD) {
00824                 printk("comedi%d: usbduxfast: ai_cmd: sampling rate too low.\n",
00825                         dev->minor);
00826                 up(&this_usbduxfastsub->sem);
00827                 return -EINVAL;
00828         }
00829         if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1)
00830                 && (cmd->chanlist_len != 16)) {
00831                 printk("comedi%d: usbduxfast: ai_cmd: TRIG_EXT only with 1 or 16 channels possible.\n", dev->minor);
00832                 up(&this_usbduxfastsub->sem);
00833                 return -EINVAL;
00834         }
00835 #ifdef CONFIG_COMEDI_DEBUG
00836         printk("comedi%d: usbduxfast: steps=%ld, convert_arg=%u, ai_timer=%u\n",
00837                 dev->minor,
00838                 steps, cmd->convert_arg, this_usbduxfastsub->ai_timer);
00839 #endif
00840 
00841         switch (cmd->chanlist_len) {
00842                 // one channel
00843         case 1:
00844                 if (CR_RANGE(cmd->chanlist[0]) > 0)
00845                         rngmask = 0xff - 0x04;
00846                 else
00847                         rngmask = 0xff;
00848 
00849                 // for external trigger: looping in this state until the RDY0 pin
00850                 // becomes zero
00851                 if (cmd->start_src == TRIG_EXT) {       // we loop here until ready has been set
00852                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 0x01;   // branch back to state 0
00853                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0x01;    // deceision state w/o data
00854                         this_usbduxfastsub->dux_commands[OUTBASE + 0] =
00855                                 0xFF & rngmask;
00856                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0x00;   // RDY0 = 0
00857                 } else {        // we just proceed to state 1
00858                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 1;
00859                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0;
00860                         this_usbduxfastsub->dux_commands[OUTBASE + 0] =
00861                                 0xFF & rngmask;
00862                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
00863                 }
00864 
00865                 if (steps < MIN_SAMPLING_PERIOD) {
00866                         // for fast single channel aqu without mux
00867                         if (steps <= 1) {
00868                                 // we just stay here at state 1 and rexecute the same state
00869                                 // this gives us 30MHz sampling rate
00870                                 this_usbduxfastsub->dux_commands[LENBASE + 1] = 0x89;   // branch back to state 1
00871                                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0x03;    // deceision state with data
00872                                 this_usbduxfastsub->dux_commands[OUTBASE + 1] =
00873                                         0xFF & rngmask;
00874                                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0xFF;   // doesn't matter
00875                         } else {
00876                                 // we loop through two states: data and delay: max rate is 15Mhz
00877                                 this_usbduxfastsub->dux_commands[LENBASE + 1] =
00878                                         steps - 1;
00879                                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0x02;    // data
00880                                 this_usbduxfastsub->dux_commands[OUTBASE + 1] =
00881                                         0xFF & rngmask;
00882                                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;      // doesn't matter
00883 
00884                                 this_usbduxfastsub->dux_commands[LENBASE + 2] = 0x09;   // branch back to state 1
00885                                 this_usbduxfastsub->dux_commands[OPBASE + 2] = 0x01;    // deceision state w/o data
00886                                 this_usbduxfastsub->dux_commands[OUTBASE + 2] =
00887                                         0xFF & rngmask;
00888                                 this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0xFF;   // doesn't matter
00889                         }
00890                 } else {
00891                         // we loop through 3 states: 2x delay and 1x data. This gives a min
00892                         // sampling rate of 60kHz.
00893 
00894                         // we have 1 state with duration 1
00895                         steps = steps - 1;
00896 
00897                         // do the first part of the delay
00898                         this_usbduxfastsub->dux_commands[LENBASE + 1] =
00899                                 steps / 2;
00900                         this_usbduxfastsub->dux_commands[OPBASE + 1] = 0;
00901                         this_usbduxfastsub->dux_commands[OUTBASE + 1] =
00902                                 0xFF & rngmask;
00903                         this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
00904 
00905                         // and the second part
00906                         this_usbduxfastsub->dux_commands[LENBASE + 2] =
00907                                 steps - steps / 2;
00908                         this_usbduxfastsub->dux_commands[OPBASE + 2] = 0;
00909                         this_usbduxfastsub->dux_commands[OUTBASE + 2] =
00910                                 0xFF & rngmask;
00911                         this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
00912 
00913                         // get the data and branch back
00914                         this_usbduxfastsub->dux_commands[LENBASE + 3] = 0x09;   // branch back to state 1
00915                         this_usbduxfastsub->dux_commands[OPBASE + 3] = 0x03;    // deceision state w data
00916                         this_usbduxfastsub->dux_commands[OUTBASE + 3] =
00917                                 0xFF & rngmask;
00918                         this_usbduxfastsub->dux_commands[LOGBASE + 3] = 0xFF;   // doesn't matter
00919                 }
00920                 break;
00921 
00922         case 2:
00923                 // two channels
00924                 // commit data to the FIFO
00925                 if (CR_RANGE(cmd->chanlist[0]) > 0)
00926                         rngmask = 0xff - 0x04;
00927                 else
00928                         rngmask = 0xff;
00929                 this_usbduxfastsub->dux_commands[LENBASE + 0] = 1;
00930                 this_usbduxfastsub->dux_commands[OPBASE + 0] = 0x02;    // data
00931                 this_usbduxfastsub->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
00932                 this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
00933 
00934                 // we have 1 state with duration 1: state 0
00935                 steps_tmp = steps - 1;
00936 
00937                 if (CR_RANGE(cmd->chanlist[1]) > 0)
00938                         rngmask = 0xff - 0x04;
00939                 else
00940                         rngmask = 0xff;
00941                 // do the first part of the delay
00942                 this_usbduxfastsub->dux_commands[LENBASE + 1] = steps_tmp / 2;
00943                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0;
00944                 this_usbduxfastsub->dux_commands[OUTBASE + 1] = 0xFE & rngmask; //count
00945                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
00946 
00947                 // and the second part
00948                 this_usbduxfastsub->dux_commands[LENBASE + 2] =
00949                         steps_tmp - steps_tmp / 2;
00950                 this_usbduxfastsub->dux_commands[OPBASE + 2] = 0;
00951                 this_usbduxfastsub->dux_commands[OUTBASE + 2] = 0xFF & rngmask;
00952                 this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
00953 
00954                 this_usbduxfastsub->dux_commands[LENBASE + 3] = 1;
00955                 this_usbduxfastsub->dux_commands[OPBASE + 3] = 0x02;    // data
00956                 this_usbduxfastsub->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
00957                 this_usbduxfastsub->dux_commands[LOGBASE + 3] = 0;
00958 
00959                 // we have 2 states with duration 1: step 6 and the IDLE state
00960                 steps_tmp = steps - 2;
00961 
00962                 if (CR_RANGE(cmd->chanlist[0]) > 0)
00963                         rngmask = 0xff - 0x04;
00964                 else
00965                         rngmask = 0xff;
00966                 // do the first part of the delay
00967                 this_usbduxfastsub->dux_commands[LENBASE + 4] = steps_tmp / 2;
00968                 this_usbduxfastsub->dux_commands[OPBASE + 4] = 0;
00969                 this_usbduxfastsub->dux_commands[OUTBASE + 4] = (0xFF - 0x02) & rngmask;        //reset
00970                 this_usbduxfastsub->dux_commands[LOGBASE + 4] = 0;
00971 
00972                 // and the second part
00973                 this_usbduxfastsub->dux_commands[LENBASE + 5] =
00974                         steps_tmp - steps_tmp / 2;
00975                 this_usbduxfastsub->dux_commands[OPBASE + 5] = 0;
00976                 this_usbduxfastsub->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
00977                 this_usbduxfastsub->dux_commands[LOGBASE + 5] = 0;
00978 
00979                 this_usbduxfastsub->dux_commands[LENBASE + 6] = 1;
00980                 this_usbduxfastsub->dux_commands[OPBASE + 6] = 0;
00981                 this_usbduxfastsub->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
00982                 this_usbduxfastsub->dux_commands[LOGBASE + 6] = 0;
00983                 break;
00984 
00985         case 3:
00986                 // three channels
00987                 for (j = 0; j < 1; j++) {
00988                         if (CR_RANGE(cmd->chanlist[j]) > 0)
00989                                 rngmask = 0xff - 0x04;
00990                         else
00991                                 rngmask = 0xff;
00992                         // commit data to the FIFO and do the first part of the delay
00993                         this_usbduxfastsub->dux_commands[LENBASE + j * 2] =
00994                                 steps / 2;
00995                         this_usbduxfastsub->dux_commands[OPBASE + j * 2] = 0x02;        // data
00996                         this_usbduxfastsub->dux_commands[OUTBASE + j * 2] = 0xFF & rngmask;     // no change
00997                         this_usbduxfastsub->dux_commands[LOGBASE + j * 2] = 0;
00998 
00999                         if (CR_RANGE(cmd->chanlist[j + 1]) > 0)
01000                                 rngmask = 0xff - 0x04;
01001                         else
01002                                 rngmask = 0xff;
01003                         // do the second part of the delay
01004                         this_usbduxfastsub->dux_commands[LENBASE + j * 2 + 1] =
01005                                 steps - steps / 2;
01006                         this_usbduxfastsub->dux_commands[OPBASE + j * 2 + 1] = 0;       // no data
01007                         this_usbduxfastsub->dux_commands[OUTBASE + j * 2 + 1] = 0xFE & rngmask; //count
01008                         this_usbduxfastsub->dux_commands[LOGBASE + j * 2 + 1] =
01009                                 0;
01010                 }
01011 
01012                 // 2 steps with duration 1: the idele step and step 6:
01013                 steps_tmp = steps - 2;
01014                 // commit data to the FIFO and do the first part of the delay
01015                 this_usbduxfastsub->dux_commands[LENBASE + 4] = steps_tmp / 2;
01016                 this_usbduxfastsub->dux_commands[OPBASE + 4] = 0x02;    // data
01017                 this_usbduxfastsub->dux_commands[OUTBASE + 4] = 0xFF & rngmask; // no change
01018                 this_usbduxfastsub->dux_commands[LOGBASE + 4] = 0;
01019 
01020                 if (CR_RANGE(cmd->chanlist[0]) > 0)
01021                         rngmask = 0xff - 0x04;
01022                 else
01023                         rngmask = 0xff;
01024                 // do the second part of the delay
01025                 this_usbduxfastsub->dux_commands[LENBASE + 5] =
01026                         steps_tmp - steps_tmp / 2;
01027                 this_usbduxfastsub->dux_commands[OPBASE + 5] = 0;       // no data
01028                 this_usbduxfastsub->dux_commands[OUTBASE + 5] = (0xFF - 0x02) & rngmask;        // reset
01029                 this_usbduxfastsub->dux_commands[LOGBASE + 5] = 0;
01030 
01031                 this_usbduxfastsub->dux_commands[LENBASE + 6] = 1;
01032                 this_usbduxfastsub->dux_commands[OPBASE + 6] = 0;
01033                 this_usbduxfastsub->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
01034                 this_usbduxfastsub->dux_commands[LOGBASE + 6] = 0;
01035 
01036         case 16:
01037                 if (CR_RANGE(cmd->chanlist[0]) > 0)
01038                         rngmask = 0xff - 0x04;
01039                 else
01040                         rngmask = 0xff;
01041                 if (cmd->start_src == TRIG_EXT) {       // we loop here until ready has been set
01042                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 0x01;   // branch back to state 0
01043                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0x01;    // deceision state w/o data
01044                         this_usbduxfastsub->dux_commands[OUTBASE + 0] = (0xFF - 0x02) & rngmask;        // reset
01045                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0x00;   // RDY0 = 0
01046                 } else {        // we just proceed to state 1
01047                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 255;    // 30us reset pulse
01048                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0;
01049                         this_usbduxfastsub->dux_commands[OUTBASE + 0] = (0xFF - 0x02) & rngmask;        // reset
01050                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
01051                 }
01052 
01053                 // commit data to the FIFO
01054                 this_usbduxfastsub->dux_commands[LENBASE + 1] = 1;
01055                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0x02;    // data
01056                 this_usbduxfastsub->dux_commands[OUTBASE + 1] = 0xFF & rngmask;
01057                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
01058 
01059                 // we have 2 states with duration 1
01060                 steps = steps - 2;
01061 
01062                 // do the first part of the delay
01063                 this_usbduxfastsub->dux_commands[LENBASE + 2] = steps / 2;
01064                 this_usbduxfastsub->dux_commands[OPBASE + 2] = 0;
01065                 this_usbduxfastsub->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
01066                 this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
01067 
01068                 // and the second part
01069                 this_usbduxfastsub->dux_commands[LENBASE + 3] =
01070                         steps - steps / 2;
01071                 this_usbduxfastsub->dux_commands[OPBASE + 3] = 0;
01072                 this_usbduxfastsub->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
01073                 this_usbduxfastsub->dux_commands[LOGBASE + 3] = 0;
01074 
01075                 this_usbduxfastsub->dux_commands[LENBASE + 4] = 0x09;   // branch back to state 1
01076                 this_usbduxfastsub->dux_commands[OPBASE + 4] = 0x01;    // deceision state w/o data
01077                 this_usbduxfastsub->dux_commands[OUTBASE + 4] = 0xFF & rngmask;
01078                 this_usbduxfastsub->dux_commands[LOGBASE + 4] = 0xFF;   // doesn't matter
01079 
01080                 break;
01081 
01082         default:
01083                 printk("comedi %d: unsupported combination of channels\n",
01084                         dev->minor);
01085                 up(&this_usbduxfastsub->sem);
01086                 return -EFAULT;
01087         }
01088 
01089 #ifdef CONFIG_COMEDI_DEBUG
01090         printk("comedi %d: sending commands to the usb device\n", dev->minor);
01091 #endif
01092         // 0 means that the AD commands are sent
01093         result = send_dux_commands(this_usbduxfastsub, SENDADCOMMANDS);
01094         if (result < 0) {
01095                 printk("comedi%d: adc command could not be submitted. Aborting...\n", dev->minor);
01096                 up(&this_usbduxfastsub->sem);
01097                 return result;
01098         }
01099         if (cmd->stop_src == TRIG_COUNT) {
01100                 this_usbduxfastsub->ai_sample_count =
01101                         (cmd->stop_arg) * (cmd->scan_end_arg);
01102                 if (usbduxfastsub->ai_sample_count < 1) {
01103                         printk("comedi%d: (cmd->stop_arg)*(cmd->scan_end_arg)<1, aborting.\n", dev->minor);
01104                         up(&this_usbduxfastsub->sem);
01105                         return -EFAULT;
01106                 }
01107                 this_usbduxfastsub->ai_continous = 0;
01108         } else {
01109                 // continous aquisition
01110                 this_usbduxfastsub->ai_continous = 1;
01111                 this_usbduxfastsub->ai_sample_count = 0;
01112         }
01113 
01114         if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) {
01115                 // enable this acquisition operation
01116                 this_usbduxfastsub->ai_cmd_running = 1;
01117                 ret = usbduxfastsub_submit_InURBs(this_usbduxfastsub);
01118                 if (ret < 0) {
01119                         this_usbduxfastsub->ai_cmd_running = 0;
01120                         // fixme: unlink here??
01121                         up(&this_usbduxfastsub->sem);
01122                         return ret;
01123                 }
01124                 s->async->inttrig = NULL;
01125         } else {
01126                 /* TRIG_INT */
01127                 // don't enable the acquision operation
01128                 // wait for an internal signal
01129                 s->async->inttrig = usbduxfast_ai_inttrig;
01130         }
01131         up(&this_usbduxfastsub->sem);
01132 
01133         return 0;
01134 }
01135 
01136 /* Mode 0 is used to get a single conversion on demand */
01137 static int usbduxfast_ai_insn_read(comedi_device * dev,
01138         comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
01139 {
01140         int i, j, n, actual_length;
01141         int chan, range, rngmask;
01142         int err;
01143         usbduxfastsub_t *usbduxfastsub = dev->private;
01144 
01145         if (!usbduxfastsub) {
01146                 printk("comedi%d: ai_insn_read: no usb dev.\n", dev->minor);
01147                 return -ENODEV;
01148         }
01149 #ifdef CONFIG_COMEDI_DEBUG
01150         printk("comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
01151                 dev->minor, insn->n, insn->subdev);
01152 #endif
01153         down(&usbduxfastsub->sem);
01154         if (!(usbduxfastsub->probed)) {
01155                 up(&usbduxfastsub->sem);
01156                 return -ENODEV;
01157         }
01158         if (usbduxfastsub->ai_cmd_running) {
01159                 printk("comedi%d: ai_insn_read not possible. Async Command is running.\n", dev->minor);
01160                 up(&usbduxfastsub->sem);
01161                 return -EBUSY;
01162         }
01163         // sample one channel
01164         chan = CR_CHAN(insn->chanspec);
01165         range = CR_RANGE(insn->chanspec);
01166         // set command for the first channel
01167 
01168         if (range > 0)
01169                 rngmask = 0xff - 0x04;
01170         else
01171                 rngmask = 0xff;
01172         // commit data to the FIFO
01173         usbduxfastsub->dux_commands[LENBASE + 0] = 1;
01174         usbduxfastsub->dux_commands[OPBASE + 0] = 0x02; // data
01175         usbduxfastsub->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
01176         usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
01177 
01178         // do the first part of the delay
01179         usbduxfastsub->dux_commands[LENBASE + 1] = 12;
01180         usbduxfastsub->dux_commands[OPBASE + 1] = 0;
01181         usbduxfastsub->dux_commands[OUTBASE + 1] = 0xFE & rngmask;
01182         usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
01183 
01184         usbduxfastsub->dux_commands[LENBASE + 2] = 1;
01185         usbduxfastsub->dux_commands[OPBASE + 2] = 0;
01186         usbduxfastsub->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
01187         usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
01188 
01189         usbduxfastsub->dux_commands[LENBASE + 3] = 1;
01190         usbduxfastsub->dux_commands[OPBASE + 3] = 0;
01191         usbduxfastsub->dux_commands[OUTBASE + 3] = 0xFE & rngmask;
01192         usbduxfastsub->dux_commands[LOGBASE + 3] = 0;
01193 
01194         usbduxfastsub->dux_commands[LENBASE + 4] = 1;
01195         usbduxfastsub->dux_commands[OPBASE + 4] = 0;
01196         usbduxfastsub->dux_commands[OUTBASE + 4] = 0xFE & rngmask;
01197         usbduxfastsub->dux_commands[LOGBASE + 4] = 0;
01198 
01199         // second part
01200         usbduxfastsub->dux_commands[LENBASE + 5] = 12;
01201         usbduxfastsub->dux_commands[OPBASE + 5] = 0;
01202         usbduxfastsub->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
01203         usbduxfastsub->dux_commands[LOGBASE + 5] = 0;
01204 
01205         usbduxfastsub->dux_commands[LENBASE + 6] = 1;
01206         usbduxfastsub->dux_commands[OPBASE + 6] = 0;
01207         usbduxfastsub->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
01208         usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
01209 
01210 #ifdef CONFIG_COMEDI_DEBUG
01211         printk("comedi %d: sending commands to the usb device\n", dev->minor);
01212 #endif
01213         // 0 means that the AD commands are sent
01214         err = send_dux_commands(usbduxfastsub, SENDADCOMMANDS);
01215         if (err < 0) {
01216                 printk("comedi%d: adc command could not be submitted. Aborting...\n", dev->minor);
01217                 up(&usbduxfastsub->sem);
01218                 return err;
01219         }
01220 #ifdef CONFIG_COMEDI_DEBUG
01221         printk("comedi%d: usbduxfast: submitting in-urb: %x,%x\n",
01222                 usbduxfastsub->comedidev->minor,
01223                 (int)(usbduxfastsub->urbIn->context),
01224                 (int)(usbduxfastsub->urbIn->dev));
01225 #endif
01226         for (i = 0; i < PACKETS_TO_IGNORE; i++) {
01227                 err = USB_BULK_MSG(usbduxfastsub->usbdev,
01228                         usb_rcvbulkpipe(usbduxfastsub->usbdev, BULKINEP),
01229                         usbduxfastsub->transfer_buffer,
01230                         SIZEINBUF, &actual_length, 10000);
01231                 if (err < 0) {
01232                         printk("comedi%d: insn timeout. No data.\n",
01233                                 dev->minor);
01234                         up(&usbduxfastsub->sem);
01235                         return err;
01236                 }
01237         }
01238         // data points
01239         for (i = 0; i < insn->n;) {
01240                 err = USB_BULK_MSG(usbduxfastsub->usbdev,
01241                         usb_rcvbulkpipe(usbduxfastsub->usbdev, BULKINEP),
01242                         usbduxfastsub->transfer_buffer,
01243                         SIZEINBUF, &actual_length, 10000);
01244                 if (err < 0) {
01245                         printk("comedi%d: insn data error: %d\n",
01246                                 dev->minor, err);
01247                         up(&usbduxfastsub->sem);
01248                         return err;
01249                 }
01250                 n = actual_length / sizeof(uint16_t);
01251                 if ((n % 16) != 0) {
01252                         printk("comedi%d: insn data packet corrupted.\n",
01253                                 dev->minor);
01254                         up(&usbduxfastsub->sem);
01255                         return -EINVAL;
01256                 }
01257                 for (j = chan; (j < n) && (i < insn->n); j = j + 16) {
01258                         data[i] =
01259                                 ((uint16_t *) (usbduxfastsub->
01260                                         transfer_buffer))[j];
01261                         i++;
01262                 }
01263         }
01264         up(&usbduxfastsub->sem);
01265         return i;
01266 }
01267 
01268 static unsigned hex2unsigned(char *h)
01269 {
01270         unsigned hi, lo;
01271         if (h[0] > '9') {
01272                 hi = h[0] - 'A' + 0x0a;
01273         } else {
01274                 hi = h[0] - '0';
01275         }
01276         if (h[1] > '9') {
01277                 lo = h[1] - 'A' + 0x0a;
01278         } else {
01279                 lo = h[1] - '0';
01280         }
01281         return hi * 0x10 + lo;
01282 }
01283 
01284 // for FX2
01285 #define FIRMWARE_MAX_LEN 0x2000
01286 
01287 // taken from David Brownell's fxload and adjusted for this driver
01288 static int read_firmware(usbduxfastsub_t * usbduxfastsub,
01289                          const void *firmwarePtr,
01290                          long size)
01291 {
01292         int i = 0;
01293         unsigned char *fp = (char *)firmwarePtr;
01294         unsigned char *firmwareBinary = NULL;
01295         int res = 0;
01296         int maxAddr = 0;
01297 
01298         firmwareBinary = kmalloc(FIRMWARE_MAX_LEN, GFP_KERNEL);
01299         if (!firmwareBinary) {
01300                 printk("comedi_: usbduxfast: mem alloc for firmware failed\n");
01301                 return -ENOMEM;
01302         }
01303 
01304         for (;;) {
01305                 char buf[256], *cp;
01306                 char type;
01307                 int len;
01308                 int idx, off;
01309                 int j = 0;
01310 
01311                 // get one line
01312                 while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) {
01313                         buf[j] = fp[i];
01314                         i++;
01315                         j++;
01316                         if (j >= sizeof(buf)) {
01317                                 printk("comedi_: usbduxfast: bogus firmware file!\n");
01318                                 return -1;
01319                         }
01320                 }
01321                 // get rid of LF/CR/...
01322                 while ((i < size) && ((fp[i] == 13) || (fp[i] == 10)
01323                                 || (fp[i] == 0))) {
01324                         i++;
01325                 }
01326 
01327                 buf[j] = 0;
01328                 //printk("comedi_: buf=%s\n",buf);
01329 
01330                 /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
01331                 if (buf[0] == '#')
01332                         continue;
01333 
01334                 if (buf[0] != ':') {
01335                         printk("comedi_: usbduxfast: upload: not an ihex record: %s", buf);
01336                         return -EFAULT;
01337                 }
01338 
01339                 /* Read the length field (up to 16 bytes) */
01340                 len = hex2unsigned(buf + 1);
01341 
01342                 /* Read the target offset */
01343                 off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5);
01344 
01345                 if ((off + len) > maxAddr) {
01346                         maxAddr = off + len;
01347                 }
01348 
01349                 if (maxAddr >= FIRMWARE_MAX_LEN) {
01350                         printk("comedi_: usbduxfast: firmware upload goes beyond FX2 RAM boundaries.");
01351                         return -EFAULT;
01352                 }
01353                 //printk("comedi_: usbduxfast: off=%x, len=%x:",off,len);
01354 
01355                 /* Read the record type */
01356                 type = hex2unsigned(buf + 7);
01357 
01358                 /* If this is an EOF record, then make it so. */
01359                 if (type == 1) {
01360                         break;
01361                 }
01362 
01363                 if (type != 0) {
01364                         printk("comedi_: usbduxfast: unsupported record type: %u\n", type);
01365                         return -EFAULT;
01366                 }
01367 
01368                 for (idx = 0, cp = buf + 9; idx < len; idx += 1, cp += 2) {
01369                         firmwareBinary[idx + off] = hex2unsigned(cp);
01370                         //printk("%02x ",firmwareBinary[idx+off]);
01371                 }
01372                 //printk("\n");
01373 
01374                 if (i >= size) {
01375                         printk("comedi_: usbduxfast: unexpected end of hex file\n");
01376                         break;
01377                 }
01378 
01379         }
01380         res = firmwareUpload(usbduxfastsub, firmwareBinary, maxAddr + 1);
01381         kfree(firmwareBinary);
01382         return res;
01383 }
01384 
01385 static void tidy_up(usbduxfastsub_t * usbduxfastsub_tmp)
01386 {
01387 #ifdef CONFIG_COMEDI_DEBUG
01388         printk("comedi_: usbduxfast: tiding up\n");
01389 #endif
01390         if (!usbduxfastsub_tmp) {
01391                 return;
01392         }
01393 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
01394         // shows the usb subsystem that the driver is down
01395         if (usbduxfastsub_tmp->interface) {
01396                 usb_set_intfdata(usbduxfastsub_tmp->interface, NULL);
01397         }
01398 #endif
01399 
01400         usbduxfastsub_tmp->probed = 0;
01401 
01402         if (usbduxfastsub_tmp->urbIn) {
01403 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
01404                 // waits until a running transfer is over
01405                 // thus, under 2.4 hotplugging while a command
01406                 // is running is not safe
01407                 usb_kill_urb(usbduxfastsub_tmp->urbIn);
01408 #endif
01409                 if (usbduxfastsub_tmp->transfer_buffer) {
01410                         kfree(usbduxfastsub_tmp->transfer_buffer);
01411                         usbduxfastsub_tmp->transfer_buffer = NULL;
01412                 }
01413                 usb_free_urb(usbduxfastsub_tmp->urbIn);
01414                 usbduxfastsub_tmp->urbIn = NULL;
01415         }
01416         if (usbduxfastsub_tmp->insnBuffer) {
01417                 kfree(usbduxfastsub_tmp->insnBuffer);
01418                 usbduxfastsub_tmp->insnBuffer = NULL;
01419         }
01420         if (usbduxfastsub_tmp->dux_commands) {
01421                 kfree(usbduxfastsub_tmp->dux_commands);
01422                 usbduxfastsub_tmp->dux_commands = NULL;
01423         }
01424         usbduxfastsub_tmp->ai_cmd_running = 0;
01425 }
01426 
01427 static void usbduxfast_firmware_request_complete_handler(
01428         const struct firmware *fw,
01429         void *context)
01430 {
01431         usbduxfastsub_t * usbduxfastsub_tmp = (usbduxfastsub_t *)context;
01432         struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
01433         int ret;
01434 
01435         if(fw == NULL) {
01436                 return;
01437         }
01438 
01439         // we need to upload the firmware here because fw will be
01440         // freed one we've left this function
01441         ret=read_firmware(usbduxfastsub_tmp,
01442                           fw->data,
01443                           fw->size);
01444 
01445         if (ret) {
01446                 dev_err(&usbdev->dev,
01447                         "Could not upload firmware (err=%d)\n",
01448                         ret);
01449                 return;
01450         }
01451 
01452         comedi_usb_auto_config(usbdev, BOARDNAME);
01453 }
01454 
01455 // allocate memory for the urbs and initialise them
01456 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
01457 static void *usbduxfastsub_probe(struct usb_device *udev,
01458                                  unsigned int interfnum,
01459                                  const struct usb_device_id *id)
01460 {
01461 #else
01462 static int usbduxfastsub_probe(struct usb_interface *uinterf,
01463         const struct usb_device_id *id)
01464 {
01465         struct usb_device *udev = interface_to_usbdev(uinterf);
01466 #endif
01467         int i;
01468         int index;
01469         int ret;
01470 
01471         if (udev->speed != USB_SPEED_HIGH) {
01472                 printk("comedi_: usbduxfast_: This driver needs USB 2.0 to operate. Aborting...\n");
01473                 return PROBE_ERR_RETURN(-ENODEV);
01474         }
01475 #ifdef CONFIG_COMEDI_DEBUG
01476         printk("comedi_: usbduxfast_: finding a free structure for the usb-device\n");
01477 #endif
01478         down(&start_stop_sem);
01479         // look for a free place in the usbduxfast array
01480         index = -1;
01481         for (i = 0; i < NUMUSBDUXFAST; i++) {
01482                 if (!(usbduxfastsub[i].probed)) {
01483                         index = i;
01484                         break;
01485                 }
01486         }
01487 
01488         // no more space
01489         if (index == -1) {
01490                 printk("Too many usbduxfast-devices connected.\n");
01491                 up(&start_stop_sem);
01492                 return PROBE_ERR_RETURN(-EMFILE);
01493         }
01494 #ifdef CONFIG_COMEDI_DEBUG
01495         printk("comedi_: usbduxfast: usbduxfastsub[%d] is ready to connect to comedi.\n", index);
01496 #endif
01497 
01498         init_MUTEX(&(usbduxfastsub[index].sem));
01499         // save a pointer to the usb device
01500         usbduxfastsub[index].usbdev = udev;
01501 
01502 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
01503         // save the interface number
01504         usbduxfastsub[index].ifnum = interfnum;
01505 #else
01506         // 2.6: save the interface itself
01507         usbduxfastsub[index].interface = uinterf;
01508         // get the interface number from the interface
01509         usbduxfastsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
01510         // hand the private data over to the usb subsystem
01511         // will be needed for disconnect
01512         usb_set_intfdata(uinterf, &(usbduxfastsub[index]));
01513 #endif
01514 
01515 #ifdef CONFIG_COMEDI_DEBUG
01516         printk("comedi_: usbduxfast: ifnum=%d\n", usbduxfastsub[index].ifnum);
01517 #endif
01518         // create space for the commands going to the usb device
01519         usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER,
01520                 GFP_KERNEL);
01521         if (!usbduxfastsub[index].dux_commands) {
01522                 printk("comedi_: usbduxfast: error alloc space for dac commands\n");
01523                 tidy_up(&(usbduxfastsub[index]));
01524                 up(&start_stop_sem);
01525                 return PROBE_ERR_RETURN(-ENOMEM);
01526         }
01527         // create space of the instruction buffer
01528         usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL);
01529         if (!(usbduxfastsub[index].insnBuffer)) {
01530                 printk("comedi_: usbduxfast: could not alloc space for insnBuffer\n");
01531                 tidy_up(&(usbduxfastsub[index]));
01532                 up(&start_stop_sem);
01533                 return PROBE_ERR_RETURN(-ENOMEM);
01534         }
01535         // setting to alternate setting 1: enabling bulk ep
01536         i = usb_set_interface(usbduxfastsub[index].usbdev,
01537                 usbduxfastsub[index].ifnum, 1);
01538         if (i < 0) {
01539                 printk("comedi_: usbduxfast%d: could not switch to alternate setting 1.\n", index);
01540                 tidy_up(&(usbduxfastsub[index]));
01541                 up(&start_stop_sem);
01542                 return PROBE_ERR_RETURN(-ENODEV);
01543         }
01544         usbduxfastsub[index].urbIn = USB_ALLOC_URB(0);
01545         if (usbduxfastsub[index].urbIn == NULL) {
01546                 printk("comedi_: usbduxfast%d: Could not alloc. urb\n", index);
01547                 tidy_up(&(usbduxfastsub[index]));
01548                 up(&start_stop_sem);
01549                 return PROBE_ERR_RETURN(-ENOMEM);
01550         }
01551         usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL);
01552         if (!(usbduxfastsub[index].transfer_buffer)) {
01553                 printk("comedi_: usbduxfast%d: could not alloc. transb.\n",
01554                         index);
01555                 tidy_up(&(usbduxfastsub[index]));
01556                 up(&start_stop_sem);
01557                 return PROBE_ERR_RETURN(-ENOMEM);
01558         }
01559         // we've reached the bottom of the function
01560         usbduxfastsub[index].probed = 1;
01561         up(&start_stop_sem);
01562 
01563         ret = request_firmware_nowait(THIS_MODULE,
01564                                       FW_ACTION_HOTPLUG,
01565                                       "usbduxfast_firmware.hex",
01566                                       &udev->dev,
01567                                       usbduxfastsub + index,
01568                                       usbduxfast_firmware_request_complete_handler);
01569 
01570         if (ret) {
01571                 dev_err(&udev->dev,
01572                         "could not load firmware (err=%d)\n",
01573                         ret);
01574                 return ret;
01575         }
01576 
01577         printk("comedi_: usbduxfast%d has been successfully initialized.\n",
01578                index);
01579 
01580 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
01581         return (void *)(&usbduxfastsub[index]);
01582 #else
01583         // success
01584         return 0;
01585 #endif
01586 }
01587 
01588 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
01589 static void usbduxfastsub_disconnect(struct usb_device *udev, void *ptr)
01590 {
01591         usbduxfastsub_t *usbduxfastsub_tmp = (usbduxfastsub_t *) ptr;
01592 #else
01593 static void usbduxfastsub_disconnect(struct usb_interface *intf)
01594 {
01595         usbduxfastsub_t *usbduxfastsub_tmp = usb_get_intfdata(intf);
01596         struct usb_device *udev = interface_to_usbdev(intf);
01597 #endif
01598         if (!usbduxfastsub_tmp) {
01599                 printk("comedi_: usbduxfast: disconnect called with null pointer.\n");
01600                 return;
01601         }
01602         if (usbduxfastsub_tmp->usbdev != udev) {
01603                 printk("comedi_: usbduxfast: BUG! called with wrong ptr!!!\n");
01604                 return;
01605         }
01606 
01607         comedi_usb_auto_unconfig(udev);
01608 
01609         down(&start_stop_sem);
01610         down(&usbduxfastsub_tmp->sem);
01611         tidy_up(usbduxfastsub_tmp);
01612         up(&usbduxfastsub_tmp->sem);
01613         up(&start_stop_sem);
01614 #ifdef CONFIG_COMEDI_DEBUG
01615         printk("comedi_: usbduxfast: disconnected from the usb\n");
01616 #endif
01617 }
01618 
01619 // is called when comedi-config is called
01620 static int usbduxfast_attach(comedi_device * dev, comedi_devconfig * it)
01621 {
01622         int ret;
01623         int index;
01624         int i;
01625         comedi_subdevice *s = NULL;
01626         dev->private = NULL;
01627 
01628         down(&start_stop_sem);
01629         // find a valid device which has been detected by the probe function of the usb
01630         index = -1;
01631         for (i = 0; i < NUMUSBDUXFAST; i++) {
01632                 if ((usbduxfastsub[i].probed) && (!usbduxfastsub[i].attached)) {
01633                         index = i;
01634                         break;
01635                 }
01636         }
01637 
01638         if (index < 0) {
01639                 printk("comedi%d: usbduxfast: error: attach failed, no usbduxfast devs connected to the usb bus.\n", dev->minor);
01640                 up(&start_stop_sem);
01641                 return -ENODEV;
01642         }
01643 
01644         down(&(usbduxfastsub[index].sem));
01645         // pointer back to the corresponding comedi device
01646         usbduxfastsub[index].comedidev = dev;
01647 
01648         // trying to upload the firmware into the chip
01649         if (comedi_aux_data(it->options, 0) &&
01650             it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
01651                 read_firmware(&usbduxfastsub[index],
01652                               comedi_aux_data(it->options, 0),
01653                               it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
01654         }
01655 
01656         dev->board_name = BOARDNAME;
01657 
01658         /* set number of subdevices */
01659         dev->n_subdevices = N_SUBDEVICES;
01660 
01661         // allocate space for the subdevices
01662         if ((ret = alloc_subdevices(dev, N_SUBDEVICES)) < 0) {
01663                 printk("comedi%d: usbduxfast: error alloc space for subdev\n",
01664                         dev->minor);
01665                 up(&start_stop_sem);
01666                 return ret;
01667         }
01668 
01669         printk("comedi%d: usbduxfast: usb-device %d is attached to comedi.\n",
01670                 dev->minor, index);
01671         // private structure is also simply the usb-structure
01672         dev->private = usbduxfastsub + index;
01673         // the first subdevice is the A/D converter
01674         s = dev->subdevices + SUBDEV_AD;
01675         // the URBs get the comedi subdevice
01676         // which is responsible for reading
01677         // this is the subdevice which reads data
01678         dev->read_subdev = s;
01679         // the subdevice receives as private structure the
01680         // usb-structure
01681         s->private = NULL;
01682         // analog input
01683         s->type = COMEDI_SUBD_AI;
01684         // readable and ref is to ground
01685         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
01686         // 16 channels
01687         s->n_chan = 16;
01688         // length of the channellist
01689         s->len_chanlist = 16;
01690         // callback functions
01691         s->insn_read = usbduxfast_ai_insn_read;
01692         s->do_cmdtest = usbduxfast_ai_cmdtest;
01693         s->do_cmd = usbduxfast_ai_cmd;
01694         s->cancel = usbduxfast_ai_cancel;
01695         // max value from the A/D converter (12bit+1 bit for overflow)
01696         s->maxdata = 0x1000;
01697         // range table to convert to physical units
01698         s->range_table = &range_usbduxfast_ai_range;
01699 
01700         // finally decide that it's attached
01701         usbduxfastsub[index].attached = 1;
01702 
01703         up(&(usbduxfastsub[index].sem));
01704 
01705         up(&start_stop_sem);
01706 
01707         printk("comedi%d: successfully attached to usbduxfast.\n", dev->minor);
01708 
01709         return 0;
01710 }
01711 
01712 static int usbduxfast_detach(comedi_device * dev)
01713 {
01714         usbduxfastsub_t *usbduxfastsub_tmp;
01715 
01716 #ifdef CONFIG_COMEDI_DEBUG
01717         printk("comedi%d: usbduxfast: detach usb device\n", dev->minor);
01718 #endif
01719 
01720         if (!dev) {
01721                 printk("comedi?: usbduxfast: detach without dev variable...\n");
01722                 return -EFAULT;
01723         }
01724 
01725         usbduxfastsub_tmp = dev->private;
01726         if (!usbduxfastsub_tmp) {
01727                 printk("comedi?: usbduxfast: detach without ptr to usbduxfastsub[]\n");
01728                 return -EFAULT;
01729         }
01730 
01731         down(&usbduxfastsub_tmp->sem);
01732         down(&start_stop_sem);
01733         // Don't allow detach to free the private structure
01734         // It's one entry of of usbduxfastsub[]
01735         dev->private = NULL;
01736         usbduxfastsub_tmp->attached = 0;
01737         usbduxfastsub_tmp->comedidev = NULL;
01738 #ifdef CONFIG_COMEDI_DEBUG
01739         printk("comedi%d: usbduxfast: detach: successfully removed\n",
01740                 dev->minor);
01741 #endif
01742         up(&start_stop_sem);
01743         up(&usbduxfastsub_tmp->sem);
01744         return 0;
01745 }
01746 
01747 /* main driver struct */
01748 static comedi_driver driver_usbduxfast = {
01749       driver_name:"usbduxfast",
01750       module:THIS_MODULE,
01751       attach:usbduxfast_attach,
01752       detach:usbduxfast_detach,
01753 };
01754 
01755 static void init_usb_devices(void)
01756 {
01757         int index;
01758 #ifdef CONFIG_COMEDI_DEBUG
01759         printk("comedi_: usbduxfast: setting all possible devs to invalid\n");
01760 #endif
01761         // all devices entries are invalid to begin with
01762         // they will become valid by the probe function
01763         // and then finally by the attach-function
01764         for (index = 0; index < NUMUSBDUXFAST; index++) {
01765                 memset(&(usbduxfastsub[index]), 0x00,
01766                         sizeof(usbduxfastsub[index]));
01767                 init_MUTEX(&(usbduxfastsub[index].sem));
01768         }
01769 }
01770 
01771 // Table with the USB-devices: just now only testing IDs
01772 static struct usb_device_id usbduxfastsub_table[] = {
01773         //        { USB_DEVICE(0x4b4, 0x8613), //testing
01774         //        },
01775         {USB_DEVICE(0x13d8, 0x0010)     //real ID
01776                 },
01777         {USB_DEVICE(0x13d8, 0x0011)     //real ID
01778                 },
01779         {}                      /* Terminating entry */
01780 };
01781 
01782 MODULE_DEVICE_TABLE(usb, usbduxfastsub_table);
01783 
01784 // The usbduxfastsub-driver
01785 static struct usb_driver usbduxfastsub_driver = {
01786 #ifdef COMEDI_HAVE_USB_DRIVER_OWNER
01787       owner:THIS_MODULE,
01788 #endif
01789       name:BOARDNAME,
01790       probe:usbduxfastsub_probe,
01791       disconnect:usbduxfastsub_disconnect,
01792       id_table:usbduxfastsub_table,
01793 };
01794 
01795 // Can't use the nice macro as I have also to initialise the USB
01796 // subsystem:
01797 // registering the usb-system _and_ the comedi-driver
01798 static int init_usbduxfast(void)
01799 {
01800         printk(KERN_INFO KBUILD_MODNAME ": "
01801                DRIVER_VERSION ":" DRIVER_DESC "\n");
01802         init_usb_devices();
01803         usb_register(&usbduxfastsub_driver);
01804         comedi_driver_register(&driver_usbduxfast);
01805         return 0;
01806 }
01807 
01808 // deregistering the comedi driver and the usb-subsystem
01809 static void exit_usbduxfast(void)
01810 {
01811         comedi_driver_unregister(&driver_usbduxfast);
01812         usb_deregister(&usbduxfastsub_driver);
01813 }
01814 
01815 module_init(init_usbduxfast);
01816 module_exit(exit_usbduxfast);
01817 
01818 MODULE_AUTHOR(DRIVER_AUTHOR);
01819 MODULE_DESCRIPTION(DRIVER_DESC);
01820 MODULE_LICENSE("GPL");
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines