Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4db666cc3d199a8b837174bb0ad00d6b8f6115d6
Commit:     4db666cc3d199a8b837174bb0ad00d6b8f6115d6
Parent:     401c27ce96382b3bdbc7a9c7e7303fd1b3af9ef0
Author:     Mike Isely <[EMAIL PROTECTED]>
AuthorDate: Sat Sep 8 22:16:27 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Tue Oct 9 22:14:34 2007 -0300

    V4L/DVB (6208): pvrusb2: Implement programmatic means to extract prom 
contents
    
    The pvrusb2 driver already has a method for extracting the FX2's
    program memory back out to a user application; this ability is used to
    facilitate manual firmware extraction as per the procedure documented
    on the pvrusb2 web site.  This change follows that pattern and
    implements a corresponding method to grab the binary contents of the
    PVR USB2 prom (which for PVR USB2 devices can contain information in
    addition to the usual Hauppauge metadata).
    
    Signed-off-by: Mike Isely <[EMAIL PROTECTED]>
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/video/pvrusb2/pvrusb2-debugifc.c     |   16 ++-
 drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h |    1 +
 drivers/media/video/pvrusb2/pvrusb2-hdw.c          |  150 ++++++++++++++++----
 drivers/media/video/pvrusb2/pvrusb2-hdw.h          |   12 +-
 4 files changed, 147 insertions(+), 32 deletions(-)

diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c 
b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index e9da9bb..6f135f4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -397,10 +397,22 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw 
*hdw,const char *buf,
                count -= scnt; buf += scnt;
                if (!wptr) return -EINVAL;
                if (debugifc_match_keyword(wptr,wlen,"fetch")) {
-                       pvr2_hdw_cpufw_set_enabled(hdw,!0);
+                       scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+                       if (scnt && wptr) {
+                               count -= scnt; buf += scnt;
+                               if (debugifc_match_keyword(wptr,wlen,"prom")) {
+                                       pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
+                               } else if (debugifc_match_keyword(wptr,wlen,
+                                                                 "ram")) {
+                                       pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
+                               } else {
+                                       return -EINVAL;
+                               }
+                       }
+                       pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
                        return 0;
                } else if (debugifc_match_keyword(wptr,wlen,"done")) {
-                       pvr2_hdw_cpufw_set_enabled(hdw,0);
+                       pvr2_hdw_cpufw_set_enabled(hdw,0,0);
                        return 0;
                } else {
                        return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h 
b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index ce66ab8..985d9ae 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -238,6 +238,7 @@ struct pvr2_hdw {
        // CPU firmware info (used to help find / save firmware data)
        char *fw_buffer;
        unsigned int fw_size;
+       int fw_cpu_flag; /* True if we are dealing with the CPU */
 
        // Which subsystem pieces have been enabled / configured
        unsigned long subsys_enabled_mask;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c 
b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 5d90452..7172f66 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2605,7 +2605,85 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
        } while (0); LOCK_GIVE(hdw->big_lock);
 }
 
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+
+/* Grab EEPROM contents, needed for direct method. */
+#define EEPROM_SIZE 8192
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+       struct i2c_msg msg[2];
+       u8 *eeprom;
+       u8 iadd[2];
+       u8 addr;
+       u16 eepromSize;
+       unsigned int offs;
+       int ret;
+       int mode16 = 0;
+       unsigned pcnt,tcnt;
+       eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+       if (!eeprom) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to allocate memory"
+                          " required to read eeprom");
+               return NULL;
+       }
+
+       trace_eeprom("Value for eeprom addr from controller was 0x%x",
+                    hdw->eeprom_addr);
+       addr = hdw->eeprom_addr;
+       /* Seems that if the high bit is set, then the *real* eeprom
+          address is shifted right now bit position (noticed this in
+          newer PVR USB2 hardware) */
+       if (addr & 0x80) addr >>= 1;
+
+       /* FX2 documentation states that a 16bit-addressed eeprom is
+          expected if the I2C address is an odd number (yeah, this is
+          strange but it's what they do) */
+       mode16 = (addr & 1);
+       eepromSize = (mode16 ? EEPROM_SIZE : 256);
+       trace_eeprom("Examining %d byte eeprom at location 0x%x"
+                    " using %d bit addressing",eepromSize,addr,
+                    mode16 ? 16 : 8);
+
+       msg[0].addr = addr;
+       msg[0].flags = 0;
+       msg[0].len = mode16 ? 2 : 1;
+       msg[0].buf = iadd;
+       msg[1].addr = addr;
+       msg[1].flags = I2C_M_RD;
+
+       /* We have to do the actual eeprom data fetch ourselves, because
+          (1) we're only fetching part of the eeprom, and (2) if we were
+          getting the whole thing our I2C driver can't grab it in one
+          pass - which is what tveeprom is otherwise going to attempt */
+       memset(eeprom,0,EEPROM_SIZE);
+       for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+               pcnt = 16;
+               if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+               offs = tcnt + (eepromSize - EEPROM_SIZE);
+               if (mode16) {
+                       iadd[0] = offs >> 8;
+                       iadd[1] = offs;
+               } else {
+                       iadd[0] = offs;
+               }
+               msg[1].len = pcnt;
+               msg[1].buf = eeprom+tcnt;
+               if ((ret = i2c_transfer(&hdw->i2c_adap,
+                                       msg,ARRAY_SIZE(msg))) != 2) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "eeprom fetch set offs err=%d",ret);
+                       kfree(eeprom);
+                       return NULL;
+               }
+       }
+       return eeprom;
+}
+
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
+                               int prom_flag,
+                               int enable_flag)
 {
        int ret;
        u16 address;
@@ -2619,37 +2697,59 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, 
int enable_flag)
                        kfree(hdw->fw_buffer);
                        hdw->fw_buffer = NULL;
                        hdw->fw_size = 0;
-                       /* Now release the CPU.  It will disconnect and
-                          reconnect later. */
-                       pvr2_hdw_cpureset_assert(hdw,0);
+                       if (hdw->fw_cpu_flag) {
+                               /* Now release the CPU.  It will disconnect
+                                  and reconnect later. */
+                               pvr2_hdw_cpureset_assert(hdw,0);
+                       }
                        break;
                }
 
-               pvr2_trace(PVR2_TRACE_FIRMWARE,
-                          "Preparing to suck out CPU firmware");
-               hdw->fw_size = 0x2000;
-               hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
-               if (!hdw->fw_buffer) {
-                       hdw->fw_size = 0;
-                       break;
-               }
+               hdw->fw_cpu_flag = (prom_flag == 0);
+               if (hdw->fw_cpu_flag) {
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Preparing to suck out CPU firmware");
+                       hdw->fw_size = 0x2000;
+                       hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
+                       if (!hdw->fw_buffer) {
+                               hdw->fw_size = 0;
+                               break;
+                       }
 
-               /* We have to hold the CPU during firmware upload. */
-               pvr2_hdw_cpureset_assert(hdw,1);
+                       /* We have to hold the CPU during firmware upload. */
+                       pvr2_hdw_cpureset_assert(hdw,1);
 
-               /* download the firmware from address 0000-1fff in 2048
-                  (=0x800) bytes chunk. */
+                       /* download the firmware from address 0000-1fff in 2048
+                          (=0x800) bytes chunk. */
 
-               pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
-               pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
-               for(address = 0; address < hdw->fw_size; address += 0x800) {
-                       ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
-                                             address,0,
-                                             hdw->fw_buffer+address,0x800,HZ);
-                       if (ret < 0) break;
-               }
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Grabbing CPU firmware");
+                       pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+                       for(address = 0; address < hdw->fw_size;
+                           address += 0x800) {
+                               ret = usb_control_msg(hdw->usb_dev,pipe,
+                                                     0xa0,0xc0,
+                                                     address,0,
+                                                     hdw->fw_buffer+address,
+                                                     0x800,HZ);
+                               if (ret < 0) break;
+                       }
 
-               pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Done grabbing CPU firmware");
+               } else {
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Sucking down EEPROM contents");
+                       hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw);
+                       if (!hdw->fw_buffer) {
+                               pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                          "EEPROM content suck failed.");
+                               break;
+                       }
+                       hdw->fw_size = EEPROM_SIZE;
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Done sucking down EEPROM contents");
+               }
 
        } while (0); LOCK_GIVE(hdw->big_lock);
 }
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h 
b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 4dba8d0..e2f9d5e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -197,11 +197,13 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
 unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
 
 
-/* Enable / disable retrieval of CPU firmware.  This must be enabled before
-   pvr2_hdw_cpufw_get() will function.  Note that doing this may prevent
-   the device from running (and leaving this mode may imply a device
-   reset). */
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+/* Enable / disable retrieval of CPU firmware or prom contents.  This must
+   be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
+   this may prevent the device from running (and leaving this mode may
+   imply a device reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *,
+                               int prom_flag,
+                               int enable_flag);
 
 /* Return true if we're in a mode for retrieval CPU firmware */
 int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to