Hi,
I'm trying to write a driver for a usb device that requires a large bulk
out transfer to patch the firmware. I borrowed the bulk out code from
mass storage's transport.c, but still can't seem to get this to work
(the device does work under windows, and I have no problem with control
transfers). After calling usb_submit_urb(), the blocking callback
returns almost immediately with a value 0f 0, and actual_len of 0. The
urb->status is -ETIMEOUT. A catc trace shows that the first packet
tries to go out 3 times but apparantly doesn't get either an ACK or a
NAK. My controller is uhci, so I dug through that code and it looks like
it may keep retrying until it times out. My suspicion is that the
device is a little slow (on top of delays in the analyser and an
external hub), so I'd like to try changing the timeout value but I can't
find where to do this. Can I do this with a parameter change without
having to recompile the kernel? If not, can someone point me to where
the timeout value is set? I've also pasted the relevant code below if
anyone can find something stupid that I've done. Thanks,
Steve
------------------
int stv674_send_bulk_msg(struct stv674_camera* cam,
void* data,
int data_len)
{
int status = 0;
unsigned int actual_len = 0;
struct urb* burb = cam->bulk_out_strmbuf.urb;
struct completion bulk_done;
DBG("stv674_send_bulk_msg(): len = 0x%0X, data = 0x%0X\n",
data_len, (u32)data);
status = stv674_usb_set_alternate(cam, USBIF_BULK);
/* Finish initializing the URB, send the data, then wait
* for completion
*/
init_completion(&bulk_done);
down(&(cam->bulk_urb_sem)); /* Lock URB */
burb->transfer_buffer = data;
burb->transfer_buffer_length = data_len;
burb->actual_length = 0;
burb->error_count = 0;
burb->transfer_flags = USB_ASYNC_UNLINK;
burb->complete = stv674_usb_blocking_completion;
burb->context = &bulk_done;
/* Submit the urb. */
status = usb_submit_urb(burb);
if (status) {
/* Something went wrong */
up(&(cam->bulk_urb_sem));
ERR("Error from usb_submit_urb(burb): %d\n", status);
return status;
}
/* Wait for completion of the URB */
up(&(cam->bulk_urb_sem));
wait_for_completion(&bulk_done);
down(&(cam->bulk_urb_sem));
actual_len = burb->actual_length;
DBG("stv674_send_bulk_msg(): ret = %d, actual len = 0x%0X\n",
status, actual_len);
DBG("stv674_send_bulk_msg(): URB status = %d\n", burb->status);
up(&(cam->bulk_urb_sem));
// usb_unlink_urb(burb);
return status;
}
/******************************************************************************
*
* stv674_usb_blocking_completion
*
*****************************************************************************/
static void stv674_usb_blocking_completion(struct urb* urb)
{
struct completion *urb_done_ptr = (struct completion *)urb->context;
DBG("Enter blocking completion\n");
complete(urb_done_ptr);
DBG("Leaving blocking completion\n");
}
--
Steve Miller
Software Engineer
STMicroelectronics
phone (602) 485-2014
--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive: http://mail.nl.linux.org/kernelnewbies/
FAQ: http://kernelnewbies.org/faq/