X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fstaging%2Fcomedi%2Fdrivers%2Fusbdux.c;h=86f035d00675067b8d020cbc90ad4b2ca97eaaf5;hb=94002c07ff0e207a883519ccc35c0b5390b29331;hp=41872a3a68b2086042c8cf9839cbd191cf376a72;hpb=34c43922e62708d45e9660eee4b4f1fb7b4bf2c7;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 41872a3..86f035d 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -1,4 +1,4 @@ -#define DRIVER_VERSION "v2.2" +#define DRIVER_VERSION "v2.4" #define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com" #define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com" /* @@ -80,6 +80,9 @@ sampling rate. If you sample two channels you get 4kHz and so on. * 2.0: PWM seems to be stable and is not interfering with the other functions * 2.1: changed PWM API * 2.2: added firmware kernel request to fix an udev problem + * 2.3: corrected a bug in bulk timeouts which were far too short + * 2.4: fixed a bug which causes the driver to hang when it ran out of data. + * Thanks to Jan-Matthias Braun and Ian to spot the bug and fix it. * */ @@ -92,7 +95,6 @@ sampling rate. If you sample two channels you get 4kHz and so on. #include #include #include -#include #include #include #include @@ -101,8 +103,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. #define BOARDNAME "usbdux" -/* timeout for the USB-transfer */ -#define EZTIMEOUT 30 +/* timeout for the USB-transfer in ms*/ +#define BULK_TIMEOUT 1000 /* constants for "firmware" upload and download */ #define USBDUXSUB_FIRMWARE 0xA0 @@ -214,18 +216,24 @@ sampling rate. If you sample two channels you get 4kHz and so on. /**************************************************/ /* comedi constants */ -static const comedi_lrange range_usbdux_ai_range = { 4, { - BIP_RANGE(4.096), - BIP_RANGE(4.096 / 2), - UNI_RANGE(4.096), - UNI_RANGE(4.096 / 2) - } +static const struct comedi_lrange range_usbdux_ai_range = { 4, { + BIP_RANGE + (4.096), + BIP_RANGE(4.096 + / 2), + UNI_RANGE + (4.096), + UNI_RANGE(4.096 + / 2) + } }; -static const comedi_lrange range_usbdux_ao_range = { 2, { - BIP_RANGE(4.096), - UNI_RANGE(4.096), - } +static const struct comedi_lrange range_usbdux_ao_range = { 2, { + BIP_RANGE + (4.096), + UNI_RANGE + (4.096), + } }; /* @@ -280,7 +288,7 @@ struct usbduxsub { /* continous aquisition */ short int ai_continous; short int ao_continous; - /* number of samples to aquire */ + /* number of samples to acquire */ int ai_sample_count; int ao_sample_count; /* time between samples in units of the timer */ @@ -363,7 +371,8 @@ static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink) * This will cancel a running acquisition operation. * This is called by comedi but never from inside the driver. */ -static int usbdux_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +static int usbdux_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct usbduxsub *this_usbduxsub; int res = 0; @@ -407,7 +416,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) case 0: /* copy the result in the transfer buffer */ memcpy(this_usbduxsub->inBuffer, - urb->transfer_buffer, SIZEINBUF); + urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: /* error in the ISOchronous data */ @@ -509,17 +518,22 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) for (i = 0; i < n; i++) { /* transfer data */ if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) { - comedi_buf_put - (s->async, - le16_to_cpu(this_usbduxsub-> - inBuffer[i]) ^ 0x800); + err = comedi_buf_put + (s->async, + le16_to_cpu(this_usbduxsub->inBuffer[i]) ^ 0x800); } else { - comedi_buf_put - (s->async, - le16_to_cpu(this_usbduxsub->inBuffer[i])); + err = comedi_buf_put + (s->async, + le16_to_cpu(this_usbduxsub->inBuffer[i])); + } + if (unlikely(err == 0)) { + /* buffer overflow */ + usbdux_ai_stop(this_usbduxsub, 0); + return; } } /* tell comedi that data is there */ + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(this_usbduxsub->comedidev, s); } @@ -561,7 +575,8 @@ static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink) } /* force unlink, is called by comedi */ -static int usbdux_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +static int usbdux_ao_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct usbduxsub *this_usbduxsub = dev->private; int res = 0; @@ -654,7 +669,7 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) } /* transmit data to the USB bus */ ((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++) { short temp; if (i >= NUMOUTCHANNELS) @@ -662,7 +677,7 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) /* pointer to the DA */ datap = - (&(((int8_t *)urb->transfer_buffer)[i * 3 + 1])); + (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1])); /* get the data from comedi */ ret = comedi_buf_get(s->async, &temp); datap[0] = temp; @@ -738,7 +753,7 @@ static int usbduxsub_start(struct usbduxsub *usbduxsub) /* Length */ 1, /* Timeout */ - EZTIMEOUT); + BULK_TIMEOUT); if (errcode < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: control msg failed (start)\n"); @@ -768,7 +783,7 @@ static int usbduxsub_stop(struct usbduxsub *usbduxsub) /* Length */ 1, /* Timeout */ - EZTIMEOUT); + BULK_TIMEOUT); if (errcode < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: control msg failed (stop)\n"); @@ -784,57 +799,77 @@ static int usbduxsub_upload(struct usbduxsub *usbduxsub, int errcode; errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* brequest, firmware */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* value */ - startAddr, - /* index */ - 0x0000, - /* our local safe buffer */ - local_transfer_buffer, - /* length */ - len, - /* timeout */ - EZTIMEOUT); - dev_dbg(&usbduxsub->interface->dev, - "comedi_: result=%d\n", errcode); + usb_sndctrlpipe(usbduxsub->usbdev, 0), + /* brequest, firmware */ + USBDUXSUB_FIRMWARE, + /* bmRequestType */ + VENDOR_DIR_OUT, + /* value */ + startAddr, + /* index */ + 0x0000, + /* our local safe buffer */ + local_transfer_buffer, + /* length */ + len, + /* timeout */ + BULK_TIMEOUT); + dev_dbg(&usbduxsub->interface->dev, "comedi_: result=%d\n", errcode); if (errcode < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: upload failed\n"); + dev_err(&usbduxsub->interface->dev, "comedi_: upload failed\n"); return errcode; } return 0; } -static int firmwareUpload(struct usbduxsub *usbduxsub, uint8_t *firmwareBinary, - int sizeFirmware) +#define FIRMWARE_MAX_LEN 0x2000 + +static int firmwareUpload(struct usbduxsub *usbduxsub, + const u8 *firmwareBinary, int sizeFirmware) { int ret; + uint8_t *fwBuf; if (!firmwareBinary) return 0; + if (sizeFirmware > FIRMWARE_MAX_LEN) { + dev_err(&usbduxsub->interface->dev, + "usbdux firmware binary it too large for FX2.\n"); + return -ENOMEM; + } + + /* we generate a local buffer for the firmware */ + fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL); + if (!fwBuf) { + dev_err(&usbduxsub->interface->dev, + "comedi_: mem alloc for firmware failed\n"); + return -ENOMEM; + } + ret = usbduxsub_stop(usbduxsub); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: can not stop firmware\n"); + kfree(fwBuf); return ret; } - ret = usbduxsub_upload(usbduxsub, firmwareBinary, 0, sizeFirmware); + + ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: firmware upload failed\n"); + kfree(fwBuf); return ret; } ret = usbduxsub_start(usbduxsub); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: can not start firmware\n"); + kfree(fwBuf); return ret; } + kfree(fwBuf); return 0; } @@ -896,8 +931,8 @@ static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub) return 0; } -static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_cmd *cmd) +static int usbdux_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0, tmp, i; unsigned int tmpTimer; @@ -946,11 +981,11 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice /* * step 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatiblity is not an issue here + * note that mutual compatibility is not an issue here */ if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) + cmd->scan_begin_src != TRIG_EXT && + cmd->scan_begin_src != TRIG_TIMER) err++; if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) err++; @@ -992,8 +1027,8 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice /* now calc the real sampling rate with all the * rounding errors */ tmpTimer = - ((unsigned int)(cmd->scan_begin_arg / 125000)) * - 125000; + ((unsigned int)(cmd->scan_begin_arg / 125000)) * + 125000; if (cmd->scan_begin_arg != tmpTimer) { cmd->scan_begin_arg = tmpTimer; err++; @@ -1009,7 +1044,7 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice * calc the real sampling rate with the rounding errors */ tmpTimer = ((unsigned int)(cmd->scan_begin_arg / - 1000000)) * 1000000; + 1000000)) * 1000000; if (cmd->scan_begin_arg != tmpTimer) { cmd->scan_begin_arg = tmpTimer; err++; @@ -1068,7 +1103,7 @@ static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type) this_usbduxsub->dux_commands[0] = cmd_type; #ifdef NOISY_DUX_DEBUGBUG printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ", - this_usbduxsub->comedidev->minor); + this_usbduxsub->comedidev->minor); for (result = 0; result < SIZEOFDUXBUFFER; result++) printk(" %02x", this_usbduxsub->dux_commands[result]); printk("\n"); @@ -1077,7 +1112,7 @@ static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type) usb_sndbulkpipe(this_usbduxsub->usbdev, COMMAND_OUT_EP), this_usbduxsub->dux_commands, SIZEOFDUXBUFFER, - &nsent, 10); + &nsent, BULK_TIMEOUT); if (result < 0) dev_err(&this_usbduxsub->interface->dev, "comedi%d: " "could not transmit dux_command to the usb-device, " @@ -1097,7 +1132,7 @@ static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command) usb_rcvbulkpipe(this_usbduxsub->usbdev, COMMAND_IN_EP), this_usbduxsub->insnBuffer, SIZEINSNBUF, - &nrec, 1); + &nrec, BULK_TIMEOUT); if (result < 0) { dev_err(&this_usbduxsub->interface->dev, "comedi%d: " "insn: USB error %d while receiving DUX command" @@ -1116,8 +1151,8 @@ static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command) return -EFAULT; } -static int usbdux_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int usbdux_ai_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int trignum) { int ret; struct usbduxsub *this_usbduxsub = dev->private; @@ -1162,7 +1197,7 @@ static int usbdux_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - comedi_cmd *cmd = &s->async->cmd; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int chan, range; int i, ret; struct usbduxsub *this_usbduxsub = dev->private; @@ -1202,7 +1237,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) break; } this_usbduxsub->dux_commands[i + 2] = - create_adc_command(chan, range); + create_adc_command(chan, range); } dev_dbg(&this_usbduxsub->interface->dev, @@ -1225,10 +1260,11 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* 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_interval) * 2; } this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 * - (this_usbduxsub->ai_interval)); + (this_usbduxsub-> + ai_interval)); } else { /* interval always 1ms */ this_usbduxsub->ai_interval = 1; @@ -1276,8 +1312,9 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* 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, - comedi_insn *insn, unsigned int *data) +static int usbdux_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; unsigned int one = 0; @@ -1337,8 +1374,9 @@ static int usbdux_ai_insn_read(struct comedi_device *dev, struct comedi_subdevic /************************************/ /* analog out */ -static int usbdux_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -1359,8 +1397,9 @@ static int usbdux_ao_insn_read(struct comedi_device *dev, struct comedi_subdevic return i; } -static int usbdux_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, err; int chan = CR_CHAN(insn->chanspec); @@ -1394,7 +1433,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, struct comedi_subdevi this_usbduxsub->dux_commands[1] = 1; /* one 16 bit value */ *((int16_t *) (this_usbduxsub->dux_commands + 2)) = - cpu_to_le16(data[i]); + cpu_to_le16(data[i]); this_usbduxsub->outBuffer[chan] = data[i]; /* channel number */ this_usbduxsub->dux_commands[4] = (chan << 6); @@ -1409,8 +1448,8 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, struct comedi_subdevi return i; } -static int usbdux_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int usbdux_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int trignum) { int ret; struct usbduxsub *this_usbduxsub = dev->private; @@ -1450,8 +1489,8 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice return 1; } -static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_cmd *cmd) +static int usbdux_ao_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0, tmp; struct usbduxsub *this_usbduxsub = dev->private; @@ -1520,11 +1559,11 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice /* * step 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatiblity is not an issue here + * note that mutual compatibility is not an issue here */ if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) + cmd->scan_begin_src != TRIG_EXT && + cmd->scan_begin_src != TRIG_TIMER) err++; if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) err++; @@ -1591,7 +1630,7 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - comedi_cmd *cmd = &s->async->cmd; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int chan, gain; int i, ret; struct usbduxsub *this_usbduxsub = dev->private; @@ -1661,7 +1700,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* 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); + (cmd->stop_arg) * (cmd->scan_end_arg); } else { /* there's no scan as the scan has been */ /* perf inside the FX2 */ @@ -1697,8 +1736,9 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int usbdux_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); @@ -1716,8 +1756,7 @@ static int usbdux_dio_insn_config(struct comedi_device *dev, struct comedi_subde break; case INSN_CONFIG_DIO_QUERY: data[1] = - (s-> - io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; + (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; break; default: return -EINVAL; @@ -1728,8 +1767,9 @@ static int usbdux_dio_insn_config(struct comedi_device *dev, struct comedi_subde return insn->n; } -static int usbdux_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct usbduxsub *this_usbduxsub = dev->private; @@ -1738,7 +1778,6 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevi if (!this_usbduxsub) return -EFAULT; - if (insn->n != 2) return -EINVAL; @@ -1775,8 +1814,9 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevi } /* reads the 4 counters, only two are used just now */ -static int usbdux_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_counter_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct usbduxsub *this_usbduxsub = dev->private; int chan = insn->chanspec; @@ -1809,8 +1849,9 @@ static int usbdux_counter_read(struct comedi_device *dev, struct comedi_subdevic return 1; } -static int usbdux_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_counter_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct usbduxsub *this_usbduxsub = dev->private; int err; @@ -1839,8 +1880,9 @@ static int usbdux_counter_write(struct comedi_device *dev, struct comedi_subdevi return 1; } -static int usbdux_counter_config(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_counter_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { /* nothing to do so far */ return 2; @@ -1876,14 +1918,14 @@ static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink) if (do_unlink) ret = usbduxsub_unlink_PwmURBs(this_usbduxsub); - this_usbduxsub->pwm_cmd_running = 0; return ret; } /* force unlink - is called by comedi */ -static int usbdux_pwm_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +static int usbdux_pwm_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct usbduxsub *this_usbduxsub = dev->private; int res = 0; @@ -1981,10 +2023,11 @@ static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub) /* in case of a resubmission after an unlink... */ usb_fill_bulk_urb(usbduxsub->urbPwm, - usbduxsub->usbdev, - usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP), - usbduxsub->urbPwm->transfer_buffer, - usbduxsub->sizePwmBuf, usbduxsub_pwm_irq, usbduxsub->comedidev); + usbduxsub->usbdev, + usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP), + usbduxsub->urbPwm->transfer_buffer, + usbduxsub->sizePwmBuf, usbduxsub_pwm_irq, + usbduxsub->comedidev); errFlag = usb_submit_urb(usbduxsub->urbPwm, GFP_ATOMIC); if (errFlag) { @@ -1996,8 +2039,8 @@ static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub) return 0; } -static int usbdux_pwm_period(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int period) +static int usbdux_pwm_period(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int period) { struct usbduxsub *this_usbduxsub = dev->private; int fx2delay = 255; @@ -2008,11 +2051,11 @@ static int usbdux_pwm_period(struct comedi_device *dev, struct comedi_subdevice dev->minor); return -EAGAIN; } else { - fx2delay = period / ((int)(6*512*(1.0/0.033))) - 6; + fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6; if (fx2delay > 255) { dev_err(&this_usbduxsub->interface->dev, "comedi%d: period %d for pwm is too low.\n", - dev->minor, period); + dev->minor, period); return -EAGAIN; } } @@ -2024,7 +2067,8 @@ static int usbdux_pwm_period(struct comedi_device *dev, struct comedi_subdevice } /* is called from insn so there's no need to do all the sanity checks */ -static int usbdux_pwm_start(struct comedi_device *dev, struct comedi_subdevice *s) +static int usbdux_pwm_start(struct comedi_device *dev, + struct comedi_subdevice *s) { int ret, i; struct usbduxsub *this_usbduxsub = dev->private; @@ -2056,8 +2100,9 @@ static int usbdux_pwm_start(struct comedi_device *dev, struct comedi_subdevice * } /* generates the bit pattern for PWM with the optional sign bit */ -static int usbdux_pwm_pattern(struct comedi_device *dev, struct comedi_subdevice *s, - int channel, unsigned int value, unsigned int sign) +static int usbdux_pwm_pattern(struct comedi_device *dev, + struct comedi_subdevice *s, int channel, + unsigned int value, unsigned int sign) { struct usbduxsub *this_usbduxsub = dev->private; int i, szbuf; @@ -2097,8 +2142,9 @@ static int usbdux_pwm_pattern(struct comedi_device *dev, struct comedi_subdevice return 1; } -static int usbdux_pwm_write(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_pwm_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct usbduxsub *this_usbduxsub = dev->private; @@ -2118,20 +2164,21 @@ static int usbdux_pwm_write(struct comedi_device *dev, struct comedi_subdevice * * normal operation * relay sign 0 by default */ - return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), - data[0], 0); + return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0); } -static int usbdux_pwm_read(struct comedi_device *x1, struct comedi_subdevice *x2, - comedi_insn *x3, unsigned int *x4) +static int usbdux_pwm_read(struct comedi_device *x1, + struct comedi_subdevice *x2, struct comedi_insn *x3, + unsigned int *x4) { /* not needed */ return -EINVAL; }; /* switches on/off PWM */ -static int usbdux_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, - comedi_insn *insn, unsigned int *data) +static int usbdux_pwm_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct usbduxsub *this_usbduxsub = dev->private; switch (data[0]) { @@ -2220,10 +2267,10 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp) } for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) { if (usbduxsub_tmp->urbOut[i]->transfer_buffer) { - kfree(usbduxsub_tmp->urbOut[i]-> - transfer_buffer); + kfree(usbduxsub_tmp-> + urbOut[i]->transfer_buffer); usbduxsub_tmp->urbOut[i]->transfer_buffer = - NULL; + NULL; } if (usbduxsub_tmp->urbOut[i]) { usb_kill_urb(usbduxsub_tmp->urbOut[i]); @@ -2260,134 +2307,6 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp) usbduxsub_tmp->pwm_cmd_running = 0; } -static unsigned hex2unsigned(char *h) -{ - unsigned hi, lo; - - if (h[0] > '9') - hi = h[0] - 'A' + 0x0a; - else - hi = h[0] - '0'; - - if (h[1] > '9') - lo = h[1] - 'A' + 0x0a; - else - lo = h[1] - '0'; - - return hi * 0x10 + lo; -} - -/* for FX2 */ -#define FIRMWARE_MAX_LEN 0x2000 - -/* taken from David Brownell's fxload and adjusted for this driver */ -static int read_firmware(struct usbduxsub *usbduxsub, const void *firmwarePtr, - long size) -{ - struct device *dev = &usbduxsub->interface->dev; - int i = 0; - unsigned char *fp = (char *)firmwarePtr; - unsigned char *firmwareBinary; - int res = 0; - int maxAddr = 0; - - firmwareBinary = kzalloc(FIRMWARE_MAX_LEN, GFP_KERNEL); - if (!firmwareBinary) { - dev_err(dev, "comedi_: mem alloc for firmware failed\n"); - return -ENOMEM; - } - - for (;;) { - char buf[256], *cp; - char type; - int len; - int idx, off; - int j = 0; - - /* get one line */ - while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) { - buf[j] = fp[i]; - i++; - j++; - if (j >= sizeof(buf)) { - dev_err(dev, "comedi_: bogus firmware file!\n"); - kfree(firmwareBinary); - return -1; - } - } - /* get rid of LF/CR/... */ - while ((i < size) && ((fp[i] == 13) || (fp[i] == 10) - || (fp[i] == 0))) { - i++; - } - - buf[j] = 0; - /* dev_dbg(dev, "comedi_: buf=%s\n", buf); */ - - /* - * EXTENSION: - * "# comment-till-end-of-line", for copyrights etc - */ - if (buf[0] == '#') - continue; - - if (buf[0] != ':') { - dev_err(dev, "comedi_: upload: not an ihex record: %s", - buf); - kfree(firmwareBinary); - return -EFAULT; - } - - /* Read the length field (up to 16 bytes) */ - len = hex2unsigned(buf + 1); - - /* Read the target offset */ - off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5); - - if ((off + len) > maxAddr) - maxAddr = off + len; - - - if (maxAddr >= FIRMWARE_MAX_LEN) { - dev_err(dev, "comedi_: firmware upload goes " - "beyond FX2 RAM boundaries.\n"); - kfree(firmwareBinary); - return -EFAULT; - } - /* dev_dbg(dev, "comedi_: off=%x, len=%x:\n", off, len); */ - - /* Read the record type */ - type = hex2unsigned(buf + 7); - - /* If this is an EOF record, then make it so. */ - if (type == 1) - break; - - - if (type != 0) { - dev_err(dev, "comedi_: unsupported record type: %u\n", - type); - kfree(firmwareBinary); - return -EFAULT; - } - - for (idx = 0, cp = buf + 9; idx < len; idx += 1, cp += 2) { - firmwareBinary[idx + off] = hex2unsigned(cp); - /*printk("%02x ",firmwareBinary[idx+off]); */ - } - /*printk("\n"); */ - - if (i >= size) { - dev_err(dev, "comedi_: unexpected end of hex file\n"); - break; - } - - } - res = firmwareUpload(usbduxsub, firmwareBinary, maxAddr + 1); - kfree(firmwareBinary); - return res; -} - static void usbdux_firmware_request_complete_handler(const struct firmware *fw, void *context) { @@ -2405,15 +2324,16 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, * we need to upload the firmware here because fw will be * freed once we've left this function */ - ret = read_firmware(usbduxsub_tmp, fw->data, fw->size); + ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size); if (ret) { dev_err(&usbdev->dev, - "Could not upload firmware (err=%d)\n", - ret); - return; + "Could not upload firmware (err=%d)\n", ret); + goto out; } comedi_usb_auto_config(usbdev, BOARDNAME); + out: + release_firmware(fw); } /* allocate memory for the urbs and initialise them */ @@ -2464,7 +2384,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf, /* test if it is high speed (USB 2.0) */ usbduxsub[index].high_speed = - (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH); + (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH); /* create space for the commands of the DA converter */ usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); @@ -2528,8 +2448,8 @@ static int usbduxsub_probe(struct usb_interface *uinterf, usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL; usbduxsub[index].urbIn = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers, - GFP_KERNEL); + kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers, + GFP_KERNEL); if (!(usbduxsub[index].urbIn)) { dev_err(dev, "comedi_: usbdux: Could not alloc. urbIn array\n"); tidy_up(&(usbduxsub[index])); @@ -2551,10 +2471,10 @@ static int usbduxsub_probe(struct usb_interface *uinterf, /* and ONLY then the urb should be submitted */ usbduxsub[index].urbIn[i]->context = NULL; usbduxsub[index].urbIn[i]->pipe = - usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP); + usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP); usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP; usbduxsub[index].urbIn[i]->transfer_buffer = - kzalloc(SIZEINBUF, GFP_KERNEL); + kzalloc(SIZEINBUF, GFP_KERNEL); if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) { dev_err(dev, "comedi_: usbdux%d: " "could not alloc. transb.\n", index); @@ -2576,8 +2496,8 @@ static int usbduxsub_probe(struct usb_interface *uinterf, usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL; usbduxsub[index].urbOut = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers, - GFP_KERNEL); + kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers, + GFP_KERNEL); if (!(usbduxsub[index].urbOut)) { dev_err(dev, "comedi_: usbdux: " "Could not alloc. urbOut array\n"); @@ -2600,10 +2520,10 @@ static int usbduxsub_probe(struct usb_interface *uinterf, /* and ONLY then the urb should be submitted */ usbduxsub[index].urbOut[i]->context = NULL; usbduxsub[index].urbOut[i]->pipe = - usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP); + usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP); usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP; usbduxsub[index].urbOut[i]->transfer_buffer = - kzalloc(SIZEOUTBUF, GFP_KERNEL); + kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) { dev_err(dev, "comedi_: usbdux%d: " "could not alloc. transb.\n", index); @@ -2616,7 +2536,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf, usbduxsub[index].urbOut[i]->transfer_buffer_length = SIZEOUTBUF; usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0; usbduxsub[index].urbOut[i]->iso_frame_desc[0].length = - SIZEOUTBUF; + SIZEOUTBUF; if (usbduxsub[index].high_speed) { /* uframes */ usbduxsub[index].urbOut[i]->interval = 8; @@ -2639,7 +2559,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf, return -ENOMEM; } usbduxsub[index].urbPwm->transfer_buffer = - kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL); + kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL); if (!(usbduxsub[index].urbPwm->transfer_buffer)) { dev_err(dev, "comedi_: usbdux%d: " "could not alloc. transb. for pwm\n", index); @@ -2662,8 +2582,9 @@ static int usbduxsub_probe(struct usb_interface *uinterf, ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "usbdux_firmware.hex", + "usbdux_firmware.bin", &udev->dev, + GFP_KERNEL, usbduxsub + index, usbdux_firmware_request_complete_handler); @@ -2689,8 +2610,7 @@ static void usbduxsub_disconnect(struct usb_interface *intf) return; } if (usbduxsub_tmp->usbdev != udev) { - dev_err(&intf->dev, - "comedi_: BUG! called with wrong ptr!!!\n"); + dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n"); return; } comedi_usb_auto_unconfig(udev); @@ -2703,7 +2623,7 @@ static void usbduxsub_disconnect(struct usb_interface *intf) } /* is called when comedi-config is called */ -static int usbdux_attach(struct comedi_device *dev, comedi_devconfig *it) +static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; int index; @@ -2738,9 +2658,9 @@ static int usbdux_attach(struct comedi_device *dev, comedi_devconfig *it) /* trying to upload the firmware into the chip */ if (comedi_aux_data(it->options, 0) && - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - read_firmware(udev, comedi_aux_data(it->options, 0), - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); + it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { + firmwareUpload(udev, comedi_aux_data(it->options, 0), + it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); } dev->board_name = BOARDNAME; @@ -2764,8 +2684,8 @@ static int usbdux_attach(struct comedi_device *dev, comedi_devconfig *it) } dev_info(&udev->interface->dev, - "comedi%d: usb-device %d is attached to comedi.\n", - dev->minor, index); + "comedi%d: usb-device %d is attached to comedi.\n", + dev->minor, index); /* private structure is also simply the usb-structure */ dev->private = udev; @@ -2876,14 +2796,14 @@ static int usbdux_detach(struct comedi_device *dev) if (!dev) { printk(KERN_ERR - "comedi?: usbdux: detach without dev variable...\n"); + "comedi?: usbdux: detach without dev variable...\n"); return -EFAULT; } usbduxsub_tmp = dev->private; if (!usbduxsub_tmp) { printk(KERN_ERR - "comedi?: usbdux: detach without ptr to usbduxsub[]\n"); + "comedi?: usbdux: detach without ptr to usbduxsub[]\n"); return -EFAULT; } @@ -2903,17 +2823,17 @@ static int usbdux_detach(struct comedi_device *dev) } /* main driver struct */ -static comedi_driver driver_usbdux = { - .driver_name = "usbdux", - .module = THIS_MODULE, - .attach = usbdux_attach, - .detach = usbdux_detach, +static struct comedi_driver driver_usbdux = { + .driver_name = "usbdux", + .module = THIS_MODULE, + .attach = usbdux_attach, + .detach = usbdux_detach, }; /* Table with the USB-devices: just now only testing IDs */ -static struct usb_device_id usbduxsub_table[] = { - {USB_DEVICE(0x13d8, 0x0001) }, - {USB_DEVICE(0x13d8, 0x0002) }, +static const struct usb_device_id usbduxsub_table[] = { + {USB_DEVICE(0x13d8, 0x0001)}, + {USB_DEVICE(0x13d8, 0x0002)}, {} /* Terminating entry */ }; @@ -2921,10 +2841,10 @@ MODULE_DEVICE_TABLE(usb, usbduxsub_table); /* The usbduxsub-driver */ static struct usb_driver usbduxsub_driver = { - .name = BOARDNAME, - .probe = usbduxsub_probe, - .disconnect = usbduxsub_disconnect, - .id_table = usbduxsub_table, + .name = BOARDNAME, + .probe = usbduxsub_probe, + .disconnect = usbduxsub_disconnect, + .id_table = usbduxsub_table, }; /* Can't use the nice macro as I have also to initialise the USB */