staging: comedi: usbdux: tidy up usbdux_dio_insn_config()
[linux-2.6-block.git] / drivers / staging / comedi / drivers / usbdux.c
index 1f6750950a5d719dc87d2598cd62d637c6829706..cdb02876a7190798e9dbcb3322fa5c432e093070 100644 (file)
@@ -449,22 +449,19 @@ static int usbdux_ao_stop(struct comedi_device *dev, int do_unlink)
        return ret;
 }
 
-/* force unlink, is called by comedi */
 static int usbdux_ao_cancel(struct comedi_device *dev,
                            struct comedi_subdevice *s)
 {
-       struct usbdux_private *this_usbduxsub = dev->private;
-       int res = 0;
-
-       if (!this_usbduxsub)
-               return -EFAULT;
+       struct usbdux_private *devpriv = dev->private;
+       int ret = 0;
 
        /* prevent other CPUs from submitting a command just now */
-       down(&this_usbduxsub->sem);
+       down(&devpriv->sem);
        /* unlink only if it is really running */
-       res = usbdux_ao_stop(dev, this_usbduxsub->ao_cmd_running);
-       up(&this_usbduxsub->sem);
-       return res;
+       ret = usbdux_ao_stop(dev, devpriv->ao_cmd_running);
+       up(&devpriv->sem);
+
+       return ret;
 }
 
 static void usbduxsub_ao_isoc_irq(struct urb *urb)
@@ -855,114 +852,109 @@ static int receive_dux_commands(struct comedi_device *dev, int command)
 }
 
 static int usbdux_ai_inttrig(struct comedi_device *dev,
-                            struct comedi_subdevice *s, unsigned int trignum)
+                            struct comedi_subdevice *s,
+                            unsigned int trignum)
 {
-       int ret;
-       struct usbdux_private *this_usbduxsub = dev->private;
-       if (!this_usbduxsub)
-               return -EFAULT;
+       struct usbdux_private *devpriv = dev->private;
+       int ret = -EINVAL;
 
-       down(&this_usbduxsub->sem);
+       down(&devpriv->sem);
 
-       if (trignum != 0) {
-               up(&this_usbduxsub->sem);
-               return -EINVAL;
-       }
-       if (!(this_usbduxsub->ai_cmd_running)) {
-               this_usbduxsub->ai_cmd_running = 1;
+       if (trignum != 0)
+               goto ai_trig_exit;
+
+       if (!devpriv->ai_cmd_running) {
+               devpriv->ai_cmd_running = 1;
                ret = usbduxsub_submit_inurbs(dev);
                if (ret < 0) {
-                       this_usbduxsub->ai_cmd_running = 0;
-                       up(&this_usbduxsub->sem);
-                       return ret;
+                       devpriv->ai_cmd_running = 0;
+                       goto ai_trig_exit;
                }
                s->async->inttrig = NULL;
+       } else {
+               ret = -EBUSY;
        }
-       up(&this_usbduxsub->sem);
-       return 1;
+
+ai_trig_exit:
+       up(&devpriv->sem);
+       return ret;
 }
 
 static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+       struct usbdux_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
-       unsigned int chan, range;
-       int i, ret;
-       struct usbdux_private *this_usbduxsub = dev->private;
-       int result;
-
-       if (!this_usbduxsub)
-               return -EFAULT;
+       int len = cmd->chanlist_len;
+       int ret = -EBUSY;
+       int i;
 
        /* block other CPUs from starting an ai_cmd */
-       down(&this_usbduxsub->sem);
-       if (this_usbduxsub->ai_cmd_running) {
-               up(&this_usbduxsub->sem);
-               return -EBUSY;
-       }
+       down(&devpriv->sem);
+
+       if (devpriv->ai_cmd_running)
+               goto ai_cmd_exit;
+
        /* set current channel of the running acquisition to zero */
        s->async->cur_chan = 0;
 
-       this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
-       for (i = 0; i < cmd->chanlist_len; ++i) {
-               chan = CR_CHAN(cmd->chanlist[i]);
-               range = CR_RANGE(cmd->chanlist[i]);
+       devpriv->dux_commands[1] = len;
+       for (i = 0; i < len; ++i) {
+               unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+               unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
                if (i >= NUMCHANNELS)
                        break;
-               this_usbduxsub->dux_commands[i + 2] =
-                   create_adc_command(chan, range);
-       }
 
-       result = send_dux_commands(dev, SENDADCOMMANDS);
-       if (result < 0) {
-               up(&this_usbduxsub->sem);
-               return result;
+               devpriv->dux_commands[i + 2] = create_adc_command(chan, range);
        }
 
-       if (this_usbduxsub->high_speed) {
+       ret = send_dux_commands(dev, SENDADCOMMANDS);
+       if (ret < 0)
+               goto ai_cmd_exit;
+
+       if (devpriv->high_speed) {
                /*
                 * every channel gets a time window of 125us. Thus, if we
                 * sample all 8 channels we need 1ms. If we sample only one
                 * channel we need only 125us
                 */
-               this_usbduxsub->ai_interval = 1;
+               devpriv->ai_interval = 1;
                /* find a power of 2 for the interval */
-               while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
-                       this_usbduxsub->ai_interval =
-                           (this_usbduxsub->ai_interval) * 2;
-               }
-               this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 *
-                                                         (this_usbduxsub->
-                                                          ai_interval));
+               while (devpriv->ai_interval < len)
+                       devpriv->ai_interval *= 2;
+
+               devpriv->ai_timer = cmd->scan_begin_arg /
+                                   (125000 * devpriv->ai_interval);
        } else {
                /* interval always 1ms */
-               this_usbduxsub->ai_interval = 1;
-               this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
+               devpriv->ai_interval = 1;
+               devpriv->ai_timer = cmd->scan_begin_arg / 1000000;
        }
-       if (this_usbduxsub->ai_timer < 1) {
-               up(&this_usbduxsub->sem);
-               return -EINVAL;
+       if (devpriv->ai_timer < 1) {
+               ret = -EINVAL;
+               goto ai_cmd_exit;
        }
-       this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
+
+       devpriv->ai_counter = devpriv->ai_timer;
 
        if (cmd->stop_src == TRIG_COUNT) {
                /* data arrives as one packet */
-               this_usbduxsub->ai_sample_count = cmd->stop_arg;
-               this_usbduxsub->ai_continous = 0;
+               devpriv->ai_sample_count = cmd->stop_arg;
+               devpriv->ai_continous = 0;
        } else {
                /* continous acquisition */
-               this_usbduxsub->ai_continous = 1;
-               this_usbduxsub->ai_sample_count = 0;
+               devpriv->ai_continous = 1;
+               devpriv->ai_sample_count = 0;
        }
 
        if (cmd->start_src == TRIG_NOW) {
                /* enable this acquisition operation */
-               this_usbduxsub->ai_cmd_running = 1;
+               devpriv->ai_cmd_running = 1;
                ret = usbduxsub_submit_inurbs(dev);
                if (ret < 0) {
-                       this_usbduxsub->ai_cmd_running = 0;
+                       devpriv->ai_cmd_running = 0;
                        /* fixme: unlink here?? */
-                       up(&this_usbduxsub->sem);
-                       return ret;
+                       goto ai_cmd_exit;
                }
                s->async->inttrig = NULL;
        } else {
@@ -971,144 +963,143 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                /* wait for an internal signal */
                s->async->inttrig = usbdux_ai_inttrig;
        }
-       up(&this_usbduxsub->sem);
-       return 0;
+
+ai_cmd_exit:
+       up(&devpriv->sem);
+
+       return ret;
 }
 
 /* Mode 0 is used to get a single conversion on demand */
 static int usbdux_ai_insn_read(struct comedi_device *dev,
                               struct comedi_subdevice *s,
-                              struct comedi_insn *insn, unsigned int *data)
+                              struct comedi_insn *insn,
+                              unsigned int *data)
 {
+       struct usbdux_private *devpriv = dev->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       unsigned int range = CR_RANGE(insn->chanspec);
+       unsigned int val;
+       int ret = -EBUSY;
        int i;
-       unsigned int one = 0;
-       int chan, range;
-       int err;
-       struct usbdux_private *this_usbduxsub = dev->private;
 
-       if (!this_usbduxsub)
-               return 0;
+       down(&devpriv->sem);
 
-       down(&this_usbduxsub->sem);
-       if (this_usbduxsub->ai_cmd_running) {
-               up(&this_usbduxsub->sem);
-               return 0;
-       }
+       if (devpriv->ai_cmd_running)
+               goto ai_read_exit;
 
-       /* sample one channel */
-       chan = CR_CHAN(insn->chanspec);
-       range = CR_RANGE(insn->chanspec);
        /* set command for the first channel */
-       this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
+       devpriv->dux_commands[1] = create_adc_command(chan, range);
 
        /* adc commands */
-       err = send_dux_commands(dev, SENDSINGLEAD);
-       if (err < 0) {
-               up(&this_usbduxsub->sem);
-               return err;
-       }
+       ret = send_dux_commands(dev, SENDSINGLEAD);
+       if (ret < 0)
+               goto ai_read_exit;
 
        for (i = 0; i < insn->n; i++) {
-               err = receive_dux_commands(dev, SENDSINGLEAD);
-               if (err < 0) {
-                       up(&this_usbduxsub->sem);
-                       return 0;
-               }
-               one = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
-               if (CR_RANGE(insn->chanspec) <= 1)
-                       one = one ^ 0x800;
+               ret = receive_dux_commands(dev, SENDSINGLEAD);
+               if (ret < 0)
+                       goto ai_read_exit;
+
+               val = le16_to_cpu(devpriv->insn_buffer[1]);
+
+               /* bipolar data is two's-complement */
+               if (comedi_range_is_bipolar(s, range))
+                       val ^= ((s->maxdata + 1) >> 1);
 
-               data[i] = one;
+               data[i] = val;
        }
-       up(&this_usbduxsub->sem);
-       return i;
-}
 
-/************************************/
-/* analog out */
+ai_read_exit:
+       up(&devpriv->sem);
+
+       return ret ? ret : insn->n;
+}
 
 static int usbdux_ao_insn_read(struct comedi_device *dev,
                               struct comedi_subdevice *s,
-                              struct comedi_insn *insn, unsigned int *data)
+                              struct comedi_insn *insn,
+                              unsigned int *data)
 {
+       struct usbdux_private *devpriv = dev->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
        int i;
-       int chan = CR_CHAN(insn->chanspec);
-       struct usbdux_private *this_usbduxsub = dev->private;
 
-       if (!this_usbduxsub)
-               return -EFAULT;
-
-       down(&this_usbduxsub->sem);
+       down(&devpriv->sem);
        for (i = 0; i < insn->n; i++)
-               data[i] = this_usbduxsub->out_buffer[chan];
+               data[i] = devpriv->out_buffer[chan];
+       up(&devpriv->sem);
 
-       up(&this_usbduxsub->sem);
-       return i;
+       return insn->n;
 }
 
 static int usbdux_ao_insn_write(struct comedi_device *dev,
                                struct comedi_subdevice *s,
-                               struct comedi_insn *insn, unsigned int *data)
+                               struct comedi_insn *insn,
+                               unsigned int *data)
 {
-       int i, err;
-       int chan = CR_CHAN(insn->chanspec);
-       struct usbdux_private *this_usbduxsub = dev->private;
+       struct usbdux_private *devpriv = dev->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       unsigned int val = devpriv->out_buffer[chan];
+       int16_t *p = (int16_t *)&devpriv->dux_commands[2];
+       int ret = -EBUSY;
+       int i;
 
-       if (!this_usbduxsub)
-               return -EFAULT;
+       down(&devpriv->sem);
 
-       down(&this_usbduxsub->sem);
-       if (this_usbduxsub->ao_cmd_running) {
-               up(&this_usbduxsub->sem);
-               return 0;
-       }
+       if (devpriv->ao_cmd_running)
+               goto ao_write_exit;
+
+       /* number of channels: 1 */
+       devpriv->dux_commands[1] = 1;
+       /* channel number */
+       devpriv->dux_commands[4] = chan << 6;
 
        for (i = 0; i < insn->n; i++) {
-               /* number of channels: 1 */
-               this_usbduxsub->dux_commands[1] = 1;
+               val = data[i];
+
                /* one 16 bit value */
-               *((int16_t *) (this_usbduxsub->dux_commands + 2)) =
-                   cpu_to_le16(data[i]);
-               this_usbduxsub->out_buffer[chan] = data[i];
-               /* channel number */
-               this_usbduxsub->dux_commands[4] = (chan << 6);
-               err = send_dux_commands(dev, SENDDACOMMANDS);
-               if (err < 0) {
-                       up(&this_usbduxsub->sem);
-                       return err;
-               }
+               *p = cpu_to_le16(val);
+
+               ret = send_dux_commands(dev, SENDDACOMMANDS);
+               if (ret < 0)
+                       goto ao_write_exit;
        }
-       up(&this_usbduxsub->sem);
+       devpriv->out_buffer[chan] = val;
 
-       return i;
+ao_write_exit:
+       up(&devpriv->sem);
+
+       return ret ? ret : insn->n;
 }
 
 static int usbdux_ao_inttrig(struct comedi_device *dev,
-                            struct comedi_subdevice *s, unsigned int trignum)
+                            struct comedi_subdevice *s,
+                            unsigned int trignum)
 {
-       int ret;
-       struct usbdux_private *this_usbduxsub = dev->private;
+       struct usbdux_private *devpriv = dev->private;
+       int ret = -EINVAL;
 
-       if (!this_usbduxsub)
-               return -EFAULT;
+       down(&devpriv->sem);
 
-       down(&this_usbduxsub->sem);
-       if (trignum != 0) {
-               up(&this_usbduxsub->sem);
-               return -EINVAL;
-       }
-       if (!(this_usbduxsub->ao_cmd_running)) {
-               this_usbduxsub->ao_cmd_running = 1;
+       if (trignum != 0)
+               goto ao_trig_exit;
+
+       if (!devpriv->ao_cmd_running) {
+               devpriv->ao_cmd_running = 1;
                ret = usbduxsub_submit_outurbs(dev);
                if (ret < 0) {
-                       this_usbduxsub->ao_cmd_running = 0;
-                       up(&this_usbduxsub->sem);
-                       return ret;
+                       devpriv->ao_cmd_running = 0;
+                       goto ao_trig_exit;
                }
                s->async->inttrig = NULL;
+       } else {
+               ret = -EBUSY;
        }
-       up(&this_usbduxsub->sem);
-       return 1;
+
+ao_trig_exit:
+       up(&devpriv->sem);
+       return ret;
 }
 
 static int usbdux_ao_cmdtest(struct comedi_device *dev,
@@ -1197,72 +1188,74 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev,
 
 static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+       struct usbdux_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
-       unsigned int chan, gain;
-       int i, ret;
-       struct usbdux_private *this_usbduxsub = dev->private;
+       int ret = -EBUSY;
+       int i;
 
-       if (!this_usbduxsub)
-               return -EFAULT;
+       down(&devpriv->sem);
 
-       down(&this_usbduxsub->sem);
+       if (devpriv->ao_cmd_running)
+               goto ao_cmd_exit;
 
        /* set current channel of the running acquisition to zero */
        s->async->cur_chan = 0;
+
        for (i = 0; i < cmd->chanlist_len; ++i) {
-               chan = CR_CHAN(cmd->chanlist[i]);
-               gain = CR_RANGE(cmd->chanlist[i]);
+               unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
                if (i >= NUMOUTCHANNELS)
                        break;
-               this_usbduxsub->dac_commands[i] = (chan << 6);
+
+               devpriv->dac_commands[i] = chan << 6;
        }
 
        /* we count in steps of 1ms (125us) */
        /* 125us mode not used yet */
-       if (0) {                /* (this_usbduxsub->high_speed) */
+       if (0) {                /* (devpriv->high_speed) */
                /* 125us */
                /* timing of the conversion itself: every 125 us */
-               this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
+               devpriv->ao_timer = cmd->convert_arg / 125000;
        } else {
                /* 1ms */
                /* timing of the scan: we get all channels at once */
-               this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000;
-               if (this_usbduxsub->ao_timer < 1) {
-                       up(&this_usbduxsub->sem);
-                       return -EINVAL;
+               devpriv->ao_timer = cmd->scan_begin_arg / 1000000;
+               if (devpriv->ao_timer < 1) {
+                       ret = -EINVAL;
+                       goto ao_cmd_exit;
                }
        }
-       this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
+
+       devpriv->ao_counter = devpriv->ao_timer;
 
        if (cmd->stop_src == TRIG_COUNT) {
                /* not continuous */
                /* counter */
                /* high speed also scans everything at once */
-               if (0) {        /* (this_usbduxsub->high_speed) */
-                       this_usbduxsub->ao_sample_count =
-                           (cmd->stop_arg) * (cmd->scan_end_arg);
+               if (0) {        /* (devpriv->high_speed) */
+                       devpriv->ao_sample_count = cmd->stop_arg *
+                                                  cmd->scan_end_arg;
                } else {
                        /* there's no scan as the scan has been */
                        /* perf inside the FX2 */
                        /* data arrives as one packet */
-                       this_usbduxsub->ao_sample_count = cmd->stop_arg;
+                       devpriv->ao_sample_count = cmd->stop_arg;
                }
-               this_usbduxsub->ao_continous = 0;
+               devpriv->ao_continous = 0;
        } else {
                /* continous acquisition */
-               this_usbduxsub->ao_continous = 1;
-               this_usbduxsub->ao_sample_count = 0;
+               devpriv->ao_continous = 1;
+               devpriv->ao_sample_count = 0;
        }
 
        if (cmd->start_src == TRIG_NOW) {
                /* enable this acquisition operation */
-               this_usbduxsub->ao_cmd_running = 1;
+               devpriv->ao_cmd_running = 1;
                ret = usbduxsub_submit_outurbs(dev);
                if (ret < 0) {
-                       this_usbduxsub->ao_cmd_running = 0;
+                       devpriv->ao_cmd_running = 0;
                        /* fixme: unlink here?? */
-                       up(&this_usbduxsub->sem);
-                       return ret;
+                       goto ao_cmd_exit;
                }
                s->async->inttrig = NULL;
        } else {
@@ -1272,38 +1265,38 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                s->async->inttrig = usbdux_ao_inttrig;
        }
 
-       up(&this_usbduxsub->sem);
-       return 0;
+ao_cmd_exit:
+       up(&devpriv->sem);
+
+       return ret;
 }
 
 static int usbdux_dio_insn_config(struct comedi_device *dev,
                                  struct comedi_subdevice *s,
-                                 struct comedi_insn *insn, unsigned int *data)
+                                 struct comedi_insn *insn,
+                                 unsigned int *data)
 {
-       int chan = CR_CHAN(insn->chanspec);
-
-       /* The input or output configuration of each digital line is
-        * configured by a special insn_config instruction.  chanspec
-        * contains the channel to be changed, and data[0] contains the
-        * value COMEDI_INPUT or COMEDI_OUTPUT. */
+       unsigned int mask = 1 << CR_CHAN(insn->chanspec);
 
        switch (data[0]) {
        case INSN_CONFIG_DIO_OUTPUT:
-               s->io_bits |= 1 << chan;        /* 1 means Out */
+               s->io_bits |= mask;
                break;
        case INSN_CONFIG_DIO_INPUT:
-               s->io_bits &= ~(1 << chan);
+               s->io_bits &= ~mask;
                break;
        case INSN_CONFIG_DIO_QUERY:
-               data[1] =
-                   (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
                break;
        default:
                return -EINVAL;
                break;
        }
-       /* we don't tell the firmware here as it would take 8 frames */
-       /* to submit the information. We do it in the insn_bits. */
+
+       /*
+        * We don't tell the firmware here as it would take 8 frames
+        * to submit the information. We do it in the insn_bits.
+        */
        return insn->n;
 }