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@xxxxxxxxxxxxxxxxxxx> Cc: Ian Abbott <abbotti@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/staging/comedi/drivers/usbdux.c | 49 +++++++++++++++------------------ 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index bd46bec..1399305 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -99,6 +99,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. #define VENDOR_DIR_OUT 0x40 #define USBDUX_CPU_CS 0xe600 +#define USBDUX_NUM_AO_CHAN 4 + /* timeout for the USB-transfer in ms */ #define BULK_TIMEOUT 1000 @@ -195,8 +197,8 @@ struct usbdux_private { int16_t *in_buf; /* input buffer for single insn */ 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 ai_cmd_running:1; @@ -486,25 +488,24 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) ((uint8_t *) (urb->transfer_buffer))[0] = s->async->cmd.chanlist_len; for (i = 0; i < s->async->cmd.chanlist_len; i++) { - short temp; - if (i >= NUMOUTCHANNELS) - break; + unsigned int chan = devpriv->dac_commands[i]; + short val; + 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 */ datap = (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1])); /* get the data from comedi */ - ret = comedi_buf_get(s->async, &temp); - datap[0] = temp; - datap[1] = temp >> 8; - datap[2] = devpriv->dac_commands[i]; - 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 */ + datap[0] = val; + datap[1] = val >> 8; + datap[2] = chan; + devpriv->ao_readback[chan] = val; + s->async->events |= COMEDI_CB_BLOCK; comedi_event(dev, s); } @@ -907,7 +908,7 @@ static int usbdux_ao_insn_read(struct comedi_device *dev, down(&devpriv->sem); for (i = 0; i < insn->n; i++) - data[i] = devpriv->out_buffer[chan]; + data[i] = devpriv->ao_readback[chan]; up(&devpriv->sem); return insn->n; @@ -920,7 +921,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, { struct usbdux_private *devpriv = dev->private; 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]; int ret = -EBUSY; int i; @@ -945,7 +946,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, if (ret < 0) goto ao_write_exit; } - devpriv->out_buffer[chan] = val; + devpriv->ao_readback[chan] = val; ao_write_exit: up(&devpriv->sem); @@ -1660,11 +1661,6 @@ static int usbdux_alloc_usb_buffers(struct comedi_device *dev) if (!devpriv->insn_buf) return -ENOMEM; - /* create space for the outbuffer */ - devpriv->out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!devpriv->out_buffer) - return -ENOMEM; - /* in urbs */ devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(*urb), GFP_KERNEL); @@ -1779,7 +1775,6 @@ static void usbdux_free_usb_buffers(struct usbdux_private *devpriv) } kfree(devpriv->ai_urbs); } - kfree(devpriv->out_buffer); kfree(devpriv->insn_buf); kfree(devpriv->in_buf); kfree(devpriv->dux_commands); @@ -1854,9 +1849,9 @@ static int usbdux_auto_attach(struct comedi_device *dev, dev->write_subdev = s; s->type = COMEDI_SUBD_AO; 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->len_chanlist = 4; + s->len_chanlist = s->n_chan; s->range_table = &range_usbdux_ao_range; s->do_cmdtest = usbdux_ao_cmdtest; s->do_cmd = usbdux_ao_cmd; -- 1.8.3.2 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel