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 
  3  Siano Mobile Silicon, Inc.
  4  MDTV receiver kernel modules.
  5  Copyright (C) 2006-2009, Uri Shkolnik
  6 
  7  This program is free software: you can redistribute it and/or modify
  8  it under the terms of the GNU General Public License as published by
  9  the Free Software Foundation, either version 2 of the License, or
 10  (at your option) any later version.
 11 
 12  This program is distributed in the hope that it will be useful,
 13  but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  GNU General Public License for more details.
 16 
 17  You should have received a copy of the GNU General Public License
 18  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 19 
 20  ****************************************************************/
 21 
 22 
 23 #include <linux/types.h>
 24 #include <linux/input.h>
 25 
 26 #include "smscoreapi.h"
 27 #include "smsir.h"
 28 #include "sms-cards.h"
 29 
 30 /* In order to add new IR remote control -
 31  * 1) Add it to the <enum ir_kb_type> @ smsir,h,
 32  * 2) Add its map to keyboard_layout_maps below
 33  * 3) Set your board (sms-cards sub-module) to use it
 34  */
 35 
 36 static struct keyboard_layout_map_t keyboard_layout_maps[] = {
 37                 [SMS_IR_KB_DEFAULT_TV] = {
 38                         .ir_protocol = IR_RC5,
 39                         .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
 40                         .keyboard_layout_map = {
 41                                         KEY_0, KEY_1, KEY_2,
 42                                         KEY_3, KEY_4, KEY_5,
 43                                         KEY_6, KEY_7, KEY_8,
 44                                         KEY_9, 0, 0, KEY_POWER,
 45                                         KEY_MUTE, 0, 0,
 46                                         KEY_VOLUMEUP, KEY_VOLUMEDOWN,
 47                                         KEY_BRIGHTNESSUP,
 48                                         KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
 49                                         KEY_CHANNELDOWN,
 50                                         0, 0, 0, 0, 0, 0, 0, 0,
 51                                         0, 0, 0, 0, 0, 0, 0, 0,
 52                                         0, 0, 0, 0, 0, 0, 0, 0,
 53                                         0, 0, 0, 0, 0, 0, 0, 0,
 54                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 55                         }
 56                 },
 57                 [SMS_IR_KB_HCW_SILVER] = {
 58                         .ir_protocol = IR_RC5,
 59                         .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
 60                         .keyboard_layout_map = {
 61                                         KEY_0, KEY_1, KEY_2,
 62                                         KEY_3, KEY_4, KEY_5,
 63                                         KEY_6, KEY_7, KEY_8,
 64                                         KEY_9, KEY_TEXT, KEY_RED,
 65                                         KEY_RADIO, KEY_MENU,
 66                                         KEY_SUBTITLE,
 67                                         KEY_MUTE, KEY_VOLUMEUP,
 68                                         KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
 69                                         KEY_UP, KEY_DOWN, KEY_LEFT,
 70                                         KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
 71                                         KEY_MHP, KEY_EPG, KEY_TV,
 72                                         0, KEY_NEXTSONG, KEY_EXIT,
 73                                         KEY_CHANNELUP,  KEY_CHANNELDOWN,
 74                                         KEY_CHANNEL, 0,
 75                                         KEY_PREVIOUSSONG, KEY_ENTER,
 76                                         KEY_SLEEP, 0, 0, KEY_BLUE,
 77                                         0, 0, 0, 0, KEY_GREEN, 0,
 78                                         KEY_PAUSE, 0, KEY_REWIND,
 79                                         0, KEY_FASTFORWARD, KEY_PLAY,
 80                                         KEY_STOP, KEY_RECORD,
 81                                         KEY_YELLOW, 0, 0, KEY_SELECT,
 82                                         KEY_ZOOM, KEY_POWER, 0, 0
 83                         }
 84                 },
 85                 { } /* Terminating entry */
 86 };
 87 
 88 u32 ir_pos;
 89 u32     ir_word;
 90 u32 ir_toggle;
 91 
 92 #define RC5_PUSH_BIT(dst, bit, pos)     \
 93         { dst <<= 1; dst |= bit; pos++; }
 94 
 95 
 96 static void sms_ir_rc5_event(struct smscore_device_t *coredev,
 97                                 u32 toggle, u32 addr, u32 cmd)
 98 {
 99         bool toggle_changed;
100         u16 keycode;
101 
102         sms_log("IR RC5 word: address %d, command %d, toggle %d",
103                                 addr, cmd, toggle);
104 
105         toggle_changed = ir_toggle != toggle;
106         /* keep toggle */
107         ir_toggle = toggle;
108 
109         if (addr !=
110                 keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
111                 return; /* Check for valid address */
112 
113         keycode =
114                 keyboard_layout_maps
115                 [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
116 
117         if (!toggle_changed &&
118                         (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
119                 return; /* accept only repeated volume, reject other keys */
120 
121         sms_log("kernel input keycode (from ir) %d", keycode);
122         input_report_key(coredev->ir.input_dev, keycode, 1);
123         input_sync(coredev->ir.input_dev);
124 
125 }
126 
127 /* decode raw bit pattern to RC5 code */
128 /* taken from ir-functions.c */
129 static u32 ir_rc5_decode(unsigned int code)
130 {
131 /*      unsigned int org_code = code;*/
132         unsigned int pair;
133         unsigned int rc5 = 0;
134         int i;
135 
136         for (i = 0; i < 14; ++i) {
137                 pair = code & 0x3;
138                 code >>= 2;
139 
140                 rc5 <<= 1;
141                 switch (pair) {
142                 case 0:
143                 case 2:
144                         break;
145                 case 1:
146                         rc5 |= 1;
147                         break;
148                 case 3:
149 /*      dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
150                         sms_log("bad code");
151                         return 0;
152                 }
153         }
154 /*
155         dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
156                 toggle=%x, address=%x, "
157                 "instr=%x\n", rc5, org_code, RC5_START(rc5),
158                 RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
159 */
160         return rc5;
161 }
162 
163 static void sms_rc5_parse_word(struct smscore_device_t *coredev)
164 {
165         #define RC5_START(x)    (((x)>>12)&3)
166         #define RC5_TOGGLE(x)   (((x)>>11)&1)
167         #define RC5_ADDR(x)     (((x)>>6)&0x1F)
168         #define RC5_INSTR(x)    ((x)&0x3F)
169 
170         int i, j;
171         u32 rc5_word = 0;
172 
173         /* Reverse the IR word direction */
174         for (i = 0 ; i < 28 ; i++)
175                 RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
176 
177         rc5_word = ir_rc5_decode(rc5_word);
178         /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
179 
180         sms_ir_rc5_event(coredev,
181                                 RC5_TOGGLE(rc5_word),
182                                 RC5_ADDR(rc5_word),
183                                 RC5_INSTR(rc5_word));
184 }
185 
186 
187 static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
188                 s32 ir_sample)
189 {
190         #define RC5_TIME_GRANULARITY    200
191         #define RC5_DEF_BIT_TIME                889
192         #define RC5_MAX_SAME_BIT_CONT   4
193         #define RC5_WORD_LEN                    27 /* 28 bit */
194 
195         u32 i, j;
196         s32 delta_time;
197         u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
198         u32 level = (ir_sample < 0) ? 0 : 1;
199 
200         for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
201                 delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
202                 if (delta_time < 0)
203                         continue; /* not so many consecutive bits */
204                 if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
205                         /* timeout */
206                         if (ir_pos == (RC5_WORD_LEN-1))
207                                 /* complete last bit */
208                                 RC5_PUSH_BIT(ir_word, level, ir_pos)
209 
210                         if (ir_pos == RC5_WORD_LEN)
211                                 sms_rc5_parse_word(coredev);
212                         else if (ir_pos) /* timeout within a word */
213                                 sms_log("IR error parsing a word");
214 
215                         ir_pos = 0;
216                         ir_word = 0;
217                         /* sms_log("timeout %d", time); */
218                         break;
219                 }
220                 /* The time is within the range of this number of bits */
221                 for (j = 0 ; j < i ; j++)
222                         RC5_PUSH_BIT(ir_word, level, ir_pos)
223 
224                 break;
225         }
226 }
227 
228 void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
229 {
230         #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
231         u32 i;
232         enum ir_protocol ir_protocol =
233                         keyboard_layout_maps[coredev->ir.ir_kb_type]
234                                              .ir_protocol;
235         s32 *samples;
236         int count = len>>2;
237 
238         samples = (s32 *)buf;
239 /*      sms_log("IR buffer received, length = %d", count);*/
240 
241         for (i = 0; i < count; i++)
242                 if (ir_protocol == IR_RC5)
243                         sms_rc5_accumulate_bits(coredev, samples[i]);
244         /*  IR_RCMM not implemented */
245 }
246 
247 int sms_ir_init(struct smscore_device_t *coredev)
248 {
249         struct input_dev *input_dev;
250 
251         sms_log("Allocating input device");
252         input_dev = input_allocate_device();
253         if (!input_dev) {
254                 sms_err("Not enough memory");
255                 return -ENOMEM;
256         }
257 
258         coredev->ir.input_dev = input_dev;
259         coredev->ir.ir_kb_type =
260                 sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
261         coredev->ir.keyboard_layout_map =
262                 keyboard_layout_maps[coredev->ir.ir_kb_type].
263                                 keyboard_layout_map;
264         sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
265 
266         coredev->ir.controller = 0;     /* Todo: vega/nova SPI number */
267         coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
268         sms_log("IR port %d, timeout %d ms",
269                         coredev->ir.controller, coredev->ir.timeout);
270 
271         snprintf(coredev->ir.name,
272                                 IR_DEV_NAME_MAX_LEN,
273                                 "SMS IR w/kbd type %d",
274                                 coredev->ir.ir_kb_type);
275         input_dev->name = coredev->ir.name;
276         input_dev->phys = coredev->ir.name;
277         input_dev->dev.parent = coredev->device;
278 
279         /* Key press events only */
280         input_dev->evbit[0] = BIT_MASK(EV_KEY);
281         input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
282 
283         sms_log("Input device (IR) %s is set for key events", input_dev->name);
284 
285         if (input_register_device(input_dev)) {
286                 sms_err("Failed to register device");
287                 input_free_device(input_dev);
288                 return -EACCES;
289         }
290 
291         return 0;
292 }
293 
294 void sms_ir_exit(struct smscore_device_t *coredev)
295 {
296         if (coredev->ir.input_dev)
297                 input_unregister_device(coredev->ir.input_dev);
298 
299         sms_log("");
300 }
301 
302 
  This page was automatically generated by the LXR engine.