V4L/DVB: af9015: reimplement remote controller
Remove HID and polling via firmware API. Implement direct access to remote codes via memory read and write. HID and polling via firmware api never worked 100% well and there was also some limitations which tied used remote and device together. After that it is possible to use upcoming kernel remote controller core. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
2ec01b41e3
commit
d3bb73de97
|
@ -599,37 +599,6 @@ free:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int af9015_download_ir_table(struct dvb_usb_device *d)
|
|
||||||
{
|
|
||||||
int i, packets = 0, ret;
|
|
||||||
u16 addr = 0x9a56; /* ir-table start address */
|
|
||||||
struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
|
|
||||||
u8 *data = NULL;
|
|
||||||
deb_info("%s:\n", __func__);
|
|
||||||
|
|
||||||
data = af9015_config.ir_table;
|
|
||||||
packets = af9015_config.ir_table_size;
|
|
||||||
|
|
||||||
/* no remote */
|
|
||||||
if (!packets)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
/* load remote ir-table */
|
|
||||||
for (i = 0; i < packets; i++) {
|
|
||||||
req.addr = addr + i;
|
|
||||||
req.data = &data[i];
|
|
||||||
ret = af9015_ctrl_msg(d, &req);
|
|
||||||
if (ret) {
|
|
||||||
err("ir-table download failed at packet %d with " \
|
|
||||||
"code %d", i, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int af9015_init(struct dvb_usb_device *d)
|
static int af9015_init(struct dvb_usb_device *d)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -639,10 +608,6 @@ static int af9015_init(struct dvb_usb_device *d)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ret = af9015_download_ir_table(d);
|
|
||||||
if (ret)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -739,8 +704,6 @@ struct af9015_setup {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
struct ir_scancode *rc_key_map;
|
struct ir_scancode *rc_key_map;
|
||||||
unsigned int rc_key_map_size;
|
unsigned int rc_key_map_size;
|
||||||
u8 *ir_table;
|
|
||||||
unsigned int ir_table_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct af9015_setup *af9015_setup_match(unsigned int id,
|
static const struct af9015_setup *af9015_setup_match(unsigned int id,
|
||||||
|
@ -753,57 +716,40 @@ static const struct af9015_setup *af9015_setup_match(unsigned int id,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct af9015_setup af9015_setup_modparam[] = {
|
static const struct af9015_setup af9015_setup_modparam[] = {
|
||||||
{ AF9015_REMOTE_A_LINK_DTU_M,
|
{ AF9015_REMOTE_A_LINK_DTU_M, af9015_rc_a_link,
|
||||||
ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
|
ARRAY_SIZE(af9015_rc_a_link) },
|
||||||
af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
|
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, af9015_rc_msi,
|
||||||
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
|
ARRAY_SIZE(af9015_rc_msi) },
|
||||||
ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
|
{ AF9015_REMOTE_MYGICTV_U718, af9015_rc_mygictv,
|
||||||
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
|
ARRAY_SIZE(af9015_rc_mygictv) },
|
||||||
{ AF9015_REMOTE_MYGICTV_U718,
|
{ AF9015_REMOTE_DIGITTRADE_DVB_T, af9015_rc_digittrade,
|
||||||
ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
|
ARRAY_SIZE(af9015_rc_digittrade) },
|
||||||
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
|
{ AF9015_REMOTE_AVERMEDIA_KS, af9015_rc_avermedia_ks,
|
||||||
{ AF9015_REMOTE_DIGITTRADE_DVB_T,
|
ARRAY_SIZE(af9015_rc_avermedia_ks) },
|
||||||
ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
|
|
||||||
af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
|
|
||||||
{ AF9015_REMOTE_AVERMEDIA_KS,
|
|
||||||
ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
|
|
||||||
af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* don't add new entries here anymore, use hashes instead */
|
/* don't add new entries here anymore, use hashes instead */
|
||||||
static const struct af9015_setup af9015_setup_usbids[] = {
|
static const struct af9015_setup af9015_setup_usbids[] = {
|
||||||
{ USB_VID_LEADTEK,
|
{ USB_VID_LEADTEK, af9015_rc_leadtek,
|
||||||
ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
|
ARRAY_SIZE(af9015_rc_leadtek) },
|
||||||
af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
|
{ USB_VID_VISIONPLUS, af9015_rc_twinhan,
|
||||||
{ USB_VID_VISIONPLUS,
|
ARRAY_SIZE(af9015_rc_twinhan) },
|
||||||
ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
|
{ USB_VID_KWORLD_2, af9015_rc_kworld,
|
||||||
af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
|
ARRAY_SIZE(af9015_rc_kworld) },
|
||||||
{ USB_VID_KWORLD_2, /* TODO: use correct rc keys */
|
{ USB_VID_AVERMEDIA, af9015_rc_avermedia,
|
||||||
ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
|
ARRAY_SIZE(af9015_rc_avermedia) },
|
||||||
af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
|
{ USB_VID_MSI_2, af9015_rc_msi_digivox_iii,
|
||||||
{ USB_VID_AVERMEDIA,
|
ARRAY_SIZE(af9015_rc_msi_digivox_iii) },
|
||||||
ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
|
{ USB_VID_TERRATEC, af9015_rc_terratec,
|
||||||
af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
|
ARRAY_SIZE(af9015_rc_terratec) },
|
||||||
{ USB_VID_MSI_2,
|
|
||||||
ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
|
|
||||||
af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
|
|
||||||
{ USB_VID_TERRATEC,
|
|
||||||
ir_codes_terratec, ARRAY_SIZE(ir_codes_terratec),
|
|
||||||
af9015_ir_terratec, ARRAY_SIZE(af9015_ir_terratec) },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct af9015_setup af9015_setup_hashes[] = {
|
static const struct af9015_setup af9015_setup_hashes[] = {
|
||||||
{ 0xb8feb708,
|
{ 0xb8feb708, af9015_rc_msi, ARRAY_SIZE(af9015_rc_msi) },
|
||||||
ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
|
{ 0xa3703d00, af9015_rc_a_link, ARRAY_SIZE(af9015_rc_a_link) },
|
||||||
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
|
{ 0x9b7dc64e, af9015_rc_mygictv, ARRAY_SIZE(af9015_rc_mygictv) },
|
||||||
{ 0xa3703d00,
|
|
||||||
ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
|
|
||||||
af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
|
|
||||||
{ 0x9b7dc64e,
|
|
||||||
ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
|
|
||||||
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -841,11 +787,8 @@ static void af9015_set_remote_config(struct usb_device *udev,
|
||||||
} else if (udev->descriptor.idProduct ==
|
} else if (udev->descriptor.idProduct ==
|
||||||
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
|
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
|
||||||
table = &(const struct af9015_setup){ 0,
|
table = &(const struct af9015_setup){ 0,
|
||||||
ir_codes_af9015_table_trekstor,
|
af9015_rc_trekstor,
|
||||||
ARRAY_SIZE(ir_codes_af9015_table_trekstor),
|
ARRAY_SIZE(af9015_rc_trekstor) };
|
||||||
af9015_ir_table_trekstor,
|
|
||||||
ARRAY_SIZE(af9015_ir_table_trekstor)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
} else if (!table)
|
} else if (!table)
|
||||||
table = af9015_setup_match(vendor, af9015_setup_usbids);
|
table = af9015_setup_match(vendor, af9015_setup_usbids);
|
||||||
|
@ -854,8 +797,6 @@ static void af9015_set_remote_config(struct usb_device *udev,
|
||||||
if (table) {
|
if (table) {
|
||||||
props->rc.legacy.rc_key_map = table->rc_key_map;
|
props->rc.legacy.rc_key_map = table->rc_key_map;
|
||||||
props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
|
props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
|
||||||
af9015_config.ir_table = table->ir_table;
|
|
||||||
af9015_config.ir_table_size = table->ir_table_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,34 +1006,66 @@ static int af9015_identify_state(struct usb_device *udev,
|
||||||
|
|
||||||
static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||||
{
|
{
|
||||||
u8 buf[8];
|
struct af9015_state *priv = d->priv;
|
||||||
struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
|
int ret;
|
||||||
struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
|
u8 ircode[5], repeat;
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
/* read registers needed to detect remote controller code */
|
||||||
|
ret = af9015_read_reg(d, 0x98df, &repeat);
|
||||||
ret = af9015_ctrl_msg(d, &req);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto error;
|
||||||
|
|
||||||
*event = 0;
|
ret = af9015_read_reg(d, 0x98e7, &ircode[3]);
|
||||||
*state = REMOTE_NO_KEY_PRESSED;
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
|
ret = af9015_read_reg(d, 0x98e8, &ircode[4]);
|
||||||
if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
|
if (ret)
|
||||||
rc5_data(&keymap[i]) == buf[2]) {
|
goto error;
|
||||||
*event = keymap[i].keycode;
|
|
||||||
*state = REMOTE_KEY_PRESSED;
|
if (ircode[3] || ircode[4]) {
|
||||||
break;
|
deb_rc("%s: key pressed\n", __func__);
|
||||||
}
|
ircode[0] = 1; /* DVB_USB_RC_NEC_KEY_PRESSED */
|
||||||
|
|
||||||
|
/* read 1st address byte */
|
||||||
|
ret = af9015_read_reg(d, 0x98e5, &ircode[1]);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* clean data bytes from mem */
|
||||||
|
ret = af9015_write_reg(d, 0x98e7, 0);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ret = af9015_write_reg(d, 0x98e8, 0);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* FIXME: Hack to pass checksum on the custom field for the
|
||||||
|
remote controllers using NEC extended address.
|
||||||
|
That must done since dvb_usb_nec_rc_key_to_event()
|
||||||
|
does not support NEC extended address format. */
|
||||||
|
ircode[2] = ~ircode[1];
|
||||||
|
} else if (priv->rc_repeat != repeat) {
|
||||||
|
deb_rc("%s: key repeated\n", __func__);
|
||||||
|
ircode[0] = 2; /* DVB_USB_RC_NEC_KEY_REPEATED */
|
||||||
|
} else {
|
||||||
|
deb_rc("%s: no key press\n", __func__);
|
||||||
|
ircode[0] = 0; /* DVB_USB_RC_NEC_EMPTY */
|
||||||
}
|
}
|
||||||
if (!buf[1])
|
|
||||||
deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
||||||
__func__, buf[0], buf[1], buf[2], buf[3], buf[4],
|
|
||||||
buf[5], buf[6], buf[7]);
|
|
||||||
|
|
||||||
return 0;
|
priv->rc_repeat = repeat;
|
||||||
|
|
||||||
|
deb_rc("%s: ", __func__);
|
||||||
|
debug_dump(ircode, sizeof(ircode), deb_rc);
|
||||||
|
|
||||||
|
dvb_usb_nec_rc_key_to_event(d, ircode, event, state);
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (ret)
|
||||||
|
err("%s: failed:%d", __func__, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init 2nd I2C adapter */
|
/* init 2nd I2C adapter */
|
||||||
|
@ -1329,6 +1302,7 @@ static struct usb_device_id af9015_usb_table[] = {
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
|
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
|
||||||
|
|
||||||
|
#define AF9015_RC_INTERVAL 500
|
||||||
static struct dvb_usb_device_properties af9015_properties[] = {
|
static struct dvb_usb_device_properties af9015_properties[] = {
|
||||||
{
|
{
|
||||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||||
|
@ -1381,7 +1355,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
||||||
|
|
||||||
.rc.legacy = {
|
.rc.legacy = {
|
||||||
.rc_query = af9015_rc_query,
|
.rc_query = af9015_rc_query,
|
||||||
.rc_interval = 150,
|
.rc_interval = AF9015_RC_INTERVAL,
|
||||||
},
|
},
|
||||||
|
|
||||||
.i2c_algo = &af9015_i2c_algo,
|
.i2c_algo = &af9015_i2c_algo,
|
||||||
|
@ -1500,7 +1474,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
||||||
|
|
||||||
.rc.legacy = {
|
.rc.legacy = {
|
||||||
.rc_query = af9015_rc_query,
|
.rc_query = af9015_rc_query,
|
||||||
.rc_interval = 150,
|
.rc_interval = AF9015_RC_INTERVAL,
|
||||||
},
|
},
|
||||||
|
|
||||||
.i2c_algo = &af9015_i2c_algo,
|
.i2c_algo = &af9015_i2c_algo,
|
||||||
|
@ -1609,7 +1583,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
||||||
|
|
||||||
.rc.legacy = {
|
.rc.legacy = {
|
||||||
.rc_query = af9015_rc_query,
|
.rc_query = af9015_rc_query,
|
||||||
.rc_interval = 150,
|
.rc_interval = AF9015_RC_INTERVAL,
|
||||||
},
|
},
|
||||||
|
|
||||||
.i2c_algo = &af9015_i2c_algo,
|
.i2c_algo = &af9015_i2c_algo,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue