summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/pvrusb2
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/pvrusb2')
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c132
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h13
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);