aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2007-09-08 21:16:27 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:14:34 -0400
commit4db666cc3d199a8b837174bb0ad00d6b8f6115d6 (patch)
treefbc661aca967d62f814ea2e3667fefc3fd386cea /drivers/media
parent401c27ce96382b3bdbc7a9c7e7303fd1b3af9ef0 (diff)
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 <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c150
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h12
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 e9da9bb8f8de..6f135f4a2497 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,
397 count -= scnt; buf += scnt; 397 count -= scnt; buf += scnt;
398 if (!wptr) return -EINVAL; 398 if (!wptr) return -EINVAL;
399 if (debugifc_match_keyword(wptr,wlen,"fetch")) { 399 if (debugifc_match_keyword(wptr,wlen,"fetch")) {
400 pvr2_hdw_cpufw_set_enabled(hdw,!0); 400 scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
401 if (scnt && wptr) {
402 count -= scnt; buf += scnt;
403 if (debugifc_match_keyword(wptr,wlen,"prom")) {
404 pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
405 } else if (debugifc_match_keyword(wptr,wlen,
406 "ram")) {
407 pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
408 } else {
409 return -EINVAL;
410 }
411 }
412 pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
401 return 0; 413 return 0;
402 } else if (debugifc_match_keyword(wptr,wlen,"done")) { 414 } else if (debugifc_match_keyword(wptr,wlen,"done")) {
403 pvr2_hdw_cpufw_set_enabled(hdw,0); 415 pvr2_hdw_cpufw_set_enabled(hdw,0,0);
404 return 0; 416 return 0;
405 } else { 417 } else {
406 return -EINVAL; 418 return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index ce66ab8ff2d8..985d9ae7f5ee 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 {
238 // CPU firmware info (used to help find / save firmware data) 238 // CPU firmware info (used to help find / save firmware data)
239 char *fw_buffer; 239 char *fw_buffer;
240 unsigned int fw_size; 240 unsigned int fw_size;
241 int fw_cpu_flag; /* True if we are dealing with the CPU */
241 242
242 // Which subsystem pieces have been enabled / configured 243 // Which subsystem pieces have been enabled / configured
243 unsigned long subsys_enabled_mask; 244 unsigned long subsys_enabled_mask;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 5d9045268cf5..7172f66a6a28 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)
2605 } while (0); LOCK_GIVE(hdw->big_lock); 2605 } while (0); LOCK_GIVE(hdw->big_lock);
2606} 2606}
2607 2607
2608void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) 2608
2609/* Grab EEPROM contents, needed for direct method. */
2610#define EEPROM_SIZE 8192
2611#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
2612static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw)
2613{
2614 struct i2c_msg msg[2];
2615 u8 *eeprom;
2616 u8 iadd[2];
2617 u8 addr;
2618 u16 eepromSize;
2619 unsigned int offs;
2620 int ret;
2621 int mode16 = 0;
2622 unsigned pcnt,tcnt;
2623 eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
2624 if (!eeprom) {
2625 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
2626 "Failed to allocate memory"
2627 " required to read eeprom");
2628 return NULL;
2629 }
2630
2631 trace_eeprom("Value for eeprom addr from controller was 0x%x",
2632 hdw->eeprom_addr);
2633 addr = hdw->eeprom_addr;
2634 /* Seems that if the high bit is set, then the *real* eeprom
2635 address is shifted right now bit position (noticed this in
2636 newer PVR USB2 hardware) */
2637 if (addr & 0x80) addr >>= 1;
2638
2639 /* FX2 documentation states that a 16bit-addressed eeprom is
2640 expected if the I2C address is an odd number (yeah, this is
2641 strange but it's what they do) */
2642 mode16 = (addr & 1);
2643 eepromSize = (mode16 ? EEPROM_SIZE : 256);
2644 trace_eeprom("Examining %d byte eeprom at location 0x%x"
2645 " using %d bit addressing",eepromSize,addr,
2646 mode16 ? 16 : 8);
2647
2648 msg[0].addr = addr;
2649 msg[0].flags = 0;
2650 msg[0].len = mode16 ? 2 : 1;
2651 msg[0].buf = iadd;
2652 msg[1].addr = addr;
2653 msg[1].flags = I2C_M_RD;
2654
2655 /* We have to do the actual eeprom data fetch ourselves, because
2656 (1) we're only fetching part of the eeprom, and (2) if we were
2657 getting the whole thing our I2C driver can't grab it in one
2658 pass - which is what tveeprom is otherwise going to attempt */
2659 memset(eeprom,0,EEPROM_SIZE);
2660 for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
2661 pcnt = 16;
2662 if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
2663 offs = tcnt + (eepromSize - EEPROM_SIZE);
2664 if (mode16) {
2665 iadd[0] = offs >> 8;
2666 iadd[1] = offs;
2667 } else {
2668 iadd[0] = offs;
2669 }
2670 msg[1].len = pcnt;
2671 msg[1].buf = eeprom+tcnt;
2672 if ((ret = i2c_transfer(&hdw->i2c_adap,
2673 msg,ARRAY_SIZE(msg))) != 2) {
2674 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
2675 "eeprom fetch set offs err=%d",ret);
2676 kfree(eeprom);
2677 return NULL;
2678 }
2679 }
2680 return eeprom;
2681}
2682
2683
2684void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
2685 int prom_flag,
2686 int enable_flag)
2609{ 2687{
2610 int ret; 2688 int ret;
2611 u16 address; 2689 u16 address;
@@ -2619,37 +2697,59 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
2619 kfree(hdw->fw_buffer); 2697 kfree(hdw->fw_buffer);
2620 hdw->fw_buffer = NULL; 2698 hdw->fw_buffer = NULL;
2621 hdw->fw_size = 0; 2699 hdw->fw_size = 0;
2622 /* Now release the CPU. It will disconnect and 2700 if (hdw->fw_cpu_flag) {
2623 reconnect later. */ 2701 /* Now release the CPU. It will disconnect
2624 pvr2_hdw_cpureset_assert(hdw,0); 2702 and reconnect later. */
2703 pvr2_hdw_cpureset_assert(hdw,0);
2704 }
2625 break; 2705 break;
2626 } 2706 }
2627 2707
2628 pvr2_trace(PVR2_TRACE_FIRMWARE, 2708 hdw->fw_cpu_flag = (prom_flag == 0);
2629 "Preparing to suck out CPU firmware"); 2709 if (hdw->fw_cpu_flag) {
2630 hdw->fw_size = 0x2000; 2710 pvr2_trace(PVR2_TRACE_FIRMWARE,
2631 hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); 2711 "Preparing to suck out CPU firmware");
2632 if (!hdw->fw_buffer) { 2712 hdw->fw_size = 0x2000;
2633 hdw->fw_size = 0; 2713 hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
2634 break; 2714 if (!hdw->fw_buffer) {
2635 } 2715 hdw->fw_size = 0;
2716 break;
2717 }
2636 2718
2637 /* We have to hold the CPU during firmware upload. */ 2719 /* We have to hold the CPU during firmware upload. */
2638 pvr2_hdw_cpureset_assert(hdw,1); 2720 pvr2_hdw_cpureset_assert(hdw,1);
2639 2721
2640 /* download the firmware from address 0000-1fff in 2048 2722 /* download the firmware from address 0000-1fff in 2048
2641 (=0x800) bytes chunk. */ 2723 (=0x800) bytes chunk. */
2642 2724
2643 pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware"); 2725 pvr2_trace(PVR2_TRACE_FIRMWARE,
2644 pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); 2726 "Grabbing CPU firmware");
2645 for(address = 0; address < hdw->fw_size; address += 0x800) { 2727 pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
2646 ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0, 2728 for(address = 0; address < hdw->fw_size;
2647 address,0, 2729 address += 0x800) {
2648 hdw->fw_buffer+address,0x800,HZ); 2730 ret = usb_control_msg(hdw->usb_dev,pipe,
2649 if (ret < 0) break; 2731 0xa0,0xc0,
2650 } 2732 address,0,
2733 hdw->fw_buffer+address,
2734 0x800,HZ);
2735 if (ret < 0) break;
2736 }
2651 2737
2652 pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware"); 2738 pvr2_trace(PVR2_TRACE_FIRMWARE,
2739 "Done grabbing CPU firmware");
2740 } else {
2741 pvr2_trace(PVR2_TRACE_FIRMWARE,
2742 "Sucking down EEPROM contents");
2743 hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw);
2744 if (!hdw->fw_buffer) {
2745 pvr2_trace(PVR2_TRACE_FIRMWARE,
2746 "EEPROM content suck failed.");
2747 break;
2748 }
2749 hdw->fw_size = EEPROM_SIZE;
2750 pvr2_trace(PVR2_TRACE_FIRMWARE,
2751 "Done sucking down EEPROM contents");
2752 }
2653 2753
2654 } while (0); LOCK_GIVE(hdw->big_lock); 2754 } while (0); LOCK_GIVE(hdw->big_lock);
2655} 2755}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 4dba8d006324..e2f9d5e4cb65 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,
197unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); 197unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
198 198
199 199
200/* Enable / disable retrieval of CPU firmware. This must be enabled before 200/* Enable / disable retrieval of CPU firmware or prom contents. This must
201 pvr2_hdw_cpufw_get() will function. Note that doing this may prevent 201 be enabled before pvr2_hdw_cpufw_get() will function. Note that doing
202 the device from running (and leaving this mode may imply a device 202 this may prevent the device from running (and leaving this mode may
203 reset). */ 203 imply a device reset). */
204void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag); 204void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *,
205 int prom_flag,
206 int enable_flag);
205 207
206/* Return true if we're in a mode for retrieval CPU firmware */ 208/* Return true if we're in a mode for retrieval CPU firmware */
207int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); 209int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);