Staging: Use kmemdup
[safe/jmp/linux-2.6] / drivers / staging / comedi / drivers / usbdux.c
index 41872a3..86f035d 100644 (file)
@@ -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 <linux/slab.h>
 #include <linux/input.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 #include <linux/fcntl.h>
 #include <linux/compiler.h>
 #include <linux/firmware.h>
@@ -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 */