aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/usbduxsigma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/usbduxsigma.c')
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c214
1 files changed, 91 insertions, 123 deletions
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index eaa9add491df..649cf47184a4 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -1,6 +1,6 @@
/*
* usbduxsigma.c
- * Copyright (C) 2011-2014 Bernd Porr, mail@berndporr.me.uk
+ * Copyright (C) 2011-2015 Bernd Porr, mail@berndporr.me.uk
*
* 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
@@ -18,7 +18,7 @@
* Description: University of Stirling USB DAQ & INCITE Technology Limited
* Devices: [ITL] USB-DUX-SIGMA (usbduxsigma)
* Author: Bernd Porr <mail@berndporr.me.uk>
- * Updated: 10 Oct 2014
+ * Updated: 20 July 2015
* Status: stable
*/
@@ -39,6 +39,7 @@
* 0.4: fixed D/A voltage range
* 0.5: various bug fixes, health check at startup
* 0.6: corrected wrong input range
+ * 0.7: rewrite code that urb->interval is always 1
*/
#include <linux/kernel.h>
@@ -122,7 +123,7 @@
#define RETRIES 10
/* bulk transfer commands to usbduxsigma */
-#define USBBUXSIGMA_AD_CMD 0
+#define USBBUXSIGMA_AD_CMD 9
#define USBDUXSIGMA_DA_CMD 1
#define USBDUXSIGMA_DIO_CFG_CMD 2
#define USBDUXSIGMA_DIO_BITS_CMD 3
@@ -217,24 +218,28 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev,
int ret;
int i;
- devpriv->ai_counter--;
- if (devpriv->ai_counter == 0) {
- devpriv->ai_counter = devpriv->ai_timer;
-
- /* get the data from the USB bus and hand it over to comedi */
- for (i = 0; i < cmd->chanlist_len; i++) {
- /* transfer data, note first byte is the DIO state */
- val = be32_to_cpu(devpriv->in_buf[i+1]);
- val &= 0x00ffffff; /* strip status byte */
- val ^= 0x00800000; /* convert to unsigned */
+ if ((urb->actual_length > 0) && (urb->status != -EXDEV)) {
+ devpriv->ai_counter--;
+ if (devpriv->ai_counter == 0) {
+ devpriv->ai_counter = devpriv->ai_timer;
+
+ /* get the data from the USB bus
+ and hand it over to comedi */
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ /* transfer data,
+ note first byte is the DIO state */
+ val = be32_to_cpu(devpriv->in_buf[i+1]);
+ val &= 0x00ffffff; /* strip status byte */
+ val ^= 0x00800000; /* convert to unsigned */
+
+ if (!comedi_buf_write_samples(s, &val, 1))
+ return;
+ }
- if (!comedi_buf_write_samples(s, &val, 1))
- return;
+ if (cmd->stop_src == TRIG_COUNT &&
+ async->scans_done >= cmd->stop_arg)
+ async->events |= COMEDI_CB_EOA;
}
-
- if (cmd->stop_src == TRIG_COUNT &&
- async->scans_done >= cmd->stop_arg)
- async->events |= COMEDI_CB_EOA;
}
/* if command is still running, resubmit urb */
@@ -374,10 +379,7 @@ static void usbduxsigma_ao_handle_urb(struct comedi_device *dev,
urb->transfer_buffer_length = SIZEOUTBUF;
urb->dev = comedi_to_usb_dev(dev);
urb->status = 0;
- if (devpriv->high_speed)
- urb->interval = 8; /* uframes */
- else
- urb->interval = 1; /* frames */
+ urb->interval = 1; /* (u)frames */
urb->number_of_packets = 1;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = SIZEOUTBUF;
@@ -441,7 +443,6 @@ static int usbduxsigma_submit_urbs(struct comedi_device *dev,
int input_urb)
{
struct usb_device *usb = comedi_to_usb_dev(dev);
- struct usbduxsigma_private *devpriv = dev->private;
struct urb *urb;
int ret;
int i;
@@ -452,7 +453,7 @@ static int usbduxsigma_submit_urbs(struct comedi_device *dev,
/* in case of a resubmission after an unlink... */
if (input_urb)
- urb->interval = devpriv->ai_interval;
+ urb->interval = 1;
urb->context = dev;
urb->dev = usb;
urb->status = 0;
@@ -481,6 +482,7 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
struct usbduxsigma_private *devpriv = dev->private;
int high_speed = devpriv->high_speed;
int interval = usbduxsigma_chans_to_interval(cmd->chanlist_len);
+ unsigned int tmp;
int err = 0;
/* Step 1 : check if triggers are trivially valid */
@@ -508,35 +510,20 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
- if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
- err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- unsigned int tmp;
-
- if (high_speed) {
- /*
- * In high speed mode microframes are possible.
- * However, during one microframe we can roughly
- * sample two channels. Thus, the more channels
- * are in the channel list the more time we need.
- */
- err |= comedi_check_trigger_arg_min(&cmd->
- scan_begin_arg,
- (1000000 / 8 *
- interval));
-
- tmp = (cmd->scan_begin_arg / 125000) * 125000;
- } else {
- /* full speed */
- /* 1kHz scans every USB frame */
- err |= comedi_check_trigger_arg_min(&cmd->
- scan_begin_arg,
- 1000000);
-
- tmp = (cmd->scan_begin_arg / 1000000) * 1000000;
- }
- err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp);
+ if (high_speed) {
+ /*
+ * In high speed mode microframes are possible.
+ * However, during one microframe we can roughly
+ * sample two channels. Thus, the more channels
+ * are in the channel list the more time we need.
+ */
+ err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
+ (125000 * interval));
+ } else {
+ /* full speed */
+ /* 1kHz scans every USB frame */
+ err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
+ 1000000);
}
err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
@@ -552,21 +539,8 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
/* Step 4: fix up any arguments */
- if (high_speed) {
- /*
- * every 2 channels get a time window of 125us. Thus, if we
- * sample all 16 channels we need 1ms. If we sample only one
- * channel we need only 125us
- */
- devpriv->ai_interval = interval;
- devpriv->ai_timer = cmd->scan_begin_arg / (125000 * interval);
- } else {
- /* interval always 1ms */
- devpriv->ai_interval = 1;
- devpriv->ai_timer = cmd->scan_begin_arg / 1000000;
- }
- if (devpriv->ai_timer < 1)
- err |= -EINVAL;
+ tmp = rounddown(cmd->scan_begin_arg, high_speed ? 125000 : 1000000);
+ err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp);
if (err)
return 4;
@@ -668,19 +642,36 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
down(&devpriv->sem);
+ if (devpriv->high_speed) {
+ /*
+ * every 2 channels get a time window of 125us. Thus, if we
+ * sample all 16 channels we need 1ms. If we sample only one
+ * channel we need only 125us
+ */
+ unsigned int interval = usbduxsigma_chans_to_interval(len);
+
+ devpriv->ai_interval = interval;
+ devpriv->ai_timer = cmd->scan_begin_arg / (125000 * interval);
+ } else {
+ /* interval always 1ms */
+ devpriv->ai_interval = 1;
+ devpriv->ai_timer = cmd->scan_begin_arg / 1000000;
+ }
+
for (i = 0; i < len; i++) {
unsigned int chan = CR_CHAN(cmd->chanlist[i]);
create_adc_command(chan, &muxsg0, &muxsg1);
}
- devpriv->dux_commands[1] = len; /* num channels per time step */
- devpriv->dux_commands[2] = 0x12; /* CONFIG0 */
- devpriv->dux_commands[3] = 0x03; /* CONFIG1: 23kHz sample, delay 0us */
- devpriv->dux_commands[4] = 0x00; /* CONFIG3: diff. channels off */
- devpriv->dux_commands[5] = muxsg0;
- devpriv->dux_commands[6] = muxsg1;
- devpriv->dux_commands[7] = sysred;
+ devpriv->dux_commands[1] = devpriv->ai_interval;
+ devpriv->dux_commands[2] = len; /* num channels per time step */
+ devpriv->dux_commands[3] = 0x12; /* CONFIG0 */
+ devpriv->dux_commands[4] = 0x03; /* CONFIG1: 23kHz sample, delay 0us */
+ devpriv->dux_commands[5] = 0x00; /* CONFIG3: diff. channels off */
+ devpriv->dux_commands[6] = muxsg0;
+ devpriv->dux_commands[7] = muxsg1;
+ devpriv->dux_commands[8] = sysred;
ret = usbbuxsigma_send_cmd(dev, USBBUXSIGMA_AD_CMD);
if (ret < 0) {
@@ -848,29 +839,22 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
struct usbduxsigma_private *devpriv = dev->private;
+ unsigned int tmp;
int err = 0;
- int high_speed;
- unsigned int flags;
-
- /* high speed conversions are not used yet */
- high_speed = 0; /* (devpriv->high_speed) */
/* Step 1 : check if triggers are trivially valid */
err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
- if (high_speed) {
- /*
- * start immediately a new scan
- * the sampling rate is set by the coversion rate
- */
- flags = TRIG_FOLLOW;
- } else {
- /* start a new scan (output at once) with a timer */
- flags = TRIG_TIMER;
- }
- err |= comedi_check_trigger_src(&cmd->scan_begin_src, flags);
-
+ /*
+ * For now, always use "scan" timing with all channels updated at once
+ * (cmd->scan_begin_src == TRIG_TIMER, cmd->convert_src == TRIG_NOW).
+ *
+ * In a future version, "convert" timing with channels updated
+ * indivually may be supported in high speed mode
+ * (cmd->scan_begin_src == TRIG_FOLLOW, cmd->convert_src == TRIG_TIMER).
+ */
+ err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
@@ -894,17 +878,7 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev,
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
- if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
- err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
- 1000000);
- }
-
- /* not used now, is for later use */
- if (cmd->convert_src == TRIG_TIMER)
- err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 125000);
+ err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 1000000);
err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
cmd->chanlist_len);
@@ -919,19 +893,8 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev,
/* Step 4: fix up any arguments */
- /* we count in timer steps */
- if (high_speed) {
- /* timing of the conversion itself: every 125 us */
- devpriv->ao_timer = cmd->convert_arg / 125000;
- } else {
- /*
- * timing of the scan: every 1ms
- * we get all channels at once
- */
- devpriv->ao_timer = cmd->scan_begin_arg / 1000000;
- }
- if (devpriv->ao_timer < 1)
- err |= -EINVAL;
+ tmp = rounddown(cmd->scan_begin_arg, 1000000);
+ err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp);
if (err)
return 4;
@@ -948,6 +911,14 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
down(&devpriv->sem);
+ /*
+ * For now, only "scan" timing is supported. A future version may
+ * support "convert" timing in high speed mode.
+ *
+ * Timing of the scan: every 1ms all channels updated at once.
+ */
+ devpriv->ao_timer = cmd->scan_begin_arg / 1000000;
+
devpriv->ao_counter = devpriv->ao_timer;
if (cmd->start_src == TRIG_NOW) {
@@ -1427,10 +1398,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
urb->transfer_buffer_length = SIZEOUTBUF;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = SIZEOUTBUF;
- if (devpriv->high_speed)
- urb->interval = 8; /* uframes */
- else
- urb->interval = 1; /* frames */
+ urb->interval = 1; /* (u)frames */
}
if (devpriv->pwm_buf_sz) {
@@ -1653,7 +1621,7 @@ static struct usb_driver usbduxsigma_usb_driver = {
};
module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver);
-MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
-MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com");
+MODULE_AUTHOR("Bernd Porr, mail@berndporr.me.uk");
+MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- mail@berndporr.me.uk");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE);