Skip to content

Commit

Permalink
V4L/DVB: af9015: reimplement remote controller
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Antti Palosaari authored and Mauro Carvalho Chehab committed Oct 21, 2010
1 parent 2ec01b4 commit d3bb73d
Show file tree
Hide file tree
Showing 2 changed files with 466 additions and 870 deletions.
194 changes: 84 additions & 110 deletions drivers/media/dvb/dvb-usb/af9015.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,37 +599,6 @@ static int af9015_eeprom_hash(struct usb_device *udev)
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)
{
int ret;
Expand All @@ -639,10 +608,6 @@ static int af9015_init(struct dvb_usb_device *d)
if (ret)
goto error;

ret = af9015_download_ir_table(d);
if (ret)
goto error;

error:
return ret;
}
Expand Down Expand Up @@ -739,8 +704,6 @@ struct af9015_setup {
unsigned int id;
struct ir_scancode *rc_key_map;
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,
Expand All @@ -753,57 +716,40 @@ static const struct af9015_setup *af9015_setup_match(unsigned int id,
}

static const struct af9015_setup af9015_setup_modparam[] = {
{ AF9015_REMOTE_A_LINK_DTU_M,
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) },
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
{ AF9015_REMOTE_MYGICTV_U718,
ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
{ AF9015_REMOTE_DIGITTRADE_DVB_T,
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) },
{ AF9015_REMOTE_A_LINK_DTU_M, af9015_rc_a_link,
ARRAY_SIZE(af9015_rc_a_link) },
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, af9015_rc_msi,
ARRAY_SIZE(af9015_rc_msi) },
{ AF9015_REMOTE_MYGICTV_U718, af9015_rc_mygictv,
ARRAY_SIZE(af9015_rc_mygictv) },
{ AF9015_REMOTE_DIGITTRADE_DVB_T, af9015_rc_digittrade,
ARRAY_SIZE(af9015_rc_digittrade) },
{ AF9015_REMOTE_AVERMEDIA_KS, af9015_rc_avermedia_ks,
ARRAY_SIZE(af9015_rc_avermedia_ks) },
{ }
};

/* don't add new entries here anymore, use hashes instead */
static const struct af9015_setup af9015_setup_usbids[] = {
{ USB_VID_LEADTEK,
ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
{ USB_VID_VISIONPLUS,
ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
{ USB_VID_KWORLD_2, /* TODO: use correct rc keys */
ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
{ USB_VID_AVERMEDIA,
ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
{ 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) },
{ USB_VID_LEADTEK, af9015_rc_leadtek,
ARRAY_SIZE(af9015_rc_leadtek) },
{ USB_VID_VISIONPLUS, af9015_rc_twinhan,
ARRAY_SIZE(af9015_rc_twinhan) },
{ USB_VID_KWORLD_2, af9015_rc_kworld,
ARRAY_SIZE(af9015_rc_kworld) },
{ USB_VID_AVERMEDIA, af9015_rc_avermedia,
ARRAY_SIZE(af9015_rc_avermedia) },
{ USB_VID_MSI_2, af9015_rc_msi_digivox_iii,
ARRAY_SIZE(af9015_rc_msi_digivox_iii) },
{ USB_VID_TERRATEC, af9015_rc_terratec,
ARRAY_SIZE(af9015_rc_terratec) },
{ }
};

static const struct af9015_setup af9015_setup_hashes[] = {
{ 0xb8feb708,
ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
{ 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) },
{ 0xb8feb708, af9015_rc_msi, ARRAY_SIZE(af9015_rc_msi) },
{ 0xa3703d00, af9015_rc_a_link, ARRAY_SIZE(af9015_rc_a_link) },
{ 0x9b7dc64e, af9015_rc_mygictv, ARRAY_SIZE(af9015_rc_mygictv) },
{ }
};

Expand Down Expand Up @@ -841,11 +787,8 @@ static void af9015_set_remote_config(struct usb_device *udev,
} else if (udev->descriptor.idProduct ==
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
table = &(const struct af9015_setup){ 0,
ir_codes_af9015_table_trekstor,
ARRAY_SIZE(ir_codes_af9015_table_trekstor),
af9015_ir_table_trekstor,
ARRAY_SIZE(af9015_ir_table_trekstor)
};
af9015_rc_trekstor,
ARRAY_SIZE(af9015_rc_trekstor) };
}
} else if (!table)
table = af9015_setup_match(vendor, af9015_setup_usbids);
Expand All @@ -854,8 +797,6 @@ static void af9015_set_remote_config(struct usb_device *udev,
if (table) {
props->rc.legacy.rc_key_map = table->rc_key_map;
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;
}
}

Expand Down Expand Up @@ -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)
{
u8 buf[8];
struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
int i, ret;
struct af9015_state *priv = d->priv;
int ret;
u8 ircode[5], repeat;

memset(buf, 0, sizeof(buf));
/* read registers needed to detect remote controller code */
ret = af9015_read_reg(d, 0x98df, &repeat);
if (ret)
goto error;

ret = af9015_ctrl_msg(d, &req);
ret = af9015_read_reg(d, 0x98e7, &ircode[3]);
if (ret)
return ret;
goto error;

ret = af9015_read_reg(d, 0x98e8, &ircode[4]);
if (ret)
goto error;

*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
if (ircode[3] || ircode[4]) {
deb_rc("%s: key pressed\n", __func__);
ircode[0] = 1; /* DVB_USB_RC_NEC_KEY_PRESSED */

for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
rc5_data(&keymap[i]) == buf[2]) {
*event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
break;
}
/* 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 */
Expand Down Expand Up @@ -1329,6 +1302,7 @@ static struct usb_device_id af9015_usb_table[] = {
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);

#define AF9015_RC_INTERVAL 500
static struct dvb_usb_device_properties af9015_properties[] = {
{
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
Expand Down Expand Up @@ -1381,7 +1355,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {

.rc.legacy = {
.rc_query = af9015_rc_query,
.rc_interval = 150,
.rc_interval = AF9015_RC_INTERVAL,
},

.i2c_algo = &af9015_i2c_algo,
Expand Down Expand Up @@ -1500,7 +1474,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {

.rc.legacy = {
.rc_query = af9015_rc_query,
.rc_interval = 150,
.rc_interval = AF9015_RC_INTERVAL,
},

.i2c_algo = &af9015_i2c_algo,
Expand Down Expand Up @@ -1609,7 +1583,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {

.rc.legacy = {
.rc_query = af9015_rc_query,
.rc_interval = 150,
.rc_interval = AF9015_RC_INTERVAL,
},

.i2c_algo = &af9015_i2c_algo,
Expand Down
Loading

0 comments on commit d3bb73d

Please sign in to comment.