struct usbduxsigma_private { /* actual number of in-buffers */ int n_ai_urbs; /* actual number of out-buffers */ int n_ao_urbs; /* ISO-transfer handling: buffers */ struct urb **ai_urbs; struct urb **ao_urbs; /* pwm-transfer handling */ struct urb *pwm_urb; /* PWM period */ unsignedint pwm_period; /* PWM internal delay for the GPIF in the FX2 */
u8 pwm_delay; /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */
__be32 *in_buf; /* input buffer for single insn */
u8 *insn_buf;
/* time between samples in units of the timer */ unsignedint ai_timer; unsignedint ao_timer; /* counter between acquisitions */ unsignedint ai_counter; unsignedint ao_counter; /* interval in frames/uframes */ unsignedint ai_interval; /* commands */
u8 *dux_commands; struct mutex mut;
};
staticvoid usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs)
{ int i;
for (i = 0; i < num_urbs; i++)
usb_kill_urb(urbs[i]);
}
if ((urb->actual_length > 0) && (urb->status != -EXDEV)) {
devpriv->ai_counter--; if (devpriv->ai_counter == 0) {
devpriv->ai_counter = devpriv->ai_timer;
/* *GetthedatafromtheUSBbusandhanditover *tocomedi.Note,firstbyteistheDIOstate.
*/ for (i = 0; i < cmd->chanlist_len; i++) {
val = be32_to_cpu(devpriv->in_buf[i + 1]);
val &= 0x00ffffff; /* strip status byte */
val = comedi_offset_munge(s, val); if (!comedi_buf_write_samples(s, &val, 1)) return;
}
/* exit if not running a command, do not resubmit urb */ if (!devpriv->ai_cmd_running) return;
switch (urb->status) { case0: /* copy the result in the transfer buffer */
memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF);
usbduxsigma_ai_handle_urb(dev, s, urb); break;
case -EILSEQ: /* *errorintheISOchronousdata *wedon'tcopythedataintothetransferbuffer *andrecyclethelastdatabyte
*/
dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n");
usbduxsigma_ai_handle_urb(dev, s, urb); break;
case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */
async->events |= COMEDI_CB_ERROR; break;
default: /* a real error */
dev_err(dev->class_dev, "non-zero urb status (%d)\n",
urb->status);
async->events |= COMEDI_CB_ERROR; break;
}
/* *comedi_handle_events()cannotbeusedinthisdriver.The(*cancel) *operationwouldunlinktheurb.
*/ if (async->events & COMEDI_CB_CANCEL_MASK)
usbduxsigma_ai_stop(dev, 0);
/* transmit data to the USB bus */
datap = urb->transfer_buffer;
*datap++ = cmd->chanlist_len; for (i = 0; i < cmd->chanlist_len; i++) { unsignedint chan = CR_CHAN(cmd->chanlist[i]); unsignedshort val;
case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */
async->events |= COMEDI_CB_ERROR; break;
default: /* a real error */
dev_err(dev->class_dev, "non-zero urb status (%d)\n",
urb->status);
async->events |= COMEDI_CB_ERROR; break;
}
/* *comedi_handle_events()cannotbeusedinthisdriver.The(*cancel) *operationwouldunlinktheurb.
*/ if (async->events & COMEDI_CB_CANCEL_MASK)
usbduxsigma_ao_stop(dev, 0);
comedi_event(dev, s);
}
staticint usbduxsigma_submit_urbs(struct comedi_device *dev, struct urb **urbs, int num_urbs, int input_urb)
{ struct usb_device *usb = comedi_to_usb_dev(dev); struct urb *urb; int ret; int i;
/* Submit all URBs and start the transfer on the bus */ for (i = 0; i < num_urbs; i++) {
urb = urbs[i];
/* in case of a resubmission after an unlink... */ if (input_urb)
urb->interval = 1;
urb->context = dev;
urb->dev = usb;
urb->status = 0;
urb->transfer_flags = URB_ISO_ASAP;
ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) return ret;
} return0;
}
staticint usbduxsigma_receive_cmd(struct comedi_device *dev, int command)
{ struct usb_device *usb = comedi_to_usb_dev(dev); struct usbduxsigma_private *devpriv = dev->private; int nrec; int ret; int i;
for (i = 0; i < RETRIES; i++) {
ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8),
devpriv->insn_buf, SIZEINSNBUF,
&nrec, BULK_TIMEOUT); if (ret < 0) return ret;
mutex_lock(&devpriv->mut); if (devpriv->ai_cmd_running) {
mutex_unlock(&devpriv->mut); return -EBUSY;
}
create_adc_command(chan, &muxsg0, &muxsg1);
/* Mode 0 is used to get a single conversion on demand */
devpriv->dux_commands[1] = 0x16; /* CONFIG0: chopper on */
devpriv->dux_commands[2] = 0x80; /* CONFIG1: 2kHz sampling rate */
devpriv->dux_commands[3] = 0x00; /* CONFIG3: diff. channels off */
devpriv->dux_commands[4] = muxsg0;
devpriv->dux_commands[5] = muxsg1;
devpriv->dux_commands[6] = sysred;
/* adc commands */
ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) {
mutex_unlock(&devpriv->mut); return ret;
}
for (i = 0; i < insn->n; i++) {
u32 val;
ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) {
mutex_unlock(&devpriv->mut); return ret;
}
/* 32 bits big endian from the A/D converter */
val = be32_to_cpu(get_unaligned((__be32
*)(devpriv->insn_buf + 1)));
val &= 0x00ffffff; /* strip status byte */
data[i] = comedi_offset_munge(s, val);
}
mutex_unlock(&devpriv->mut);
ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DIO_BITS_CMD); if (ret < 0) goto done;
ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_DIO_BITS_CMD); if (ret < 0) goto done;
case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ if (devpriv->pwm_cmd_running)
usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ return;
default: /* a real error */ if (devpriv->pwm_cmd_running) {
dev_err(dev->class_dev, "non-zero urb status (%d)\n",
urb->status);
usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */
} return;
}
if (!devpriv->pwm_cmd_running) return;
urb->transfer_buffer_length = devpriv->pwm_buf_sz;
urb->dev = comedi_to_usb_dev(dev);
urb->status = 0;
ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) {
dev_err(dev->class_dev, "urb resubmit failed (%d)\n", ret); if (ret == -EL2NSYNC)
dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler\n");
usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */
}
}
/* in case of a resubmission after an unlink... */
usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4),
urb->transfer_buffer, devpriv->pwm_buf_sz,
usbduxsigma_pwm_urb_complete, dev);
ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) return ret;
/* 32 bits big endian from the A/D converter */
val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1)));
val &= 0x00ffffff; /* strip status byte */
if (size > FIRMWARE_MAX_LEN) {
dev_err(dev->class_dev, "firmware binary too large for FX2\n"); return -ENOMEM;
}
/* we generate a local buffer for the firmware */
buf = kmemdup(data, size, GFP_KERNEL); if (!buf) return -ENOMEM;
/* we need a malloc'ed buffer for usb_control_msg() */
tmp = kmalloc(1, GFP_KERNEL); if (!tmp) {
kfree(buf); return -ENOMEM;
}
/* stop the current firmware on the device */
*tmp = 1; /* 7f92 to one */
ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
USBDUXSUB_FIRMWARE,
VENDOR_DIR_OUT,
USBDUXSUB_CPUCS, 0x0000,
tmp, 1,
BULK_TIMEOUT); if (ret < 0) {
dev_err(dev->class_dev, "can not stop firmware\n"); goto done;
}
/* upload the new firmware to the device */
ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
USBDUXSUB_FIRMWARE,
VENDOR_DIR_OUT, 0, 0x0000,
buf, size,
BULK_TIMEOUT); if (ret < 0) {
dev_err(dev->class_dev, "firmware upload failed\n"); goto done;
}
/* start the new firmware on the device */
*tmp = 0; /* 7f92 to zero */
ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
USBDUXSUB_FIRMWARE,
VENDOR_DIR_OUT,
USBDUXSUB_CPUCS, 0x0000,
tmp, 1,
BULK_TIMEOUT); if (ret < 0)
dev_err(dev->class_dev, "can not start firmware\n");
for (i = 0; i < devpriv->n_ai_urbs; i++) { /* one frame: 1ms */
urb = usb_alloc_urb(1, GFP_KERNEL); if (!urb) return -ENOMEM;
devpriv->ai_urbs[i] = urb;
urb->dev = usb; /* will be filled later with a pointer to the comedi-device */ /* and ONLY then the urb should be submitted */
urb->context = NULL;
urb->pipe = usb_rcvisocpipe(usb, 6);
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); if (!urb->transfer_buffer) return -ENOMEM;
urb->complete = usbduxsigma_ai_urb_complete;
urb->number_of_packets = 1;
urb->transfer_buffer_length = SIZEINBUF;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = SIZEINBUF;
}
for (i = 0; i < devpriv->n_ao_urbs; i++) { /* one frame: 1ms */
urb = usb_alloc_urb(1, GFP_KERNEL); if (!urb) return -ENOMEM;
devpriv->ao_urbs[i] = urb;
urb->dev = usb; /* will be filled later with a pointer to the comedi-device */ /* and ONLY then the urb should be submitted */
urb->context = NULL;
urb->pipe = usb_sndisocpipe(usb, 2);
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!urb->transfer_buffer) return -ENOMEM;
urb->complete = usbduxsigma_ao_urb_complete;
urb->number_of_packets = 1;
urb->transfer_buffer_length = SIZEOUTBUF;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = SIZEOUTBUF;
urb->interval = 1; /* (u)frames */
}
if (devpriv->pwm_buf_sz) {
urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM;
devpriv->pwm_urb = urb;
urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz,
GFP_KERNEL); if (!urb->transfer_buffer) return -ENOMEM;
}
ret = usbduxsigma_alloc_usb_buffers(dev); if (ret) return ret;
/* setting to alternate setting 3: enabling iso ep and bulk ep. */
ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber, 3); if (ret < 0) {
dev_err(dev->class_dev, "could not set alternate setting 3 in high speed\n"); return ret;
}
ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
usbduxsigma_firmware_upload, 0); if (ret) return ret;
ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 4 : 3); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.