1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* dvb-usb-remote.c is part of the DVB USB library.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
5*4882a593Smuzhiyun * see dvb-usb-init.c for copyright information.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This file contains functions for initializing the input-device and for handling remote-control-queries.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun #include "dvb-usb-common.h"
10*4882a593Smuzhiyun #include <linux/usb/input.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun static unsigned int
legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry * ke,struct rc_map_table * keymap,unsigned int keymap_size)13*4882a593Smuzhiyun legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
14*4882a593Smuzhiyun struct rc_map_table *keymap,
15*4882a593Smuzhiyun unsigned int keymap_size)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun unsigned int index;
18*4882a593Smuzhiyun unsigned int scancode;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
21*4882a593Smuzhiyun index = ke->index;
22*4882a593Smuzhiyun } else {
23*4882a593Smuzhiyun if (input_scancode_to_scalar(ke, &scancode))
24*4882a593Smuzhiyun return keymap_size;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* See if we can match the raw key code. */
27*4882a593Smuzhiyun for (index = 0; index < keymap_size; index++)
28*4882a593Smuzhiyun if (keymap[index].scancode == scancode)
29*4882a593Smuzhiyun break;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* See if there is an unused hole in the map */
32*4882a593Smuzhiyun if (index >= keymap_size) {
33*4882a593Smuzhiyun for (index = 0; index < keymap_size; index++) {
34*4882a593Smuzhiyun if (keymap[index].keycode == KEY_RESERVED ||
35*4882a593Smuzhiyun keymap[index].keycode == KEY_UNKNOWN) {
36*4882a593Smuzhiyun break;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun return index;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
legacy_dvb_usb_getkeycode(struct input_dev * dev,struct input_keymap_entry * ke)45*4882a593Smuzhiyun static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
46*4882a593Smuzhiyun struct input_keymap_entry *ke)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct dvb_usb_device *d = input_get_drvdata(dev);
49*4882a593Smuzhiyun struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
50*4882a593Smuzhiyun unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
51*4882a593Smuzhiyun unsigned int index;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
54*4882a593Smuzhiyun if (index >= keymap_size)
55*4882a593Smuzhiyun return -EINVAL;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun ke->keycode = keymap[index].keycode;
58*4882a593Smuzhiyun if (ke->keycode == KEY_UNKNOWN)
59*4882a593Smuzhiyun ke->keycode = KEY_RESERVED;
60*4882a593Smuzhiyun ke->len = sizeof(keymap[index].scancode);
61*4882a593Smuzhiyun memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
62*4882a593Smuzhiyun ke->index = index;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun return 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
legacy_dvb_usb_setkeycode(struct input_dev * dev,const struct input_keymap_entry * ke,unsigned int * old_keycode)67*4882a593Smuzhiyun static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
68*4882a593Smuzhiyun const struct input_keymap_entry *ke,
69*4882a593Smuzhiyun unsigned int *old_keycode)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun struct dvb_usb_device *d = input_get_drvdata(dev);
72*4882a593Smuzhiyun struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
73*4882a593Smuzhiyun unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
74*4882a593Smuzhiyun unsigned int index;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun * FIXME: Currently, it is not possible to increase the size of
79*4882a593Smuzhiyun * scancode table. For it to happen, one possibility
80*4882a593Smuzhiyun * would be to allocate a table with key_map_size + 1,
81*4882a593Smuzhiyun * copying data, appending the new key on it, and freeing
82*4882a593Smuzhiyun * the old one - or maybe just allocating some spare space
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun if (index >= keymap_size)
85*4882a593Smuzhiyun return -EINVAL;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun *old_keycode = keymap[index].keycode;
88*4882a593Smuzhiyun keymap->keycode = ke->keycode;
89*4882a593Smuzhiyun __set_bit(ke->keycode, dev->keybit);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (*old_keycode != KEY_RESERVED) {
92*4882a593Smuzhiyun __clear_bit(*old_keycode, dev->keybit);
93*4882a593Smuzhiyun for (index = 0; index < keymap_size; index++) {
94*4882a593Smuzhiyun if (keymap[index].keycode == *old_keycode) {
95*4882a593Smuzhiyun __set_bit(*old_keycode, dev->keybit);
96*4882a593Smuzhiyun break;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* Remote-control poll function - called every dib->rc_query_interval ms to see
105*4882a593Smuzhiyun * whether the remote control has received anything.
106*4882a593Smuzhiyun *
107*4882a593Smuzhiyun * TODO: Fix the repeat rate of the input device.
108*4882a593Smuzhiyun */
legacy_dvb_usb_read_remote_control(struct work_struct * work)109*4882a593Smuzhiyun static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun struct dvb_usb_device *d =
112*4882a593Smuzhiyun container_of(work, struct dvb_usb_device, rc_query_work.work);
113*4882a593Smuzhiyun u32 event;
114*4882a593Smuzhiyun int state;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* TODO: need a lock here. We can simply skip checking for the remote control
117*4882a593Smuzhiyun if we're busy. */
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /* when the parameter has been set to 1 via sysfs while the driver was running */
120*4882a593Smuzhiyun if (dvb_usb_disable_rc_polling)
121*4882a593Smuzhiyun return;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (d->props.rc.legacy.rc_query(d,&event,&state)) {
124*4882a593Smuzhiyun err("error while querying for an remote control event.");
125*4882a593Smuzhiyun goto schedule;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun switch (state) {
130*4882a593Smuzhiyun case REMOTE_NO_KEY_PRESSED:
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun case REMOTE_KEY_PRESSED:
133*4882a593Smuzhiyun deb_rc("key pressed\n");
134*4882a593Smuzhiyun d->last_event = event;
135*4882a593Smuzhiyun input_event(d->input_dev, EV_KEY, event, 1);
136*4882a593Smuzhiyun input_sync(d->input_dev);
137*4882a593Smuzhiyun input_event(d->input_dev, EV_KEY, d->last_event, 0);
138*4882a593Smuzhiyun input_sync(d->input_dev);
139*4882a593Smuzhiyun break;
140*4882a593Smuzhiyun case REMOTE_KEY_REPEAT:
141*4882a593Smuzhiyun deb_rc("key repeated\n");
142*4882a593Smuzhiyun input_event(d->input_dev, EV_KEY, event, 1);
143*4882a593Smuzhiyun input_sync(d->input_dev);
144*4882a593Smuzhiyun input_event(d->input_dev, EV_KEY, d->last_event, 0);
145*4882a593Smuzhiyun input_sync(d->input_dev);
146*4882a593Smuzhiyun break;
147*4882a593Smuzhiyun default:
148*4882a593Smuzhiyun break;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* improved repeat handling ???
152*4882a593Smuzhiyun switch (state) {
153*4882a593Smuzhiyun case REMOTE_NO_KEY_PRESSED:
154*4882a593Smuzhiyun deb_rc("NO KEY PRESSED\n");
155*4882a593Smuzhiyun if (d->last_state != REMOTE_NO_KEY_PRESSED) {
156*4882a593Smuzhiyun deb_rc("releasing event %d\n",d->last_event);
157*4882a593Smuzhiyun input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
158*4882a593Smuzhiyun input_sync(d->rc_input_dev);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun d->last_state = REMOTE_NO_KEY_PRESSED;
161*4882a593Smuzhiyun d->last_event = 0;
162*4882a593Smuzhiyun break;
163*4882a593Smuzhiyun case REMOTE_KEY_PRESSED:
164*4882a593Smuzhiyun deb_rc("KEY PRESSED\n");
165*4882a593Smuzhiyun deb_rc("pressing event %d\n",event);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun input_event(d->rc_input_dev, EV_KEY, event, 1);
168*4882a593Smuzhiyun input_sync(d->rc_input_dev);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun d->last_event = event;
171*4882a593Smuzhiyun d->last_state = REMOTE_KEY_PRESSED;
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun case REMOTE_KEY_REPEAT:
174*4882a593Smuzhiyun deb_rc("KEY_REPEAT\n");
175*4882a593Smuzhiyun if (d->last_state != REMOTE_NO_KEY_PRESSED) {
176*4882a593Smuzhiyun deb_rc("repeating event %d\n",d->last_event);
177*4882a593Smuzhiyun input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);
178*4882a593Smuzhiyun input_sync(d->rc_input_dev);
179*4882a593Smuzhiyun d->last_state = REMOTE_KEY_REPEAT;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun default:
182*4882a593Smuzhiyun break;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun */
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun schedule:
187*4882a593Smuzhiyun schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
legacy_dvb_usb_remote_init(struct dvb_usb_device * d)190*4882a593Smuzhiyun static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun int i, err, rc_interval;
193*4882a593Smuzhiyun struct input_dev *input_dev;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun input_dev = input_allocate_device();
196*4882a593Smuzhiyun if (!input_dev)
197*4882a593Smuzhiyun return -ENOMEM;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun input_dev->evbit[0] = BIT_MASK(EV_KEY);
200*4882a593Smuzhiyun input_dev->name = "IR-receiver inside an USB DVB receiver";
201*4882a593Smuzhiyun input_dev->phys = d->rc_phys;
202*4882a593Smuzhiyun usb_to_input_id(d->udev, &input_dev->id);
203*4882a593Smuzhiyun input_dev->dev.parent = &d->udev->dev;
204*4882a593Smuzhiyun d->input_dev = input_dev;
205*4882a593Smuzhiyun d->rc_dev = NULL;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun input_dev->getkeycode = legacy_dvb_usb_getkeycode;
208*4882a593Smuzhiyun input_dev->setkeycode = legacy_dvb_usb_setkeycode;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /* set the bits for the keys */
211*4882a593Smuzhiyun deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
212*4882a593Smuzhiyun for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
213*4882a593Smuzhiyun deb_rc("setting bit for event %d item %d\n",
214*4882a593Smuzhiyun d->props.rc.legacy.rc_map_table[i].keycode, i);
215*4882a593Smuzhiyun set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* setting these two values to non-zero, we have to manage key repeats */
219*4882a593Smuzhiyun input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
220*4882a593Smuzhiyun input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun input_set_drvdata(input_dev, d);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun err = input_register_device(input_dev);
225*4882a593Smuzhiyun if (err)
226*4882a593Smuzhiyun input_free_device(input_dev);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun rc_interval = d->props.rc.legacy.rc_interval;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun info("schedule remote query interval to %d msecs.", rc_interval);
233*4882a593Smuzhiyun schedule_delayed_work(&d->rc_query_work,
234*4882a593Smuzhiyun msecs_to_jiffies(rc_interval));
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun d->state |= DVB_USB_STATE_REMOTE;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun return err;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /* Remote-control poll function - called every dib->rc_query_interval ms to see
242*4882a593Smuzhiyun * whether the remote control has received anything.
243*4882a593Smuzhiyun *
244*4882a593Smuzhiyun * TODO: Fix the repeat rate of the input device.
245*4882a593Smuzhiyun */
dvb_usb_read_remote_control(struct work_struct * work)246*4882a593Smuzhiyun static void dvb_usb_read_remote_control(struct work_struct *work)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun struct dvb_usb_device *d =
249*4882a593Smuzhiyun container_of(work, struct dvb_usb_device, rc_query_work.work);
250*4882a593Smuzhiyun int err;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* TODO: need a lock here. We can simply skip checking for the remote control
253*4882a593Smuzhiyun if we're busy. */
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /* when the parameter has been set to 1 via sysfs while the
256*4882a593Smuzhiyun * driver was running, or when bulk mode is enabled after IR init
257*4882a593Smuzhiyun */
258*4882a593Smuzhiyun if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
259*4882a593Smuzhiyun return;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun err = d->props.rc.core.rc_query(d);
262*4882a593Smuzhiyun if (err)
263*4882a593Smuzhiyun err("error %d while querying for an remote control event.", err);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun schedule_delayed_work(&d->rc_query_work,
266*4882a593Smuzhiyun msecs_to_jiffies(d->props.rc.core.rc_interval));
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
rc_core_dvb_usb_remote_init(struct dvb_usb_device * d)269*4882a593Smuzhiyun static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun int err, rc_interval;
272*4882a593Smuzhiyun struct rc_dev *dev;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun dev = rc_allocate_device(d->props.rc.core.driver_type);
275*4882a593Smuzhiyun if (!dev)
276*4882a593Smuzhiyun return -ENOMEM;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun dev->driver_name = d->props.rc.core.module_name;
279*4882a593Smuzhiyun dev->map_name = d->props.rc.core.rc_codes;
280*4882a593Smuzhiyun dev->change_protocol = d->props.rc.core.change_protocol;
281*4882a593Smuzhiyun dev->allowed_protocols = d->props.rc.core.allowed_protos;
282*4882a593Smuzhiyun usb_to_input_id(d->udev, &dev->input_id);
283*4882a593Smuzhiyun dev->device_name = d->desc->name;
284*4882a593Smuzhiyun dev->input_phys = d->rc_phys;
285*4882a593Smuzhiyun dev->dev.parent = &d->udev->dev;
286*4882a593Smuzhiyun dev->priv = d;
287*4882a593Smuzhiyun dev->scancode_mask = d->props.rc.core.scancode_mask;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun err = rc_register_device(dev);
290*4882a593Smuzhiyun if (err < 0) {
291*4882a593Smuzhiyun rc_free_device(dev);
292*4882a593Smuzhiyun return err;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun d->input_dev = NULL;
296*4882a593Smuzhiyun d->rc_dev = dev;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
299*4882a593Smuzhiyun return 0;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* Polling mode - initialize a work queue for handling it */
302*4882a593Smuzhiyun INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun rc_interval = d->props.rc.core.rc_interval;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun info("schedule remote query interval to %d msecs.", rc_interval);
307*4882a593Smuzhiyun schedule_delayed_work(&d->rc_query_work,
308*4882a593Smuzhiyun msecs_to_jiffies(rc_interval));
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun return 0;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
dvb_usb_remote_init(struct dvb_usb_device * d)313*4882a593Smuzhiyun int dvb_usb_remote_init(struct dvb_usb_device *d)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun int err;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun if (dvb_usb_disable_rc_polling)
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
321*4882a593Smuzhiyun d->props.rc.mode = DVB_RC_LEGACY;
322*4882a593Smuzhiyun else if (d->props.rc.core.rc_codes)
323*4882a593Smuzhiyun d->props.rc.mode = DVB_RC_CORE;
324*4882a593Smuzhiyun else
325*4882a593Smuzhiyun return 0;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
328*4882a593Smuzhiyun strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun /* Start the remote-control polling. */
331*4882a593Smuzhiyun if (d->props.rc.legacy.rc_interval < 40)
332*4882a593Smuzhiyun d->props.rc.legacy.rc_interval = 100; /* default */
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if (d->props.rc.mode == DVB_RC_LEGACY)
335*4882a593Smuzhiyun err = legacy_dvb_usb_remote_init(d);
336*4882a593Smuzhiyun else
337*4882a593Smuzhiyun err = rc_core_dvb_usb_remote_init(d);
338*4882a593Smuzhiyun if (err)
339*4882a593Smuzhiyun return err;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun d->state |= DVB_USB_STATE_REMOTE;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun return 0;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
dvb_usb_remote_exit(struct dvb_usb_device * d)346*4882a593Smuzhiyun int dvb_usb_remote_exit(struct dvb_usb_device *d)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun if (d->state & DVB_USB_STATE_REMOTE) {
349*4882a593Smuzhiyun cancel_delayed_work_sync(&d->rc_query_work);
350*4882a593Smuzhiyun if (d->props.rc.mode == DVB_RC_LEGACY)
351*4882a593Smuzhiyun input_unregister_device(d->input_dev);
352*4882a593Smuzhiyun else
353*4882a593Smuzhiyun rc_unregister_device(d->rc_dev);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun d->state &= ~DVB_USB_STATE_REMOTE;
356*4882a593Smuzhiyun return 0;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun #define DVB_USB_RC_NEC_EMPTY 0x00
360*4882a593Smuzhiyun #define DVB_USB_RC_NEC_KEY_PRESSED 0x01
361*4882a593Smuzhiyun #define DVB_USB_RC_NEC_KEY_REPEATED 0x02
dvb_usb_nec_rc_key_to_event(struct dvb_usb_device * d,u8 keybuf[5],u32 * event,int * state)362*4882a593Smuzhiyun int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
363*4882a593Smuzhiyun u8 keybuf[5], u32 *event, int *state)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun int i;
366*4882a593Smuzhiyun struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
367*4882a593Smuzhiyun *event = 0;
368*4882a593Smuzhiyun *state = REMOTE_NO_KEY_PRESSED;
369*4882a593Smuzhiyun switch (keybuf[0]) {
370*4882a593Smuzhiyun case DVB_USB_RC_NEC_EMPTY:
371*4882a593Smuzhiyun break;
372*4882a593Smuzhiyun case DVB_USB_RC_NEC_KEY_PRESSED:
373*4882a593Smuzhiyun if ((u8) ~keybuf[1] != keybuf[2] ||
374*4882a593Smuzhiyun (u8) ~keybuf[3] != keybuf[4]) {
375*4882a593Smuzhiyun deb_err("remote control checksum failed.\n");
376*4882a593Smuzhiyun break;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun /* See if we can match the raw key code. */
379*4882a593Smuzhiyun for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
380*4882a593Smuzhiyun if (rc5_custom(&keymap[i]) == keybuf[1] &&
381*4882a593Smuzhiyun rc5_data(&keymap[i]) == keybuf[3]) {
382*4882a593Smuzhiyun *event = keymap[i].keycode;
383*4882a593Smuzhiyun *state = REMOTE_KEY_PRESSED;
384*4882a593Smuzhiyun return 0;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun deb_err("key mapping failed - no appropriate key found in keymapping\n");
387*4882a593Smuzhiyun break;
388*4882a593Smuzhiyun case DVB_USB_RC_NEC_KEY_REPEATED:
389*4882a593Smuzhiyun *state = REMOTE_KEY_REPEAT;
390*4882a593Smuzhiyun break;
391*4882a593Smuzhiyun default:
392*4882a593Smuzhiyun deb_err("unknown type of remote status: %d\n",keybuf[0]);
393*4882a593Smuzhiyun break;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
398