Skip to content

Commit

Permalink
Staging: comedi: usbdux[fast] firmware upload changes
Browse files Browse the repository at this point in the history
usbdux and usbduxfast upload now their firmware via the firmware kernel
meachanism. No udev rules are needed for that except the default ones.
The firmware will usually be loaded from /lib/firmware. Upload via
comedi_config is still possible for static comedi devices
(comedi_num_legacy_minors>0).

Frank, thanks for the example code which sped up rewriting of the code
substantially.

From: Bernd Porr <BerndPorr@f2s.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Cc: Frank Mori Hess <fmhess@users.sourceforge.net>
Cc: David Schleef <ds@schleef.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Bernd Porr authored and Greg Kroah-Hartman committed Apr 3, 2009
1 parent c28264d commit 6742c0a
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 84 deletions.
168 changes: 100 additions & 68 deletions drivers/staging/comedi/drivers/usbdux.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#define DRIVER_VERSION "v2.1"
#define DRIVER_VERSION "v2.2"
#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
/*
Expand All @@ -25,8 +25,8 @@ Driver: usbdux
Description: University of Stirling USB DAQ & INCITE Technology Limited
Devices: [ITL] USB-DUX (usbdux.o)
Author: Bernd Porr <BerndPorr@f2s.com>
Updated: 25 Nov 2007
Status: Testing
Updated: 8 Dec 2008
Status: Stable
Configuration options:
You have to upload firmware with the -i option. The
firmware is usually installed under /usr/share/usb or
Expand Down Expand Up @@ -79,6 +79,7 @@ sampling rate. If you sample two channels you get 4kHz and so on.
* 1.2: added PWM suport via EP4
* 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
*
*/

Expand All @@ -94,6 +95,7 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#include <linux/smp_lock.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
#include <linux/firmware.h>

#include "../comedidev.h"

Expand Down Expand Up @@ -718,31 +720,29 @@ static int usbduxsub_start(struct usbduxsub *usbduxsub)
int errcode = 0;
uint8_t local_transfer_buffer[16];

if (usbduxsub->probed) {
/* 7f92 to zero */
local_transfer_buffer[0] = 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 */
EZTIMEOUT);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: control msg failed (start)\n");
return errcode;
}
/* 7f92 to zero */
local_transfer_buffer[0] = 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 */
EZTIMEOUT);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: control msg failed (start)\n");
return errcode;
}
return 0;
}
Expand All @@ -752,28 +752,27 @@ static int usbduxsub_stop(struct usbduxsub *usbduxsub)
int errcode = 0;

uint8_t local_transfer_buffer[16];
if (usbduxsub->probed) {
/* 7f92 to one */
local_transfer_buffer[0] = 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 */
EZTIMEOUT);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: control msg failed (stop)\n");
return errcode;
}

/* 7f92 to one */
local_transfer_buffer[0] = 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 */
EZTIMEOUT);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: control msg failed (stop)\n");
return errcode;
}
return 0;
}
Expand All @@ -784,13 +783,7 @@ static int usbduxsub_upload(struct usbduxsub *usbduxsub,
{
int errcode;

if (usbduxsub->probed) {
dev_dbg(&usbduxsub->interface->dev,
"comedi%d: usbdux: uploading %d bytes"
" to addr %d, first byte=%d.\n",
usbduxsub->comedidev->minor, len,
startAddr, local_transfer_buffer[0]);
errcode = usb_control_msg(usbduxsub->usbdev,
errcode = usb_control_msg(usbduxsub->usbdev,
usb_sndctrlpipe(usbduxsub->usbdev, 0),
/* brequest, firmware */
USBDUXSUB_FIRMWARE,
Expand All @@ -806,16 +799,12 @@ static int usbduxsub_upload(struct usbduxsub *usbduxsub,
len,
/* timeout */
EZTIMEOUT);
dev_dbg(&usbduxsub->interface->dev,
"comedi_: result=%d\n", errcode);
if (errcode < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: upload failed\n");
return errcode;
}
} else {
/* no device on the bus for this index */
return -EFAULT;
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;
}
Expand Down Expand Up @@ -2292,7 +2281,7 @@ static unsigned hex2unsigned(char *h)
#define FIRMWARE_MAX_LEN 0x2000

/* taken from David Brownell's fxload and adjusted for this driver */
static int read_firmware(struct usbduxsub *usbduxsub, void *firmwarePtr,
static int read_firmware(struct usbduxsub *usbduxsub, const void *firmwarePtr,
long size)
{
struct device *dev = &usbduxsub->interface->dev;
Expand Down Expand Up @@ -2399,6 +2388,34 @@ static int read_firmware(struct usbduxsub *usbduxsub, void *firmwarePtr,
return res;
}

static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
void *context)
{
struct usbduxsub *usbduxsub_tmp = context;
struct usb_device *usbdev = usbduxsub_tmp->usbdev;
int ret;

if (fw == NULL) {
dev_err(&usbdev->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 = read_firmware(usbduxsub_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 */
static int usbduxsub_probe(struct usb_interface *uinterf,
const struct usb_device_id *id)
Expand All @@ -2407,6 +2424,7 @@ static int usbduxsub_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");
Expand Down Expand Up @@ -2641,6 +2659,19 @@ static int usbduxsub_probe(struct usb_interface *uinterf,
/* we've reached the bottom of the function */
usbduxsub[index].probed = 1;
up(&start_stop_sem);

ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_HOTPLUG,
"usbdux_firmware.hex",
&udev->dev,
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 */
Expand All @@ -2662,6 +2693,7 @@ static void usbduxsub_disconnect(struct usb_interface *intf)
"comedi_: BUG! called with wrong ptr!!!\n");
return;
}
comedi_usb_auto_unconfig(udev);
down(&start_stop_sem);
down(&usbduxsub_tmp->sem);
tidy_up(usbduxsub_tmp);
Expand Down
Loading

0 comments on commit 6742c0a

Please sign in to comment.