diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/usbdux.c')
-rw-r--r-- | drivers/staging/comedi/drivers/usbdux.c | 236 |
1 files changed, 60 insertions, 176 deletions
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 6f5da67e26cb..279e5bd493fa 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -11,11 +11,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: usbdux @@ -94,7 +89,6 @@ sampling rate. If you sample two channels you get 4kHz and so on. #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> -#include <linux/firmware.h> #include "../comedidev.h" @@ -727,154 +721,82 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) } } -static int usbduxsub_start(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t *local_transfer_buffer; - - local_transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to zero */ - *local_transfer_buffer = 0; - errcode = usb_control_msg(usbduxsub->usbdev, - /* create a pipe for a control transfer */ - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, - /* address of the transfer buffer */ - local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (start)\n"); - - kfree(local_transfer_buffer); - return errcode; -} - -static int usbduxsub_stop(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t *local_transfer_buffer; - - local_transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to one */ - *local_transfer_buffer = 1; - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (stop)\n"); - - kfree(local_transfer_buffer); - return errcode; -} - -static int usbduxsub_upload(struct usbduxsub *usbduxsub, - uint8_t *local_transfer_buffer, - unsigned int start_addr, unsigned int len) -{ - int errcode; - - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* brequest, firmware */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* value */ - start_addr, - /* 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"); - return errcode; - } - return 0; -} - #define FIRMWARE_MAX_LEN 0x2000 -static int firmware_upload(struct usbduxsub *usbduxsub, - const u8 *firmware_binary, int size_firmware) +static int usbdux_firmware_upload(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { + struct usbduxsub *usbduxsub = dev->private; + struct usb_device *usb = usbduxsub->usbdev; + uint8_t *buf; + uint8_t *tmp; int ret; - uint8_t *fw_buf; - if (!firmware_binary) + if (!data) return 0; - if (size_firmware > FIRMWARE_MAX_LEN) { + if (size > 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 */ - fw_buf = kmemdup(firmware_binary, size_firmware, GFP_KERNEL); - if (!fw_buf) { - dev_err(&usbduxsub->interface->dev, - "comedi_: mem alloc for firmware failed\n"); + 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; } - ret = usbduxsub_stop(usbduxsub); + /* 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(&usbduxsub->interface->dev, "comedi_: can not stop firmware\n"); - kfree(fw_buf); - return ret; + goto done; } - ret = usbduxsub_upload(usbduxsub, fw_buf, 0, size_firmware); + /* 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(&usbduxsub->interface->dev, "comedi_: firmware upload failed\n"); - kfree(fw_buf); - return ret; + goto done; } - ret = usbduxsub_start(usbduxsub); - if (ret < 0) { + + /* 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(&usbduxsub->interface->dev, "comedi_: can not start firmware\n"); - kfree(fw_buf); - return ret; - } - kfree(fw_buf); - return 0; + +done: + kfree(tmp); + kfree(buf); + return ret; } static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub) @@ -2328,13 +2250,21 @@ static int usbdux_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct usb_interface *uinterf = comedi_to_usb_interface(dev); + struct usbduxsub *this_usbduxsub = usb_get_intfdata(uinterf); + struct usb_device *usb = usbduxsub->usbdev; int ret; - struct usbduxsub *this_usbduxsub; + + dev->private = this_usbduxsub; /* This is temporary... */ + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, + usbdux_firmware_upload, 0); + if (ret < 0) { + dev->private = NULL; + return ret; + } dev->private = NULL; down(&start_stop_sem); - this_usbduxsub = usb_get_intfdata(uinterf); if (!this_usbduxsub || !this_usbduxsub->probed) { dev_err(dev->class_dev, "usbdux: error: auto_attach failed, not connected\n"); @@ -2369,35 +2299,6 @@ static struct comedi_driver usbdux_driver = { .detach = usbdux_detach, }; -static void usbdux_firmware_request_complete_handler(const struct firmware *fw, - void *context) -{ - struct usbduxsub *usbduxsub_tmp = context; - struct usb_interface *uinterf = usbduxsub_tmp->interface; - int ret; - - if (fw == NULL) { - dev_err(&uinterf->dev, - "Firmware complete handler without firmware!\n"); - return; - } - - /* - * we need to upload the firmware here because fw will be - * freed once we've left this function - */ - ret = firmware_upload(usbduxsub_tmp, fw->data, fw->size); - - if (ret) { - dev_err(&uinterf->dev, - "Could not upload firmware (err=%d)\n", ret); - goto out; - } - comedi_usb_auto_config(uinterf, &usbdux_driver, 0); - out: - release_firmware(fw); -} - static int usbdux_usb_probe(struct usb_interface *uinterf, const struct usb_device_id *id) { @@ -2405,7 +2306,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, struct device *dev = &uinterf->dev; int i; int index; - int ret; dev_dbg(dev, "comedi_: usbdux_: " "finding a free structure for the usb-device\n"); @@ -2622,23 +2522,7 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].probed = 1; up(&start_stop_sem); - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, - FIRMWARE, - &udev->dev, - GFP_KERNEL, - usbduxsub + index, - usbdux_firmware_request_complete_handler); - - if (ret) { - dev_err(dev, "Could not load firmware (err=%d)\n", ret); - return ret; - } - - dev_info(dev, "comedi_: usbdux%d " - "has been successfully initialised.\n", index); - /* success */ - return 0; + return comedi_usb_auto_config(uinterf, &usbdux_driver, 0); } static void usbdux_usb_disconnect(struct usb_interface *intf) |