^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* DVB USB compliant Linux driver for the Afatech 9005
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * USB1.1 DVB-T receiver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Standard remote decode function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Thanks to Afatech who kindly provided information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "af9005.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /* debug */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) static int dvb_usb_af9005_remote_debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) MODULE_PARM_DESC(debug,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) "enable (1) or disable (0) debug messages."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) DVB_USB_DEBUG_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct rc_map_table rc_map_af9005_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {0x01b7, KEY_POWER},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {0x01a7, KEY_VOLUMEUP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {0x0187, KEY_CHANNELUP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {0x017f, KEY_MUTE},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {0x01bf, KEY_VOLUMEDOWN},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {0x013f, KEY_CHANNELDOWN},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {0x01df, KEY_1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {0x015f, KEY_2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {0x019f, KEY_3},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {0x011f, KEY_4},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {0x01ef, KEY_5},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {0x016f, KEY_6},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {0x01af, KEY_7},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {0x0127, KEY_8},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {0x0107, KEY_9},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {0x01cf, KEY_ZOOM},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {0x014f, KEY_0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {0x018f, KEY_GOTO}, /* marked jump on the remote */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {0x00bd, KEY_POWER},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {0x007d, KEY_VOLUMEUP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {0x00fd, KEY_CHANNELUP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {0x009d, KEY_MUTE},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {0x005d, KEY_VOLUMEDOWN},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {0x00dd, KEY_CHANNELDOWN},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {0x00ad, KEY_1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {0x006d, KEY_2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {0x00ed, KEY_3},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {0x008d, KEY_4},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {0x004d, KEY_5},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {0x00cd, KEY_6},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {0x00b5, KEY_7},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {0x0075, KEY_8},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {0x00f5, KEY_9},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {0x0095, KEY_ZOOM},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {0x0055, KEY_0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {0x00d5, KEY_GOTO}, /* marked jump on the remote */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int repeatable_keys[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) KEY_VOLUMEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) KEY_VOLUMEDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) KEY_CHANNELUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) KEY_CHANNELDOWN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u16 mark, space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u8 cust, dat, invdat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (len >= 6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mark = (u16) (data[0] << 8) + data[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) space = (u16) (data[2] << 8) + data[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (space * 3 < mark) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (d->last_event == repeatable_keys[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) *state = REMOTE_KEY_REPEAT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *event = d->last_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) deb_decode("repeat key, event %x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) *event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) deb_decode("repeated key ignored (non repeatable)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) } else if (len >= 33 * 4) { /*32 bits + start code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) for (i = 4; i < 4 + 32 * 4; i += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) result <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) mark = (u16) (data[i] << 8) + data[i + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) mark >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) space = (u16) (data[i + 2] << 8) + data[i + 3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) space >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (mark * 2 > space)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) result += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) deb_decode("key pressed, raw value %x\n", result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if ((result & 0xff000000) != 0xfe000000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) deb_decode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ("doesn't start with 0xfe, ignored\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) cust = (result >> 16) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) dat = (result >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) invdat = (~result) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (dat != invdat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) deb_decode("code != inverted code\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) for (i = 0; i < rc_map_af9005_table_size; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (rc5_custom(&rc_map_af9005_table[i]) == cust
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) && rc5_data(&rc_map_af9005_table[i]) == dat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) *event = rc_map_af9005_table[i].keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *state = REMOTE_KEY_PRESSED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) deb_decode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ("key pressed, event %x\n", *event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) deb_decode("not found in table\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) EXPORT_SYMBOL(rc_map_af9005_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) EXPORT_SYMBOL(rc_map_af9005_table_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) EXPORT_SYMBOL(af9005_rc_decode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) MODULE_DESCRIPTION
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) MODULE_VERSION("1.0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) MODULE_LICENSE("GPL");