![]() |
RTXI 1.3
|
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");