diff options
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r-- | linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c | 132 | ||||
-rw-r--r-- | linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h | 13 |
2 files changed, 112 insertions, 33 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1ee2fcda4..31fdff2f5 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1003,11 +1003,55 @@ static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw) } +static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) +{ + /* Try a harmless request to fetch the eeprom's address over + endpoint 1. See what happens. Only the full FX2 image can + respond to this. If this probe fails then likely the FX2 + firmware needs be loaded. */ + int result; + LOCK_TAKE(hdw->ctl_lock); do { + hdw->cmd_buffer[0] = 0xeb; + result = pvr2_send_request_ex(hdw,HZ*1,!0, + hdw->cmd_buffer,1, + hdw->cmd_buffer,1); + if (result < 0) break; + } while(0); LOCK_GIVE(hdw->ctl_lock); + if (result) { + pvr2_trace(PVR2_TRACE_INIT, + "Probe of device endpoint 1 result status %d", + result); + } else { + pvr2_trace(PVR2_TRACE_INIT, + "Probe of device endpoint 1 succeeded"); + } + return result == 0; +} + + static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) { int ret; unsigned int idx; - if (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints == 0) { + int reloadFl = 0; + if (!reloadFl) { + reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints + == 0); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "USB endpoint config looks strange" + "; possibly firmware needs to be loaded"); + } + } + if (!reloadFl) { + reloadFl = !pvr2_hdw_check_firmware(hdw); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "Check for FX2 firmware failed" + "; possibly firmware needs to be loaded"); + } + } + if (reloadFl) { if (pvr2_upload_firmware1(hdw) != 0) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Failure uploading firmware1"); @@ -1921,31 +1965,33 @@ static void pvr2_ctl_timeout(unsigned long data) } -int pvr2_send_request(struct pvr2_hdw *hdw, - void *write_data,unsigned int write_len, - void *read_data,unsigned int read_len) +int pvr2_send_request_ex(struct pvr2_hdw *hdw, + unsigned int timeout,int probe_fl, + void *write_data,unsigned int write_len, + void *read_data,unsigned int read_len) { unsigned int idx; - int status; + int status = 0; struct timer_list timer; if (!hdw->ctl_lock_held) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " without lock!!"); - status = -EINVAL; - goto done; + return -EDEADLK; } - if (!hdw->flag_ok) { + if ((!hdw->flag_ok) && !probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " when device not ok"); return -EIO; } if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " when USB is disconnected"); - return -EIO; + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Attempted to execute control transfer" + " when USB is disconnected"); + } + return -ENOTTY; } /* Ensure that we have sane parameters */ @@ -1989,7 +2035,7 @@ int pvr2_send_request(struct pvr2_hdw *hdw, hdw->ctl_write_pend_flag = 0; hdw->ctl_read_pend_flag = 0; init_timer(&timer); - timer.expires = jiffies + HZ*4; + timer.expires = jiffies + timeout; timer.data = (unsigned long)hdw; timer.function = pvr2_ctl_timeout; @@ -2020,6 +2066,7 @@ int pvr2_send_request(struct pvr2_hdw *hdw, "Failed to submit write-control" " URB status=%d",status); hdw->ctl_write_pend_flag = 0; + goto done; } } @@ -2046,6 +2093,7 @@ int pvr2_send_request(struct pvr2_hdw *hdw, "Failed to submit read-control" " URB status=%d",status); hdw->ctl_read_pend_flag = 0; + goto done; } } @@ -2067,8 +2115,10 @@ int pvr2_send_request(struct pvr2_hdw *hdw, if (hdw->ctl_timeout_flag) { status = -ETIMEDOUT; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Timed out control-write"); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Timed out control-write"); + } goto done; } @@ -2081,19 +2131,24 @@ int pvr2_send_request(struct pvr2_hdw *hdw, /* USB subsystem is reporting some kind of failure on the write */ status = hdw->ctl_write_urb->status; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB failure, status=%d", - status); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-write URB failure," + " status=%d", + status); + } goto done; } if (hdw->ctl_write_urb->actual_length < write_len) { /* Failed to write enough data */ status = -EIO; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB short," - " expected=%d got=%d", - write_len, - hdw->ctl_write_urb->actual_length); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-write URB short," + " expected=%d got=%d", + write_len, + hdw->ctl_write_urb->actual_length); + } goto done; } } @@ -2106,18 +2161,24 @@ int pvr2_send_request(struct pvr2_hdw *hdw, /* USB subsystem is reporting some kind of failure on the read */ status = hdw->ctl_read_urb->status; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB failure, status=%d", - status); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-read URB failure," + " status=%d", + status); + } goto done; } if (hdw->ctl_read_urb->actual_length < read_len) { /* Failed to read enough data */ status = -EIO; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB short," - " expected=%d got=%d", - read_len,hdw->ctl_read_urb->actual_length); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-read URB short," + " expected=%d got=%d", + read_len, + hdw->ctl_read_urb->actual_length); + } goto done; } /* Transfer retrieved data out from internal buffer */ @@ -2129,13 +2190,22 @@ int pvr2_send_request(struct pvr2_hdw *hdw, done: hdw->cmd_debug_state = 0; - if (status < 0) { + if ((status < 0) && (!probe_fl)) { pvr2_hdw_render_useless_unlocked(hdw); } return status; } +int pvr2_send_request(struct pvr2_hdw *hdw, + void *write_data,unsigned int write_len, + void *read_data,unsigned int read_len) +{ + return pvr2_send_request_ex(hdw,HZ*4,0, + write_data,write_len, + read_data,read_len); +} + int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data) { int ret; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 2f9c4cb6d..cfde4a0c5 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -322,8 +322,17 @@ void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw); /* Issue a command and get a response from the device. LOTS of higher level stuff is built on this. */ -int pvr2_send_request(struct pvr2_hdw *, void *, unsigned int, - void *, unsigned int); +int pvr2_send_request(struct pvr2_hdw *, + void *write_ptr,unsigned int write_len, + void *read_ptr,unsigned int read_len); + +/* Issue a command and get a response from the device. This extended + version includes a probe flag (which if set means that device errors + should not be logged or treated as fatal) and a timeout in jiffies. + This can be used to non-lethally probe the health of endpoint 1. */ +int pvr2_send_request_ex(struct pvr2_hdw *,unsigned int timeout,int probe_fl, + void *write_ptr,unsigned int write_len, + void *read_ptr,unsigned int read_len); /* Slightly higher level device communication functions. */ int pvr2_write_register(struct pvr2_hdw *, u16, u32); |