18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* DVB USB compliant Linux driver for the Afatech 9005
38c2ecf20Sopenharmony_ci * USB1.1 DVB-T receiver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Standard remote decode function
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Thanks to Afatech who kindly provided information.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include "af9005.h"
148c2ecf20Sopenharmony_ci/* debug */
158c2ecf20Sopenharmony_cistatic int dvb_usb_af9005_remote_debug;
168c2ecf20Sopenharmony_cimodule_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
178c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug,
188c2ecf20Sopenharmony_ci		 "enable (1) or disable (0) debug messages."
198c2ecf20Sopenharmony_ci		 DVB_USB_DEBUG_STATUS);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct rc_map_table rc_map_af9005_table[] = {
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	{0x01b7, KEY_POWER},
268c2ecf20Sopenharmony_ci	{0x01a7, KEY_VOLUMEUP},
278c2ecf20Sopenharmony_ci	{0x0187, KEY_CHANNELUP},
288c2ecf20Sopenharmony_ci	{0x017f, KEY_MUTE},
298c2ecf20Sopenharmony_ci	{0x01bf, KEY_VOLUMEDOWN},
308c2ecf20Sopenharmony_ci	{0x013f, KEY_CHANNELDOWN},
318c2ecf20Sopenharmony_ci	{0x01df, KEY_1},
328c2ecf20Sopenharmony_ci	{0x015f, KEY_2},
338c2ecf20Sopenharmony_ci	{0x019f, KEY_3},
348c2ecf20Sopenharmony_ci	{0x011f, KEY_4},
358c2ecf20Sopenharmony_ci	{0x01ef, KEY_5},
368c2ecf20Sopenharmony_ci	{0x016f, KEY_6},
378c2ecf20Sopenharmony_ci	{0x01af, KEY_7},
388c2ecf20Sopenharmony_ci	{0x0127, KEY_8},
398c2ecf20Sopenharmony_ci	{0x0107, KEY_9},
408c2ecf20Sopenharmony_ci	{0x01cf, KEY_ZOOM},
418c2ecf20Sopenharmony_ci	{0x014f, KEY_0},
428c2ecf20Sopenharmony_ci	{0x018f, KEY_GOTO},	/* marked jump on the remote */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	{0x00bd, KEY_POWER},
458c2ecf20Sopenharmony_ci	{0x007d, KEY_VOLUMEUP},
468c2ecf20Sopenharmony_ci	{0x00fd, KEY_CHANNELUP},
478c2ecf20Sopenharmony_ci	{0x009d, KEY_MUTE},
488c2ecf20Sopenharmony_ci	{0x005d, KEY_VOLUMEDOWN},
498c2ecf20Sopenharmony_ci	{0x00dd, KEY_CHANNELDOWN},
508c2ecf20Sopenharmony_ci	{0x00ad, KEY_1},
518c2ecf20Sopenharmony_ci	{0x006d, KEY_2},
528c2ecf20Sopenharmony_ci	{0x00ed, KEY_3},
538c2ecf20Sopenharmony_ci	{0x008d, KEY_4},
548c2ecf20Sopenharmony_ci	{0x004d, KEY_5},
558c2ecf20Sopenharmony_ci	{0x00cd, KEY_6},
568c2ecf20Sopenharmony_ci	{0x00b5, KEY_7},
578c2ecf20Sopenharmony_ci	{0x0075, KEY_8},
588c2ecf20Sopenharmony_ci	{0x00f5, KEY_9},
598c2ecf20Sopenharmony_ci	{0x0095, KEY_ZOOM},
608c2ecf20Sopenharmony_ci	{0x0055, KEY_0},
618c2ecf20Sopenharmony_ci	{0x00d5, KEY_GOTO},	/* marked jump on the remote */
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciint rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic int repeatable_keys[] = {
678c2ecf20Sopenharmony_ci	KEY_VOLUMEUP,
688c2ecf20Sopenharmony_ci	KEY_VOLUMEDOWN,
698c2ecf20Sopenharmony_ci	KEY_CHANNELUP,
708c2ecf20Sopenharmony_ci	KEY_CHANNELDOWN
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ciint af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
748c2ecf20Sopenharmony_ci		     int *state)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	u16 mark, space;
778c2ecf20Sopenharmony_ci	u32 result;
788c2ecf20Sopenharmony_ci	u8 cust, dat, invdat;
798c2ecf20Sopenharmony_ci	int i;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (len >= 6) {
828c2ecf20Sopenharmony_ci		mark = (u16) (data[0] << 8) + data[1];
838c2ecf20Sopenharmony_ci		space = (u16) (data[2] << 8) + data[3];
848c2ecf20Sopenharmony_ci		if (space * 3 < mark) {
858c2ecf20Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
868c2ecf20Sopenharmony_ci				if (d->last_event == repeatable_keys[i]) {
878c2ecf20Sopenharmony_ci					*state = REMOTE_KEY_REPEAT;
888c2ecf20Sopenharmony_ci					*event = d->last_event;
898c2ecf20Sopenharmony_ci					deb_decode("repeat key, event %x\n",
908c2ecf20Sopenharmony_ci						   *event);
918c2ecf20Sopenharmony_ci					return 0;
928c2ecf20Sopenharmony_ci				}
938c2ecf20Sopenharmony_ci			}
948c2ecf20Sopenharmony_ci			deb_decode("repeated key ignored (non repeatable)\n");
958c2ecf20Sopenharmony_ci			return 0;
968c2ecf20Sopenharmony_ci		} else if (len >= 33 * 4) {	/*32 bits + start code */
978c2ecf20Sopenharmony_ci			result = 0;
988c2ecf20Sopenharmony_ci			for (i = 4; i < 4 + 32 * 4; i += 4) {
998c2ecf20Sopenharmony_ci				result <<= 1;
1008c2ecf20Sopenharmony_ci				mark = (u16) (data[i] << 8) + data[i + 1];
1018c2ecf20Sopenharmony_ci				mark >>= 1;
1028c2ecf20Sopenharmony_ci				space = (u16) (data[i + 2] << 8) + data[i + 3];
1038c2ecf20Sopenharmony_ci				space >>= 1;
1048c2ecf20Sopenharmony_ci				if (mark * 2 > space)
1058c2ecf20Sopenharmony_ci					result += 1;
1068c2ecf20Sopenharmony_ci			}
1078c2ecf20Sopenharmony_ci			deb_decode("key pressed, raw value %x\n", result);
1088c2ecf20Sopenharmony_ci			if ((result & 0xff000000) != 0xfe000000) {
1098c2ecf20Sopenharmony_ci				deb_decode
1108c2ecf20Sopenharmony_ci				    ("doesn't start with 0xfe, ignored\n");
1118c2ecf20Sopenharmony_ci				return 0;
1128c2ecf20Sopenharmony_ci			}
1138c2ecf20Sopenharmony_ci			cust = (result >> 16) & 0xff;
1148c2ecf20Sopenharmony_ci			dat = (result >> 8) & 0xff;
1158c2ecf20Sopenharmony_ci			invdat = (~result) & 0xff;
1168c2ecf20Sopenharmony_ci			if (dat != invdat) {
1178c2ecf20Sopenharmony_ci				deb_decode("code != inverted code\n");
1188c2ecf20Sopenharmony_ci				return 0;
1198c2ecf20Sopenharmony_ci			}
1208c2ecf20Sopenharmony_ci			for (i = 0; i < rc_map_af9005_table_size; i++) {
1218c2ecf20Sopenharmony_ci				if (rc5_custom(&rc_map_af9005_table[i]) == cust
1228c2ecf20Sopenharmony_ci				    && rc5_data(&rc_map_af9005_table[i]) == dat) {
1238c2ecf20Sopenharmony_ci					*event = rc_map_af9005_table[i].keycode;
1248c2ecf20Sopenharmony_ci					*state = REMOTE_KEY_PRESSED;
1258c2ecf20Sopenharmony_ci					deb_decode
1268c2ecf20Sopenharmony_ci					    ("key pressed, event %x\n", *event);
1278c2ecf20Sopenharmony_ci					return 0;
1288c2ecf20Sopenharmony_ci				}
1298c2ecf20Sopenharmony_ci			}
1308c2ecf20Sopenharmony_ci			deb_decode("not found in table\n");
1318c2ecf20Sopenharmony_ci		}
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rc_map_af9005_table);
1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rc_map_af9005_table_size);
1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(af9005_rc_decode);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
1418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION
1428c2ecf20Sopenharmony_ci    ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
1438c2ecf20Sopenharmony_ciMODULE_VERSION("1.0");
1448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
145