-#define DRIVER_VERSION "v1.00pre2"
+#define DRIVER_VERSION "v1.00pre8"
#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
-#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@cn.stir.ac.uk"
+#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
/*
module/usbdux.c
- Copyright (C) 2003 Bernd Porr, Bernd.Porr@cn.stir.ac.uk
+ Copyright (C) 2003 Bernd Porr, Bernd.Porr@f2s.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Description: University of Stirling USB DAQ & INCITE Technology Limited
Devices: [ITL] USB-DUX (usbdux.o)
Author: Bernd Porr <BerndPorr@f2s.com>
-Updated: 24 Jul 2004
+Updated: 10 Aug 2004
Status: testing
*/
* chipsets miss out IRQs. Deeper buffering is needed.
* 1.00: full USB 2.0 support for the A/D converter. Now: max 8kHz sampling rate.
* Firmware vers 1.00 is needed for this.
+ * Two 16 bit up/down/reset counter with a sampling rate of 1kHz
+ * And loads of cleaning up, in particular streamlining the
+ * bulk transfers.
*
*
*
* Todo:
* - use EP1in/out for sync digital I/O
+ * - PWM with the GPIF
*/
-//#define CONFIG_COMEDI_DEBUG
+//#define NOISY_DUX_DEBUGBUG
#define IRQOUTEP 2
-// Endpoint for the A/D channellist: bulk OUT
-#define CHANNELLISTEP 4
+// This EP sends DUX commands to USBDUX
+#define COMMAND_OUT_EP 4
-// Endpoint for a single A/D acquisition: bulk IN
-#define ADSINGLEEP 8
+// This EP receives the DUX commands from USBDUX
+#define COMMAND_IN_EP 8
// Number of channels
#define NUMCHANNELS 8
#define SUBDEV_COUNTER 3
+// number of retries to get the right dux command
+#define RETRIES 10
+
+
/////////////////////////////////////////////
// comedi constants
static comedi_lrange range_usbdux_ai_range = { 4, {
int16_t *inBuffer;
// input buffer for single insn
int16_t *insnBuffer;
- // output buffer for the ISO-transfer
+ // output buffer for single DA outputs
int16_t *outBuffer;
// interface number
int ifnum;
unsigned int ao_counter;
// interval in frames/uframes
unsigned int ai_interval;
- // A/D commands
- unsigned char *adc_commands;
// D/A commands
- unsigned char *dac_commands;
+ int8_t *dac_commands;
// commands
- unsigned char *dux_commands;
- short int insn_running;
+ int8_t *dux_commands;
struct semaphore sem;
} usbduxsub_t;
printk("comedi: usbdux_ai_cancel: this_usbduxsub=NULL\n");
return -EFAULT;
}
+ // prevent other CPUs from submitting new commands just now
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
static void usbduxsub_ai_IsocIrq(struct urb *urb)
#else
static void usbduxsub_ai_IsocIrq(struct urb *urb, struct pt_regs *regs)
-#endif
+#endif
{
- int i,err;
+ int i,err,n;
usbduxsub_t* this_usbduxsub;
comedi_device *this_comedidev;
comedi_subdevice *s;
-
+
// sanity checks
// is the urb there?
if (!urb) {
printk("comedi_: usbdux_: ao int-handler called with urb=NULL!\n");
return;
}
-
+
// the context variable points to the subdevice
this_comedidev=urb->context;
- if (!this_comedidev) {
- printk("comedi_: usbdux_: urb context is a NULL pointer!\n");
+ if (unlikely(!this_comedidev)) {
+ printk("comedi_: usbdux_: BUG! urb context is a NULL pointer!\n");
return;
}
-
+
// the private structure of the subdevice is usbduxsub_t
this_usbduxsub=this_comedidev->private;
- if (!this_usbduxsub) {
- printk("comedi_: usbdux_: private of comedi subdev is a NULL pointer!\n");
+ if (unlikely(!this_usbduxsub)) {
+ printk("comedi_: usbdux_: BUG! private of comedi subdev is a NULL pointer!\n");
return;
}
-
+
// subdevice which is the AD converter
s=this_comedidev->subdevices + SUBDEV_AD;
-
+
// first we test if something unusual has just happened
switch (urb->status) {
case 0:
- // success
// copy the result in the transfer buffer
memcpy(this_usbduxsub->inBuffer,
urb->transfer_buffer,
printk("comedi%d: usbdux: CRC error in ISO IN stream.\n",
this_usbduxsub->comedidev->minor);
#endif
-
+
break;
-
+
// happens after an unlink command
case -ECONNRESET:
case -ENOENT:
}
return;
-
// a real error on the bus
default:
// pass error to comedi if we are really running a command
// at this point we are reasonably sure that nothing dodgy has happened
// are we running a command?
- if (!(this_usbduxsub->ai_cmd_running)) {
+ if (unlikely((!(this_usbduxsub->ai_cmd_running)))) {
// not running a command
// do not continue execution if no asynchronous command is running
// in particular not resubmit
return;
}
- // really executing a command in this subdevice without USB errors
- this_usbduxsub->ai_counter--;
- if (this_usbduxsub->ai_counter<=0) {
- // timer zero, transfer measurements to comedi
- this_usbduxsub->ai_counter=this_usbduxsub->ai_timer;
-
- // test, if we transmit only a fixed number of samples
- if (!(this_usbduxsub->ai_continous)) {
- // not continous, fixed number of samples
- this_usbduxsub->ai_sample_count--;
-
- if (this_usbduxsub->ai_sample_count<0){
- // all samples transmitted to comedi
- usbdux_ai_stop(this_usbduxsub,
- 0);
- // say comedi that the acquistion is over
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(this_usbduxsub->comedidev,
- s,
- s->async->events);
- return;
- }
- }
+ urb->dev = this_usbduxsub->usbdev;
- // get the data from the USB bus and hand it over
- // to comedi
- for(i=0;i<s->async->cmd.chanlist_len;i++) {
- // transfer data
- if (CR_RANGE(s->async->cmd.chanlist[i])<=1) {
- comedi_buf_put
- (s->async,
- (this_usbduxsub->inBuffer[i])^0x800);
- } else {
- comedi_buf_put
- (s->async,
- this_usbduxsub->inBuffer[i]);
- }
+ // resubmit the urb
+ err=USB_SUBMIT_URB(urb);
+ if (unlikely(err<0)) {
+ printk("comedi_: usbdux_: urb resubmit failed in int-context! err=%d ",
+ err);
+ if (err==-EL2NSYNC) {
+ printk("--> buggy USB host controller or bug in IRQ handler!\n");
+ } else {
+ printk("\n");
}
- // tell comedi that data is there
+ s->async->events |= COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
comedi_event(this_usbduxsub->comedidev,
s,
s->async->events);
+ // don't do an unlink here
+ usbdux_ai_stop(this_usbduxsub,0);
+ return;
+ }
+
+ this_usbduxsub->ai_counter--;
+ if (likely(this_usbduxsub->ai_counter>0)) {
+ return;
}
- // it's an ISO transfer: we have to resubmit
- // are we still running a command?
- if (this_usbduxsub->ai_cmd_running) {
- // command is still running
- // resubmit urb for ISO transfer
- urb->dev = this_usbduxsub->usbdev;
- if ((err=USB_SUBMIT_URB(urb))<0) {
- printk("comedi_: usbdux_: urb resubmit failed in int-context! err=%d\n",
- err);
+ // timer zero, transfer measurements to comedi
+ this_usbduxsub->ai_counter=this_usbduxsub->ai_timer;
+
+ // test, if we transmit only a fixed number of samples
+ if (!(this_usbduxsub->ai_continous)) {
+ // not continous, fixed number of samples
+ this_usbduxsub->ai_sample_count--;
+ // all samples received?
+ if (this_usbduxsub->ai_sample_count<0){
+ // prevent a resubmit next time
+ usbdux_ai_stop(this_usbduxsub,
+ 0);
+ // say comedi that the acquistion is over
+ s->async->events |= COMEDI_CB_EOA;
+ comedi_event(this_usbduxsub->comedidev,
+ s,
+ s->async->events);
+ return;
}
}
+
+ // get the data from the USB bus and hand it over
+ // to comedi
+ n=s->async->cmd.chanlist_len;
+ for(i=0;i<n;i++) {
+ // transfer data
+ if (CR_RANGE(s->async->cmd.chanlist[i])<=1) {
+ comedi_buf_put
+ (s->async,
+ le16_to_cpu(this_usbduxsub->inBuffer[i])^0x800);
+ } else {
+ comedi_buf_put
+ (s->async,
+ le16_to_cpu(this_usbduxsub->inBuffer[i]));
+ }
+ }
+ // tell comedi that data is there
+ comedi_event(this_usbduxsub->comedidev,
+ s,
+ s->async->events);
}
+
static int usbduxsub_unlink_OutURBs(usbduxsub_t* usbduxsub_tmp) {
int i,j=0;
int err=0;
printk("comedi: usbdux_ao_cancel: this_usbduxsub=NULL\n");
return -EFAULT;
}
+ // prevent other CPUs from submitting a command just now
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
+
+
+
+
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
static void usbduxsub_ao_IsocIrq(struct urb *urb) {
#else
static void usbduxsub_ao_IsocIrq(struct urb *urb, struct pt_regs *regs) {
#endif
int i,ret;
- unsigned char* datap;
+ int8_t* datap;
usbduxsub_t* this_usbduxsub;
comedi_device *this_comedidev;
comedi_subdevice *s;
}
// transmit data to the USB bus
- ((unsigned char*)(urb->transfer_buffer))[0]=
+ ((uint8_t*)(urb->transfer_buffer))[0]=
s->async->cmd.chanlist_len;
for(i=0;i<s->async->cmd.chanlist_len;i++) {
if (i>=NUMOUTCHANNELS) {
break;
}
- datap=&(((unsigned char*)urb->transfer_buffer)[i*3+1]);
+ // pointer to the DA
+ datap=&(((int8_t*)urb->transfer_buffer)[i*3+1]);
+ // get the data from comedi
ret=comedi_buf_get
(s->async,
((sampl_t*)datap));
+ (uint16_t)(datap[0])=cpu_to_le16((uint16_t)(datap[0]));
datap[2]=this_usbduxsub->dac_commands[i];
/*printk("data[0]=%x, data[1]=%x, data[2]=%x\n",
datap[0],datap[1],datap[2]);*/
urb->iso_frame_desc[0].status = 0;
if ((ret=USB_SUBMIT_URB(urb))<0) {
printk("comedi_: usbdux_: ao urb resubm failed in int-cont.");
- printk("ret=%d\n",ret);
+ printk("ret=%d",ret);
+ if (ret==EL2NSYNC) {
+ printk("--> buggy USB host controller or bug in IRQ handling!\n");
+ } else {
+ printk("\n");
+ }
+ s->async->events |= COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
+ comedi_event(this_usbduxsub->comedidev,
+ s,
+ s->async->events);
+ // don't do an unlink here
+ usbdux_ai_stop(this_usbduxsub,0);
}
}
}
+
+
+
+
+
+
+
+
+
+
static int usbduxsub_start(usbduxsub_t* usbduxsub) {
int errcode=0;
- unsigned char local_transfer_buffer[16];
+ uint8_t local_transfer_buffer[16];
if (usbduxsub->probed) {
// 7f92 to zero
static int usbduxsub_stop(usbduxsub_t* usbduxsub) {
int errcode=0;
- unsigned char local_transfer_buffer[16];
+ uint8_t local_transfer_buffer[16];
if (usbduxsub->probed) {
// 7f92 to one
local_transfer_buffer[0]=1;
static int usbduxsub_upload(usbduxsub_t* usbduxsub,
- unsigned char* local_transfer_buffer,
+ uint8_t* local_transfer_buffer,
unsigned int startAddr,
unsigned int len) {
int errcode;
int firmwareUpload(usbduxsub_t* usbduxsub,
- unsigned char* firmwareBinary,
+ uint8_t* firmwareBinary,
int sizeFirmware) {
int ret;
// creates the ADC command for the MAX1271
-
-static unsigned char create_adc_command(unsigned int chan, int polarity, int range) {
+// range is the range value from comedi
+static int8_t create_adc_command(unsigned int chan, int range) {
+ int8_t p=(range<=1);
+ int8_t r=((range%2)==0);
return (chan<<4)|
- ((polarity==1)<<2)|
- ((range==1)<<3);
+ ((p==1)<<2)|
+ ((r==1)<<3);
}
static int send_dux_commands(usbduxsub_t* this_usbduxsub,int cmd_type) {
- int result,nsent,i;
- comedi_subdevice *s;
+ int result,nsent;
this_usbduxsub->dux_commands[0]=cmd_type;
- switch (cmd_type) {
- case SENDADCOMMANDS:
- case SENDSINGLEAD:
- // AD commands
- memcpy((this_usbduxsub->dux_commands)+1,
- this_usbduxsub->adc_commands,
- NUMCHANNELS);
- break;
- case SENDDACOMMANDS:
- // DA commands: send one channel to the USB board
- // Same format as in the synchronous case:
- // channel number + 16 bit value
- // number of channels: 1
- this_usbduxsub->dux_commands[1]=1;
- // one 16 bit value
- *((int16_t*)(this_usbduxsub->dux_commands+2))=this_usbduxsub->outBuffer[1];
- // channel number
- this_usbduxsub->dux_commands[4]=(this_usbduxsub->outBuffer[0]<<6);
- break;
- case SENDDIOCONFIGCOMMAND:
- // the firmware will ignore s->state and will set
- // only the direction
- case SENDDIOBITSCOMMAND:
- // sets the out bits at port B and write the data to it
- s=this_usbduxsub->comedidev->subdevices+SUBDEV_DIO;
- this_usbduxsub->dux_commands[1]=s->io_bits;
- this_usbduxsub->dux_commands[2]=s->state;
- break;
- case READCOUNTERCOMMAND:
- break;
- case WRITECOUNTERCOMMAND:
- break;
- default:
- printk("comedi%d: usbdux: illegal dux_command.\n",
- this_usbduxsub->comedidev->minor);
- return -EFAULT;
- }
-#ifdef CONFIG_COMEDI_DEBUG
+#ifdef NOISY_DUX_DEBUGBUG
printk("comedi%d: usbdux: dux_commands: ",
this_usbduxsub->comedidev->minor);
- for(i=0;i<SIZEOFDUXBUFFER;i++) {
- printk(" %02x",this_usbduxsub->dux_commands[i]);
+ for(result=0;result<SIZEOFDUXBUFFER;result++) {
+ printk(" %02x",this_usbduxsub->dux_commands[result]);
}
printk("\n");
#endif
result = usb_bulk_msg(this_usbduxsub->usbdev,
usb_sndbulkpipe(this_usbduxsub->usbdev,
- CHANNELLISTEP),
+ COMMAND_OUT_EP),
this_usbduxsub->dux_commands,
SIZEOFDUXBUFFER,
&nsent,
10*HZ);
if (result<0) {
- printk("comedi%d: could not transmit dux_commands to the usb-device, err=%d\n",
+ printk("comedi%d: could not transmit dux_command to the usb-device, err=%d\n",
this_usbduxsub->comedidev->minor,result);
}
return result;
+
+
+
+static int receive_dux_commands(usbduxsub_t* this_usbduxsub,int command) {
+ int result=-EFAULT;
+ int nrec;
+ int i;
+
+ for(i=0;i<RETRIES;i++) {
+ result = usb_bulk_msg(this_usbduxsub->usbdev,
+ usb_rcvbulkpipe(this_usbduxsub->usbdev,
+ COMMAND_IN_EP),
+ this_usbduxsub->insnBuffer,
+ SIZEINSNBUF,
+ &nrec,
+ 1*HZ);
+ if (result<0) {
+ printk("comedi%d: insn: USB error %d while receiving DUX command\n",
+ this_usbduxsub->comedidev->minor,result);
+ return result;
+ }
+ if (le16_to_cpu(this_usbduxsub->insnBuffer[0])==command) {
+ return result;
+ }
+ }
+ // this is only reached if the data has been requested a couple of times
+ printk("comedi%d: insn: wrong data returned from firmware: want cmd %d, got cmd %d.\n",
+ this_usbduxsub->comedidev->minor,
+ command,
+ le16_to_cpu(this_usbduxsub->insnBuffer[0]));
+ return -EFAULT;
+}
+
+
+
+
+
+
+
+
+
+
static int usbdux_ai_inttrig(comedi_device *dev,
comedi_subdevice *s,
unsigned int trignum)
static int usbdux_ai_cmd(comedi_device *dev, comedi_subdevice *s)
{
comedi_cmd *cmd = &s->async->cmd;
- unsigned int chan, gain;
+ unsigned int chan, range;
int i,ret;
usbduxsub_t* this_usbduxsub=dev->private;
int result;
if (!this_usbduxsub) {
return -EFAULT;
}
+
+ // block other CPUs from starting an ai_cmd
down(&this_usbduxsub->sem);
+
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
- if (this_usbduxsub->insn_running) {
- printk("comedi%d: ai_cmd not possible. Sync command is running.\n",
- dev->minor);
- up(&this_usbduxsub->sem);
- return -EBUSY;
- }
if (this_usbduxsub->ai_cmd_running) {
printk("comedi%d: ai_cmd not possible. Another ai_cmd is running.\n",
dev->minor);
}
// set current channel of the running aquisition to zero
- s->async->cur_chan = 0;
+ s->async->cur_chan=0;
- this_usbduxsub->adc_commands[0]=cmd->chanlist_len;
+ this_usbduxsub->dux_commands[1]=cmd->chanlist_len;
for(i=0; i < cmd->chanlist_len; ++i ) {
chan = CR_CHAN(cmd->chanlist[i]);
- gain = CR_RANGE(cmd->chanlist[i]);
+ range = CR_RANGE(cmd->chanlist[i]);
if (i>=NUMCHANNELS) {
printk("comedi%d: channel list too long\n",dev->minor);
break;
}
- this_usbduxsub->adc_commands[i+1]=create_adc_command(chan,gain<=1,(gain%2)==0);
-#ifdef CONFIG_COMEDI_DEBUG
- printk("comedi%d: adc command for ch %d is %x\n",
- dev->minor,
- i,
- this_usbduxsub->adc_commands[i]);
-#endif
+ this_usbduxsub->dux_commands[i+2]=create_adc_command(chan,range);
}
printk("size=%u\n",
NUMCHANNELS);
#endif
- // 0 means that the AD commands are sent
- result=send_dux_commands(this_usbduxsub,SENDADCOMMANDS);
- if (result<0) {
- printk("comedi%d: adc command could not be submitted. Aborting...\n",
- dev->minor);
+ if ((result=send_dux_commands(this_usbduxsub,SENDADCOMMANDS))<0) {
up(&this_usbduxsub->sem);
return result;
- }
+ }
+
if (this_usbduxsub->high_speed) {
// every channel gets a time window of 125us. Thus, if we
// sample all 8 channels we need 1ms. If we sample only
-static int single_adc_conv(usbduxsub_t* this_usbduxsub,lsampl_t* value) {
- int result=-EFAULT;
- int nrec;
-
- result = usb_bulk_msg(this_usbduxsub->usbdev,
- usb_rcvbulkpipe(this_usbduxsub->usbdev,
- ADSINGLEEP),
- this_usbduxsub->insnBuffer,
- SIZEINSNBUF,
- &nrec,
- 1*HZ);
- if (result<0) {
- printk("comedi%d: insn: USB error %d while requesting AD data.\n",
- this_usbduxsub->comedidev->minor,result);
- return result;
- }
- *value=((uint16_t*)(this_usbduxsub->insnBuffer))[0];
-#ifdef CONFIG_COMEDI_DEBUG
- printk("comedi%d: singleADC: value=%d\n",
- this_usbduxsub->comedidev->minor,
- *value);
-#endif
- return result;
-}
-
-
-
-
-
/* Mode 0 is used to get a single conversion on demand */
static int usbdux_ai_insn_read(comedi_device * dev,
lsampl_t *data)
{
int i;
- int twice;
lsampl_t one=0;
- int chan,gain;
+ int chan,range;
int err;
usbduxsub_t* this_usbduxsub=dev->private;
dev->minor);
return 0;
}
-#ifdef CONFIG_COMEDI_DEBUG
+#ifdef NOISY_DUX_DEBUGBUG
printk("comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
dev->minor,
insn->n,
up(&this_usbduxsub->sem);
return 0;
}
- if (this_usbduxsub->insn_running) {
- printk("comedi%d: another insn is running.\n",
- dev->minor);
- up(&this_usbduxsub->sem);
- return 0;
- }
+
// sample one channel
chan = CR_CHAN(insn->chanspec);
- gain = CR_RANGE(insn->chanspec);
+ range = CR_RANGE(insn->chanspec);
// set command for the first channel
- this_usbduxsub->adc_commands[0]=create_adc_command(chan,gain<=1,(gain%2)==0);
-#ifdef CONFIG_COMEDI_DEBUG
- printk("comedi%d: ai_insn_read, adc_command=%x\n",
- dev->minor,
- this_usbduxsub->adc_commands[0]);
-#endif
+ this_usbduxsub->dux_commands[1]=create_adc_command(chan,range);
+
// adc commands
- err=send_dux_commands(this_usbduxsub,SENDSINGLEAD);
- if (err<0) {
- printk("comedi%d: usb err =%d\n",
- dev->minor,err);
+ if ((err=send_dux_commands(this_usbduxsub,SENDSINGLEAD))<0) {
up(&this_usbduxsub->sem);
- return 0;
+ return err;
}
- this_usbduxsub->insn_running=1;
for(i=0 ; i < insn->n ; i++) {
- err=single_adc_conv(this_usbduxsub,&one);
- twice=1;
- if (err<0) {
- printk("comedi%d: insn. error: %d\n",dev->minor,err);
- this_usbduxsub->insn_running=0;
+ if ((err=receive_dux_commands(this_usbduxsub,SENDSINGLEAD))<0) {
up(&this_usbduxsub->sem);
return 0;
}
+ one=le16_to_cpu(this_usbduxsub->insnBuffer[1]);
if (CR_RANGE(insn->chanspec)<=1) {
one=one^0x800;
}
data[i]=one;
}
- this_usbduxsub->insn_running=0;
up(&this_usbduxsub->sem);
return i;
}
static int usbdux_ao_insn_write(comedi_device *dev, comedi_subdevice *s,
comedi_insn *insn, lsampl_t *data)
{
- int i;
+ int i,err;
int chan = CR_CHAN(insn->chanspec);
usbduxsub_t* this_usbduxsub=dev->private;
-#ifdef CONFIG_COMEDI_DEBUG
+#ifdef NOISY_DUX_DEBUGBUG
printk("comedi%d: ao_insn_write\n",dev->minor);
#endif
if (!this_usbduxsub) {
return 0;
}
- this_usbduxsub->insn_running=1;
for(i=0;i<insn->n;i++){
-#ifdef CONFIG_COMEDI_DEBUG
+#ifdef NOISY_DUX_DEBUGBUG
printk("comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",dev->minor,chan,i,data[i]);
#endif
- // send one channel to the board
- this_usbduxsub->outBuffer[0] = chan;
- this_usbduxsub->outBuffer[1] = data[i];
- send_dux_commands(this_usbduxsub,SENDDACOMMANDS);
+ // number of channels: 1
+ this_usbduxsub->dux_commands[1]=1;
+ // one 16 bit value
+ *((int16_t*)(this_usbduxsub->dux_commands+2))=cpu_to_le16(data[i]);
+ this_usbduxsub->outBuffer[chan]=data[i];
+ // channel number
+ this_usbduxsub->dux_commands[4]=(chan<<6);
+ if ((err=send_dux_commands(this_usbduxsub,SENDDACOMMANDS))<0) {
+ up(&this_usbduxsub->sem);
+ return err;
+ }
}
- this_usbduxsub->insn_running=0;
up(&this_usbduxsub->sem);
return i;
printk("comedi%d: usbdux_ao_cmd\n",dev->minor);
#endif
- if (this_usbduxsub->insn_running) {
- printk("comedi%d: ao_cmd: ERROR: synchronous insn is running\n",
- dev->minor
- );
- up(&this_usbduxsub->sem);
- return 0;
- }
-
// set current channel of the running aquisition to zero
s->async->cur_chan = 0;
for(i=0; i < cmd->chanlist_len; ++i ) {
-static unsigned hex2unsigned(char *h) {
- unsigned hi,lo;
- if (h[0]>'9') {
- hi=h[0]-'A'+0x0a;
- } else {
- hi=h[0]-'0';
- }
- if (h[1]>'9') {
- lo=h[1]-'A'+0x0a;
- } else {
- lo=h[1]-'0';
- }
- return hi*0x10+lo;
-}
-
-
-// for FX2
-#define FIRMWARE_MAX_LEN 0x2000
-
-// taken from David Brownell's fxload and adjusted for this driver
-static int read_firmware(usbduxsub_t* usbduxsub,int firmwarePtr,long size) {
- int i=0;
- unsigned char* fp=(char*)firmwarePtr;
- unsigned char* firmwareBinary=NULL;
- int res=0;
- int maxAddr=0;
-
- firmwareBinary = kmalloc(FIRMWARE_MAX_LEN,GFP_KERNEL);
- if(!firmwareBinary){
- printk("comedi_: usbdux: mem alloc for firmware failed\n"
- );
- return -ENOMEM;
- }
-
- for (;;) {
- char buf[256],*cp;
- char type;
- int len;
- int idx, off;
- int j=0;
-
- // get one line
- while ((i<size)&&(fp[i]!=13)&&(fp[i]!=10)) {
- buf[j]=fp[i];
- i++;
- j++;
- if (j>=sizeof(buf)) {
- printk("comedi_: usbdux: bogus firmware file!\n");
- return -1;
- }
- }
- // get rid of LF/CR/...
- while ((i<size)&&((fp[i]==13)||(fp[i]==10)||(fp[i]==0))) {
- i++;
- }
-
- buf[j]=0;
- //printk("comedi_: buf=%s\n",buf);
-
- /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
- if (buf[0] == '#')
- continue;
-
- if (buf[0] != ':') {
- printk("comedi_: usbdux: upload: not an ihex record: %s", buf);
- return -EFAULT;
- }
-
- /* Read the length field (up to 16 bytes) */
- len = hex2unsigned(buf+1);
-
- /* Read the target offset */
- off = (hex2unsigned(buf+3)*0x0100)+hex2unsigned(buf+5);
-
- if ((off+len)>maxAddr) {
- maxAddr=off+len;
- }
-
- if (maxAddr>=FIRMWARE_MAX_LEN) {
- printk("comedi_: usbdux: firmware upload goes beyond FX2 RAM boundaries.");
- return -EFAULT;
- }
-
- //printk("comedi_: usbdux: off=%x, len=%x:",off,len);
-
- /* Read the record type */
- type = hex2unsigned(buf+7);
-
- /* If this is an EOF record, then make it so. */
- if (type == 1) {
- break;
- }
-
- if (type != 0) {
- printk("comedi_: usbdux: unsupported record type: %u\n",type);
- return -EFAULT;
- }
-
- for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) {
- firmwareBinary[idx+off] = hex2unsigned(cp);
- //printk("%02x ",firmwareBinary[idx+off]);
- }
- //printk("\n");
-
- if (i>=size) {
- printk("comedi_: usbdux: unexpected end of hex file\n");
- break;
- }
-
- }
- res=firmwareUpload(usbduxsub,firmwareBinary,maxAddr+1);
- kfree(firmwareBinary);
- return res;
-}
-
-
-
static int usbdux_dio_insn_config (comedi_device *dev,
comedi_subdevice *s,
comedi_insn *insn,
-static int single_dio_read(usbduxsub_t* this_usbduxsub,lsampl_t* value) {
- int result=-EFAULT;
- int nrec;
-
- result = usb_bulk_msg(this_usbduxsub->usbdev,
- usb_rcvbulkpipe(this_usbduxsub->usbdev,
- ADSINGLEEP),
- this_usbduxsub->insnBuffer,
- SIZEINSNBUF,
- &nrec,
- 1*HZ);
- if (result<0) {
- printk("comedi%d: insn: USB error %d while DIO data.\n",
- this_usbduxsub->comedidev->minor,result);
- return result;
- }
-#ifdef CONFIG_COMEDI_DEBUG
- printk("comedi%d: usbdux: dio_read: buffer[0]=%d\n",
- this_usbduxsub->comedidev->minor,
- this_usbduxsub->insnBuffer[0]);
-#endif
- *value=(lsampl_t)(this_usbduxsub->insnBuffer[0]);
- return result;
-}
-
-
-
-
static int usbdux_dio_insn_bits (comedi_device *dev,
comedi_subdevice *s,
comedi_insn *insn,
lsampl_t *data) {
usbduxsub_t* this_usbduxsub=dev->private;
+ int err;
if (!this_usbduxsub) {
return -EFAULT;
}
+
+ if (insn->n!=2) return -EINVAL;
+
down(&this_usbduxsub->sem);
+
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
- if (insn->n!=2) return -EINVAL;
-
- if (this_usbduxsub->insn_running) {
- printk("comedi%d: dio not possible. Sync command is running.\n",dev->minor);
- up(&this_usbduxsub->sem);
- return -EBUSY;
- }
-
/* The insn data is a mask in data[0] and the new data
* in data[1], each channel cooresponding to a bit. */
s->state &= ~data[0];
s->state |= data[0]&data[1];
-
- this_usbduxsub->insn_running=1;
+ this_usbduxsub->dux_commands[1]=s->io_bits;
+ this_usbduxsub->dux_commands[2]=s->state;
- /* Write out the new digital output lines */
// This command also tells the firmware to return
// the digital input lines
- send_dux_commands(this_usbduxsub,
- SENDDIOBITSCOMMAND);
- /* on return, data[1] contains the value of the digital
- * input/output lines. */
- single_dio_read(this_usbduxsub,data+1);
+ if ((err=send_dux_commands(this_usbduxsub,SENDDIOBITSCOMMAND))<0) {
+ up(&this_usbduxsub->sem);
+ return err;
+ }
+ if ((err=receive_dux_commands(this_usbduxsub,SENDDIOBITSCOMMAND))<0) {
+ up(&this_usbduxsub->sem);
+ return err;
+ }
- this_usbduxsub->insn_running=0;
+ data[1]=le16_to_cpu(this_usbduxsub->insnBuffer[1]);
up(&this_usbduxsub->sem);
-
return 2;
}
-static int counter_read(usbduxsub_t* this_usbduxsub,int chan,lsampl_t* value) {
- int result=-EFAULT;
- int nrec;
-
- result = usb_bulk_msg(this_usbduxsub->usbdev,
- usb_rcvbulkpipe(this_usbduxsub->usbdev,
- ADSINGLEEP),
- this_usbduxsub->insnBuffer,
- SIZEINSNBUF,
- &nrec,
- 1*HZ);
- if (result<0) {
- printk("comedi%d: insn: USB error %d while counter data rec.\n",
- this_usbduxsub->comedidev->minor,result);
- return result;
- }
- *value=(lsampl_t)(((int16_t*)(this_usbduxsub->insnBuffer))[chan]);
-#ifdef CONFIG_COMEDI_DEBUG
- printk("comedi%d: usbdux: counter #%d read: value=%d\n",
- this_usbduxsub->comedidev->minor,
- chan,
- *value);
-#endif
- return result;
-}
-
-
// reads the 4 counters
// only two are used just now
static int usbdux_counter_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) {
usbduxsub_t* this_usbduxsub=dev->private;
int chan=insn->chanspec;
+ int err;
if (!this_usbduxsub) {
return -EFAULT;
return -ENODEV;
}
-
- if (this_usbduxsub->insn_running) {
- printk("comedi%d: counter read: another sync command is running.\n",dev->minor);
+ if ((err=send_dux_commands(this_usbduxsub,READCOUNTERCOMMAND))<0) {
up(&this_usbduxsub->sem);
- return -EBUSY;
- }
-
- this_usbduxsub->insn_running=1;
-
- send_dux_commands(this_usbduxsub,
- READCOUNTERCOMMAND);
-
- counter_read(this_usbduxsub,chan,data);
+ return err;
+ }
- this_usbduxsub->insn_running=0;
+ if ((err=receive_dux_commands(this_usbduxsub,READCOUNTERCOMMAND))<0) {
+ up(&this_usbduxsub->sem);
+ return err;
+ }
+ data[0]=le16_to_cpu(this_usbduxsub->insnBuffer[chan+1]);
up(&this_usbduxsub->sem);
-
- return 1;
+ return 1;
}
-static int usbdux_counter_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) {
+static int usbdux_counter_write(comedi_device *dev,comedi_subdevice *s,
+ comedi_insn *insn,lsampl_t *data) {
usbduxsub_t* this_usbduxsub=dev->private;
+ int err;
if (!this_usbduxsub) {
return -EFAULT;
return -ENODEV;
}
- if (this_usbduxsub->insn_running) {
- printk("comedi%d: counter write: another sync command is running.\n",dev->minor);
- up(&this_usbduxsub->sem);
- return -EBUSY;
- }
-
- this_usbduxsub->insn_running=1;
-
this_usbduxsub->dux_commands[1]=insn->chanspec;
- *((int16_t*)(this_usbduxsub->dux_commands+2))=*data;
-
- send_dux_commands(this_usbduxsub,
- WRITECOUNTERCOMMAND);
+ *((int16_t*)(this_usbduxsub->dux_commands+2))=cpu_to_le16(*data);
- this_usbduxsub->insn_running=0;
+ if ((err=send_dux_commands(this_usbduxsub,WRITECOUNTERCOMMAND))<0) {
+ up(&this_usbduxsub->sem);
+ return err;
+ }
up(&this_usbduxsub->sem);
kfree(usbduxsub_tmp->inBuffer);
usbduxsub_tmp->inBuffer=NULL;
}
- if (usbduxsub_tmp->adc_commands) {
- kfree(usbduxsub_tmp->adc_commands);
- usbduxsub_tmp->adc_commands=NULL;
- }
if (usbduxsub_tmp->dac_commands) {
kfree(usbduxsub_tmp->dac_commands);
usbduxsub_tmp->dac_commands=NULL;
}
usbduxsub_tmp->ai_cmd_running=0;
usbduxsub_tmp->ao_cmd_running=0;
- usbduxsub_tmp->insn_running=0;
}
+static unsigned hex2unsigned(char *h) {
+ unsigned hi,lo;
+ if (h[0]>'9') {
+ hi=h[0]-'A'+0x0a;
+ } else {
+ hi=h[0]-'0';
+ }
+ if (h[1]>'9') {
+ lo=h[1]-'A'+0x0a;
+ } else {
+ lo=h[1]-'0';
+ }
+ return hi*0x10+lo;
+}
+
+
+// for FX2
+#define FIRMWARE_MAX_LEN 0x2000
+
+// taken from David Brownell's fxload and adjusted for this driver
+static int read_firmware(usbduxsub_t* usbduxsub,int firmwarePtr,long size) {
+ int i=0;
+ unsigned char* fp=(char*)firmwarePtr;
+ unsigned char* firmwareBinary=NULL;
+ int res=0;
+ int maxAddr=0;
+
+ firmwareBinary = kmalloc(FIRMWARE_MAX_LEN,GFP_KERNEL);
+ if(!firmwareBinary){
+ printk("comedi_: usbdux: mem alloc for firmware failed\n"
+ );
+ return -ENOMEM;
+ }
+
+ for (;;) {
+ char buf[256],*cp;
+ char type;
+ int len;
+ int idx, off;
+ int j=0;
+
+ // get one line
+ while ((i<size)&&(fp[i]!=13)&&(fp[i]!=10)) {
+ buf[j]=fp[i];
+ i++;
+ j++;
+ if (j>=sizeof(buf)) {
+ printk("comedi_: usbdux: bogus firmware file!\n");
+ return -1;
+ }
+ }
+ // get rid of LF/CR/...
+ while ((i<size)&&((fp[i]==13)||(fp[i]==10)||(fp[i]==0))) {
+ i++;
+ }
+
+ buf[j]=0;
+ //printk("comedi_: buf=%s\n",buf);
+
+ /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
+ if (buf[0] == '#')
+ continue;
+
+ if (buf[0] != ':') {
+ printk("comedi_: usbdux: upload: not an ihex record: %s", buf);
+ return -EFAULT;
+ }
+
+ /* Read the length field (up to 16 bytes) */
+ len = hex2unsigned(buf+1);
+
+ /* Read the target offset */
+ off = (hex2unsigned(buf+3)*0x0100)+hex2unsigned(buf+5);
+
+ if ((off+len)>maxAddr) {
+ maxAddr=off+len;
+ }
+
+ if (maxAddr>=FIRMWARE_MAX_LEN) {
+ printk("comedi_: usbdux: firmware upload goes beyond FX2 RAM boundaries.");
+ return -EFAULT;
+ }
+
+ //printk("comedi_: usbdux: off=%x, len=%x:",off,len);
+
+ /* Read the record type */
+ type = hex2unsigned(buf+7);
+
+ /* If this is an EOF record, then make it so. */
+ if (type == 1) {
+ break;
+ }
+
+ if (type != 0) {
+ printk("comedi_: usbdux: unsupported record type: %u\n",type);
+ return -EFAULT;
+ }
+
+ for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) {
+ firmwareBinary[idx+off] = hex2unsigned(cp);
+ //printk("%02x ",firmwareBinary[idx+off]);
+ }
+ //printk("\n");
+
+ if (i>=size) {
+ printk("comedi_: usbdux: unexpected end of hex file\n");
+ break;
+ }
+
+ }
+ res=firmwareUpload(usbduxsub,firmwareBinary,maxAddr+1);
+ kfree(firmwareBinary);
+ return res;
+}
+
+
+
+
+
+
usbduxsub[index].high_speed=(usbduxsub[index].usbdev->speed==USB_SPEED_HIGH);
- // create space for the commands of the AD converter: max num of ch plus actual number
- usbduxsub[index].adc_commands=kmalloc(NUMCHANNELS+1,
- GFP_KERNEL);
- if (!usbduxsub[index].adc_commands) {
- printk("comedi_: usbdux: error alloc space for adc commands\n");
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return PROBE_ERR_RETURN( -ENOMEM);
- }
-
// create space for the commands of the DA converter
usbduxsub[index].dac_commands=kmalloc(NUMOUTCHANNELS,
GFP_KERNEL);