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