]> err.no Git - linux-2.6/commitdiff
V4L/DVB (6208): pvrusb2: Implement programmatic means to extract prom contents
authorMike Isely <isely@pobox.com>
Sun, 9 Sep 2007 01:16:27 +0000 (22:16 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 10 Oct 2007 01:14:34 +0000 (22:14 -0300)
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 <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/pvrusb2/pvrusb2-debugifc.c
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h

index e9da9bb8f8dea1f8901b1428c48b2cc1ce95c8cc..6f135f4a2497d89d55d760d6f6f812cc87a5253f 100644 (file)
@@ -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;
index ce66ab8ff2d8eec0a5de487bc6cf68956a3c121a..985d9ae7f5ee1c11486ba7ff6cfeb4303a920b95 100644 (file)
@@ -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;
index 5d9045268cf56a47417884d849a559a04f03de9a..7172f66a6a2870f87f869a07b3706ea81d0ead3f 100644 (file)
@@ -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);
 }
index 4dba8d0063244fbb85128a13a170841ed91c46b1..e2f9d5e4cb653c191f1a07ed94bf14a5799d3a4f 100644 (file)
@@ -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 *);