Staging: comedi: Remove comedi_driver typedef
[linux-2.6-block.git] / drivers / staging / comedi / drivers / usbduxfast.c
index c6d34703a344f38e1698e0e6ce4bca1e0a47a2db..54b49580505accb3bd3a8e2b586f3ca4557ab26d 100644 (file)
  *       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>
@@ -48,7 +51,7 @@
 #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"
@@ -176,7 +179,7 @@ struct usbduxfastsub_s {
        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 */
@@ -281,7 +284,7 @@ static int usbduxfast_ai_stop(struct usbduxfastsub_s *udfs,
  * 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;
@@ -315,8 +318,8 @@ static void usbduxfastsub_ai_Irq(struct urb *urb PT_REGS_ARG)
 {
        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? */
@@ -444,9 +447,6 @@ static int usbduxfastsub_start(struct usbduxfastsub_s *udfs)
        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,
@@ -471,9 +471,6 @@ static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs)
        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,
@@ -500,13 +497,8 @@ static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs,
 {
        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
@@ -585,8 +577,8 @@ int usbduxfastsub_submit_InURBs(struct usbduxfastsub_s *udfs)
        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;
@@ -727,8 +719,8 @@ static int usbduxfast_ai_cmdtest(comedi_device *dev,
 
 }
 
-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;
@@ -779,7 +771,7 @@ static int usbduxfast_ai_inttrig(comedi_device *dev,
 #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;
@@ -1238,8 +1230,8 @@ static int usbduxfast_ai_cmd(comedi_device *dev, comedi_subdevice *s)
 /*
  * 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;
@@ -1396,8 +1388,8 @@ static unsigned hex2unsigned(char *h)
 /*
  * 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;
@@ -1538,6 +1530,32 @@ static void tidy_up(struct usbduxfastsub_s *udfs)
        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
  */
@@ -1547,6 +1565,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf,
        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"
@@ -1644,6 +1663,20 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf,
        /* 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 */
@@ -1665,6 +1698,9 @@ static void usbduxfastsub_disconnect(struct usb_interface *intf)
                       "ptr!!!\n");
                return;
        }
+
+       comedi_usb_auto_unconfig(udev);
+
        down(&start_stop_sem);
        down(&udfs->sem);
        tidy_up(udfs);
@@ -1679,12 +1715,12 @@ static void usbduxfastsub_disconnect(struct usb_interface *intf)
 /*
  * 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);
@@ -1714,10 +1750,10 @@ static int usbduxfast_attach(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(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;
@@ -1730,6 +1766,7 @@ static int usbduxfast_attach(comedi_device *dev, comedi_devconfig *it)
        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;
        }
@@ -1776,7 +1813,7 @@ static int usbduxfast_attach(comedi_device *dev, comedi_devconfig *it)
        return 0;
 }
 
-static int usbduxfast_detach(comedi_device *dev)
+static int usbduxfast_detach(struct comedi_device *dev)
 {
        struct usbduxfastsub_s *udfs;
 
@@ -1819,33 +1856,13 @@ static int usbduxfast_detach(comedi_device *dev)
 /*
  * 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
  */
@@ -1875,11 +1892,10 @@ static struct usb_driver usbduxfastsub_driver = {
  * 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;
@@ -1888,7 +1904,7 @@ static int init_usbduxfast(void)
 /*
  * 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);