aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pvrusb2/pvrusb2-hdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-hdw.c')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c150
1 files changed, 125 insertions, 25 deletions
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}