2 * dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices
3 * based on reference design made by DiBcom (http://www.dibcom.fr/)
5 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
7 * see dvb-dibusb-core.c for more copyright details.
9 * This file contains functions for handling the event device on the software
10 * side and the remote control on the hardware side.
12 #include "dvb-dibusb.h"
14 /* Table to map raw key codes to key events. This should not be hard-wired
16 static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
18 /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
19 { 0x00, 0xff, 0x16, KEY_POWER },
20 { 0x00, 0xff, 0x10, KEY_MUTE },
21 { 0x00, 0xff, 0x03, KEY_1 },
22 { 0x00, 0xff, 0x01, KEY_2 },
23 { 0x00, 0xff, 0x06, KEY_3 },
24 { 0x00, 0xff, 0x09, KEY_4 },
25 { 0x00, 0xff, 0x1d, KEY_5 },
26 { 0x00, 0xff, 0x1f, KEY_6 },
27 { 0x00, 0xff, 0x0d, KEY_7 },
28 { 0x00, 0xff, 0x19, KEY_8 },
29 { 0x00, 0xff, 0x1b, KEY_9 },
30 { 0x00, 0xff, 0x15, KEY_0 },
31 { 0x00, 0xff, 0x05, KEY_CHANNELUP },
32 { 0x00, 0xff, 0x02, KEY_CHANNELDOWN },
33 { 0x00, 0xff, 0x1e, KEY_VOLUMEUP },
34 { 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN },
35 { 0x00, 0xff, 0x11, KEY_RECORD },
36 { 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
37 { 0x00, 0xff, 0x14, KEY_PLAY },
38 { 0x00, 0xff, 0x1a, KEY_STOP },
39 { 0x00, 0xff, 0x40, KEY_REWIND },
40 { 0x00, 0xff, 0x12, KEY_FASTFORWARD },
41 { 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
42 { 0x00, 0xff, 0x4c, KEY_PAUSE },
43 { 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
44 { 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
45 /* additional keys TwinHan VisionPlus, the Artec seemingly not have */
46 { 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
47 { 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
48 { 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
49 { 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
50 { 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
51 { 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
52 /* Key codes for the KWorld/ADSTech/JetWay remote. */
53 { 0x86, 0x6b, 0x12, KEY_POWER },
54 { 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
55 { 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */
56 { 0x86, 0x6b, 0x0b, KEY_EPG },
57 { 0x86, 0x6b, 0x10, KEY_MUTE },
58 { 0x86, 0x6b, 0x01, KEY_1 },
59 { 0x86, 0x6b, 0x02, KEY_2 },
60 { 0x86, 0x6b, 0x03, KEY_3 },
61 { 0x86, 0x6b, 0x04, KEY_4 },
62 { 0x86, 0x6b, 0x05, KEY_5 },
63 { 0x86, 0x6b, 0x06, KEY_6 },
64 { 0x86, 0x6b, 0x07, KEY_7 },
65 { 0x86, 0x6b, 0x08, KEY_8 },
66 { 0x86, 0x6b, 0x09, KEY_9 },
67 { 0x86, 0x6b, 0x0a, KEY_0 },
68 { 0x86, 0x6b, 0x18, KEY_ZOOM },
69 { 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */
70 { 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */
71 { 0x86, 0x6b, 0x00, KEY_UNDO },
72 { 0x86, 0x6b, 0x1d, KEY_RECORD },
73 { 0x86, 0x6b, 0x0d, KEY_STOP },
74 { 0x86, 0x6b, 0x0e, KEY_PAUSE },
75 { 0x86, 0x6b, 0x16, KEY_PLAY },
76 { 0x86, 0x6b, 0x11, KEY_BACK },
77 { 0x86, 0x6b, 0x19, KEY_FORWARD },
78 { 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */
79 { 0x86, 0x6b, 0x15, KEY_ESC },
80 { 0x86, 0x6b, 0x1a, KEY_UP },
81 { 0x86, 0x6b, 0x1e, KEY_DOWN },
82 { 0x86, 0x6b, 0x1f, KEY_LEFT },
83 { 0x86, 0x6b, 0x1b, KEY_RIGHT },
87 * Read the remote control and feed the appropriate event.
88 * NEC protocol is used for remote controls
90 static int dibusb_read_remote_control(struct usb_dibusb *dib)
92 u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
95 if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
99 case DIBUSB_RC_NEC_KEY_PRESSED:
100 /* rb[1-3] is the actual key, rb[4] is a checksum */
101 deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
102 rb[1], rb[2], rb[3], rb[4]);
104 if ((0xff - rb[3]) != rb[4]) {
105 deb_rc("remote control checksum failed.\n");
109 /* See if we can match the raw key code. */
110 for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) {
111 if (rc_keys[i].c0 == rb[1] &&
112 rc_keys[i].c1 == rb[2] &&
113 rc_keys[i].c2 == rb[3]) {
114 dib->rc_input_event = rc_keys[i].key;
115 deb_rc("Translated key 0x%04x\n", dib->rc_input_event);
116 /* Signal down and up events for this key. */
117 input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1);
118 input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0);
119 input_sync(&dib->rc_input_dev);
124 case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
126 case DIBUSB_RC_NEC_KEY_REPEATED:
127 /* rb[1]..rb[4] are always zero.*/
128 /* Repeats often seem to occur so for the moment just ignore this. */
129 deb_rc("Key repeat\n");
137 /* Remote-control poll function - called every dib->rc_query_interval ms to see
138 whether the remote control has received anything. */
139 static void dibusb_remote_query(void *data)
141 struct usb_dibusb *dib = (struct usb_dibusb *) data;
142 /* TODO: need a lock here. We can simply skip checking for the remote control
144 dibusb_read_remote_control(dib);
145 schedule_delayed_work(&dib->rc_query_work,
146 msecs_to_jiffies(dib->rc_query_interval));
149 int dibusb_remote_init(struct usb_dibusb *dib)
153 if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
156 /* Initialise the remote-control structures.*/
157 init_input_dev(&dib->rc_input_dev);
159 dib->rc_input_dev.evbit[0] = BIT(EV_KEY);
160 dib->rc_input_dev.keycodesize = sizeof(unsigned char);
161 dib->rc_input_dev.keycodemax = KEY_MAX;
162 dib->rc_input_dev.name = DRIVER_DESC " remote control";
164 for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
165 set_bit(rc_keys[i].key, dib->rc_input_dev.keybit);
167 input_register_device(&dib->rc_input_dev);
169 dib->rc_input_event = KEY_MAX;
171 INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
173 /* Start the remote-control polling. */
174 if (dib->rc_query_interval < 40)
175 dib->rc_query_interval = 100; /* default */
177 info("schedule remote query interval to %d msecs.",dib->rc_query_interval);
178 schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(dib->rc_query_interval));
180 dib->init_state |= DIBUSB_STATE_REMOTE;
185 int dibusb_remote_exit(struct usb_dibusb *dib)
187 if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
190 if (dib->init_state & DIBUSB_STATE_REMOTE) {
191 cancel_delayed_work(&dib->rc_query_work);
192 flush_scheduled_work();
193 input_unregister_device(&dib->rc_input_dev);
195 dib->init_state &= ~DIBUSB_STATE_REMOTE;