mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-03 19:24:02 +08:00
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>
This commit is contained in:
parent
401c27ce96
commit
4db666cc3d
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,38 +2697,60 @@ 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);
|
||||
|
||||
/* 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,
|
||||
"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");
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
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");
|
||||
|
||||
} while (0); LOCK_GIVE(hdw->big_lock);
|
||||
}
|
||||
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user