18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FireDTV driver (formerly known as FireSAT) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci#include <linux/input.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "firedtv.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* fixed table with older keycodes, geared towards MythTV */ 198c2ecf20Sopenharmony_cistatic const u16 oldtable[] = { 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* code from device: 0x4501...0x451f */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci KEY_ESC, 248c2ecf20Sopenharmony_ci KEY_F9, 258c2ecf20Sopenharmony_ci KEY_1, 268c2ecf20Sopenharmony_ci KEY_2, 278c2ecf20Sopenharmony_ci KEY_3, 288c2ecf20Sopenharmony_ci KEY_4, 298c2ecf20Sopenharmony_ci KEY_5, 308c2ecf20Sopenharmony_ci KEY_6, 318c2ecf20Sopenharmony_ci KEY_7, 328c2ecf20Sopenharmony_ci KEY_8, 338c2ecf20Sopenharmony_ci KEY_9, 348c2ecf20Sopenharmony_ci KEY_I, 358c2ecf20Sopenharmony_ci KEY_0, 368c2ecf20Sopenharmony_ci KEY_ENTER, 378c2ecf20Sopenharmony_ci KEY_RED, 388c2ecf20Sopenharmony_ci KEY_UP, 398c2ecf20Sopenharmony_ci KEY_GREEN, 408c2ecf20Sopenharmony_ci KEY_F10, 418c2ecf20Sopenharmony_ci KEY_SPACE, 428c2ecf20Sopenharmony_ci KEY_F11, 438c2ecf20Sopenharmony_ci KEY_YELLOW, 448c2ecf20Sopenharmony_ci KEY_DOWN, 458c2ecf20Sopenharmony_ci KEY_BLUE, 468c2ecf20Sopenharmony_ci KEY_Z, 478c2ecf20Sopenharmony_ci KEY_P, 488c2ecf20Sopenharmony_ci KEY_PAGEDOWN, 498c2ecf20Sopenharmony_ci KEY_LEFT, 508c2ecf20Sopenharmony_ci KEY_W, 518c2ecf20Sopenharmony_ci KEY_RIGHT, 528c2ecf20Sopenharmony_ci KEY_P, 538c2ecf20Sopenharmony_ci KEY_M, 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* code from device: 0x4540...0x4542 */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci KEY_R, 588c2ecf20Sopenharmony_ci KEY_V, 598c2ecf20Sopenharmony_ci KEY_C, 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* user-modifiable table for a remote as sold in 2008 */ 638c2ecf20Sopenharmony_cistatic const u16 keytable[] = { 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* code from device: 0x0300...0x031f */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci [0x00] = KEY_POWER, 688c2ecf20Sopenharmony_ci [0x01] = KEY_SLEEP, 698c2ecf20Sopenharmony_ci [0x02] = KEY_STOP, 708c2ecf20Sopenharmony_ci [0x03] = KEY_OK, 718c2ecf20Sopenharmony_ci [0x04] = KEY_RIGHT, 728c2ecf20Sopenharmony_ci [0x05] = KEY_1, 738c2ecf20Sopenharmony_ci [0x06] = KEY_2, 748c2ecf20Sopenharmony_ci [0x07] = KEY_3, 758c2ecf20Sopenharmony_ci [0x08] = KEY_LEFT, 768c2ecf20Sopenharmony_ci [0x09] = KEY_4, 778c2ecf20Sopenharmony_ci [0x0a] = KEY_5, 788c2ecf20Sopenharmony_ci [0x0b] = KEY_6, 798c2ecf20Sopenharmony_ci [0x0c] = KEY_UP, 808c2ecf20Sopenharmony_ci [0x0d] = KEY_7, 818c2ecf20Sopenharmony_ci [0x0e] = KEY_8, 828c2ecf20Sopenharmony_ci [0x0f] = KEY_9, 838c2ecf20Sopenharmony_ci [0x10] = KEY_DOWN, 848c2ecf20Sopenharmony_ci [0x11] = KEY_TITLE, /* "OSD" - fixme */ 858c2ecf20Sopenharmony_ci [0x12] = KEY_0, 868c2ecf20Sopenharmony_ci [0x13] = KEY_F20, /* "16:9" - fixme */ 878c2ecf20Sopenharmony_ci [0x14] = KEY_SCREEN, /* "FULL" - fixme */ 888c2ecf20Sopenharmony_ci [0x15] = KEY_MUTE, 898c2ecf20Sopenharmony_ci [0x16] = KEY_SUBTITLE, 908c2ecf20Sopenharmony_ci [0x17] = KEY_RECORD, 918c2ecf20Sopenharmony_ci [0x18] = KEY_TEXT, 928c2ecf20Sopenharmony_ci [0x19] = KEY_AUDIO, 938c2ecf20Sopenharmony_ci [0x1a] = KEY_RED, 948c2ecf20Sopenharmony_ci [0x1b] = KEY_PREVIOUS, 958c2ecf20Sopenharmony_ci [0x1c] = KEY_REWIND, 968c2ecf20Sopenharmony_ci [0x1d] = KEY_PLAYPAUSE, 978c2ecf20Sopenharmony_ci [0x1e] = KEY_NEXT, 988c2ecf20Sopenharmony_ci [0x1f] = KEY_VOLUMEUP, 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* code from device: 0x0340...0x0354 */ 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci [0x20] = KEY_CHANNELUP, 1038c2ecf20Sopenharmony_ci [0x21] = KEY_F21, /* "4:3" - fixme */ 1048c2ecf20Sopenharmony_ci [0x22] = KEY_TV, 1058c2ecf20Sopenharmony_ci [0x23] = KEY_DVD, 1068c2ecf20Sopenharmony_ci [0x24] = KEY_VCR, 1078c2ecf20Sopenharmony_ci [0x25] = KEY_AUX, 1088c2ecf20Sopenharmony_ci [0x26] = KEY_GREEN, 1098c2ecf20Sopenharmony_ci [0x27] = KEY_YELLOW, 1108c2ecf20Sopenharmony_ci [0x28] = KEY_BLUE, 1118c2ecf20Sopenharmony_ci [0x29] = KEY_CHANNEL, /* "CH.LIST" */ 1128c2ecf20Sopenharmony_ci [0x2a] = KEY_VENDOR, /* "CI" - fixme */ 1138c2ecf20Sopenharmony_ci [0x2b] = KEY_VOLUMEDOWN, 1148c2ecf20Sopenharmony_ci [0x2c] = KEY_CHANNELDOWN, 1158c2ecf20Sopenharmony_ci [0x2d] = KEY_LAST, 1168c2ecf20Sopenharmony_ci [0x2e] = KEY_INFO, 1178c2ecf20Sopenharmony_ci [0x2f] = KEY_FORWARD, 1188c2ecf20Sopenharmony_ci [0x30] = KEY_LIST, 1198c2ecf20Sopenharmony_ci [0x31] = KEY_FAVORITES, 1208c2ecf20Sopenharmony_ci [0x32] = KEY_MENU, 1218c2ecf20Sopenharmony_ci [0x33] = KEY_EPG, 1228c2ecf20Sopenharmony_ci [0x34] = KEY_EXIT, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciint fdtv_register_rc(struct firedtv *fdtv, struct device *dev) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct input_dev *idev; 1288c2ecf20Sopenharmony_ci int i, err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci idev = input_allocate_device(); 1318c2ecf20Sopenharmony_ci if (!idev) 1328c2ecf20Sopenharmony_ci return -ENOMEM; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci fdtv->remote_ctrl_dev = idev; 1358c2ecf20Sopenharmony_ci idev->name = "FireDTV remote control"; 1368c2ecf20Sopenharmony_ci idev->dev.parent = dev; 1378c2ecf20Sopenharmony_ci idev->evbit[0] = BIT_MASK(EV_KEY); 1388c2ecf20Sopenharmony_ci idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); 1398c2ecf20Sopenharmony_ci if (!idev->keycode) { 1408c2ecf20Sopenharmony_ci err = -ENOMEM; 1418c2ecf20Sopenharmony_ci goto fail; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci idev->keycodesize = sizeof(keytable[0]); 1448c2ecf20Sopenharmony_ci idev->keycodemax = ARRAY_SIZE(keytable); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(keytable); i++) 1478c2ecf20Sopenharmony_ci set_bit(keytable[i], idev->keybit); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci err = input_register_device(idev); 1508c2ecf20Sopenharmony_ci if (err) 1518c2ecf20Sopenharmony_ci goto fail_free_keymap; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cifail_free_keymap: 1568c2ecf20Sopenharmony_ci kfree(idev->keycode); 1578c2ecf20Sopenharmony_cifail: 1588c2ecf20Sopenharmony_ci input_free_device(idev); 1598c2ecf20Sopenharmony_ci return err; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_civoid fdtv_unregister_rc(struct firedtv *fdtv) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci cancel_work_sync(&fdtv->remote_ctrl_work); 1658c2ecf20Sopenharmony_ci kfree(fdtv->remote_ctrl_dev->keycode); 1668c2ecf20Sopenharmony_ci input_unregister_device(fdtv->remote_ctrl_dev); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_civoid fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct input_dev *idev = fdtv->remote_ctrl_dev; 1728c2ecf20Sopenharmony_ci u16 *keycode = idev->keycode; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (code >= 0x0300 && code <= 0x031f) 1758c2ecf20Sopenharmony_ci code = keycode[code - 0x0300]; 1768c2ecf20Sopenharmony_ci else if (code >= 0x0340 && code <= 0x0354) 1778c2ecf20Sopenharmony_ci code = keycode[code - 0x0320]; 1788c2ecf20Sopenharmony_ci else if (code >= 0x4501 && code <= 0x451f) 1798c2ecf20Sopenharmony_ci code = oldtable[code - 0x4501]; 1808c2ecf20Sopenharmony_ci else if (code >= 0x4540 && code <= 0x4542) 1818c2ecf20Sopenharmony_ci code = oldtable[code - 0x4521]; 1828c2ecf20Sopenharmony_ci else { 1838c2ecf20Sopenharmony_ci dev_dbg(fdtv->device, 1848c2ecf20Sopenharmony_ci "invalid key code 0x%04x from remote control\n", 1858c2ecf20Sopenharmony_ci code); 1868c2ecf20Sopenharmony_ci return; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci input_report_key(idev, code, 1); 1908c2ecf20Sopenharmony_ci input_sync(idev); 1918c2ecf20Sopenharmony_ci input_report_key(idev, code, 0); 1928c2ecf20Sopenharmony_ci input_sync(idev); 1938c2ecf20Sopenharmony_ci} 194