smsir.c 7.7 KB

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