162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* dvb-usb-remote.c is part of the DVB USB library. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de) 562306a36Sopenharmony_ci * see dvb-usb-init.c for copyright information. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file contains functions for initializing the input-device and for handling remote-control-queries. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include "dvb-usb-common.h" 1062306a36Sopenharmony_ci#include <linux/usb/input.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic unsigned int 1362306a36Sopenharmony_cilegacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, 1462306a36Sopenharmony_ci struct rc_map_table *keymap, 1562306a36Sopenharmony_ci unsigned int keymap_size) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci unsigned int index; 1862306a36Sopenharmony_ci unsigned int scancode; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (ke->flags & INPUT_KEYMAP_BY_INDEX) { 2162306a36Sopenharmony_ci index = ke->index; 2262306a36Sopenharmony_ci } else { 2362306a36Sopenharmony_ci if (input_scancode_to_scalar(ke, &scancode)) 2462306a36Sopenharmony_ci return keymap_size; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* See if we can match the raw key code. */ 2762306a36Sopenharmony_ci for (index = 0; index < keymap_size; index++) 2862306a36Sopenharmony_ci if (keymap[index].scancode == scancode) 2962306a36Sopenharmony_ci break; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* See if there is an unused hole in the map */ 3262306a36Sopenharmony_ci if (index >= keymap_size) { 3362306a36Sopenharmony_ci for (index = 0; index < keymap_size; index++) { 3462306a36Sopenharmony_ci if (keymap[index].keycode == KEY_RESERVED || 3562306a36Sopenharmony_ci keymap[index].keycode == KEY_UNKNOWN) { 3662306a36Sopenharmony_ci break; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci return index; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int legacy_dvb_usb_getkeycode(struct input_dev *dev, 4662306a36Sopenharmony_ci struct input_keymap_entry *ke) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct dvb_usb_device *d = input_get_drvdata(dev); 4962306a36Sopenharmony_ci struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; 5062306a36Sopenharmony_ci unsigned int keymap_size = d->props.rc.legacy.rc_map_size; 5162306a36Sopenharmony_ci unsigned int index; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); 5462306a36Sopenharmony_ci if (index >= keymap_size) 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ke->keycode = keymap[index].keycode; 5862306a36Sopenharmony_ci if (ke->keycode == KEY_UNKNOWN) 5962306a36Sopenharmony_ci ke->keycode = KEY_RESERVED; 6062306a36Sopenharmony_ci ke->len = sizeof(keymap[index].scancode); 6162306a36Sopenharmony_ci memcpy(&ke->scancode, &keymap[index].scancode, ke->len); 6262306a36Sopenharmony_ci ke->index = index; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int legacy_dvb_usb_setkeycode(struct input_dev *dev, 6862306a36Sopenharmony_ci const struct input_keymap_entry *ke, 6962306a36Sopenharmony_ci unsigned int *old_keycode) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct dvb_usb_device *d = input_get_drvdata(dev); 7262306a36Sopenharmony_ci struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; 7362306a36Sopenharmony_ci unsigned int keymap_size = d->props.rc.legacy.rc_map_size; 7462306a36Sopenharmony_ci unsigned int index; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * FIXME: Currently, it is not possible to increase the size of 7962306a36Sopenharmony_ci * scancode table. For it to happen, one possibility 8062306a36Sopenharmony_ci * would be to allocate a table with key_map_size + 1, 8162306a36Sopenharmony_ci * copying data, appending the new key on it, and freeing 8262306a36Sopenharmony_ci * the old one - or maybe just allocating some spare space 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci if (index >= keymap_size) 8562306a36Sopenharmony_ci return -EINVAL; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci *old_keycode = keymap[index].keycode; 8862306a36Sopenharmony_ci keymap->keycode = ke->keycode; 8962306a36Sopenharmony_ci __set_bit(ke->keycode, dev->keybit); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (*old_keycode != KEY_RESERVED) { 9262306a36Sopenharmony_ci __clear_bit(*old_keycode, dev->keybit); 9362306a36Sopenharmony_ci for (index = 0; index < keymap_size; index++) { 9462306a36Sopenharmony_ci if (keymap[index].keycode == *old_keycode) { 9562306a36Sopenharmony_ci __set_bit(*old_keycode, dev->keybit); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Remote-control poll function - called every dib->rc_query_interval ms to see 10562306a36Sopenharmony_ci * whether the remote control has received anything. 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * TODO: Fix the repeat rate of the input device. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic void legacy_dvb_usb_read_remote_control(struct work_struct *work) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct dvb_usb_device *d = 11262306a36Sopenharmony_ci container_of(work, struct dvb_usb_device, rc_query_work.work); 11362306a36Sopenharmony_ci u32 event; 11462306a36Sopenharmony_ci int state; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* TODO: need a lock here. We can simply skip checking for the remote control 11762306a36Sopenharmony_ci if we're busy. */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* when the parameter has been set to 1 via sysfs while the driver was running */ 12062306a36Sopenharmony_ci if (dvb_usb_disable_rc_polling) 12162306a36Sopenharmony_ci return; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (d->props.rc.legacy.rc_query(d,&event,&state)) { 12462306a36Sopenharmony_ci err("error while querying for an remote control event."); 12562306a36Sopenharmony_ci goto schedule; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci switch (state) { 13062306a36Sopenharmony_ci case REMOTE_NO_KEY_PRESSED: 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case REMOTE_KEY_PRESSED: 13362306a36Sopenharmony_ci deb_rc("key pressed\n"); 13462306a36Sopenharmony_ci d->last_event = event; 13562306a36Sopenharmony_ci input_event(d->input_dev, EV_KEY, event, 1); 13662306a36Sopenharmony_ci input_sync(d->input_dev); 13762306a36Sopenharmony_ci input_event(d->input_dev, EV_KEY, d->last_event, 0); 13862306a36Sopenharmony_ci input_sync(d->input_dev); 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case REMOTE_KEY_REPEAT: 14162306a36Sopenharmony_ci deb_rc("key repeated\n"); 14262306a36Sopenharmony_ci input_event(d->input_dev, EV_KEY, event, 1); 14362306a36Sopenharmony_ci input_sync(d->input_dev); 14462306a36Sopenharmony_ci input_event(d->input_dev, EV_KEY, d->last_event, 0); 14562306a36Sopenharmony_ci input_sync(d->input_dev); 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci default: 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* improved repeat handling ??? 15262306a36Sopenharmony_ci switch (state) { 15362306a36Sopenharmony_ci case REMOTE_NO_KEY_PRESSED: 15462306a36Sopenharmony_ci deb_rc("NO KEY PRESSED\n"); 15562306a36Sopenharmony_ci if (d->last_state != REMOTE_NO_KEY_PRESSED) { 15662306a36Sopenharmony_ci deb_rc("releasing event %d\n",d->last_event); 15762306a36Sopenharmony_ci input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); 15862306a36Sopenharmony_ci input_sync(d->rc_input_dev); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci d->last_state = REMOTE_NO_KEY_PRESSED; 16162306a36Sopenharmony_ci d->last_event = 0; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci case REMOTE_KEY_PRESSED: 16462306a36Sopenharmony_ci deb_rc("KEY PRESSED\n"); 16562306a36Sopenharmony_ci deb_rc("pressing event %d\n",event); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci input_event(d->rc_input_dev, EV_KEY, event, 1); 16862306a36Sopenharmony_ci input_sync(d->rc_input_dev); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci d->last_event = event; 17162306a36Sopenharmony_ci d->last_state = REMOTE_KEY_PRESSED; 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci case REMOTE_KEY_REPEAT: 17462306a36Sopenharmony_ci deb_rc("KEY_REPEAT\n"); 17562306a36Sopenharmony_ci if (d->last_state != REMOTE_NO_KEY_PRESSED) { 17662306a36Sopenharmony_ci deb_rc("repeating event %d\n",d->last_event); 17762306a36Sopenharmony_ci input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); 17862306a36Sopenharmony_ci input_sync(d->rc_input_dev); 17962306a36Sopenharmony_ci d->last_state = REMOTE_KEY_REPEAT; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci default: 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci*/ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cischedule: 18762306a36Sopenharmony_ci schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci int i, err, rc_interval; 19362306a36Sopenharmony_ci struct input_dev *input_dev; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci input_dev = input_allocate_device(); 19662306a36Sopenharmony_ci if (!input_dev) 19762306a36Sopenharmony_ci return -ENOMEM; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY); 20062306a36Sopenharmony_ci input_dev->name = "IR-receiver inside an USB DVB receiver"; 20162306a36Sopenharmony_ci input_dev->phys = d->rc_phys; 20262306a36Sopenharmony_ci usb_to_input_id(d->udev, &input_dev->id); 20362306a36Sopenharmony_ci input_dev->dev.parent = &d->udev->dev; 20462306a36Sopenharmony_ci d->input_dev = input_dev; 20562306a36Sopenharmony_ci d->rc_dev = NULL; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci input_dev->getkeycode = legacy_dvb_usb_getkeycode; 20862306a36Sopenharmony_ci input_dev->setkeycode = legacy_dvb_usb_setkeycode; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* set the bits for the keys */ 21162306a36Sopenharmony_ci deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); 21262306a36Sopenharmony_ci for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { 21362306a36Sopenharmony_ci deb_rc("setting bit for event %d item %d\n", 21462306a36Sopenharmony_ci d->props.rc.legacy.rc_map_table[i].keycode, i); 21562306a36Sopenharmony_ci set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* setting these two values to non-zero, we have to manage key repeats */ 21962306a36Sopenharmony_ci input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; 22062306a36Sopenharmony_ci input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci input_set_drvdata(input_dev, d); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci err = input_register_device(input_dev); 22562306a36Sopenharmony_ci if (err) 22662306a36Sopenharmony_ci input_free_device(input_dev); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci rc_interval = d->props.rc.legacy.rc_interval; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci info("schedule remote query interval to %d msecs.", rc_interval); 23362306a36Sopenharmony_ci schedule_delayed_work(&d->rc_query_work, 23462306a36Sopenharmony_ci msecs_to_jiffies(rc_interval)); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci d->state |= DVB_USB_STATE_REMOTE; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* Remote-control poll function - called every dib->rc_query_interval ms to see 24262306a36Sopenharmony_ci * whether the remote control has received anything. 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * TODO: Fix the repeat rate of the input device. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_cistatic void dvb_usb_read_remote_control(struct work_struct *work) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct dvb_usb_device *d = 24962306a36Sopenharmony_ci container_of(work, struct dvb_usb_device, rc_query_work.work); 25062306a36Sopenharmony_ci int err; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* TODO: need a lock here. We can simply skip checking for the remote control 25362306a36Sopenharmony_ci if we're busy. */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* when the parameter has been set to 1 via sysfs while the 25662306a36Sopenharmony_ci * driver was running, or when bulk mode is enabled after IR init 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci err = d->props.rc.core.rc_query(d); 26262306a36Sopenharmony_ci if (err) 26362306a36Sopenharmony_ci err("error %d while querying for an remote control event.", err); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci schedule_delayed_work(&d->rc_query_work, 26662306a36Sopenharmony_ci msecs_to_jiffies(d->props.rc.core.rc_interval)); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci int err, rc_interval; 27262306a36Sopenharmony_ci struct rc_dev *dev; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dev = rc_allocate_device(d->props.rc.core.driver_type); 27562306a36Sopenharmony_ci if (!dev) 27662306a36Sopenharmony_ci return -ENOMEM; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci dev->driver_name = d->props.rc.core.module_name; 27962306a36Sopenharmony_ci dev->map_name = d->props.rc.core.rc_codes; 28062306a36Sopenharmony_ci dev->change_protocol = d->props.rc.core.change_protocol; 28162306a36Sopenharmony_ci dev->allowed_protocols = d->props.rc.core.allowed_protos; 28262306a36Sopenharmony_ci usb_to_input_id(d->udev, &dev->input_id); 28362306a36Sopenharmony_ci dev->device_name = d->desc->name; 28462306a36Sopenharmony_ci dev->input_phys = d->rc_phys; 28562306a36Sopenharmony_ci dev->dev.parent = &d->udev->dev; 28662306a36Sopenharmony_ci dev->priv = d; 28762306a36Sopenharmony_ci dev->scancode_mask = d->props.rc.core.scancode_mask; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci err = rc_register_device(dev); 29062306a36Sopenharmony_ci if (err < 0) { 29162306a36Sopenharmony_ci rc_free_device(dev); 29262306a36Sopenharmony_ci return err; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci d->input_dev = NULL; 29662306a36Sopenharmony_ci d->rc_dev = dev; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Polling mode - initialize a work queue for handling it */ 30262306a36Sopenharmony_ci INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci rc_interval = d->props.rc.core.rc_interval; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci info("schedule remote query interval to %d msecs.", rc_interval); 30762306a36Sopenharmony_ci schedule_delayed_work(&d->rc_query_work, 30862306a36Sopenharmony_ci msecs_to_jiffies(rc_interval)); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciint dvb_usb_remote_init(struct dvb_usb_device *d) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci int err; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (dvb_usb_disable_rc_polling) 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) 32162306a36Sopenharmony_ci d->props.rc.mode = DVB_RC_LEGACY; 32262306a36Sopenharmony_ci else if (d->props.rc.core.rc_codes) 32362306a36Sopenharmony_ci d->props.rc.mode = DVB_RC_CORE; 32462306a36Sopenharmony_ci else 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); 32862306a36Sopenharmony_ci strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Start the remote-control polling. */ 33162306a36Sopenharmony_ci if (d->props.rc.legacy.rc_interval < 40) 33262306a36Sopenharmony_ci d->props.rc.legacy.rc_interval = 100; /* default */ 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (d->props.rc.mode == DVB_RC_LEGACY) 33562306a36Sopenharmony_ci err = legacy_dvb_usb_remote_init(d); 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci err = rc_core_dvb_usb_remote_init(d); 33862306a36Sopenharmony_ci if (err) 33962306a36Sopenharmony_ci return err; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci d->state |= DVB_USB_STATE_REMOTE; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ciint dvb_usb_remote_exit(struct dvb_usb_device *d) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci if (d->state & DVB_USB_STATE_REMOTE) { 34962306a36Sopenharmony_ci cancel_delayed_work_sync(&d->rc_query_work); 35062306a36Sopenharmony_ci if (d->props.rc.mode == DVB_RC_LEGACY) 35162306a36Sopenharmony_ci input_unregister_device(d->input_dev); 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci rc_unregister_device(d->rc_dev); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci d->state &= ~DVB_USB_STATE_REMOTE; 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci#define DVB_USB_RC_NEC_EMPTY 0x00 36062306a36Sopenharmony_ci#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 36162306a36Sopenharmony_ci#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 36262306a36Sopenharmony_ciint dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, 36362306a36Sopenharmony_ci u8 keybuf[5], u32 *event, int *state) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci int i; 36662306a36Sopenharmony_ci struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; 36762306a36Sopenharmony_ci *event = 0; 36862306a36Sopenharmony_ci *state = REMOTE_NO_KEY_PRESSED; 36962306a36Sopenharmony_ci switch (keybuf[0]) { 37062306a36Sopenharmony_ci case DVB_USB_RC_NEC_EMPTY: 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci case DVB_USB_RC_NEC_KEY_PRESSED: 37362306a36Sopenharmony_ci if ((u8) ~keybuf[1] != keybuf[2] || 37462306a36Sopenharmony_ci (u8) ~keybuf[3] != keybuf[4]) { 37562306a36Sopenharmony_ci deb_err("remote control checksum failed.\n"); 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci /* See if we can match the raw key code. */ 37962306a36Sopenharmony_ci for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) 38062306a36Sopenharmony_ci if (rc5_custom(&keymap[i]) == keybuf[1] && 38162306a36Sopenharmony_ci rc5_data(&keymap[i]) == keybuf[3]) { 38262306a36Sopenharmony_ci *event = keymap[i].keycode; 38362306a36Sopenharmony_ci *state = REMOTE_KEY_PRESSED; 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci deb_err("key mapping failed - no appropriate key found in keymapping\n"); 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci case DVB_USB_RC_NEC_KEY_REPEATED: 38962306a36Sopenharmony_ci *state = REMOTE_KEY_REPEAT; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci default: 39262306a36Sopenharmony_ci deb_err("unknown type of remote status: %d\n",keybuf[0]); 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ciEXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event); 398