-#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"
/*
* 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.
*
*/
#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>
#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
/**************************************************/
/* 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),
+ }
};
/*
/* pwm-transfer handling */
struct urb *urbPwm;
/* PWM period */
- lsampl_t pwmPeriod;
+ unsigned int pwmPeriod;
/* PWM internal delay for the GPIF in the FX2 */
int8_t pwmDelay;
/* size of the PWM buffer which holds the bit pattern */
/* interface structure in 2.6 */
struct usb_interface *interface;
/* comedi device for the interrupt context */
- comedi_device *comedidev;
+ struct comedi_device *comedidev;
/* is it USB_SPEED_HIGH or not? */
short int high_speed;
/* asynchronous command is running */
/* 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 */
* This will cancel a running acquisition operation.
* This is called by comedi but never from inside the driver.
*/
-static int usbdux_ai_cancel(comedi_device *dev, comedi_subdevice *s)
+static int usbdux_ai_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct usbduxsub *this_usbduxsub;
int res = 0;
{
int i, err, n;
struct usbduxsub *this_usbduxsub;
- comedi_device *this_comedidev;
- comedi_subdevice *s;
+ struct comedi_device *this_comedidev;
+ struct comedi_subdevice *s;
/* the context variable points to the subdevice */
this_comedidev = urb->context;
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 */
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);
}
}
/* force unlink, is called by comedi */
-static int usbdux_ao_cancel(comedi_device *dev, 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;
int i, ret;
int8_t *datap;
struct usbduxsub *this_usbduxsub;
- comedi_device *this_comedidev;
- comedi_subdevice *s;
+ struct comedi_device *this_comedidev;
+ struct comedi_subdevice *s;
/* the context variable points to the subdevice */
this_comedidev = urb->context;
}
/* 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++) {
- sampl_t temp;
+ short temp;
if (i >= NUMOUTCHANNELS)
break;
/* 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;
/* Length */
1,
/* Timeout */
- EZTIMEOUT);
+ BULK_TIMEOUT);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: control msg failed (start)\n");
/* Length */
1,
/* Timeout */
- EZTIMEOUT);
+ BULK_TIMEOUT);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: control msg failed (stop)\n");
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;
}
return 0;
}
-static int usbdux_ai_cmdtest(comedi_device *dev, 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;
/*
* 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++;
/* 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++;
* 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++;
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");
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, "
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"
return -EFAULT;
}
-static int usbdux_ai_inttrig(comedi_device *dev, 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;
return 1;
}
-static int usbdux_ai_cmd(comedi_device *dev, comedi_subdevice *s)
+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;
break;
}
this_usbduxsub->dux_commands[i + 2] =
- create_adc_command(chan, range);
+ create_adc_command(chan, range);
}
dev_dbg(&this_usbduxsub->interface->dev,
/* 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;
}
/* Mode 0 is used to get a single conversion on demand */
-static int usbdux_ai_insn_read(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *data)
+static int usbdux_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
{
int i;
- lsampl_t one = 0;
+ unsigned int one = 0;
int chan, range;
int err;
struct usbduxsub *this_usbduxsub = dev->private;
/************************************/
/* analog out */
-static int usbdux_ao_insn_read(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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);
return i;
}
-static int usbdux_ao_insn_write(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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);
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);
return i;
}
-static int usbdux_ao_inttrig(comedi_device *dev, 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;
return 1;
}
-static int usbdux_ao_cmdtest(comedi_device *dev, 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;
/*
* 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++;
return 0;
}
-static int usbdux_ao_cmd(comedi_device *dev, comedi_subdevice *s)
+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;
/* 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 */
return 0;
}
-static int usbdux_dio_insn_config(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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);
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;
return insn->n;
}
-static int usbdux_dio_insn_bits(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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;
if (!this_usbduxsub)
return -EFAULT;
-
if (insn->n != 2)
return -EINVAL;
}
/* reads the 4 counters, only two are used just now */
-static int usbdux_counter_read(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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;
return 1;
}
-static int usbdux_counter_write(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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;
return 1;
}
-static int usbdux_counter_config(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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;
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(comedi_device *dev, 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;
{
int ret;
struct usbduxsub *this_usbduxsub;
- comedi_device *this_comedidev;
- comedi_subdevice *s;
+ struct comedi_device *this_comedidev;
+ struct comedi_subdevice *s;
/* printk(KERN_DEBUG "PWM: IRQ\n"); */
/* 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) {
return 0;
}
-static int usbdux_pwm_period(comedi_device *dev, comedi_subdevice *s,
- lsampl_t 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;
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;
}
}
}
/* is called from insn so there's no need to do all the sanity checks */
-static int usbdux_pwm_start(comedi_device *dev, 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;
}
/* generates the bit pattern for PWM with the optional sign bit */
-static int usbdux_pwm_pattern(comedi_device *dev, comedi_subdevice *s,
- int channel, lsampl_t value, lsampl_t 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;
return 1;
}
-static int usbdux_pwm_write(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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;
* 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(comedi_device *x1, comedi_subdevice *x2,
- comedi_insn *x3, lsampl_t *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(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *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]) {
}
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]);
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)
{
* 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 */
/* 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);
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]));
/* 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);
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");
/* 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);
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;
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);
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);
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);
}
/* is called when comedi-config is called */
-static int usbdux_attach(comedi_device *dev, comedi_devconfig *it)
+static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
int index;
int i;
struct usbduxsub *udev;
- comedi_subdevice *s = NULL;
+ struct comedi_subdevice *s = NULL;
dev->private = NULL;
down(&start_stop_sem);
/* 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;
}
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;
return 0;
}
-static int usbdux_detach(comedi_device *dev)
+static int usbdux_detach(struct comedi_device *dev)
{
struct usbduxsub *usbduxsub_tmp;
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;
}
}
/* 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 */
};
/* 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 */
/* subsystem: */
/* registering the usb-system _and_ the comedi-driver */
-static int init_usbdux(void)
+static int __init init_usbdux(void)
{
printk(KERN_INFO KBUILD_MODNAME ": "
DRIVER_VERSION ":" DRIVER_DESC "\n");
}
/* deregistering the comedi driver and the usb-subsystem */
-static void exit_usbdux(void)
+static void __exit exit_usbdux(void)
{
comedi_driver_unregister(&driver_usbdux);
usb_deregister(&usbduxsub_driver);