* 1MHz/16ch=62.5kHz
* 0.99: Ian Abbott pointed out a bug which has been corrected. Thanks!
* 0.99a: added external trigger.
+ * 1.00: added firmware kernel request to the driver which fixed
+ * udev coldplug problem
*/
#include <linux/kernel.h>
+#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include "../comedidev.h"
-#define DRIVER_VERSION "v0.99a"
+#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
#define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com"
#define BOARDNAME "usbduxfast"
int16_t *insnBuffer; /* input buffer for single insn */
int ifnum; /* interface number */
struct usb_interface *interface; /* interface structure */
- comedi_device *comedidev; /* comedi device for the interrupt
+ struct comedi_device *comedidev; /* comedi device for the interrupt
context */
short int ai_cmd_running; /* asynchronous command is running */
short int ai_continous; /* continous aquisition */
* This will cancel a running acquisition operation.
* This is called by comedi but never from inside the driver.
*/
-static int usbduxfast_ai_cancel(comedi_device *dev, comedi_subdevice *s)
+static int usbduxfast_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct usbduxfastsub_s *udfs;
int ret;
{
int n, err;
struct usbduxfastsub_s *udfs;
- comedi_device *this_comedidev;
- comedi_subdevice *s;
+ struct comedi_device *this_comedidev;
+ struct comedi_subdevice *s;
uint16_t *p;
/* sanity checks - is the urb there? */
int ret;
unsigned char local_transfer_buffer[16];
- if (!udfs->probed)
- return 0;
-
/* 7f92 to zero */
local_transfer_buffer[0] = 0;
ret = usb_control_msg(udfs->usbdev,
int ret;
unsigned char local_transfer_buffer[16];
- if (!udfs->probed)
- return 0;
-
/* 7f92 to one */
local_transfer_buffer[0] = 1;
ret = usb_control_msg(udfs->usbdev,
{
int ret;
- if (!udfs->probed)
- /* no device on the bus for this index */
- return -EFAULT;
-
#ifdef CONFIG_COMEDI_DEBUG
- printk(KERN_DEBUG "comedi%d: usbduxfast: uploading %d bytes",
- udfs->comedidev->minor, len);
+ printk(KERN_DEBUG "comedi: usbduxfast: uploading %d bytes", len);
printk(KERN_DEBUG " to addr %d, first byte=%d.\n",
startAddr, local_transfer_buffer[0]);
#endif
return 0;
}
-static int usbduxfast_ai_cmdtest(comedi_device *dev,
- comedi_subdevice *s, comedi_cmd *cmd)
+static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s, comedi_cmd *cmd)
{
int err = 0, stop_mask = 0;
long int steps, tmp;
}
-static int usbduxfast_ai_inttrig(comedi_device *dev,
- comedi_subdevice *s, unsigned int trignum)
+static int usbduxfast_ai_inttrig(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int trignum)
{
int ret;
struct usbduxfastsub_s *udfs = dev->private;
#define OUTBASE (1+0x10)
#define LOGBASE (1+0x18)
-static int usbduxfast_ai_cmd(comedi_device *dev, comedi_subdevice *s)
+static int usbduxfast_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
comedi_cmd *cmd = &s->async->cmd;
unsigned int chan, gain, rngmask = 0xff;
/*
* Mode 0 is used to get a single conversion on demand.
*/
-static int usbduxfast_ai_insn_read(comedi_device *dev,
- comedi_subdevice *s, comedi_insn *insn, lsampl_t *data)
+static int usbduxfast_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s, comedi_insn *insn, unsigned int *data)
{
int i, j, n, actual_length;
int chan, range, rngmask;
/*
* taken from David Brownell's fxload and adjusted for this driver
*/
-static int read_firmware(struct usbduxfastsub_s *udfs, void *firmwarePtr,
- long size)
+static int read_firmware(struct usbduxfastsub_s *udfs, const void *firmwarePtr,
+ long size)
{
int i = 0;
unsigned char *fp = (char *)firmwarePtr;
udfs->ai_cmd_running = 0;
}
+static void usbduxfast_firmware_request_complete_handler(const struct firmware *fw,
+ void *context)
+{
+ struct usbduxfastsub_s *usbduxfastsub_tmp = context;
+ struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
+ int ret;
+
+ if (fw == NULL)
+ return;
+
+ /*
+ * we need to upload the firmware here because fw will be
+ * freed once we've left this function
+ */
+ ret = read_firmware(usbduxfastsub_tmp, fw->data, fw->size);
+
+ if (ret) {
+ dev_err(&usbdev->dev,
+ "Could not upload firmware (err=%d)\n",
+ ret);
+ return;
+ }
+
+ comedi_usb_auto_config(usbdev, BOARDNAME);
+}
+
/*
* allocate memory for the urbs and initialise them
*/
struct usb_device *udev = interface_to_usbdev(uinterf);
int i;
int index;
+ int ret;
if (udev->speed != USB_SPEED_HIGH) {
printk(KERN_ERR "comedi_: usbduxfast_: This driver needs"
/* we've reached the bottom of the function */
usbduxfastsub[index].probed = 1;
up(&start_stop_sem);
+
+ ret = request_firmware_nowait(THIS_MODULE,
+ FW_ACTION_HOTPLUG,
+ "usbduxfast_firmware.hex",
+ &udev->dev,
+ usbduxfastsub + index,
+ usbduxfast_firmware_request_complete_handler);
+
+ if (ret) {
+ dev_err(&udev->dev, "could not load firmware (err=%d)\n",
+ ret);
+ return ret;
+ }
+
printk(KERN_INFO "comedi_: usbduxfast%d has been successfully "
"initialized.\n", index);
/* success */
"ptr!!!\n");
return;
}
+
+ comedi_usb_auto_unconfig(udev);
+
down(&start_stop_sem);
down(&udfs->sem);
tidy_up(udfs);
/*
* is called when comedi-config is called
*/
-static int usbduxfast_attach(comedi_device *dev, comedi_devconfig *it)
+static int usbduxfast_attach(struct comedi_device *dev, comedi_devconfig *it)
{
int ret;
int index;
int i;
- 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(usbduxfastsub,
- comedi_aux_data(it->options, 0),
- it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
+ it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
+ read_firmware(&usbduxfastsub[index],
+ comedi_aux_data(it->options, 0),
+ it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
}
dev->board_name = BOARDNAME;
if (ret < 0) {
printk(KERN_ERR "comedi%d: usbduxfast: error alloc space for "
"subdev\n", dev->minor);
+ up(&(usbduxfastsub[index].sem));
up(&start_stop_sem);
return ret;
}
return 0;
}
-static int usbduxfast_detach(comedi_device *dev)
+static int usbduxfast_detach(struct comedi_device *dev)
{
struct usbduxfastsub_s *udfs;
/*
* main driver struct
*/
-static comedi_driver driver_usbduxfast = {
+static struct comedi_driver driver_usbduxfast = {
.driver_name = "usbduxfast",
.module = THIS_MODULE,
.attach = usbduxfast_attach,
.detach = usbduxfast_detach
};
-static void init_usb_devices(void)
-{
- int index;
-
-#ifdef CONFIG_COMEDI_DEBUG
- printk(KERN_DEBUG "comedi_: usbduxfast: setting all possible devs to "
- "invalid\n");
-#endif
- /*
- * all devices entries are invalid to begin with
- * they will become valid by the probe function
- * and then finally by the attach-function
- */
- for (index = 0; index < NUMUSBDUXFAST; index++) {
- memset(&(usbduxfastsub[index]), 0x00,
- sizeof(usbduxfastsub[index]));
- init_MUTEX(&(usbduxfastsub[index].sem));
- }
-}
-
/*
* Table with the USB-devices: just now only testing IDs
*/
* 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_usbduxfast(void)
+static int __init init_usbduxfast(void)
{
printk(KERN_INFO
KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n");
- init_usb_devices();
usb_register(&usbduxfastsub_driver);
comedi_driver_register(&driver_usbduxfast);
return 0;
/*
* deregistering the comedi driver and the usb-subsystem
*/
-static void exit_usbduxfast(void)
+static void __exit exit_usbduxfast(void)
{
comedi_driver_unregister(&driver_usbduxfast);
usb_deregister(&usbduxfastsub_driver);