Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 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/) |
| 4 | * |
| 5 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) |
| 6 | * |
| 7 | * see dvb-dibusb-core.c for more copyright details. |
| 8 | * |
| 9 | * This file contains functions for handling the event device on the software |
| 10 | * side and the remote control on the hardware side. |
| 11 | */ |
| 12 | #include "dvb-dibusb.h" |
| 13 | |
| 14 | /* Table to map raw key codes to key events. This should not be hard-wired |
| 15 | into the kernel. */ |
| 16 | static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] = |
| 17 | { |
| 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 }, |
| 84 | }; |
| 85 | |
| 86 | /* Hauppauge NOVA-T USB2 keys */ |
| 87 | static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = { |
| 88 | { 0xddf, KEY_GOTO }, |
| 89 | { 0xdef, KEY_POWER }, |
| 90 | { 0xce7, KEY_TV }, |
| 91 | { 0xcc7, KEY_VIDEO }, |
| 92 | { 0xccf, KEY_AUDIO }, |
| 93 | { 0xcd7, KEY_MEDIA }, |
| 94 | { 0xcdf, KEY_EPG }, |
| 95 | { 0xca7, KEY_UP }, |
| 96 | { 0xc67, KEY_RADIO }, |
| 97 | { 0xcb7, KEY_LEFT }, |
| 98 | { 0xd2f, KEY_OK }, |
| 99 | { 0xcbf, KEY_RIGHT }, |
| 100 | { 0xcff, KEY_BACK }, |
| 101 | { 0xcaf, KEY_DOWN }, |
| 102 | { 0xc6f, KEY_MENU }, |
| 103 | { 0xc87, KEY_VOLUMEUP }, |
| 104 | { 0xc8f, KEY_VOLUMEDOWN }, |
| 105 | { 0xc97, KEY_CHANNEL }, |
| 106 | { 0xc7f, KEY_MUTE }, |
| 107 | { 0xd07, KEY_CHANNELUP }, |
| 108 | { 0xd0f, KEY_CHANNELDOWN }, |
| 109 | { 0xdbf, KEY_RECORD }, |
| 110 | { 0xdb7, KEY_STOP }, |
| 111 | { 0xd97, KEY_REWIND }, |
| 112 | { 0xdaf, KEY_PLAY }, |
| 113 | { 0xda7, KEY_FASTFORWARD }, |
| 114 | { 0xd27, KEY_LAST }, /* Skip backwards */ |
| 115 | { 0xd87, KEY_PAUSE }, |
| 116 | { 0xcf7, KEY_NEXT }, |
| 117 | { 0xc07, KEY_0 }, |
| 118 | { 0xc0f, KEY_1 }, |
| 119 | { 0xc17, KEY_2 }, |
| 120 | { 0xc1f, KEY_3 }, |
| 121 | { 0xc27, KEY_4 }, |
| 122 | { 0xc2f, KEY_5 }, |
| 123 | { 0xc37, KEY_6 }, |
| 124 | { 0xc3f, KEY_7 }, |
| 125 | { 0xc47, KEY_8 }, |
| 126 | { 0xc4f, KEY_9 }, |
| 127 | { 0xc57, KEY_KPASTERISK }, |
| 128 | { 0xc77, KEY_GRAVE }, /* # */ |
| 129 | { 0xc5f, KEY_RED }, |
| 130 | { 0xd77, KEY_GREEN }, |
| 131 | { 0xdc7, KEY_YELLOW }, |
| 132 | { 0xd4f, KEY_BLUE}, |
| 133 | }; |
| 134 | |
| 135 | static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5]) |
| 136 | { |
| 137 | int i; |
| 138 | switch (rb[0]) { |
| 139 | case DIBUSB_RC_NEC_KEY_PRESSED: |
| 140 | /* rb[1-3] is the actual key, rb[4] is a checksum */ |
| 141 | deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", |
| 142 | rb[1], rb[2], rb[3], rb[4]); |
| 143 | |
| 144 | if ((0xff - rb[3]) != rb[4]) { |
| 145 | deb_rc("remote control checksum failed.\n"); |
| 146 | break; |
| 147 | } |
| 148 | |
| 149 | /* See if we can match the raw key code. */ |
| 150 | for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) { |
| 151 | if (nec_rc_keys[i].c0 == rb[1] && |
| 152 | nec_rc_keys[i].c1 == rb[2] && |
| 153 | nec_rc_keys[i].c2 == rb[3]) { |
| 154 | |
| 155 | dib->last_event = nec_rc_keys[i].key; |
| 156 | return 1; |
| 157 | } |
| 158 | } |
| 159 | break; |
| 160 | case DIBUSB_RC_NEC_KEY_REPEATED: |
| 161 | /* rb[1]..rb[4] are always zero.*/ |
| 162 | /* Repeats often seem to occur so for the moment just ignore this. */ |
| 163 | return 0; |
| 164 | case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */ |
| 165 | default: |
| 166 | break; |
| 167 | } |
| 168 | return -1; |
| 169 | } |
| 170 | |
| 171 | static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4]) |
| 172 | { |
| 173 | u16 raw; |
| 174 | int i,state; |
| 175 | switch (rb[0]) { |
| 176 | case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED: |
| 177 | raw = ((rb[1] & 0x0f) << 8) | rb[2]; |
| 178 | |
| 179 | state = !!(rb[1] & 0x40); |
| 180 | |
| 181 | deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state); |
| 182 | for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) { |
| 183 | if (haupp_rc_keys[i].raw == raw) { |
| 184 | if (dib->last_event == haupp_rc_keys[i].key && |
| 185 | dib->last_state == state) { |
| 186 | deb_rc("key repeat\n"); |
| 187 | return 0; |
| 188 | } else { |
| 189 | dib->last_event = haupp_rc_keys[i].key; |
| 190 | dib->last_state = state; |
| 191 | return 1; |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | break; |
| 197 | case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY: |
| 198 | default: |
| 199 | break; |
| 200 | } |
| 201 | return -1; |
| 202 | } |
| 203 | |
| 204 | /* |
| 205 | * Read the remote control and feed the appropriate event. |
| 206 | * NEC protocol is used for remote controls |
| 207 | */ |
| 208 | static int dibusb_read_remote_control(struct usb_dibusb *dib) |
| 209 | { |
| 210 | u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5]; |
| 211 | int ret,event = 0; |
| 212 | |
| 213 | if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5))) |
| 214 | return ret; |
| 215 | |
| 216 | switch (dib->dibdev->dev_cl->remote_type) { |
| 217 | case DIBUSB_RC_NEC_PROTOCOL: |
| 218 | event = dibusb_key2event_nec(dib,rb); |
| 219 | break; |
| 220 | case DIBUSB_RC_HAUPPAUGE_PROTO: |
| 221 | event = dibusb_key2event_hauppauge(dib,rb); |
| 222 | default: |
| 223 | break; |
| 224 | } |
| 225 | |
| 226 | /* key repeat */ |
| 227 | if (event == 0) |
| 228 | if (++dib->repeat_key_count < dib->rc_key_repeat_count) { |
| 229 | deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count); |
| 230 | event = -1; /* skip this key repeat */ |
| 231 | } |
| 232 | |
| 233 | if (event == 1 || event == 0) { |
| 234 | deb_rc("Translated key 0x%04x\n",event); |
| 235 | |
| 236 | /* Signal down and up events for this key. */ |
| 237 | input_report_key(&dib->rc_input_dev, dib->last_event, 1); |
| 238 | input_report_key(&dib->rc_input_dev, dib->last_event, 0); |
| 239 | input_sync(&dib->rc_input_dev); |
| 240 | |
| 241 | if (event == 1) |
| 242 | dib->repeat_key_count = 0; |
| 243 | } |
| 244 | return 0; |
| 245 | } |
| 246 | |
| 247 | /* Remote-control poll function - called every dib->rc_query_interval ms to see |
| 248 | whether the remote control has received anything. */ |
| 249 | static void dibusb_remote_query(void *data) |
| 250 | { |
| 251 | struct usb_dibusb *dib = (struct usb_dibusb *) data; |
| 252 | /* TODO: need a lock here. We can simply skip checking for the remote control |
| 253 | if we're busy. */ |
| 254 | dibusb_read_remote_control(dib); |
| 255 | schedule_delayed_work(&dib->rc_query_work, |
| 256 | msecs_to_jiffies(dib->rc_query_interval)); |
| 257 | } |
| 258 | |
| 259 | int dibusb_remote_init(struct usb_dibusb *dib) |
| 260 | { |
| 261 | int i; |
| 262 | |
| 263 | if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO) |
| 264 | return 0; |
| 265 | |
| 266 | /* Initialise the remote-control structures.*/ |
| 267 | init_input_dev(&dib->rc_input_dev); |
| 268 | |
| 269 | dib->rc_input_dev.evbit[0] = BIT(EV_KEY); |
| 270 | dib->rc_input_dev.keycodesize = sizeof(unsigned char); |
| 271 | dib->rc_input_dev.keycodemax = KEY_MAX; |
| 272 | dib->rc_input_dev.name = DRIVER_DESC " remote control"; |
| 273 | |
| 274 | switch (dib->dibdev->dev_cl->remote_type) { |
| 275 | case DIBUSB_RC_NEC_PROTOCOL: |
| 276 | for (i=0; i<sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) |
| 277 | set_bit(nec_rc_keys[i].key, dib->rc_input_dev.keybit); |
| 278 | break; |
| 279 | case DIBUSB_RC_HAUPPAUGE_PROTO: |
| 280 | for (i=0; i<sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) |
| 281 | set_bit(haupp_rc_keys[i].key, dib->rc_input_dev.keybit); |
| 282 | break; |
| 283 | default: |
| 284 | break; |
| 285 | } |
| 286 | |
| 287 | |
| 288 | input_register_device(&dib->rc_input_dev); |
| 289 | |
| 290 | INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib); |
| 291 | |
| 292 | /* Start the remote-control polling. */ |
| 293 | if (dib->rc_query_interval < 40) |
| 294 | dib->rc_query_interval = 100; /* default */ |
| 295 | |
| 296 | info("schedule remote query interval to %d msecs.",dib->rc_query_interval); |
| 297 | schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(dib->rc_query_interval)); |
| 298 | |
| 299 | dib->init_state |= DIBUSB_STATE_REMOTE; |
| 300 | |
| 301 | return 0; |
| 302 | } |
| 303 | |
| 304 | int dibusb_remote_exit(struct usb_dibusb *dib) |
| 305 | { |
| 306 | if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO) |
| 307 | return 0; |
| 308 | |
| 309 | if (dib->init_state & DIBUSB_STATE_REMOTE) { |
| 310 | cancel_delayed_work(&dib->rc_query_work); |
| 311 | flush_scheduled_work(); |
| 312 | input_unregister_device(&dib->rc_input_dev); |
| 313 | } |
| 314 | dib->init_state &= ~DIBUSB_STATE_REMOTE; |
| 315 | return 0; |
| 316 | } |