1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2786baecfSMauro Carvalho Chehab /* dvb-usb-remote.c is part of the DVB USB library.
3786baecfSMauro Carvalho Chehab  *
499e44da7SPatrick Boettcher  * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
5786baecfSMauro Carvalho Chehab  * see dvb-usb-init.c for copyright information.
6786baecfSMauro Carvalho Chehab  *
7786baecfSMauro Carvalho Chehab  * This file contains functions for initializing the input-device and for handling remote-control-queries.
8786baecfSMauro Carvalho Chehab  */
9786baecfSMauro Carvalho Chehab #include "dvb-usb-common.h"
10786baecfSMauro Carvalho Chehab #include <linux/usb/input.h>
11786baecfSMauro Carvalho Chehab 
12786baecfSMauro Carvalho Chehab static unsigned int
legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry * ke,struct rc_map_table * keymap,unsigned int keymap_size)13786baecfSMauro Carvalho Chehab legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
14786baecfSMauro Carvalho Chehab 				struct rc_map_table *keymap,
15786baecfSMauro Carvalho Chehab 				unsigned int keymap_size)
16786baecfSMauro Carvalho Chehab {
17786baecfSMauro Carvalho Chehab 	unsigned int index;
18786baecfSMauro Carvalho Chehab 	unsigned int scancode;
19786baecfSMauro Carvalho Chehab 
20786baecfSMauro Carvalho Chehab 	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
21786baecfSMauro Carvalho Chehab 		index = ke->index;
22786baecfSMauro Carvalho Chehab 	} else {
23786baecfSMauro Carvalho Chehab 		if (input_scancode_to_scalar(ke, &scancode))
24786baecfSMauro Carvalho Chehab 			return keymap_size;
25786baecfSMauro Carvalho Chehab 
26786baecfSMauro Carvalho Chehab 		/* See if we can match the raw key code. */
27786baecfSMauro Carvalho Chehab 		for (index = 0; index < keymap_size; index++)
28786baecfSMauro Carvalho Chehab 			if (keymap[index].scancode == scancode)
29786baecfSMauro Carvalho Chehab 				break;
30786baecfSMauro Carvalho Chehab 
31786baecfSMauro Carvalho Chehab 		/* See if there is an unused hole in the map */
32786baecfSMauro Carvalho Chehab 		if (index >= keymap_size) {
33786baecfSMauro Carvalho Chehab 			for (index = 0; index < keymap_size; index++) {
34786baecfSMauro Carvalho Chehab 				if (keymap[index].keycode == KEY_RESERVED ||
35786baecfSMauro Carvalho Chehab 				    keymap[index].keycode == KEY_UNKNOWN) {
36786baecfSMauro Carvalho Chehab 					break;
37786baecfSMauro Carvalho Chehab 				}
38786baecfSMauro Carvalho Chehab 			}
39786baecfSMauro Carvalho Chehab 		}
40786baecfSMauro Carvalho Chehab 	}
41786baecfSMauro Carvalho Chehab 
42786baecfSMauro Carvalho Chehab 	return index;
43786baecfSMauro Carvalho Chehab }
44786baecfSMauro Carvalho Chehab 
legacy_dvb_usb_getkeycode(struct input_dev * dev,struct input_keymap_entry * ke)45786baecfSMauro Carvalho Chehab static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
46786baecfSMauro Carvalho Chehab 				     struct input_keymap_entry *ke)
47786baecfSMauro Carvalho Chehab {
48786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = input_get_drvdata(dev);
49786baecfSMauro Carvalho Chehab 	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
50786baecfSMauro Carvalho Chehab 	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
51786baecfSMauro Carvalho Chehab 	unsigned int index;
52786baecfSMauro Carvalho Chehab 
53786baecfSMauro Carvalho Chehab 	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
54786baecfSMauro Carvalho Chehab 	if (index >= keymap_size)
55786baecfSMauro Carvalho Chehab 		return -EINVAL;
56786baecfSMauro Carvalho Chehab 
57786baecfSMauro Carvalho Chehab 	ke->keycode = keymap[index].keycode;
58786baecfSMauro Carvalho Chehab 	if (ke->keycode == KEY_UNKNOWN)
59786baecfSMauro Carvalho Chehab 		ke->keycode = KEY_RESERVED;
60786baecfSMauro Carvalho Chehab 	ke->len = sizeof(keymap[index].scancode);
61786baecfSMauro Carvalho Chehab 	memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
62786baecfSMauro Carvalho Chehab 	ke->index = index;
63786baecfSMauro Carvalho Chehab 
64786baecfSMauro Carvalho Chehab 	return 0;
65786baecfSMauro Carvalho Chehab }
66786baecfSMauro Carvalho Chehab 
legacy_dvb_usb_setkeycode(struct input_dev * dev,const struct input_keymap_entry * ke,unsigned int * old_keycode)67786baecfSMauro Carvalho Chehab static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
68786baecfSMauro Carvalho Chehab 				     const struct input_keymap_entry *ke,
69786baecfSMauro Carvalho Chehab 				     unsigned int *old_keycode)
70786baecfSMauro Carvalho Chehab {
71786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = input_get_drvdata(dev);
72786baecfSMauro Carvalho Chehab 	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
73786baecfSMauro Carvalho Chehab 	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
74786baecfSMauro Carvalho Chehab 	unsigned int index;
75786baecfSMauro Carvalho Chehab 
76786baecfSMauro Carvalho Chehab 	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
77786baecfSMauro Carvalho Chehab 	/*
78786baecfSMauro Carvalho Chehab 	 * FIXME: Currently, it is not possible to increase the size of
79786baecfSMauro Carvalho Chehab 	 * scancode table. For it to happen, one possibility
80786baecfSMauro Carvalho Chehab 	 * would be to allocate a table with key_map_size + 1,
81786baecfSMauro Carvalho Chehab 	 * copying data, appending the new key on it, and freeing
82786baecfSMauro Carvalho Chehab 	 * the old one - or maybe just allocating some spare space
83786baecfSMauro Carvalho Chehab 	 */
84786baecfSMauro Carvalho Chehab 	if (index >= keymap_size)
85786baecfSMauro Carvalho Chehab 		return -EINVAL;
86786baecfSMauro Carvalho Chehab 
87786baecfSMauro Carvalho Chehab 	*old_keycode = keymap[index].keycode;
88786baecfSMauro Carvalho Chehab 	keymap->keycode = ke->keycode;
89786baecfSMauro Carvalho Chehab 	__set_bit(ke->keycode, dev->keybit);
90786baecfSMauro Carvalho Chehab 
91786baecfSMauro Carvalho Chehab 	if (*old_keycode != KEY_RESERVED) {
92786baecfSMauro Carvalho Chehab 		__clear_bit(*old_keycode, dev->keybit);
93786baecfSMauro Carvalho Chehab 		for (index = 0; index < keymap_size; index++) {
94786baecfSMauro Carvalho Chehab 			if (keymap[index].keycode == *old_keycode) {
95786baecfSMauro Carvalho Chehab 				__set_bit(*old_keycode, dev->keybit);
96786baecfSMauro Carvalho Chehab 				break;
97786baecfSMauro Carvalho Chehab 			}
98786baecfSMauro Carvalho Chehab 		}
99786baecfSMauro Carvalho Chehab 	}
100786baecfSMauro Carvalho Chehab 
101786baecfSMauro Carvalho Chehab 	return 0;
102786baecfSMauro Carvalho Chehab }
103786baecfSMauro Carvalho Chehab 
104786baecfSMauro Carvalho Chehab /* Remote-control poll function - called every dib->rc_query_interval ms to see
105786baecfSMauro Carvalho Chehab  * whether the remote control has received anything.
106786baecfSMauro Carvalho Chehab  *
107786baecfSMauro Carvalho Chehab  * TODO: Fix the repeat rate of the input device.
108786baecfSMauro Carvalho Chehab  */
legacy_dvb_usb_read_remote_control(struct work_struct * work)109786baecfSMauro Carvalho Chehab static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
110786baecfSMauro Carvalho Chehab {
111786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d =
112786baecfSMauro Carvalho Chehab 		container_of(work, struct dvb_usb_device, rc_query_work.work);
113786baecfSMauro Carvalho Chehab 	u32 event;
114786baecfSMauro Carvalho Chehab 	int state;
115786baecfSMauro Carvalho Chehab 
116786baecfSMauro Carvalho Chehab 	/* TODO: need a lock here.  We can simply skip checking for the remote control
117786baecfSMauro Carvalho Chehab 	   if we're busy. */
118786baecfSMauro Carvalho Chehab 
119786baecfSMauro Carvalho Chehab 	/* when the parameter has been set to 1 via sysfs while the driver was running */
120786baecfSMauro Carvalho Chehab 	if (dvb_usb_disable_rc_polling)
121786baecfSMauro Carvalho Chehab 		return;
122786baecfSMauro Carvalho Chehab 
123786baecfSMauro Carvalho Chehab 	if (d->props.rc.legacy.rc_query(d,&event,&state)) {
124786baecfSMauro Carvalho Chehab 		err("error while querying for an remote control event.");
125786baecfSMauro Carvalho Chehab 		goto schedule;
126786baecfSMauro Carvalho Chehab 	}
127786baecfSMauro Carvalho Chehab 
128786baecfSMauro Carvalho Chehab 
129786baecfSMauro Carvalho Chehab 	switch (state) {
130786baecfSMauro Carvalho Chehab 		case REMOTE_NO_KEY_PRESSED:
131786baecfSMauro Carvalho Chehab 			break;
132786baecfSMauro Carvalho Chehab 		case REMOTE_KEY_PRESSED:
133786baecfSMauro Carvalho Chehab 			deb_rc("key pressed\n");
134786baecfSMauro Carvalho Chehab 			d->last_event = event;
13539c4806eSMauro Carvalho Chehab 			input_event(d->input_dev, EV_KEY, event, 1);
13639c4806eSMauro Carvalho Chehab 			input_sync(d->input_dev);
13739c4806eSMauro Carvalho Chehab 			input_event(d->input_dev, EV_KEY, d->last_event, 0);
13839c4806eSMauro Carvalho Chehab 			input_sync(d->input_dev);
13939c4806eSMauro Carvalho Chehab 			break;
140786baecfSMauro Carvalho Chehab 		case REMOTE_KEY_REPEAT:
141786baecfSMauro Carvalho Chehab 			deb_rc("key repeated\n");
142786baecfSMauro Carvalho Chehab 			input_event(d->input_dev, EV_KEY, event, 1);
143786baecfSMauro Carvalho Chehab 			input_sync(d->input_dev);
144786baecfSMauro Carvalho Chehab 			input_event(d->input_dev, EV_KEY, d->last_event, 0);
145786baecfSMauro Carvalho Chehab 			input_sync(d->input_dev);
146786baecfSMauro Carvalho Chehab 			break;
147786baecfSMauro Carvalho Chehab 		default:
148786baecfSMauro Carvalho Chehab 			break;
149786baecfSMauro Carvalho Chehab 	}
150786baecfSMauro Carvalho Chehab 
151786baecfSMauro Carvalho Chehab /* improved repeat handling ???
152786baecfSMauro Carvalho Chehab 	switch (state) {
153786baecfSMauro Carvalho Chehab 		case REMOTE_NO_KEY_PRESSED:
154786baecfSMauro Carvalho Chehab 			deb_rc("NO KEY PRESSED\n");
155786baecfSMauro Carvalho Chehab 			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
156786baecfSMauro Carvalho Chehab 				deb_rc("releasing event %d\n",d->last_event);
157786baecfSMauro Carvalho Chehab 				input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
158786baecfSMauro Carvalho Chehab 				input_sync(d->rc_input_dev);
159786baecfSMauro Carvalho Chehab 			}
160786baecfSMauro Carvalho Chehab 			d->last_state = REMOTE_NO_KEY_PRESSED;
161786baecfSMauro Carvalho Chehab 			d->last_event = 0;
162786baecfSMauro Carvalho Chehab 			break;
163786baecfSMauro Carvalho Chehab 		case REMOTE_KEY_PRESSED:
164786baecfSMauro Carvalho Chehab 			deb_rc("KEY PRESSED\n");
165786baecfSMauro Carvalho Chehab 			deb_rc("pressing event %d\n",event);
166786baecfSMauro Carvalho Chehab 
167786baecfSMauro Carvalho Chehab 			input_event(d->rc_input_dev, EV_KEY, event, 1);
168786baecfSMauro Carvalho Chehab 			input_sync(d->rc_input_dev);
169786baecfSMauro Carvalho Chehab 
170786baecfSMauro Carvalho Chehab 			d->last_event = event;
171786baecfSMauro Carvalho Chehab 			d->last_state = REMOTE_KEY_PRESSED;
172786baecfSMauro Carvalho Chehab 			break;
173786baecfSMauro Carvalho Chehab 		case REMOTE_KEY_REPEAT:
174786baecfSMauro Carvalho Chehab 			deb_rc("KEY_REPEAT\n");
175786baecfSMauro Carvalho Chehab 			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
176786baecfSMauro Carvalho Chehab 				deb_rc("repeating event %d\n",d->last_event);
177786baecfSMauro Carvalho Chehab 				input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);
178786baecfSMauro Carvalho Chehab 				input_sync(d->rc_input_dev);
179786baecfSMauro Carvalho Chehab 				d->last_state = REMOTE_KEY_REPEAT;
180786baecfSMauro Carvalho Chehab 			}
181786baecfSMauro Carvalho Chehab 		default:
182786baecfSMauro Carvalho Chehab 			break;
183786baecfSMauro Carvalho Chehab 	}
184786baecfSMauro Carvalho Chehab */
185786baecfSMauro Carvalho Chehab 
186786baecfSMauro Carvalho Chehab schedule:
187786baecfSMauro Carvalho Chehab 	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
188786baecfSMauro Carvalho Chehab }
189786baecfSMauro Carvalho Chehab 
legacy_dvb_usb_remote_init(struct dvb_usb_device * d)190786baecfSMauro Carvalho Chehab static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
191786baecfSMauro Carvalho Chehab {
192786baecfSMauro Carvalho Chehab 	int i, err, rc_interval;
193786baecfSMauro Carvalho Chehab 	struct input_dev *input_dev;
194786baecfSMauro Carvalho Chehab 
195786baecfSMauro Carvalho Chehab 	input_dev = input_allocate_device();
196786baecfSMauro Carvalho Chehab 	if (!input_dev)
197786baecfSMauro Carvalho Chehab 		return -ENOMEM;
198786baecfSMauro Carvalho Chehab 
199786baecfSMauro Carvalho Chehab 	input_dev->evbit[0] = BIT_MASK(EV_KEY);
200786baecfSMauro Carvalho Chehab 	input_dev->name = "IR-receiver inside an USB DVB receiver";
201786baecfSMauro Carvalho Chehab 	input_dev->phys = d->rc_phys;
202786baecfSMauro Carvalho Chehab 	usb_to_input_id(d->udev, &input_dev->id);
203786baecfSMauro Carvalho Chehab 	input_dev->dev.parent = &d->udev->dev;
204786baecfSMauro Carvalho Chehab 	d->input_dev = input_dev;
205786baecfSMauro Carvalho Chehab 	d->rc_dev = NULL;
206786baecfSMauro Carvalho Chehab 
207786baecfSMauro Carvalho Chehab 	input_dev->getkeycode = legacy_dvb_usb_getkeycode;
208786baecfSMauro Carvalho Chehab 	input_dev->setkeycode = legacy_dvb_usb_setkeycode;
209786baecfSMauro Carvalho Chehab 
210786baecfSMauro Carvalho Chehab 	/* set the bits for the keys */
211786baecfSMauro Carvalho Chehab 	deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
212786baecfSMauro Carvalho Chehab 	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
213786baecfSMauro Carvalho Chehab 		deb_rc("setting bit for event %d item %d\n",
214786baecfSMauro Carvalho Chehab 			d->props.rc.legacy.rc_map_table[i].keycode, i);
215786baecfSMauro Carvalho Chehab 		set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
216786baecfSMauro Carvalho Chehab 	}
217786baecfSMauro Carvalho Chehab 
218786baecfSMauro Carvalho Chehab 	/* setting these two values to non-zero, we have to manage key repeats */
219786baecfSMauro Carvalho Chehab 	input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
220786baecfSMauro Carvalho Chehab 	input_dev->rep[REP_DELAY]  = d->props.rc.legacy.rc_interval + 150;
221786baecfSMauro Carvalho Chehab 
222786baecfSMauro Carvalho Chehab 	input_set_drvdata(input_dev, d);
223786baecfSMauro Carvalho Chehab 
224786baecfSMauro Carvalho Chehab 	err = input_register_device(input_dev);
225786baecfSMauro Carvalho Chehab 	if (err)
226786baecfSMauro Carvalho Chehab 		input_free_device(input_dev);
227786baecfSMauro Carvalho Chehab 
228786baecfSMauro Carvalho Chehab 	rc_interval = d->props.rc.legacy.rc_interval;
229786baecfSMauro Carvalho Chehab 
230786baecfSMauro Carvalho Chehab 	INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
231786baecfSMauro Carvalho Chehab 
232786baecfSMauro Carvalho Chehab 	info("schedule remote query interval to %d msecs.", rc_interval);
233786baecfSMauro Carvalho Chehab 	schedule_delayed_work(&d->rc_query_work,
234786baecfSMauro Carvalho Chehab 			      msecs_to_jiffies(rc_interval));
235786baecfSMauro Carvalho Chehab 
236786baecfSMauro Carvalho Chehab 	d->state |= DVB_USB_STATE_REMOTE;
237786baecfSMauro Carvalho Chehab 
238786baecfSMauro Carvalho Chehab 	return err;
239786baecfSMauro Carvalho Chehab }
240786baecfSMauro Carvalho Chehab 
241786baecfSMauro Carvalho Chehab /* Remote-control poll function - called every dib->rc_query_interval ms to see
242786baecfSMauro Carvalho Chehab  * whether the remote control has received anything.
243786baecfSMauro Carvalho Chehab  *
244786baecfSMauro Carvalho Chehab  * TODO: Fix the repeat rate of the input device.
245786baecfSMauro Carvalho Chehab  */
dvb_usb_read_remote_control(struct work_struct * work)246786baecfSMauro Carvalho Chehab static void dvb_usb_read_remote_control(struct work_struct *work)
247786baecfSMauro Carvalho Chehab {
248786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d =
249786baecfSMauro Carvalho Chehab 		container_of(work, struct dvb_usb_device, rc_query_work.work);
250786baecfSMauro Carvalho Chehab 	int err;
251786baecfSMauro Carvalho Chehab 
252786baecfSMauro Carvalho Chehab 	/* TODO: need a lock here.  We can simply skip checking for the remote control
253786baecfSMauro Carvalho Chehab 	   if we're busy. */
254786baecfSMauro Carvalho Chehab 
255786baecfSMauro Carvalho Chehab 	/* when the parameter has been set to 1 via sysfs while the
256786baecfSMauro Carvalho Chehab 	 * driver was running, or when bulk mode is enabled after IR init
257786baecfSMauro Carvalho Chehab 	 */
258786baecfSMauro Carvalho Chehab 	if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
259786baecfSMauro Carvalho Chehab 		return;
260786baecfSMauro Carvalho Chehab 
261786baecfSMauro Carvalho Chehab 	err = d->props.rc.core.rc_query(d);
262786baecfSMauro Carvalho Chehab 	if (err)
263786baecfSMauro Carvalho Chehab 		err("error %d while querying for an remote control event.", err);
264786baecfSMauro Carvalho Chehab 
265786baecfSMauro Carvalho Chehab 	schedule_delayed_work(&d->rc_query_work,
266786baecfSMauro Carvalho Chehab 			      msecs_to_jiffies(d->props.rc.core.rc_interval));
267786baecfSMauro Carvalho Chehab }
268786baecfSMauro Carvalho Chehab 
rc_core_dvb_usb_remote_init(struct dvb_usb_device * d)269786baecfSMauro Carvalho Chehab static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
270786baecfSMauro Carvalho Chehab {
271786baecfSMauro Carvalho Chehab 	int err, rc_interval;
272786baecfSMauro Carvalho Chehab 	struct rc_dev *dev;
273786baecfSMauro Carvalho Chehab 
2740f7499fdSAndi Shyti 	dev = rc_allocate_device(d->props.rc.core.driver_type);
275786baecfSMauro Carvalho Chehab 	if (!dev)
276786baecfSMauro Carvalho Chehab 		return -ENOMEM;
277786baecfSMauro Carvalho Chehab 
278786baecfSMauro Carvalho Chehab 	dev->driver_name = d->props.rc.core.module_name;
279786baecfSMauro Carvalho Chehab 	dev->map_name = d->props.rc.core.rc_codes;
280786baecfSMauro Carvalho Chehab 	dev->change_protocol = d->props.rc.core.change_protocol;
281c5540fbbSDavid Härdeman 	dev->allowed_protocols = d->props.rc.core.allowed_protos;
282786baecfSMauro Carvalho Chehab 	usb_to_input_id(d->udev, &dev->input_id);
283518f4b26SSean Young 	dev->device_name = d->desc->name;
284786baecfSMauro Carvalho Chehab 	dev->input_phys = d->rc_phys;
285786baecfSMauro Carvalho Chehab 	dev->dev.parent = &d->udev->dev;
286786baecfSMauro Carvalho Chehab 	dev->priv = d;
287786baecfSMauro Carvalho Chehab 	dev->scancode_mask = d->props.rc.core.scancode_mask;
288786baecfSMauro Carvalho Chehab 
289786baecfSMauro Carvalho Chehab 	err = rc_register_device(dev);
290786baecfSMauro Carvalho Chehab 	if (err < 0) {
291786baecfSMauro Carvalho Chehab 		rc_free_device(dev);
292786baecfSMauro Carvalho Chehab 		return err;
293786baecfSMauro Carvalho Chehab 	}
294786baecfSMauro Carvalho Chehab 
295786baecfSMauro Carvalho Chehab 	d->input_dev = NULL;
296786baecfSMauro Carvalho Chehab 	d->rc_dev = dev;
297786baecfSMauro Carvalho Chehab 
298786baecfSMauro Carvalho Chehab 	if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
299786baecfSMauro Carvalho Chehab 		return 0;
300786baecfSMauro Carvalho Chehab 
301786baecfSMauro Carvalho Chehab 	/* Polling mode - initialize a work queue for handling it */
302786baecfSMauro Carvalho Chehab 	INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
303786baecfSMauro Carvalho Chehab 
304786baecfSMauro Carvalho Chehab 	rc_interval = d->props.rc.core.rc_interval;
305786baecfSMauro Carvalho Chehab 
306786baecfSMauro Carvalho Chehab 	info("schedule remote query interval to %d msecs.", rc_interval);
307786baecfSMauro Carvalho Chehab 	schedule_delayed_work(&d->rc_query_work,
308786baecfSMauro Carvalho Chehab 			      msecs_to_jiffies(rc_interval));
309786baecfSMauro Carvalho Chehab 
310786baecfSMauro Carvalho Chehab 	return 0;
311786baecfSMauro Carvalho Chehab }
312786baecfSMauro Carvalho Chehab 
dvb_usb_remote_init(struct dvb_usb_device * d)313786baecfSMauro Carvalho Chehab int dvb_usb_remote_init(struct dvb_usb_device *d)
314786baecfSMauro Carvalho Chehab {
315786baecfSMauro Carvalho Chehab 	int err;
316786baecfSMauro Carvalho Chehab 
317786baecfSMauro Carvalho Chehab 	if (dvb_usb_disable_rc_polling)
318786baecfSMauro Carvalho Chehab 		return 0;
319786baecfSMauro Carvalho Chehab 
320786baecfSMauro Carvalho Chehab 	if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
321786baecfSMauro Carvalho Chehab 		d->props.rc.mode = DVB_RC_LEGACY;
322786baecfSMauro Carvalho Chehab 	else if (d->props.rc.core.rc_codes)
323786baecfSMauro Carvalho Chehab 		d->props.rc.mode = DVB_RC_CORE;
324786baecfSMauro Carvalho Chehab 	else
325786baecfSMauro Carvalho Chehab 		return 0;
326786baecfSMauro Carvalho Chehab 
327786baecfSMauro Carvalho Chehab 	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
328786baecfSMauro Carvalho Chehab 	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
329786baecfSMauro Carvalho Chehab 
330786baecfSMauro Carvalho Chehab 	/* Start the remote-control polling. */
331786baecfSMauro Carvalho Chehab 	if (d->props.rc.legacy.rc_interval < 40)
332786baecfSMauro Carvalho Chehab 		d->props.rc.legacy.rc_interval = 100; /* default */
333786baecfSMauro Carvalho Chehab 
334786baecfSMauro Carvalho Chehab 	if (d->props.rc.mode == DVB_RC_LEGACY)
335786baecfSMauro Carvalho Chehab 		err = legacy_dvb_usb_remote_init(d);
336786baecfSMauro Carvalho Chehab 	else
337786baecfSMauro Carvalho Chehab 		err = rc_core_dvb_usb_remote_init(d);
338786baecfSMauro Carvalho Chehab 	if (err)
339786baecfSMauro Carvalho Chehab 		return err;
340786baecfSMauro Carvalho Chehab 
341786baecfSMauro Carvalho Chehab 	d->state |= DVB_USB_STATE_REMOTE;
342786baecfSMauro Carvalho Chehab 
343786baecfSMauro Carvalho Chehab 	return 0;
344786baecfSMauro Carvalho Chehab }
345786baecfSMauro Carvalho Chehab 
dvb_usb_remote_exit(struct dvb_usb_device * d)346786baecfSMauro Carvalho Chehab int dvb_usb_remote_exit(struct dvb_usb_device *d)
347786baecfSMauro Carvalho Chehab {
348786baecfSMauro Carvalho Chehab 	if (d->state & DVB_USB_STATE_REMOTE) {
349786baecfSMauro Carvalho Chehab 		cancel_delayed_work_sync(&d->rc_query_work);
350786baecfSMauro Carvalho Chehab 		if (d->props.rc.mode == DVB_RC_LEGACY)
351786baecfSMauro Carvalho Chehab 			input_unregister_device(d->input_dev);
352786baecfSMauro Carvalho Chehab 		else
353786baecfSMauro Carvalho Chehab 			rc_unregister_device(d->rc_dev);
354786baecfSMauro Carvalho Chehab 	}
355786baecfSMauro Carvalho Chehab 	d->state &= ~DVB_USB_STATE_REMOTE;
356786baecfSMauro Carvalho Chehab 	return 0;
357786baecfSMauro Carvalho Chehab }
358786baecfSMauro Carvalho Chehab 
359786baecfSMauro Carvalho Chehab #define DVB_USB_RC_NEC_EMPTY           0x00
360786baecfSMauro Carvalho Chehab #define DVB_USB_RC_NEC_KEY_PRESSED     0x01
361786baecfSMauro Carvalho Chehab #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)362786baecfSMauro Carvalho Chehab int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
363786baecfSMauro Carvalho Chehab 		u8 keybuf[5], u32 *event, int *state)
364786baecfSMauro Carvalho Chehab {
365786baecfSMauro Carvalho Chehab 	int i;
366786baecfSMauro Carvalho Chehab 	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
367786baecfSMauro Carvalho Chehab 	*event = 0;
368786baecfSMauro Carvalho Chehab 	*state = REMOTE_NO_KEY_PRESSED;
369786baecfSMauro Carvalho Chehab 	switch (keybuf[0]) {
370786baecfSMauro Carvalho Chehab 		case DVB_USB_RC_NEC_EMPTY:
371786baecfSMauro Carvalho Chehab 			break;
372786baecfSMauro Carvalho Chehab 		case DVB_USB_RC_NEC_KEY_PRESSED:
373786baecfSMauro Carvalho Chehab 			if ((u8) ~keybuf[1] != keybuf[2] ||
374786baecfSMauro Carvalho Chehab 				(u8) ~keybuf[3] != keybuf[4]) {
375786baecfSMauro Carvalho Chehab 				deb_err("remote control checksum failed.\n");
376786baecfSMauro Carvalho Chehab 				break;
377786baecfSMauro Carvalho Chehab 			}
378786baecfSMauro Carvalho Chehab 			/* See if we can match the raw key code. */
379786baecfSMauro Carvalho Chehab 			for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
380786baecfSMauro Carvalho Chehab 				if (rc5_custom(&keymap[i]) == keybuf[1] &&
381786baecfSMauro Carvalho Chehab 					rc5_data(&keymap[i]) == keybuf[3]) {
382786baecfSMauro Carvalho Chehab 					*event = keymap[i].keycode;
383786baecfSMauro Carvalho Chehab 					*state = REMOTE_KEY_PRESSED;
384786baecfSMauro Carvalho Chehab 					return 0;
385786baecfSMauro Carvalho Chehab 				}
386786baecfSMauro Carvalho Chehab 			deb_err("key mapping failed - no appropriate key found in keymapping\n");
387786baecfSMauro Carvalho Chehab 			break;
388786baecfSMauro Carvalho Chehab 		case DVB_USB_RC_NEC_KEY_REPEATED:
389786baecfSMauro Carvalho Chehab 			*state = REMOTE_KEY_REPEAT;
390786baecfSMauro Carvalho Chehab 			break;
391786baecfSMauro Carvalho Chehab 		default:
392786baecfSMauro Carvalho Chehab 			deb_err("unknown type of remote status: %d\n",keybuf[0]);
393786baecfSMauro Carvalho Chehab 			break;
394786baecfSMauro Carvalho Chehab 	}
395786baecfSMauro Carvalho Chehab 	return 0;
396786baecfSMauro Carvalho Chehab }
397 EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
398