mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 00:52:01 +00:00
V4L/DVB (11158): pvrusb2: New device attribute mechanism to specify sub-devices
Set up new mechanism for declaring and loading appropriate sub-devices when driver initializes. This is another part of the v4l2-subdev adoption. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
acd92d40cc
commit
e9c64a78db
@ -33,6 +33,31 @@
|
||||
*/
|
||||
|
||||
|
||||
#define PVR2_CLIENT_ID_MSP3400 1
|
||||
#define PVR2_CLIENT_ID_CX25840 2
|
||||
#define PVR2_CLIENT_ID_SAA7115 3
|
||||
#define PVR2_CLIENT_ID_TUNER 4
|
||||
#define PVR2_CLIENT_ID_CS53132A 5
|
||||
|
||||
struct pvr2_device_client_desc {
|
||||
/* One ovr PVR2_CLIENT_ID_xxxx */
|
||||
unsigned char module_id;
|
||||
|
||||
/* Null-terminated array of I2C addresses to try in order
|
||||
initialize the module. It's safe to make this null terminated
|
||||
since we're never going to encounter an i2c device with an
|
||||
address of zero. If this is a null pointer or zero-length,
|
||||
then no I2C addresses have been specified, in which case we'll
|
||||
try some compiled in defaults for now. */
|
||||
unsigned char *i2c_address_list;
|
||||
};
|
||||
|
||||
struct pvr2_device_client_table {
|
||||
const struct pvr2_device_client_desc *lst;
|
||||
unsigned char cnt;
|
||||
};
|
||||
|
||||
|
||||
struct pvr2_string_table {
|
||||
const char **lst;
|
||||
unsigned int cnt;
|
||||
@ -66,6 +91,9 @@ struct pvr2_device_desc {
|
||||
/* List of additional client modules we need to load */
|
||||
struct pvr2_string_table client_modules;
|
||||
|
||||
/* List of defined client modules we need to load */
|
||||
struct pvr2_device_client_table client_table;
|
||||
|
||||
/* List of FX2 firmware file names we should search; if empty then
|
||||
FX2 firmware check / load is skipped and we assume the device
|
||||
was initialized from internal ROM. */
|
||||
|
@ -105,6 +105,20 @@ MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
|
||||
/* size of a firmware chunk */
|
||||
#define FIRMWARE_CHUNK_SIZE 0x2000
|
||||
|
||||
static const char *module_names[] = {
|
||||
[PVR2_CLIENT_ID_MSP3400] = "msp3400",
|
||||
[PVR2_CLIENT_ID_CX25840] = "cx25840",
|
||||
[PVR2_CLIENT_ID_SAA7115] = "saa7115",
|
||||
[PVR2_CLIENT_ID_TUNER] = "tuner",
|
||||
[PVR2_CLIENT_ID_CS53132A] = "cs53132a",
|
||||
};
|
||||
|
||||
|
||||
static const unsigned char *module_i2c_addresses[] = {
|
||||
[PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
|
||||
};
|
||||
|
||||
|
||||
/* Define the list of additional controls we'll dynamically construct based
|
||||
on query of the cx2341x module. */
|
||||
struct pvr2_mpeg_ids {
|
||||
@ -1934,6 +1948,105 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
|
||||
}
|
||||
|
||||
|
||||
static unsigned int pvr2_copy_i2c_addr_list(
|
||||
unsigned short *dst, const unsigned char *src,
|
||||
unsigned int dst_max)
|
||||
{
|
||||
unsigned int cnt;
|
||||
if (!src) return 0;
|
||||
while (src[cnt] && (cnt + 1) < dst_max) {
|
||||
dst[cnt] = src[cnt];
|
||||
cnt++;
|
||||
}
|
||||
dst[cnt] = I2C_CLIENT_END;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
static void pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
|
||||
const struct pvr2_device_client_desc *cd)
|
||||
{
|
||||
const char *fname;
|
||||
unsigned char mid;
|
||||
struct v4l2_subdev *sd;
|
||||
unsigned int i2ccnt;
|
||||
const unsigned char *p;
|
||||
/* Arbitrary count - max # i2c addresses we will probe */
|
||||
unsigned short i2caddr[25];
|
||||
|
||||
mid = cd->module_id;
|
||||
fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL;
|
||||
if (!fname) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
"Module ID %u for device %s is unknown"
|
||||
" (this is probably a bad thing...)",
|
||||
mid,
|
||||
hdw->hdw_desc->description);
|
||||
return;
|
||||
}
|
||||
|
||||
i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list,
|
||||
ARRAY_SIZE(i2caddr));
|
||||
if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ?
|
||||
module_i2c_addresses[mid] : NULL) != NULL)) {
|
||||
/* Second chance: Try default i2c address list */
|
||||
i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p,
|
||||
ARRAY_SIZE(i2caddr));
|
||||
}
|
||||
|
||||
if (!i2ccnt) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
"Module ID %u for device %s:"
|
||||
" No i2c addresses"
|
||||
" (this is probably a bad thing...)",
|
||||
mid, hdw->hdw_desc->description);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note how the 2nd and 3rd arguments are the same for both
|
||||
* v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev(). Why?
|
||||
* Well the 2nd argument is the module name to load, while the 3rd
|
||||
* argument is documented in the framework as being the "chipid" -
|
||||
* and every other place where I can find examples of this, the
|
||||
* "chipid" appears to just be the module name again. So here we
|
||||
* just do the same thing. */
|
||||
if (i2ccnt == 1) {
|
||||
sd = v4l2_i2c_new_subdev(&hdw->i2c_adap,
|
||||
fname, fname,
|
||||
i2caddr[0]);
|
||||
} else {
|
||||
sd = v4l2_i2c_new_probed_subdev(&hdw->i2c_adap,
|
||||
fname, fname,
|
||||
i2caddr);
|
||||
}
|
||||
|
||||
// ?????
|
||||
/* Based on module ID, we should remember subdev pointers
|
||||
so that we can send certain custom commands where
|
||||
needed. */
|
||||
// ?????
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw)
|
||||
{
|
||||
unsigned int idx;
|
||||
const struct pvr2_string_table *cm;
|
||||
const struct pvr2_device_client_table *ct;
|
||||
|
||||
cm = &hdw->hdw_desc->client_modules;
|
||||
for (idx = 0; idx < cm->cnt; idx++) {
|
||||
request_module(cm->lst[idx]);
|
||||
}
|
||||
|
||||
ct = &hdw->hdw_desc->client_table;
|
||||
for (idx = 0; idx < ct->cnt; idx++) {
|
||||
pvr2_hdw_load_subdev(hdw,&ct->lst[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
|
||||
{
|
||||
int ret;
|
||||
@ -1973,10 +2086,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
|
||||
|
||||
if (!pvr2_hdw_dev_ok(hdw)) return;
|
||||
|
||||
for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
|
||||
request_module(hdw->hdw_desc->client_modules.lst[idx]);
|
||||
}
|
||||
|
||||
if (!hdw->hdw_desc->flag_no_powerup) {
|
||||
pvr2_hdw_cmd_powerup(hdw);
|
||||
if (!pvr2_hdw_dev_ok(hdw)) return;
|
||||
@ -1995,6 +2104,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
|
||||
pvr2_i2c_core_init(hdw);
|
||||
if (!pvr2_hdw_dev_ok(hdw)) return;
|
||||
|
||||
pvr2_hdw_load_modules(hdw);
|
||||
|
||||
for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
|
||||
cptr = hdw->controls + idx;
|
||||
if (cptr->info->skip_init) continue;
|
||||
|
@ -608,6 +608,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
|
||||
hdw->i2c_adap.algo = &hdw->i2c_algo;
|
||||
hdw->i2c_adap.algo_data = hdw;
|
||||
hdw->i2c_linked = !0;
|
||||
i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
|
||||
i2c_add_adapter(&hdw->i2c_adap);
|
||||
if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
|
||||
/* Probe for a different type of IR receiver on this
|
||||
|
Loading…
Reference in New Issue
Block a user