staging: comedi: usbdux: cleanup the private data 'outBuffer'

This buffer is used to cache the values that are written to the
analog output channels. Currently it only caches the single writes
to the channels using the (*insn_write) callback. The async command
writes are not cached. The buffer is also being kzalloc'ed during
the attach of the driver to a size much larger that required.

Rename the CamelCase buffer and change it to an array in the private
data of the correct size to cache the analog output channel values.

Modify the analog output urb callback so it updates the cached values
with those used for the asynchronous command to allow readback after
the command completes.

The sanity check of the index to dac_commands[] (i.e. the 'chan' being
written) is not needed. The chanlist_len will always be less than the
number of channels.

Also, fix the dev_err() message so it uses the proper device pointer.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
H Hartley Sweeten 2013-07-25 16:10:07 -07:00 committed by Greg Kroah-Hartman
parent c79bc87553
commit a998a3db53

View File

@ -99,6 +99,8 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#define VENDOR_DIR_OUT 0x40 #define VENDOR_DIR_OUT 0x40
#define USBDUX_CPU_CS 0xe600 #define USBDUX_CPU_CS 0xe600
#define USBDUX_NUM_AO_CHAN 4
/* timeout for the USB-transfer in ms */ /* timeout for the USB-transfer in ms */
#define BULK_TIMEOUT 1000 #define BULK_TIMEOUT 1000
@ -195,8 +197,8 @@ struct usbdux_private {
int16_t *in_buf; int16_t *in_buf;
/* input buffer for single insn */ /* input buffer for single insn */
int16_t *insn_buf; int16_t *insn_buf;
/* output buffer for single DA outputs */
int16_t *out_buffer; unsigned int ao_readback[USBDUX_NUM_AO_CHAN];
unsigned int high_speed:1; unsigned int high_speed:1;
unsigned int ai_cmd_running:1; unsigned int ai_cmd_running:1;
@ -486,25 +488,24 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
((uint8_t *) (urb->transfer_buffer))[0] = ((uint8_t *) (urb->transfer_buffer))[0] =
s->async->cmd.chanlist_len; s->async->cmd.chanlist_len;
for (i = 0; i < s->async->cmd.chanlist_len; i++) { for (i = 0; i < s->async->cmd.chanlist_len; i++) {
short temp; unsigned int chan = devpriv->dac_commands[i];
if (i >= NUMOUTCHANNELS) short val;
break;
ret = comedi_buf_get(s->async, &val);
if (ret < 0) {
dev_err(dev->class_dev, "buffer underflow\n");
s->async->events |= (COMEDI_CB_EOA |
COMEDI_CB_OVERFLOW);
}
/* pointer to the DA */ /* pointer to the DA */
datap = datap =
(&(((int8_t *) urb->transfer_buffer)[i * 3 + 1])); (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
/* get the data from comedi */ /* get the data from comedi */
ret = comedi_buf_get(s->async, &temp); datap[0] = val;
datap[0] = temp; datap[1] = val >> 8;
datap[1] = temp >> 8; datap[2] = chan;
datap[2] = devpriv->dac_commands[i]; devpriv->ao_readback[chan] = val;
if (ret < 0) {
dev_err(&urb->dev->dev,
"comedi: buffer underflow\n");
s->async->events |= COMEDI_CB_EOA;
s->async->events |= COMEDI_CB_OVERFLOW;
}
/* transmit data to comedi */
s->async->events |= COMEDI_CB_BLOCK; s->async->events |= COMEDI_CB_BLOCK;
comedi_event(dev, s); comedi_event(dev, s);
} }
@ -907,7 +908,7 @@ static int usbdux_ao_insn_read(struct comedi_device *dev,
down(&devpriv->sem); down(&devpriv->sem);
for (i = 0; i < insn->n; i++) for (i = 0; i < insn->n; i++)
data[i] = devpriv->out_buffer[chan]; data[i] = devpriv->ao_readback[chan];
up(&devpriv->sem); up(&devpriv->sem);
return insn->n; return insn->n;
@ -920,7 +921,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev,
{ {
struct usbdux_private *devpriv = dev->private; struct usbdux_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec); unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int val = devpriv->out_buffer[chan]; unsigned int val = devpriv->ao_readback[chan];
int16_t *p = (int16_t *)&devpriv->dux_commands[2]; int16_t *p = (int16_t *)&devpriv->dux_commands[2];
int ret = -EBUSY; int ret = -EBUSY;
int i; int i;
@ -945,7 +946,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev,
if (ret < 0) if (ret < 0)
goto ao_write_exit; goto ao_write_exit;
} }
devpriv->out_buffer[chan] = val; devpriv->ao_readback[chan] = val;
ao_write_exit: ao_write_exit:
up(&devpriv->sem); up(&devpriv->sem);
@ -1660,11 +1661,6 @@ static int usbdux_alloc_usb_buffers(struct comedi_device *dev)
if (!devpriv->insn_buf) if (!devpriv->insn_buf)
return -ENOMEM; return -ENOMEM;
/* create space for the outbuffer */
devpriv->out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
if (!devpriv->out_buffer)
return -ENOMEM;
/* in urbs */ /* in urbs */
devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(*urb), devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(*urb),
GFP_KERNEL); GFP_KERNEL);
@ -1779,7 +1775,6 @@ static void usbdux_free_usb_buffers(struct usbdux_private *devpriv)
} }
kfree(devpriv->ai_urbs); kfree(devpriv->ai_urbs);
} }
kfree(devpriv->out_buffer);
kfree(devpriv->insn_buf); kfree(devpriv->insn_buf);
kfree(devpriv->in_buf); kfree(devpriv->in_buf);
kfree(devpriv->dux_commands); kfree(devpriv->dux_commands);
@ -1854,9 +1849,9 @@ static int usbdux_auto_attach(struct comedi_device *dev,
dev->write_subdev = s; dev->write_subdev = s;
s->type = COMEDI_SUBD_AO; s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
s->n_chan = 4; s->n_chan = USBDUX_NUM_AO_CHAN;
s->maxdata = 0x0fff; s->maxdata = 0x0fff;
s->len_chanlist = 4; s->len_chanlist = s->n_chan;
s->range_table = &range_usbdux_ao_range; s->range_table = &range_usbdux_ao_range;
s->do_cmdtest = usbdux_ao_cmdtest; s->do_cmdtest = usbdux_ao_cmdtest;
s->do_cmd = usbdux_ao_cmd; s->do_cmd = usbdux_ao_cmd;