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>
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index bf6ff2b..f82f50d 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -599,37 +599,6 @@
 	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;
@@ -639,10 +608,6 @@
 	if (ret)
 		goto error;
 
-	ret = af9015_download_ir_table(d);
-	if (ret)
-		goto error;
-
 error:
 	return ret;
 }
@@ -739,8 +704,6 @@
 	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,
@@ -753,57 +716,40 @@
 }
 
 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) },
 	{ }
 };
 
@@ -841,11 +787,8 @@
 			} 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);
@@ -854,8 +797,6 @@
 	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;
 	}
 }
 
@@ -1065,34 +1006,66 @@
 
 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));
-
-	ret = af9015_ctrl_msg(d, &req);
+	/* read registers needed to detect remote controller code */
+	ret = af9015_read_reg(d, 0x98df, &repeat);
 	if (ret)
-		return ret;
+		goto error;
 
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
+	ret = af9015_read_reg(d, 0x98e7, &ircode[3]);
+	if (ret)
+		goto error;
 
-	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;
-		}
+	ret = af9015_read_reg(d, 0x98e8, &ircode[4]);
+	if (ret)
+		goto error;
+
+	if (ircode[3] || ircode[4]) {
+		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 */
@@ -1329,6 +1302,7 @@
 };
 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,
@@ -1381,7 +1355,7 @@
 
 		.rc.legacy = {
 			.rc_query         = af9015_rc_query,
-			.rc_interval      = 150,
+			.rc_interval      = AF9015_RC_INTERVAL,
 		},
 
 		.i2c_algo = &af9015_i2c_algo,
@@ -1500,7 +1474,7 @@
 
 		.rc.legacy = {
 			.rc_query         = af9015_rc_query,
-			.rc_interval      = 150,
+			.rc_interval      = AF9015_RC_INTERVAL,
 		},
 
 		.i2c_algo = &af9015_i2c_algo,
@@ -1609,7 +1583,7 @@
 
 		.rc.legacy = {
 			.rc_query         = af9015_rc_query,
-			.rc_interval      = 150,
+			.rc_interval      = AF9015_RC_INTERVAL,
 		},
 
 		.i2c_algo = &af9015_i2c_algo,