Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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; } 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 /*
 87  * Read the remote control and feed the appropriate event.
 88  * NEC protocol is used for remote controls
 89  */
 90 static int dibusb_read_remote_control(struct usb_dibusb *dib)
 91 {
 92         u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
 93         int ret;
 94         int i;
 95         if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
 96                 return ret;
 97 
 98         switch (rb[0]) {
 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]);
103 
104                         if ((0xff - rb[3]) != rb[4]) {
105                                 deb_rc("remote control checksum failed.\n");
106                                 break;
107                         }
108 
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);
120                                         break;
121                                 }
122                         }
123                         break;
124                 case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
125                         break;
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");
130                         break;
131                 default:
132                         break;
133         }
134         return 0;
135 }
136 
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)
140 {
141         struct usb_dibusb *dib = (struct usb_dibusb *) data;
142         /* TODO: need a lock here.  We can simply skip checking for the remote control
143            if we're busy. */
144         dibusb_read_remote_control(dib);
145         schedule_delayed_work(&dib->rc_query_work,
146                               msecs_to_jiffies(dib->rc_query_interval));
147 }
148 
149 int dibusb_remote_init(struct usb_dibusb *dib)
150 {
151         int i;
152 
153         if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
154                 return 0;
155         
156         /* Initialise the remote-control structures.*/
157         init_input_dev(&dib->rc_input_dev);
158 
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";
163 
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);
166 
167         input_register_device(&dib->rc_input_dev);
168 
169         dib->rc_input_event = KEY_MAX;
170 
171         INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
172 
173         /* Start the remote-control polling. */
174         if (dib->rc_query_interval < 40)
175                 dib->rc_query_interval = 100; /* default */
176 
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));
179 
180         dib->init_state |= DIBUSB_STATE_REMOTE;
181         
182         return 0;
183 }
184 
185 int dibusb_remote_exit(struct usb_dibusb *dib)
186 {
187         if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
188                 return 0;
189 
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);
194         }
195         dib->init_state &= ~DIBUSB_STATE_REMOTE;
196         return 0;
197 }
198 
  This page was automatically generated by the LXR engine.