These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / usbduxsigma.c
index dc0b25a..456e9f1 100644 (file)
@@ -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>
 #define USBDUXSUB_CPUCS 0xE600
 
 /* 300Hz max frequ under PWM */
-#define MIN_PWM_PERIOD  ((long)(1E9/300))
+#define MIN_PWM_PERIOD  ((long)(1E9 / 300))
 
 /* Default PWM frequency */
-#define PWM_DEFAULT_PERIOD ((long)(1E9/100))
+#define PWM_DEFAULT_PERIOD ((long)(1E9 / 100))
 
 /* Number of channels (16 AD and offset)*/
 #define NUMCHANNELS 16
 
 /* Size of one A/D value */
-#define SIZEADIN          ((sizeof(uint32_t)))
+#define SIZEADIN          ((sizeof(u32)))
 
 /*
  * Size of the async input-buffer IN BYTES, the DIO state is transmitted
  * as the first byte.
  */
-#define SIZEINBUF         (((NUMCHANNELS+1)*SIZEADIN))
+#define SIZEINBUF         (((NUMCHANNELS + 1) * SIZEADIN))
 
 /* 16 bytes. */
 #define SIZEINSNBUF       16
 #define NUMOUTCHANNELS    8
 
 /* size of one value for the D/A converter: channel and value */
-#define SIZEDAOUT          ((sizeof(uint8_t)+sizeof(uint16_t)))
+#define SIZEDAOUT          ((sizeof(u8) + sizeof(uint16_t)))
 
 /*
  * Size of the output-buffer in bytes
  * Actually only the first 4 triplets are used but for the
  * high speed mode we need to pad it to 8 (microframes).
  */
-#define SIZEOUTBUF         ((8*SIZEDAOUT))
+#define SIZEOUTBUF         ((8 * SIZEDAOUT))
 
 /*
  * Size of the buffer for the dux commands: just now max size is determined
  * by the analogue out + command byte + panic bytes...
  */
-#define SIZEOFDUXBUFFER    ((8*SIZEDAOUT+2))
+#define SIZEOFDUXBUFFER    ((8 * SIZEDAOUT + 2))
 
 /* Number of in-URBs which receive the data: min=2 */
 #define NUMOFINBUFFERSFULL     5
 #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
@@ -149,13 +150,13 @@ struct usbduxsigma_private {
        /* PWM period */
        unsigned int pwm_period;
        /* PWM internal delay for the GPIF in the FX2 */
-       uint8_t pwm_delay;
+       u8 pwm_delay;
        /* size of the PWM buffer which holds the bit pattern */
        int pwm_buf_sz;
        /* input buffer for the ISO-transfer */
        __be32 *in_buf;
        /* input buffer for single insn */
-       uint8_t *insn_buf;
+       u8 *insn_buf;
 
        unsigned high_speed:1;
        unsigned ai_cmd_running:1;
@@ -171,8 +172,8 @@ struct usbduxsigma_private {
        /* interval in frames/uframes */
        unsigned int ai_interval;
        /* commands */
-       uint8_t *dux_commands;
-       struct semaphore sem;
+       u8 *dux_commands;
+       struct mutex mut;
 };
 
 static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs)
@@ -198,10 +199,10 @@ static int usbduxsigma_ai_cancel(struct comedi_device *dev,
 {
        struct usbduxsigma_private *devpriv = dev->private;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        /* unlink only if it is really running */
        usbduxsigma_ai_stop(dev, devpriv->ai_cmd_running);
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return 0;
 }
@@ -213,28 +214,31 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev,
        struct usbduxsigma_private *devpriv = dev->private;
        struct comedi_async *async = s->async;
        struct comedi_cmd *cmd = &async->cmd;
-       uint32_t val;
+       u32 val;
        int ret;
        int i;
 
-       devpriv->ai_counter--;
-       if (devpriv->ai_counter == 0) {
-               devpriv->ai_counter = devpriv->ai_timer;
+       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 */
+                       /*
+                        * Get the data from the USB bus and hand it over
+                        * to comedi. Note, first byte is the DIO state.
+                        */
+                       for (i = 0; i < cmd->chanlist_len; i++) {
+                               val = be32_to_cpu(devpriv->in_buf[i + 1]);
+                               val &= 0x00ffffff; /* strip status byte */
+                               val = comedi_offset_munge(s, val);
+                               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 */
@@ -321,10 +325,10 @@ static int usbduxsigma_ao_cancel(struct comedi_device *dev,
 {
        struct usbduxsigma_private *devpriv = dev->private;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        /* unlink only if it is really running */
        usbduxsigma_ao_stop(dev, devpriv->ao_cmd_running);
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return 0;
 }
@@ -336,7 +340,7 @@ static void usbduxsigma_ao_handle_urb(struct comedi_device *dev,
        struct usbduxsigma_private *devpriv = dev->private;
        struct comedi_async *async = s->async;
        struct comedi_cmd *cmd = &async->cmd;
-       uint8_t *datap;
+       u8 *datap;
        int ret;
        int i;
 
@@ -374,10 +378,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 +442,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 +452,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 +481,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 +509,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,
@@ -550,6 +536,14 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
        if (err)
                return 3;
 
+       /* Step 4: fix up any arguments */
+
+       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;
+
        return 0;
 }
 
@@ -558,13 +552,12 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
  * range is the range value from comedi
  */
 static void create_adc_command(unsigned int chan,
-                              uint8_t *muxsg0,
-                              uint8_t *muxsg1)
+                              u8 *muxsg0, u8 *muxsg1)
 {
        if (chan < 8)
                (*muxsg0) = (*muxsg0) | (1 << chan);
        else if (chan < 16)
-               (*muxsg1) = (*muxsg1) | (1 << (chan-8));
+               (*muxsg1) = (*muxsg1) | (1 << (chan - 8));
 }
 
 static int usbbuxsigma_send_cmd(struct comedi_device *dev, int cmd_type)
@@ -616,19 +609,19 @@ static int usbduxsigma_ai_inttrig(struct comedi_device *dev,
        if (trig_num != cmd->start_arg)
                return -EINVAL;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        if (!devpriv->ai_cmd_running) {
                devpriv->ai_cmd_running = 1;
                ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs,
                                              devpriv->n_ai_urbs, 1);
                if (ret < 0) {
                        devpriv->ai_cmd_running = 0;
-                       up(&devpriv->sem);
+                       mutex_unlock(&devpriv->mut);
                        return ret;
                }
                s->async->inttrig = NULL;
        }
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return 1;
 }
@@ -639,13 +632,13 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
        struct usbduxsigma_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
        unsigned int len = cmd->chanlist_len;
-       uint8_t muxsg0 = 0;
-       uint8_t muxsg1 = 0;
-       uint8_t sysred = 0;
+       u8 muxsg0 = 0;
+       u8 muxsg1 = 0;
+       u8 sysred = 0;
        int ret;
        int i;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
 
        if (devpriv->high_speed) {
                /*
@@ -669,17 +662,18 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
                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) {
-               up(&devpriv->sem);
+               mutex_unlock(&devpriv->mut);
                return ret;
        }
 
@@ -692,7 +686,7 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
                                              devpriv->n_ai_urbs, 1);
                if (ret < 0) {
                        devpriv->ai_cmd_running = 0;
-                       up(&devpriv->sem);
+                       mutex_unlock(&devpriv->mut);
                        return ret;
                }
                s->async->inttrig = NULL;
@@ -700,7 +694,7 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
                s->async->inttrig = usbduxsigma_ai_inttrig;
        }
 
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return 0;
 }
@@ -712,15 +706,15 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev,
 {
        struct usbduxsigma_private *devpriv = dev->private;
        unsigned int chan = CR_CHAN(insn->chanspec);
-       uint8_t muxsg0 = 0;
-       uint8_t muxsg1 = 0;
-       uint8_t sysred = 0;
+       u8 muxsg0 = 0;
+       u8 muxsg1 = 0;
+       u8 sysred = 0;
        int ret;
        int i;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        if (devpriv->ai_cmd_running) {
-               up(&devpriv->sem);
+               mutex_unlock(&devpriv->mut);
                return -EBUSY;
        }
 
@@ -737,16 +731,16 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev,
        /* adc commands */
        ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD);
        if (ret < 0) {
-               up(&devpriv->sem);
+               mutex_unlock(&devpriv->mut);
                return ret;
        }
 
        for (i = 0; i < insn->n; i++) {
-               uint32_t val;
+               u32 val;
 
                ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD);
                if (ret < 0) {
-                       up(&devpriv->sem);
+                       mutex_unlock(&devpriv->mut);
                        return ret;
                }
 
@@ -754,11 +748,9 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev,
                val = be32_to_cpu(get_unaligned((__be32
                                                 *)(devpriv->insn_buf + 1)));
                val &= 0x00ffffff;      /* strip status byte */
-               val ^= 0x00800000;      /* convert to unsigned */
-
-               data[i] = val;
+               data[i] = comedi_offset_munge(s, val);
        }
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return insn->n;
 }
@@ -771,9 +763,9 @@ static int usbduxsigma_ao_insn_read(struct comedi_device *dev,
        struct usbduxsigma_private *devpriv = dev->private;
        int ret;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        ret = comedi_readback_insn_read(dev, s, insn, data);
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return ret;
 }
@@ -788,9 +780,9 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev,
        int ret;
        int i;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        if (devpriv->ao_cmd_running) {
-               up(&devpriv->sem);
+               mutex_unlock(&devpriv->mut);
                return -EBUSY;
        }
 
@@ -800,12 +792,12 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev,
                devpriv->dux_commands[3] = chan;        /* channel number */
                ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DA_CMD);
                if (ret < 0) {
-                       up(&devpriv->sem);
+                       mutex_unlock(&devpriv->mut);
                        return ret;
                }
                s->readback[chan] = data[i];
        }
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return insn->n;
 }
@@ -821,19 +813,19 @@ static int usbduxsigma_ao_inttrig(struct comedi_device *dev,
        if (trig_num != cmd->start_arg)
                return -EINVAL;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
        if (!devpriv->ao_cmd_running) {
                devpriv->ao_cmd_running = 1;
                ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs,
                                              devpriv->n_ao_urbs, 0);
                if (ret < 0) {
                        devpriv->ao_cmd_running = 0;
-                       up(&devpriv->sem);
+                       mutex_unlock(&devpriv->mut);
                        return ret;
                }
                s->async->inttrig = NULL;
        }
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return 1;
 }
@@ -843,35 +835,28 @@ 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);
 
        if (err) {
-               up(&devpriv->sem);
+               mutex_unlock(&devpriv->mut);
                return 1;
        }
 
@@ -889,17 +874,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);
@@ -912,6 +887,14 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev,
        if (err)
                return 3;
 
+       /* Step 4: fix up any arguments */
+
+       tmp = rounddown(cmd->scan_begin_arg, 1000000);
+       err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp);
+
+       if (err)
+               return 4;
+
        return 0;
 }
 
@@ -922,21 +905,15 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
        struct comedi_cmd *cmd = &s->async->cmd;
        int ret;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
 
-       if (cmd->convert_src == TRIG_TIMER) {
-               /*
-                * timing of the conversion itself: every 125 us
-                * at high speed (not used yet)
-                */
-               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;
-       }
+       /*
+        * 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;
 
@@ -947,7 +924,7 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
                                              devpriv->n_ao_urbs, 0);
                if (ret < 0) {
                        devpriv->ao_cmd_running = 0;
-                       up(&devpriv->sem);
+                       mutex_unlock(&devpriv->mut);
                        return ret;
                }
                s->async->inttrig = NULL;
@@ -955,7 +932,7 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
                s->async->inttrig = usbduxsigma_ao_inttrig;
        }
 
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return 0;
 }
@@ -986,7 +963,7 @@ static int usbduxsigma_dio_insn_bits(struct comedi_device *dev,
        struct usbduxsigma_private *devpriv = dev->private;
        int ret;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
 
        comedi_dio_update_state(s, data);
 
@@ -1013,7 +990,7 @@ static int usbduxsigma_dio_insn_bits(struct comedi_device *dev,
        ret = insn->n;
 
 done:
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 
        return ret;
 }
@@ -1239,9 +1216,10 @@ static int usbduxsigma_pwm_config(struct comedi_device *dev,
 
 static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan)
 {
+       struct comedi_subdevice *s = dev->read_subdev;
        struct usbduxsigma_private *devpriv = dev->private;
-       uint8_t sysred;
-       uint32_t val;
+       u8 sysred;
+       u32 val;
        int ret;
 
        switch (chan) {
@@ -1283,9 +1261,8 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan)
        /* 32 bits big endian from the A/D converter */
        val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1)));
        val &= 0x00ffffff;      /* strip status byte */
-       val ^= 0x00800000;      /* convert to unsigned */
 
-       return (int)val;
+       return (int)comedi_offset_munge(s, val);
 }
 
 static int usbduxsigma_firmware_upload(struct comedi_device *dev,
@@ -1293,8 +1270,8 @@ static int usbduxsigma_firmware_upload(struct comedi_device *dev,
                                       unsigned long context)
 {
        struct usb_device *usb = comedi_to_usb_dev(dev);
-       uint8_t *buf;
-       uint8_t *tmp;
+       u8 *buf;
+       u8 *tmp;
        int ret;
 
        if (!data)
@@ -1417,10 +1394,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) {
@@ -1488,7 +1462,7 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev,
        if (!devpriv)
                return -ENOMEM;
 
-       sema_init(&devpriv->sem, 1);
+       mutex_init(&devpriv->mut);
 
        usb_set_intfdata(intf, devpriv);
 
@@ -1602,7 +1576,7 @@ static void usbduxsigma_detach(struct comedi_device *dev)
        if (!devpriv)
                return;
 
-       down(&devpriv->sem);
+       mutex_lock(&devpriv->mut);
 
        /* force unlink all urbs */
        usbduxsigma_ai_stop(dev, 1);
@@ -1611,7 +1585,7 @@ static void usbduxsigma_detach(struct comedi_device *dev)
 
        usbduxsigma_free_usb_buffers(dev);
 
-       up(&devpriv->sem);
+       mutex_unlock(&devpriv->mut);
 }
 
 static struct comedi_driver usbduxsigma_driver = {
@@ -1643,7 +1617,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);