18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* dvb-usb-remote.c is part of the DVB USB library. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de) 58c2ecf20Sopenharmony_ci * see dvb-usb-init.c for copyright information. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file contains functions for initializing the input-device and for handling remote-control-queries. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include "dvb-usb-common.h" 108c2ecf20Sopenharmony_ci#include <linux/usb/input.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic unsigned int 138c2ecf20Sopenharmony_cilegacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, 148c2ecf20Sopenharmony_ci struct rc_map_table *keymap, 158c2ecf20Sopenharmony_ci unsigned int keymap_size) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci unsigned int index; 188c2ecf20Sopenharmony_ci unsigned int scancode; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci if (ke->flags & INPUT_KEYMAP_BY_INDEX) { 218c2ecf20Sopenharmony_ci index = ke->index; 228c2ecf20Sopenharmony_ci } else { 238c2ecf20Sopenharmony_ci if (input_scancode_to_scalar(ke, &scancode)) 248c2ecf20Sopenharmony_ci return keymap_size; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci /* See if we can match the raw key code. */ 278c2ecf20Sopenharmony_ci for (index = 0; index < keymap_size; index++) 288c2ecf20Sopenharmony_ci if (keymap[index].scancode == scancode) 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* See if there is an unused hole in the map */ 328c2ecf20Sopenharmony_ci if (index >= keymap_size) { 338c2ecf20Sopenharmony_ci for (index = 0; index < keymap_size; index++) { 348c2ecf20Sopenharmony_ci if (keymap[index].keycode == KEY_RESERVED || 358c2ecf20Sopenharmony_ci keymap[index].keycode == KEY_UNKNOWN) { 368c2ecf20Sopenharmony_ci break; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return index; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int legacy_dvb_usb_getkeycode(struct input_dev *dev, 468c2ecf20Sopenharmony_ci struct input_keymap_entry *ke) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct dvb_usb_device *d = input_get_drvdata(dev); 498c2ecf20Sopenharmony_ci struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; 508c2ecf20Sopenharmony_ci unsigned int keymap_size = d->props.rc.legacy.rc_map_size; 518c2ecf20Sopenharmony_ci unsigned int index; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); 548c2ecf20Sopenharmony_ci if (index >= keymap_size) 558c2ecf20Sopenharmony_ci return -EINVAL; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ke->keycode = keymap[index].keycode; 588c2ecf20Sopenharmony_ci if (ke->keycode == KEY_UNKNOWN) 598c2ecf20Sopenharmony_ci ke->keycode = KEY_RESERVED; 608c2ecf20Sopenharmony_ci ke->len = sizeof(keymap[index].scancode); 618c2ecf20Sopenharmony_ci memcpy(&ke->scancode, &keymap[index].scancode, ke->len); 628c2ecf20Sopenharmony_ci ke->index = index; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int legacy_dvb_usb_setkeycode(struct input_dev *dev, 688c2ecf20Sopenharmony_ci const struct input_keymap_entry *ke, 698c2ecf20Sopenharmony_ci unsigned int *old_keycode) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct dvb_usb_device *d = input_get_drvdata(dev); 728c2ecf20Sopenharmony_ci struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; 738c2ecf20Sopenharmony_ci unsigned int keymap_size = d->props.rc.legacy.rc_map_size; 748c2ecf20Sopenharmony_ci unsigned int index; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * FIXME: Currently, it is not possible to increase the size of 798c2ecf20Sopenharmony_ci * scancode table. For it to happen, one possibility 808c2ecf20Sopenharmony_ci * would be to allocate a table with key_map_size + 1, 818c2ecf20Sopenharmony_ci * copying data, appending the new key on it, and freeing 828c2ecf20Sopenharmony_ci * the old one - or maybe just allocating some spare space 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci if (index >= keymap_size) 858c2ecf20Sopenharmony_ci return -EINVAL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci *old_keycode = keymap[index].keycode; 888c2ecf20Sopenharmony_ci keymap->keycode = ke->keycode; 898c2ecf20Sopenharmony_ci __set_bit(ke->keycode, dev->keybit); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (*old_keycode != KEY_RESERVED) { 928c2ecf20Sopenharmony_ci __clear_bit(*old_keycode, dev->keybit); 938c2ecf20Sopenharmony_ci for (index = 0; index < keymap_size; index++) { 948c2ecf20Sopenharmony_ci if (keymap[index].keycode == *old_keycode) { 958c2ecf20Sopenharmony_ci __set_bit(*old_keycode, dev->keybit); 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Remote-control poll function - called every dib->rc_query_interval ms to see 1058c2ecf20Sopenharmony_ci * whether the remote control has received anything. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * TODO: Fix the repeat rate of the input device. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic void legacy_dvb_usb_read_remote_control(struct work_struct *work) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct dvb_usb_device *d = 1128c2ecf20Sopenharmony_ci container_of(work, struct dvb_usb_device, rc_query_work.work); 1138c2ecf20Sopenharmony_ci u32 event; 1148c2ecf20Sopenharmony_ci int state; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* TODO: need a lock here. We can simply skip checking for the remote control 1178c2ecf20Sopenharmony_ci if we're busy. */ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* when the parameter has been set to 1 via sysfs while the driver was running */ 1208c2ecf20Sopenharmony_ci if (dvb_usb_disable_rc_polling) 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (d->props.rc.legacy.rc_query(d,&event,&state)) { 1248c2ecf20Sopenharmony_ci err("error while querying for an remote control event."); 1258c2ecf20Sopenharmony_ci goto schedule; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci switch (state) { 1308c2ecf20Sopenharmony_ci case REMOTE_NO_KEY_PRESSED: 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci case REMOTE_KEY_PRESSED: 1338c2ecf20Sopenharmony_ci deb_rc("key pressed\n"); 1348c2ecf20Sopenharmony_ci d->last_event = event; 1358c2ecf20Sopenharmony_ci input_event(d->input_dev, EV_KEY, event, 1); 1368c2ecf20Sopenharmony_ci input_sync(d->input_dev); 1378c2ecf20Sopenharmony_ci input_event(d->input_dev, EV_KEY, d->last_event, 0); 1388c2ecf20Sopenharmony_ci input_sync(d->input_dev); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case REMOTE_KEY_REPEAT: 1418c2ecf20Sopenharmony_ci deb_rc("key repeated\n"); 1428c2ecf20Sopenharmony_ci input_event(d->input_dev, EV_KEY, event, 1); 1438c2ecf20Sopenharmony_ci input_sync(d->input_dev); 1448c2ecf20Sopenharmony_ci input_event(d->input_dev, EV_KEY, d->last_event, 0); 1458c2ecf20Sopenharmony_ci input_sync(d->input_dev); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci default: 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* improved repeat handling ??? 1528c2ecf20Sopenharmony_ci switch (state) { 1538c2ecf20Sopenharmony_ci case REMOTE_NO_KEY_PRESSED: 1548c2ecf20Sopenharmony_ci deb_rc("NO KEY PRESSED\n"); 1558c2ecf20Sopenharmony_ci if (d->last_state != REMOTE_NO_KEY_PRESSED) { 1568c2ecf20Sopenharmony_ci deb_rc("releasing event %d\n",d->last_event); 1578c2ecf20Sopenharmony_ci input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); 1588c2ecf20Sopenharmony_ci input_sync(d->rc_input_dev); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci d->last_state = REMOTE_NO_KEY_PRESSED; 1618c2ecf20Sopenharmony_ci d->last_event = 0; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case REMOTE_KEY_PRESSED: 1648c2ecf20Sopenharmony_ci deb_rc("KEY PRESSED\n"); 1658c2ecf20Sopenharmony_ci deb_rc("pressing event %d\n",event); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci input_event(d->rc_input_dev, EV_KEY, event, 1); 1688c2ecf20Sopenharmony_ci input_sync(d->rc_input_dev); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci d->last_event = event; 1718c2ecf20Sopenharmony_ci d->last_state = REMOTE_KEY_PRESSED; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case REMOTE_KEY_REPEAT: 1748c2ecf20Sopenharmony_ci deb_rc("KEY_REPEAT\n"); 1758c2ecf20Sopenharmony_ci if (d->last_state != REMOTE_NO_KEY_PRESSED) { 1768c2ecf20Sopenharmony_ci deb_rc("repeating event %d\n",d->last_event); 1778c2ecf20Sopenharmony_ci input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); 1788c2ecf20Sopenharmony_ci input_sync(d->rc_input_dev); 1798c2ecf20Sopenharmony_ci d->last_state = REMOTE_KEY_REPEAT; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci default: 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci*/ 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cischedule: 1878c2ecf20Sopenharmony_ci schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci int i, err, rc_interval; 1938c2ecf20Sopenharmony_ci struct input_dev *input_dev; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 1968c2ecf20Sopenharmony_ci if (!input_dev) 1978c2ecf20Sopenharmony_ci return -ENOMEM; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY); 2008c2ecf20Sopenharmony_ci input_dev->name = "IR-receiver inside an USB DVB receiver"; 2018c2ecf20Sopenharmony_ci input_dev->phys = d->rc_phys; 2028c2ecf20Sopenharmony_ci usb_to_input_id(d->udev, &input_dev->id); 2038c2ecf20Sopenharmony_ci input_dev->dev.parent = &d->udev->dev; 2048c2ecf20Sopenharmony_ci d->input_dev = input_dev; 2058c2ecf20Sopenharmony_ci d->rc_dev = NULL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci input_dev->getkeycode = legacy_dvb_usb_getkeycode; 2088c2ecf20Sopenharmony_ci input_dev->setkeycode = legacy_dvb_usb_setkeycode; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* set the bits for the keys */ 2118c2ecf20Sopenharmony_ci deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); 2128c2ecf20Sopenharmony_ci for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { 2138c2ecf20Sopenharmony_ci deb_rc("setting bit for event %d item %d\n", 2148c2ecf20Sopenharmony_ci d->props.rc.legacy.rc_map_table[i].keycode, i); 2158c2ecf20Sopenharmony_ci set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* setting these two values to non-zero, we have to manage key repeats */ 2198c2ecf20Sopenharmony_ci input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; 2208c2ecf20Sopenharmony_ci input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci input_set_drvdata(input_dev, d); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci err = input_register_device(input_dev); 2258c2ecf20Sopenharmony_ci if (err) 2268c2ecf20Sopenharmony_ci input_free_device(input_dev); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci rc_interval = d->props.rc.legacy.rc_interval; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci info("schedule remote query interval to %d msecs.", rc_interval); 2338c2ecf20Sopenharmony_ci schedule_delayed_work(&d->rc_query_work, 2348c2ecf20Sopenharmony_ci msecs_to_jiffies(rc_interval)); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci d->state |= DVB_USB_STATE_REMOTE; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return err; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* Remote-control poll function - called every dib->rc_query_interval ms to see 2428c2ecf20Sopenharmony_ci * whether the remote control has received anything. 2438c2ecf20Sopenharmony_ci * 2448c2ecf20Sopenharmony_ci * TODO: Fix the repeat rate of the input device. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cistatic void dvb_usb_read_remote_control(struct work_struct *work) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct dvb_usb_device *d = 2498c2ecf20Sopenharmony_ci container_of(work, struct dvb_usb_device, rc_query_work.work); 2508c2ecf20Sopenharmony_ci int err; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* TODO: need a lock here. We can simply skip checking for the remote control 2538c2ecf20Sopenharmony_ci if we're busy. */ 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* when the parameter has been set to 1 via sysfs while the 2568c2ecf20Sopenharmony_ci * driver was running, or when bulk mode is enabled after IR init 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci err = d->props.rc.core.rc_query(d); 2628c2ecf20Sopenharmony_ci if (err) 2638c2ecf20Sopenharmony_ci err("error %d while querying for an remote control event.", err); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci schedule_delayed_work(&d->rc_query_work, 2668c2ecf20Sopenharmony_ci msecs_to_jiffies(d->props.rc.core.rc_interval)); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int err, rc_interval; 2728c2ecf20Sopenharmony_ci struct rc_dev *dev; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci dev = rc_allocate_device(d->props.rc.core.driver_type); 2758c2ecf20Sopenharmony_ci if (!dev) 2768c2ecf20Sopenharmony_ci return -ENOMEM; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dev->driver_name = d->props.rc.core.module_name; 2798c2ecf20Sopenharmony_ci dev->map_name = d->props.rc.core.rc_codes; 2808c2ecf20Sopenharmony_ci dev->change_protocol = d->props.rc.core.change_protocol; 2818c2ecf20Sopenharmony_ci dev->allowed_protocols = d->props.rc.core.allowed_protos; 2828c2ecf20Sopenharmony_ci usb_to_input_id(d->udev, &dev->input_id); 2838c2ecf20Sopenharmony_ci dev->device_name = d->desc->name; 2848c2ecf20Sopenharmony_ci dev->input_phys = d->rc_phys; 2858c2ecf20Sopenharmony_ci dev->dev.parent = &d->udev->dev; 2868c2ecf20Sopenharmony_ci dev->priv = d; 2878c2ecf20Sopenharmony_ci dev->scancode_mask = d->props.rc.core.scancode_mask; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci err = rc_register_device(dev); 2908c2ecf20Sopenharmony_ci if (err < 0) { 2918c2ecf20Sopenharmony_ci rc_free_device(dev); 2928c2ecf20Sopenharmony_ci return err; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci d->input_dev = NULL; 2968c2ecf20Sopenharmony_ci d->rc_dev = dev; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Polling mode - initialize a work queue for handling it */ 3028c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci rc_interval = d->props.rc.core.rc_interval; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci info("schedule remote query interval to %d msecs.", rc_interval); 3078c2ecf20Sopenharmony_ci schedule_delayed_work(&d->rc_query_work, 3088c2ecf20Sopenharmony_ci msecs_to_jiffies(rc_interval)); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ciint dvb_usb_remote_init(struct dvb_usb_device *d) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci int err; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (dvb_usb_disable_rc_polling) 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) 3218c2ecf20Sopenharmony_ci d->props.rc.mode = DVB_RC_LEGACY; 3228c2ecf20Sopenharmony_ci else if (d->props.rc.core.rc_codes) 3238c2ecf20Sopenharmony_ci d->props.rc.mode = DVB_RC_CORE; 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); 3288c2ecf20Sopenharmony_ci strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Start the remote-control polling. */ 3318c2ecf20Sopenharmony_ci if (d->props.rc.legacy.rc_interval < 40) 3328c2ecf20Sopenharmony_ci d->props.rc.legacy.rc_interval = 100; /* default */ 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (d->props.rc.mode == DVB_RC_LEGACY) 3358c2ecf20Sopenharmony_ci err = legacy_dvb_usb_remote_init(d); 3368c2ecf20Sopenharmony_ci else 3378c2ecf20Sopenharmony_ci err = rc_core_dvb_usb_remote_init(d); 3388c2ecf20Sopenharmony_ci if (err) 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci d->state |= DVB_USB_STATE_REMOTE; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ciint dvb_usb_remote_exit(struct dvb_usb_device *d) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci if (d->state & DVB_USB_STATE_REMOTE) { 3498c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&d->rc_query_work); 3508c2ecf20Sopenharmony_ci if (d->props.rc.mode == DVB_RC_LEGACY) 3518c2ecf20Sopenharmony_ci input_unregister_device(d->input_dev); 3528c2ecf20Sopenharmony_ci else 3538c2ecf20Sopenharmony_ci rc_unregister_device(d->rc_dev); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci d->state &= ~DVB_USB_STATE_REMOTE; 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci#define DVB_USB_RC_NEC_EMPTY 0x00 3608c2ecf20Sopenharmony_ci#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 3618c2ecf20Sopenharmony_ci#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 3628c2ecf20Sopenharmony_ciint dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, 3638c2ecf20Sopenharmony_ci u8 keybuf[5], u32 *event, int *state) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int i; 3668c2ecf20Sopenharmony_ci struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; 3678c2ecf20Sopenharmony_ci *event = 0; 3688c2ecf20Sopenharmony_ci *state = REMOTE_NO_KEY_PRESSED; 3698c2ecf20Sopenharmony_ci switch (keybuf[0]) { 3708c2ecf20Sopenharmony_ci case DVB_USB_RC_NEC_EMPTY: 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case DVB_USB_RC_NEC_KEY_PRESSED: 3738c2ecf20Sopenharmony_ci if ((u8) ~keybuf[1] != keybuf[2] || 3748c2ecf20Sopenharmony_ci (u8) ~keybuf[3] != keybuf[4]) { 3758c2ecf20Sopenharmony_ci deb_err("remote control checksum failed.\n"); 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci /* See if we can match the raw key code. */ 3798c2ecf20Sopenharmony_ci for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) 3808c2ecf20Sopenharmony_ci if (rc5_custom(&keymap[i]) == keybuf[1] && 3818c2ecf20Sopenharmony_ci rc5_data(&keymap[i]) == keybuf[3]) { 3828c2ecf20Sopenharmony_ci *event = keymap[i].keycode; 3838c2ecf20Sopenharmony_ci *state = REMOTE_KEY_PRESSED; 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci deb_err("key mapping failed - no appropriate key found in keymapping\n"); 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case DVB_USB_RC_NEC_KEY_REPEATED: 3898c2ecf20Sopenharmony_ci *state = REMOTE_KEY_REPEAT; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci default: 3928c2ecf20Sopenharmony_ci deb_err("unknown type of remote status: %d\n",keybuf[0]); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event); 398