diff options
author | Mike Isely <isely@pobox.com> | 2007-09-08 21:16:27 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-09 21:14:34 -0400 |
commit | 4db666cc3d199a8b837174bb0ad00d6b8f6115d6 (patch) | |
tree | fbc661aca967d62f814ea2e3667fefc3fd386cea /drivers/media/video/pvrusb2 | |
parent | 401c27ce96382b3bdbc7a9c7e7303fd1b3af9ef0 (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/video/pvrusb2')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-debugifc.c | 16 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 1 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.c | 150 | ||||
-rw-r--r-- | 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 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 | ||
2608 | void 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__) | ||
2612 | static 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 | |||
2684 | void 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, | |||
197 | unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); | 197 | unsigned 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). */ |
204 | void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag); | 204 | void 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 */ |
207 | int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); | 209 | int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); |