• 前言
    • 失之东隅,收之桑榆

参考文章

  本文中的所有内容大部分来源于网络资料,如有侵权请联系本人修改或删除,请大家多多支持原创!非常感谢!

1. 海思红外遥控

  • adb 调试相关命令
    • cat /proc/bus/input/devices 查看input设备
    • dumpsys input 查看input设备
    • gatevent -l 查看输入event事件

1.1 遥控器逻辑过程以及源码分析

  • 逻辑过程
    • 从xml中获取物理键值,配对解析
    • linux的标准键值
    • 自定义的字符串
    • 定义这个字符串
    • android标准键值
    • android键值上报
    • 按键事件处理

1.1.1 协议相关

  • 涉及模块
    • device/hisilicon/bigfish/sdk/source/msp/drv/ir/ir_s2
    • device/hisilicon/bigfish/system/ir_user/key_pars

  有需求才有产品,有产品才有代码。上一篇文章遥控模拟App简单的介绍了三种协议,这里我们着重分析一下海思红外协议。主要是我们当前的产品无法配置SONY协议,因为SONY的遥控的遥控器头码有点特殊,按照正常情况下应该要高位补位,将解析出来的数据码进行上报。这里就简单分析一下SONY协议相关源码解析。

  这里只需要关心几个文件即可(SONY上报的数据位不正确,这里分析SONY协议)

  • device/hisilicon/bigfish/sdk/source/msp/drv/ir/ir_s2/drv_ir_protocols_descript.h
  • device/hisilicon/bigfish/sdk/source/msp/drv/ir/ir_s2/drv_ir_protocol_entry.c
  • device/hisilicon/bigfish/sdk/source/msp/drv/ir/ir_s2/drv_ir_sony.c

  drv_ir_protocols_descript.h中,定义所有支持的协议,然后根据不同的协议进行解析。以NEC协议为例,在drv_ir_protocols_descript.h中定义了NEC协议的相关属性。比如开始的header,burst,repeat等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
* NOTE: When you are adding a protocol to this array,
* please make sure there are no header phase are simlar
* and wanna_bits is the same.
*
* If the case descripted before happened,
* you should consider the two infra code are the same,
* and its no necessary to add the new code.
*
* - Becareful to modify the factor of header/burst/repeat header.
* The factor of these too large will due to one protocol may
* parsed as another.
* Author: DPT_BSP
* Create: 2018-12-22
*/

#ifndef __IR_PROTOCOLS_DESCRIPT_H__
#define __IR_PROTOCOLS_DESCRIPT_H__

#include "drv_ir_priv.h"
#include "drv_ir_protocol.h"

static struct ir_protocol g_ir_protocols[] = {
#ifdef NEC_SUPPORT
/*
* NEC simple repeate constains
* uPD6121G/D6121/BU5777/D1913
*/
{
.node = { 0 }, /* list */
.ir_code_name = NEC_SIMPLE_UPD6121G, /* protocol name */
.idx = IR_PROT_COMSIMPLE, /* protocol */
.attr =
{
/* protocol attr */
.header = { 9000, 4500, 10 }, /* header phase */ //维沃遥控反应慢把10 改到50
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 560, 560, 50 }, /* b0 phase */
.b1 = { 560, 1690, 50 }, /* b1 phase */
.burst = { 560, 48800, 50 }, /* burst phase */
.repeat = { 9000, 2250, 20 }, /* repeate phase */ //维沃遥控反应慢把20 改到50
.repeat_burst = { 560, 98500, 50 }, /* repeate burst phase */
.wanna_bits = 32, /* wanna bits */
.burst_offset = 33 /* burst at */ //维沃遥控反应慢把33 改到32
},
.match = nec_match, /* phase matcher */
.priv = 0, /* private data */
.handle = nec_frame_parse, /* fram parser */
.key_hold_timeout_time = 300, /* key_hold_timeout_time */ //维沃遥控反应慢把300 改到120
.disabled = 0 /* num:0: enable; 1: disable */ //如果不行尝试把0 改成1
},
/* dezhou */
{
.node = { 0 }, /* list */
.ir_code_name = NEC_FULL, /* protocol name */
.idx = IR_PROT_COMFULL, /* protocol */
.attr =
{ /* protocol attr */
.header = { 3500, 1700, 25 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 400, 400, 50 }, /* b0 phase */
.b1 = { 400, 1350, 50 }, /* b1 phase */
.burst = { 400, 100000, 25 }, /* burst phase */
.repeat = { 655350, 655350, 20 }, /* repeate phase: dezhou doesn't have it */
.repeat_burst = { 400, 100000, 50}, /* repeate burst phase */
.wanna_bits = 48, /* wanna bits */
.burst_offset = 49 /* burst at */
},
.match = nec_match, /* phase matcher */
.priv = 4, /* private data */
.handle = nec_frame_parse, /* frame parser */
.key_hold_timeout_time = 300, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef NECJVC_SUPPORT
{
.node = { 0 }, /* list */
.ir_code_name = NEC_JVC, /* protocol name */
.idx = IR_PROT_NECJVC, /* protocol */
.attr =
{
/* protocol attr */
.header = { 8400, 4200, 10 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 526, 526, 20 }, /* b0 phase */
.b1 = { 526, 1574, 20 }, /* b1 phase */
.burst = { 526, 655350, 50 }, /* burst phase */
.repeat = { 526, 35900, 20 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 16, /* wanna bits */
.burst_offset = 0 /* burst at */
},
.match = nec_jvc_match, /* phase matcher */
.priv = 0, /* private data */
.handle = nec_jvc_frame_parse, /* fram parser */
.key_hold_timeout_time = 0, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef SAMSUNG_SUPPORT
/* samsung */
{
.node = { 0 }, /* list */
.ir_code_name = SAMSUNG, /* protocol name */
.idx = IR_PROT_SAMSUNG, /* protocol */
.attr =
{
/* protocol attr */
.header = { 4500, 4500, 10 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 560, 560, 50 }, /* b0 phase */
.b1 = { 560, 1690, 50 }, /* b1 phase */
.burst = { 560, 40000, 40 }, /* burst phase */
.repeat = { 0, 0, 0 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 32, /* wanna bits */
.burst_offset = 32 /* burst at */
},
.match = samsung_match, /* phase matcher */
.priv = 0, /* private data */
.handle = samsung_frame_parse, /* frame parser */
.key_hold_timeout_time = 300, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef SONY_SUPPORT

/* sony d7c5 */
{
.node = { 0 }, /* list */
.ir_code_name = SONY_D7C5, /* protocol name */
.idx = IR_PROT_SONY, /* protocol */
.attr =
{
/* protocol attr */
.header = { 2400, 600, 20 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 600, 600, 20 }, /* b0 phase */
.b1 = { 1200, 600, 20 }, /* b1 phase */
.burst = { 600, 25000, 20 }, /* burst phase */
.repeat = { 0, 0, 0 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 12, /* wanna bits */
.burst_offset = 12 /* burst at */
},
.match = sony_match, /* phase matcher */
.priv = 0, /* private data */
.handle = sony_frame_full_parse, /* frame parser */
.key_hold_timeout_time = 0, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef RC6_SUPPORT
/* rc62 */ /* philips dvd player */
{
.node = { 0 }, /* list */
.ir_code_name = RC6_16BIT, /* protocol name */
.idx = IR_PROT_RC6, /* protocol */
// | INFR_HAS_ERR_HANDLE, /* flag */
.attr =
{
/* protocol attr */
.header = { 2666, 889, 30 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 0, 0, 0 }, /* b0 phase */
.b1 = { 0, 0, 0 }, /* b1 phase */
.burst = { 0, 40000, 50 }, /* burst phase */
.repeat = { 0, 0, 0 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 16, /* wanna bits */
.burst_offset = 16 /* burst at */
},
.match = rc6_match, /* phase matcher */
.priv = 0, /* private data */
.handle = rc6_frame_parse, /* frame parser */
.key_hold_timeout_time = 220, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef RC5_SUPPORT
/* rc5 */
{
.node = { 0 }, /* list */
.ir_code_name = RC5_14BIT, /* protocol name */
.idx = IR_PROT_RC5, /* protocol */
.attr =
{
/* protocol attr */
.header = { 889, 889, 20 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 889, 889, 50 }, /* b0 phase */
.b1 = { 889, 889, 50 }, /* b1 phase */
.burst = { 889, 40000, 50 }, /* burst phase */
.repeat = { 0, 0, 0 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 14, /* wanna bits */
.burst_offset = 11 /* burst at */
},
.match = rc5_match, /* phase matcher */
.priv = 0, /* private data */
.handle = rc5_frame_parse, /* frame parser */
.key_hold_timeout_time = 0, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef KALE_SUPPORT
/* KALE */
{
.node = { 0 }, /* list */
.ir_code_name = KALE, /* protocol name */
.idx = IR_PROT_KALE, /* protocol */
.attr =
{
/* protocol attr */
.header = { 3000, 3000, 10 }, /* header phase */
.second_header = { 500, 4000, 10 }, /* second header */
.second_header_at = 17, /* second header at */
.b0 = { 500, 1500, 10 }, /* b0 phase */
.b1 = { 500, 2500, 10 }, /* b1 phase */
.burst = { 500, 10000, 10 }, /* no use */
.repeat = { 0, 0, 0 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 16, /* wanna bits */
.burst_offset = 18 /* burst at */
},
.match = kale_match, /* phase matcher */
.priv = 0, /* private data */
.handle = kale_frame_parse, /* fram parser */
.key_hold_timeout_time = 0, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef RCA_SUPPORT
/* RCA */
{
.node = { 0 }, /* list */
.ir_code_name = RCA, /* protocol name */
.idx = IR_PROT_RCA, /* protocol */
.attr =
{
/* protocol attr */
.header = { 4000, 4000, 10 }, /* header phase */
.second_header = { 0, 0, 0 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 560, 1000, 50 }, /* b0 phase */
.b1 = { 560, 2000, 50 }, /* b1 phase */
.burst = { 560, 8000, 50 }, /* burst phase */
.repeat = { 560, 50000, 50 }, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 24, /* wanna bits */
.burst_offset = 24 /* burst at .because no header,so data in 0~14,burst at 15 */
},
.match = rca_match, /* phase matcher */
.priv = 0, /* private data */
.handle = rca_frame_parse, /* fram parser */
.key_hold_timeout_time = 220, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef MITSUBISHI_SUPPORT
/* MITSUBISHI */
{
.node = { 0 }, /* list */
.ir_code_name = MITSUBISHI, /* protocol name */
.idx = IR_PROT_MITSUBISHI, /* protocol */
.attr =
{
/* protocol attr */
.header = { 8000, 4000, 10 }, /* header phase */
.second_header = { 500, 4000, 20 }, /* The first sync bit */
.second_header_at = 8, /* second header at */
.b0 = { 500, 500, 20 }, /* b0 phase */
.b1 = { 500, 1500, 20 }, /* b1 phase */
.burst = { 500, 18000, 20 }, /* burst phase */
.repeat = { 0, 0, 0}, /* repeate phase */
.repeat_burst = { 0, 0, 0 }, /* repeate burst phase */
.wanna_bits = 16, /* wanna bits */
.burst_offset = 16 /* burst at .because no header,so data in 0~14,burst at 15 */
},
.match = mitsubishi_match, /* phase matcher */
.priv = 0, /* private data */
.handle = mitsubishi_frame_parse, /* fram parser */
.key_hold_timeout_time = 300, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef TC9012_SUPPORT
/* tc9012 */
{
.node = { 0 }, /* list */
.ir_code_name =TC9012, /* protocol name */
.idx = IR_PROT_TC9012, /* protocol */
.attr =
{
/* protocol attr */
.header = { 4500, 4500, 10 }, /* header phase */
.second_header = { 560, 40000, 20 }, /* second header */
.second_header_at = 0, /* second header at */
.b0 = { 560, 560, 50 }, /* b0 phase */
.b1 = { 560, 1690, 50 }, /* b1 phase */
.burst = { 560, 59000, 40 }, /* burst phase */
.repeat = { 4500, 4500, 10 }, /* repeate phase */
.repeat_burst = { 560, 107000, 50 }, /* repeate burst phase */
.wanna_bits = 32, /* wanna bits */
.burst_offset = 33 /* burst at */
},
.match = tc9012_match, /* phase matcher */
.priv = 0, /* private data */
.handle = tc9012_frame_parse, /* frame parser */
.key_hold_timeout_time = 300, /* key_hold_timeout_time, 0 means using the default value */
.disabled = 0 /* num:0: enable; 1: disable */
},
#endif

#ifdef SOYBEAN_SUPPORT
/* SOYBEAN */
{
.idx = IR_PROT_USER_DEFINED1,
.ir_code_name = "SOYBEAN",
.match = soybean_match,
.handle = soybean_frame_parse,
},
#endif

/* DO NOT REMOVE THIS. */
{ { 0 }, NULL, IR_PROT_BUTT, { { 0 } }, NULL, 0, NULL }
};

#endif


  drv_ir_protocol_entry.c这里做的一件事就是ir_protocol_init注册协议,然后当按键按下的时候根据波形的结构体,先去匹配头,查看是否有匹配的协议,然后调用对应的解析函数。按下去的一瞬间会产生4-5个波形,所以足够正确解析出对应的协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
* Description:drv_ir_protocol_entry.c
* Author: DPT_BSP
* Create: 2011-11-29
*/

#include "drv_ir_priv.h"
#include "drv_ir_protocol.h"
#include "drv_ir_utils.h"
#include "drv_ir_protocols_descript.h"
#include "securec.h"
static struct osal_list_head g_ir_prot_head;
#ifndef __UBOOT__
#include <linux/module.h>
#endif
/* store the max & min value of pluse and space to minx and maxx */
#define mm_ps(phase, minp, maxp, mins, maxs) \
do { \
(minp) = ((HI_U32)(phase)->pluse) * (100 - ((phase)->factor)) / 100; \
(maxp) = ((HI_U32)(phase)->pluse) * (100 + ((phase)->factor)) / 100; \
(mins) = ((HI_U32)(phase)->space) * (100 - ((phase)->factor)) / 100; \
(maxs) = ((HI_U32)(phase)->space) * (100 + ((phase)->factor)) / 100; \
} while (0)

int ir_protocol_check(struct ir_protocol *ip)
{
struct osal_list_head *c = NULL;
struct ir_protocol *ci = NULL;

hi_info_func_enter();
if ((ip->node.next != NULL) && (ip->node.prev != NULL)
&& (ip->node.next != &ip->node)
&& (ip->node.prev != &ip->node)) {
HI_LOG_ERR("protocol may be link to somewhere,"
"ip->node.next:%p,ip->node.prev:%p!\n",
ip->node.next, ip->node.prev);
return HI_FAILURE;
}
if (ip->ir_code_name == NULL || ip->match == NULL || ip->handle == NULL
|| (ip->idx >= IR_PROT_BUTT)) {
hi_info_func_exit();
return HI_FAILURE;
}
if (osal_list_empty(&g_ir_prot_head)) {
return HI_SUCCESS;
}
osal_list_for_each(c, &g_ir_prot_head) {
ci = osal_list_entry(c, struct ir_protocol, node);
if (((ci->idx == ip->idx) && (ci->priv == ip->priv))) {
HI_LOG_ERR("protocol(%s)'s private data have been used by %s!\n", ip->ir_code_name, ci->ir_code_name);
return HI_FAILURE;
}
#ifdef __UBOOT__
if (!strcmp(ci->ir_code_name, ip->ir_code_name)) {
#else
if (!osal_strncmp(ci->ir_code_name, strlen(ip->ir_code_name), ip->ir_code_name,
strlen(ip->ir_code_name))) {
#endif
HI_LOG_ERR("%s have been registered or used!\n", ip->ir_code_name);
return HI_FAILURE;
}
}
hi_info_func_exit();
return HI_SUCCESS;
}

static void init_mmps(struct ir_protocol *ip)
{
hi_info_func_enter();

mm_ps(&ip->attr.header, ip->attr.header.minp, ip->attr.header.maxp,
ip->attr.header.mins, ip->attr.header.maxs);

if (ip->attr.second_header.pluse || ip->attr.second_header.space) {
mm_ps(&ip->attr.second_header, ip->attr.second_header.minp,
ip->attr.second_header.maxp, ip->attr.second_header.mins,
ip->attr.second_header.maxs);
}

mm_ps(&ip->attr.b0, ip->attr.b0.minp, ip->attr.b0.maxp, ip->attr.b0.mins,
ip->attr.b0.maxs);

mm_ps(&ip->attr.b1, ip->attr.b1.minp, ip->attr.b1.maxp, ip->attr.b1.mins,
ip->attr.b1.maxs);

mm_ps(&ip->attr.burst, ip->attr.burst.minp, ip->attr.burst.maxp,
ip->attr.burst.mins, ip->attr.burst.maxs);

if (ip->attr.repeat.pluse || ip->attr.repeat.space) {
mm_ps(&ip->attr.repeat, ip->attr.repeat.minp, ip->attr.repeat.maxp,
ip->attr.repeat.mins, ip->attr.repeat.maxs);
}

if (ip->attr.repeat_burst.pluse || ip->attr.repeat_burst.space) {
mm_ps(&ip->attr.repeat_burst, ip->attr.repeat_burst.minp, ip->attr.repeat_burst.maxp,
ip->attr.repeat_burst.mins, ip->attr.repeat_burst.maxs);
}

hi_info_func_exit();
}

static void ir_register_normal(struct ir_protocol *ip)
{
struct osal_list_head *curr = NULL;
struct osal_list_head *prev = NULL;
struct ir_protocol *p = NULL;

if (ip->attr.second_header.pluse
|| ip->attr.second_header.space) {
osal_list_add(&ip->node, &g_ir_prot_head);
} else {
prev = g_ir_prot_head.next;
osal_list_for_each(curr, &g_ir_prot_head) {
p = osal_list_entry(curr, struct ir_protocol, node);
if (!p->attr.second_header.pluse && !p->attr.second_header.space) {
break;
}

prev = curr;
}
osal_list_add(&ip->node, prev);
}
}

static void ir_register_rc6(struct ir_protocol *ip)
{
struct osal_list_head *curr = NULL;
struct osal_list_head *prev = NULL;
struct ir_protocol *p = NULL;

prev = g_ir_prot_head.next;
osal_list_for_each(curr, &g_ir_prot_head) {
p = osal_list_entry(curr, struct ir_protocol, node);
if (p->idx < IR_PROT_RC5) {
continue;
}

if (((p->idx == IR_PROT_RC6) && (p->attr.wanna_bits <= ip->attr.wanna_bits))
|| (p->idx == IR_PROT_RC5) || (p->idx == IR_PROT_RC5X)) {
break;
}

prev = curr;
}
osal_list_add(&ip->node, prev);
}

static void ir_register_rc5_x(struct ir_protocol *ip)
{
struct osal_list_head *curr = NULL;
struct osal_list_head *prev = NULL;
struct ir_protocol *p = NULL;
prev = g_ir_prot_head.next;
osal_list_for_each(curr, &g_ir_prot_head) {
p = osal_list_entry(curr, struct ir_protocol, node);
if ((p->idx != IR_PROT_RC5) && (p->idx != IR_PROT_RC5X)) {
continue;
}

if (p->attr.wanna_bits <= ip->attr.wanna_bits) {
break;
}

prev = curr;
}
osal_list_add(&ip->node, prev);
}

int ir_register_protocol(struct ir_protocol *ip)
{
#ifndef __UBOOT__
unsigned long flag = 0;
#endif

hi_info_func_enter();

if (ir_protocol_check(ip)) {
HI_LOG_ERR("ir_protocol_check(ip) failed\n");
return HI_FAILURE;
}

#ifndef __UBOOT__
osal_spin_lock_irqsave(get_var_irlock(), &flag);
#endif

OSAL_INIT_LIST_HEAD(&ip->node);

init_mmps(ip);

if (strlen(ip->ir_code_name) >= PROTOCOL_NAME_SZ) {
ip->ir_code_name[PROTOCOL_NAME_SZ - 1] = '\0';
}

if (osal_list_empty_careful(&g_ir_prot_head)) {
osal_list_add(&ip->node, &g_ir_prot_head);
goto out;
}

/* We need to do some sort.
* Sort rules:
* 1. Some protocol has obvious header/burst and
* fix number of bits data, and has second header, will be set
* in the first part of the list.
*
* 2. Some protocol has obvious header/burst and
* fix number of bits data, will be insert in the second part
* of the list.
*
* 3. rc6 will be insert in the third part.
* 4. rc5 at the last.
* 5. others at the end.
*/
if (ip->idx < IR_PROT_RC5) {
ir_register_normal(ip);
} else if (ip->idx == IR_PROT_RC6) {
ir_register_rc6(ip);
} else if ((ip->idx == IR_PROT_RC5) || (ip->idx == IR_PROT_RC5X)) {
ir_register_rc5_x(ip);
} else {
osal_list_add_tail(&ip->node, &g_ir_prot_head);
}

if (strlen(ip->ir_code_name) >= PROTOCOL_NAME_SZ) {
ip->ir_code_name[PROTOCOL_NAME_SZ - 1] = '\0';
}

out:
#ifndef __UBOOT__
osal_spin_unlock_irqrestore(get_var_irlock(), &flag);
#endif

hi_info_func_exit();
return HI_SUCCESS;
}

int ir_unregister_protocol(struct ir_protocol *ip)
{
#ifndef __UBOOT__
unsigned long flag;
#endif

hi_info_func_enter();

#ifndef __UBOOT__
osal_spin_lock_irqsave(get_var_irlock(), &flag);
#endif

osal_list_del(&ip->node);

#ifndef __UBOOT__
osal_spin_unlock_irqrestore(get_var_irlock(), &flag);
#endif

hi_info_func_exit();
return HI_SUCCESS;
}
void __ir_protocol_init(void)
{
#ifdef NEC_SUPPORT
nec_init();
#endif

#ifdef RC6_SUPPORT
rc6_init();
#endif

#ifdef RC5_SUPPORT
rc5_init();
#endif

#ifdef SONY_SUPPORT
sony_init();
#endif

#ifdef TC9012_SUPPORT
tc9012_init();
#endif

#ifdef CREDIT_SUPPORT

#endif

#ifdef RCA_SUPPORT
rca_init();
#endif

#ifdef KALE_SUPPORT
kale_init();
#endif

#ifdef SOYBEAN_SUPPORT
soybean_init();
#endif

#ifdef NECJVC_SUPPORT
nec_jvc_init();
#endif

#ifdef MITSUBISHI_SUPPORT
mitsubishi_init();
#endif

#ifdef SAMSUNG_SUPPORT
samsung_init();
#endif
}

int ir_protocol_init(void)
{
int i, cnt;
struct ir_protocol *ip = NULL;
#ifndef __UBOOT__
osal_spinlock *buffer_lock = get_var_buffer_lock();
osal_spinlock *irlock = get_var_irlock();
osal_spin_lock_init(irlock);
osal_spin_lock_init(buffer_lock);
#endif
hi_info_func_enter();
OSAL_INIT_LIST_HEAD(&g_ir_prot_head);

cnt = sizeof(g_ir_protocols) / sizeof(g_ir_protocols[0]);
for (i = 0; i < cnt; i++) {
ip = &g_ir_protocols[i];

if (ip->ir_code_name == NULL || ip->match == NULL || ip->handle == NULL
|| (ip->idx == IR_PROT_BUTT)) {
break;
}

if (ir_register_protocol(ip)) {
HI_LOG_ERR("fail to regist protocol %s\n", ip->ir_code_name);
}
}

if (!i) {
HI_LOG_ERR("no protocols registered!\n");
return HI_FAILURE;
}
__ir_protocol_init();
hi_info_func_exit();
return HI_SUCCESS;
}

void __ir_protocol_exit(void)
{
#ifdef NEC_SUPPORT
nec_exit();
#endif

#ifdef RC6_SUPPORT
rc6_exit();
#endif

#ifdef RC5_SUPPORT
rc5_exit();
#endif

#ifdef SONY_SUPPORT
sony_exit();
#endif

#ifdef TC9012_SUPPORT
tc9012_exit();
#endif

#ifdef CREDIT_SUPPORT

#endif

#ifdef KALE_SUPPORT
kale_exit();
#endif

#ifdef SOYBEAN_SUPPORT
soybean_exit();
#endif
#ifdef RCA_SUPPORT
rca_exit();
#endif

#ifdef NECJVC_SUPPORT
nec_jvc_exit();
#endif

#ifdef MITSUBISHI_SUPPORT
mitsubishi_exit();
#endif

#ifdef SAMSUNG_SUPPORT
samsung_exit();
#endif
}

int ir_protocol_exit(void)
{
struct ir_protocol *ip = NULL;

hi_info_func_enter();

while (!osal_list_empty_careful(&g_ir_prot_head)) {
ip = osal_list_first_entry(&g_ir_prot_head, struct ir_protocol, node);

(void)ir_unregister_protocol(ip);
}
__ir_protocol_exit();
hi_info_func_exit();

return HI_SUCCESS;
}

struct ir_protocol *ir_prot_first(void)
{
struct ir_protocol *ip = NULL;

if (osal_list_empty_careful(&g_ir_prot_head)) {
return NULL;
}

ip = osal_list_first_entry(&g_ir_prot_head, struct ir_protocol, node);

return ip;
}

struct ir_protocol *ir_prot_next(struct ir_protocol *curr)
{
struct osal_list_head *c = &curr->node;
struct ir_protocol *ip = NULL;

if (osal_list_is_last(c, &g_ir_prot_head)) {
return NULL;
}

c = curr->node.next;
ip = osal_list_entry(c, struct ir_protocol, node);

return ip;
}

int ir_prot_valid(struct ir_protocol *ip)
{
return (ip && ip->ir_code_name && ip->idx != IR_PROT_BUTT);
}

/* Simply check the pluse and space of this key
* is fall in the special phase's pluse and space.
* return 0 while match, others not match.
* NOTE: call this routine is not correct
* if phase is not exist or is not completely exist
* (both pluse and space) in a symbol sequence.
*/
int key_match_phase(struct key_attr *key, struct phase_attr *phase)
{
HI_U32 min, max;

hi_dbg_func_enter();

min = phase->minp;
max = phase->maxp;

hi_dbg_print_u32(phase->minp);
hi_dbg_print_u32(phase->maxp);
hi_dbg_print_u32((HI_U32)key->lower);

if (data_fallin((HI_U32)key->lower, min, max)) {
min = phase->mins;
max = phase->maxs;

hi_dbg_print_u32(phase->mins);
hi_dbg_print_u32(phase->maxs);
hi_dbg_print_u32((HI_U32)key->upper);

if (data_fallin((HI_U32)key->upper, min, max)) {
hi_dbg_func_exit();
return 0;
}
}

hi_dbg_func_exit();

return 1;
}

EXPORT_SYMBOL(ir_register_protocol);
EXPORT_SYMBOL(ir_unregister_protocol);

  这里以SONY协议为例,原代码是正常能够解析出SONY的协议头并注册使用相关的匹配框架的。从sony_frame_match满足IR_MATCH_MATCH进入sony_frame_full_parser整个框架解析,然后是sony_header_match头部匹配,sony_key_parse开始解析sony_data_parse,sony_key_parse每次读取一个Bit数据,然后将其给key_lower,最终我们得到的数据就是key_lower,比如xml中的value值是0x010001,那么key_lower就是0x10001。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793

/*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
* Description:drv_ir_sony.c
* Author: DPT_BSP
* Create: 2018-12-22
*/

#include "hi_osal.h"
#include "securec.h"
#include "drv_ir_priv.h"
#include "drv_ir_protocol.h"
#include "drv_ir_utils.h"
#include "drv_ir_report.h"
#ifndef __UBOOT__
#include <linux/module.h>
#endif
/* store the max & min value of pluse and space to minx and maxx */
#define mm_ps(phase, minp, maxp, mins, maxs) \
do { \
(minp) = (phase)->minp; \
(maxp) = (phase)->maxp; \
(mins) = (phase)->mins; \
(maxs) = (phase)->maxs; \
} while (0)

#define SONY_REPEAT_INTERVAL_TIME 300 /* The repeat interval is 300ms */
#define SONY_NORMAL_BURST 0
#define SONY_FINAL_BURST 1

static struct key_attr g_sony_last_key[MAX_SONY_INFR_NR];
static osal_timer g_sony_timer[MAX_SONY_INFR_NR];
static void sony_keyup_proc(unsigned long i)
{
struct key_attr *last_key = NULL;
struct ir_priv *ir_local = get_var_ir_local();
if (i >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony keyup timer, i > MAX_SONY_INFR_NR!\n");
return;
}

last_key = &g_sony_last_key[i];
if ((last_key->lower || last_key->upper)
&& last_key->key_stat != KEY_STAT_UP) {
last_key->key_stat = KEY_STAT_UP;
if (ir_local->key_up_event) {
ir_insert_key_tail(ir_local->key_buf, last_key);
osal_wait_wakeup(&(ir_local->read_wait));
}
last_key->lower = last_key->upper = 0;
}
}
void sony_init(void)
{
int i;
int size;

for (i = 0; i < MAX_SONY_INFR_NR; i++) {
osal_timer_init(&g_sony_timer[i]);
g_sony_timer[i].data = (unsigned long)~0;
g_sony_timer[i].handler = sony_keyup_proc;
}

size = MAX_SONY_INFR_NR * sizeof(struct key_attr);
if (EOK != memset_s(g_sony_last_key, size, 0, size)) {
HI_LOG_ERR("sony_last_key memset_s error!\n");
}
}
void sony_exit(void)
{
int i;
for (i = 0; i < MAX_SONY_INFR_NR; i++) {
osal_timer_del(&g_sony_timer[i]);
}
}
#define print_mm_sp(phase, name) \
do { \
hi_dbg_print_str(name); \
hi_dbg_print_s32((phase)->minp); \
hi_dbg_print_s32((phase)->maxp); \
hi_dbg_print_s32((phase)->mins); \
hi_dbg_print_s32((phase)->maxs); \
} while (0)
enum IR_MATCH_RESULT sony_header_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
struct key_attr *symbol = NULL;

symbol = &buf->buf[buf->reader];

if (!key_match_phase(symbol, &ip->attr.header)) {
return IR_MATCH_MATCH;
}
HI_LOG_DBG("%s->%d, header not match! ip at:%p"
" header[p, s, f]: [%d, %d, %d],"
" key[l, u]:[%d, %d]\n",
__func__, __LINE__, ip,
ip->attr.header.pluse,
ip->attr.header.space,
ip->attr.header.factor,
(HI_U32)symbol->lower, (HI_U32)symbol->upper);
print_mm_sp(&ip->attr.header, "header");
return IR_MATCH_NOT_MATCH;
}

enum IR_MATCH_RESULT sony_data_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int n, i, j;
struct key_attr *symbol = NULL;

/* try find burst. */
HI_LOG_DBG("%s->%d,idx:%d header match!\n", __func__, __LINE__, ip->priv);
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
/* check frame symbols */
for (i = 0, j = i + buf->reader + 1; i < ip->attr.wanna_bits && j != n;
i++, j++) {
if (j >= MAX_SYMBOL_NUM) {
j -= MAX_SYMBOL_NUM;
}

if (j == n) {
break;
}

symbol = &buf->buf[j];

if (!symbol->lower && !symbol->upper) {
return IR_MATCH_NEED_MORE_DATA;
}

/* check data phase is exceed or not */
if (key_match_phase(symbol, &ip->attr.b0)
&& key_match_phase(symbol, &ip->attr.b1)) {
return IR_MATCH_NOT_MATCH;
}
}
HI_LOG_DBG("%s->%d, checking burst at(%d)!\n",
__func__, __LINE__, n);
symbol = &buf->buf[n];
if (!symbol->upper && !symbol->lower) {
HI_LOG_DBG("%s->%d, idx:%d, needs more data\n",
__func__, __LINE__, ip->priv);
return IR_MATCH_NEED_MORE_DATA;
}

return IR_MATCH_MATCH;
}
enum IR_MATCH_RESULT sony_burst_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int n;
struct key_attr *symbol = NULL;
unsigned long long minp, maxp;
/* SONY frame burst may constains b0's pluse or b1's pluse
* and space will > 20000.
*/
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
symbol = &buf->buf[n];
minp = ip->attr.b0.minp;
maxp = ip->attr.b1.maxp;
if (((HI_U32)symbol->lower >= minp) && ((HI_U32)symbol->lower <= maxp)
&& ((HI_U32) symbol->upper >= ip->attr.burst.mins)) {
HI_LOG_DBG("%s->%d, idx:%d, frame burst match!\n",
__func__, __LINE__, ip->priv);
return IR_MATCH_MATCH;
} else {
HI_LOG_DBG("%s->%d, idx:%d. burst not match!"
" key[l, u][%d, %d],"
" burst[p, s, f]: [%d, %d, %d]\n",
__func__, __LINE__, ip->priv,
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.burst.pluse,
ip->attr.burst.space,
ip->attr.burst.factor);

return IR_MATCH_NOT_MATCH;
}
}


enum IR_MATCH_RESULT sony_frame_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int ret;

/* header match? */
HI_LOG_DBG("%s->%d, idx:%d, checking header!\n", __func__, __LINE__, ip->priv);
ret = sony_header_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return IR_MATCH_NOT_MATCH;
}
/* check frame symbols */
ret = sony_data_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return ret;
}
/* burst match? */
ret = sony_burst_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return ret;
}

return IR_MATCH_MATCH;
}

/* to see a frame is a full frame or a repeat frame */
enum IR_MATCH_RESULT sony_match(enum IR_MATCH_TYPE type,
struct ir_buffer *buf, struct ir_protocol *ip)
{
struct key_attr *symbol = NULL;

if (ip->priv >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony , private data error!\n");
return IR_MATCH_NOT_MATCH;
}
symbol = &buf->buf[buf->reader];
if (!symbol->upper && !symbol->lower) {
HI_LOG_DBG("%s->%d, idx:%d, key empty!\n", __func__, __LINE__, ip->priv);
return IR_MATCH_NOT_MATCH;
}
switch (type) {
case IR_MTT_HEADER:
return sony_header_match(buf, ip);
case IR_MTT_FRAME:
return sony_frame_match(buf, ip);
case IR_MTT_BURST:
/* fall though */
default:
return IR_MATCH_NOT_MATCH;
}
}
int sony_last_data_parse(struct ir_protocol *ip, struct ir_buffer *rd, struct key_attr *key)
{
struct key_attr *symbol = NULL;
unsigned long long minp, maxp;
unsigned int sony_last_data_cnt = ip->attr.wanna_bits - 1;

symbol = &rd->buf[rd->reader];
HI_LOG_DBG("%s->%d, meets burst, i:%d, ip->attr.wanna_bits:%d, rd->reader:%d!\n",
__func__, __LINE__, sony_last_data_cnt, ip->attr.wanna_bits, rd->reader);
minp = ip->attr.b1.minp;
maxp = ip->attr.b1.maxp;
if (data_fallin((HI_U32)symbol->lower, minp, maxp)) {
HI_LOG_DBG("%s->%d, burst constains bit1!\n", __func__, __LINE__);
if (sony_last_data_cnt < 64) { /* 64 is threshold of lower and upper */
key->lower |= (unsigned long long)(((unsigned long long)1) << sony_last_data_cnt);
} else {
key->upper |= (unsigned long long)(((unsigned long long)1)
<< (sony_last_data_cnt - 64)); /* 64 is threshold of lower and upper */
}
return HI_SUCCESS;
}
minp = ip->attr.b0.minp;
maxp = ip->attr.b0.maxp;
if (data_fallin((HI_U32)symbol->lower, minp, maxp)) {
HI_LOG_DBG("%s->%d, burst constains bit0!\n", __func__, __LINE__);
return HI_SUCCESS;
}
return HI_FAILURE;
}
int sony_data_parse(struct ir_protocol *ip, struct ir_buffer *rd, struct key_attr *key)
{
struct key_attr *symbol = NULL;
HI_U32 bit_cnt = 0;
int ret;
/* data phase */
symbol = ir_next_reader_clr_inc(rd);
HI_LOG_DBG("try parse data(at %d)!\n", rd->reader);
while (symbol != NULL && symbol->upper && symbol->lower && bit_cnt < ip->attr.wanna_bits) {
if (!key_match_phase(symbol, &ip->attr.b0)) {
symbol = ir_next_reader_clr_inc(rd);
bit_cnt++;
continue;
}

if (!key_match_phase(symbol, &ip->attr.b1)) {
if (bit_cnt < 64) { /* 64 is threshold of lower and upper */
key->lower |= (unsigned long long)(((unsigned long long)1) << bit_cnt);
} else {
key->upper |= (unsigned long long)(((unsigned long long)1) << (bit_cnt - 64)); /* 64 is threshold */
}
symbol = ir_next_reader_clr_inc(rd);
bit_cnt++;
continue;
}
/* meats burst. */
if (bit_cnt + 1 == ip->attr.wanna_bits) {
ret = sony_last_data_parse(ip, rd, key);
if (ret == 0) {
bit_cnt++;
break;
}
}
HI_LOG_INFO("SONY : unkown symbol[l, u]: [%d, %d],"
" b0[p, s, f]: [%d, %d, %d],"
" b1[p, s, f]: [%d, %d, %d]. Assume to 0!\n",
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.b0.pluse, ip->attr.b0.space,
ip->attr.b0.factor,
ip->attr.b1.pluse, ip->attr.b1.space,
ip->attr.b1.factor);
bit_cnt++;
symbol = ir_next_reader_clr_inc(rd);
return HI_FAILURE;
}
return HI_SUCCESS;
}
int sony_burst_parse(struct ir_protocol *ip, struct ir_buffer *rd)
{
struct key_attr *symbol = NULL;
unsigned long long mins, maxs;

symbol = ir_reader_inc(rd);
HI_LOG_DBG("try parse burst(at %d)!\n", rd->reader);
mins = ip->attr.burst.mins;
maxs = ip->attr.burst.maxs;
if (symbol && ((!data_fallin((HI_U32)symbol->lower, ip->attr.b0.minp, ip->attr.b0.maxp) &&
!data_fallin((HI_U32)symbol->lower, ip->attr.b1.minp, ip->attr.b1.maxp))
|| (symbol->upper < maxs && !data_fallin((HI_U32)symbol->upper, mins, maxs)))) {
HI_LOG_INFO("SONY : unkown symbol[l, u]: [%d, %d],"
" burst[p, s, f]: [%d, %d, %d].\n",
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.burst.pluse, ip->attr.burst.space,
ip->attr.burst.factor);
return HI_FAILURE;
}

if (symbol->upper > maxs) {
return SONY_FINAL_BURST;
}
return SONY_NORMAL_BURST;
}

int sony_key_parse(struct ir_priv *ir, struct ir_protocol *ip,
struct ir_buffer *rd, struct ir_buffer *wr)
{
struct key_attr key;
int length;
int ret;

/* data phase */
if (EOK != memset_s(&key, sizeof(struct key_attr), 0, sizeof(struct key_attr))) {
HI_LOG_ERR("sony_frame_full_parse key memset_s error!\n");
return HI_FAILURE;
}
length = osal_min((HI_U32)strlen(ip->ir_code_name), (HI_U32)(PROTOCOL_NAME_SZ - 1));
if (EOK != memcpy_s(key.protocol_name, PROTOCOL_NAME_SZ, ip->ir_code_name, length)) {
HI_LOG_ERR("sony_frame_full_parse protocol_name memcpy_s err!\n");
}
key.protocol_name[length + 1] = '\0';
ret = sony_data_parse(ip, rd, &key);
if (ret != 0) {
(HI_VOID)ir_next_reader_clr_inc(rd);
return HI_FAILURE;
}

ret = sony_burst_parse(ip, rd);
if (ret == SONY_FINAL_BURST) {
ir_key_report(&key, IR_NORMAL_FINAL_KEY, ip);
} else if (ret == SONY_NORMAL_BURST) {
ir_key_report(&key, IR_NORMAL_KEY, ip);/*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
* Description:drv_ir_sony.c
* Author: DPT_BSP
* Create: 2018-12-22
*/

#include "hi_osal.h"
#include "securec.h"
#include "drv_ir_priv.h"
#include "drv_ir_protocol.h"
#include "drv_ir_utils.h"
#include "drv_ir_report.h"
#ifndef __UBOOT__
#include <linux/module.h>
#endif
/* store the max & min value of pluse and space to minx and maxx */
#define mm_ps(phase, minp, maxp, mins, maxs) \
do { \
(minp) = (phase)->minp; \
(maxp) = (phase)->maxp; \
(mins) = (phase)->mins; \
(maxs) = (phase)->maxs; \
} while (0)

#define SONY_REPEAT_INTERVAL_TIME 300 /* The repeat interval is 300ms */
#define SONY_NORMAL_BURST 0
#define SONY_FINAL_BURST 1

static struct key_attr g_sony_last_key[MAX_SONY_INFR_NR];
static osal_timer g_sony_timer[MAX_SONY_INFR_NR];
static void sony_keyup_proc(unsigned long i)
{
struct key_attr *last_key = NULL;
struct ir_priv *ir_local = get_var_ir_local();
if (i >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony keyup timer, i > MAX_SONY_INFR_NR!\n");
return;
}

last_key = &g_sony_last_key[i];
if ((last_key->lower || last_key->upper)
&& last_key->key_stat != KEY_STAT_UP) {
last_key->key_stat = KEY_STAT_UP;
if (ir_local->key_up_event) {
ir_insert_key_tail(ir_local->key_buf, last_key);
osal_wait_wakeup(&(ir_local->read_wait));
}
last_key->lower = last_key->upper = 0;
}
}
void sony_init(void)
{
int i;
int size;

for (i = 0; i < MAX_SONY_INFR_NR; i++) {
osal_timer_init(&g_sony_timer[i]);
g_sony_timer[i].data = (unsigned long)~0;
g_sony_timer[i].handler = sony_keyup_proc;
}

size = MAX_SONY_INFR_NR * sizeof(struct key_attr);
if (EOK != memset_s(g_sony_last_key, size, 0, size)) {
HI_LOG_ERR("sony_last_key memset_s error!\n");
}
}
void sony_exit(void)
{
int i;
for (i = 0; i < MAX_SONY_INFR_NR; i++) {
osal_timer_del(&g_sony_timer[i]);
}
}
#define print_mm_sp(phase, name) \
do { \
hi_dbg_print_str(name); \
hi_dbg_print_s32((phase)->minp); \
hi_dbg_print_s32((phase)->maxp); \
hi_dbg_print_s32((phase)->mins); \
hi_dbg_print_s32((phase)->maxs); \
} while (0)
enum IR_MATCH_RESULT sony_header_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
struct key_attr *symbol = NULL;

symbol = &buf->buf[buf->reader];

if (!key_match_phase(symbol, &ip->attr.header)) {
return IR_MATCH_MATCH;
}
HI_LOG_DBG("%s->%d, header not match! ip at:%p"
" header[p, s, f]: [%d, %d, %d],"
" key[l, u]:[%d, %d]\n",
__func__, __LINE__, ip,
ip->attr.header.pluse,
ip->attr.header.space,
ip->attr.header.factor,
(HI_U32)symbol->lower, (HI_U32)symbol->upper);
print_mm_sp(&ip->attr.header, "header");
return IR_MATCH_NOT_MATCH;
}

enum IR_MATCH_RESULT sony_data_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int n, i, j;
struct key_attr *symbol = NULL;

/* try find burst. */
HI_LOG_DBG("%s->%d,idx:%d header match!\n", __func__, __LINE__, ip->priv);
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
/* check frame symbols */
for (i = 0, j = i + buf->reader + 1; i < ip->attr.wanna_bits && j != n;
i++, j++) {
if (j >= MAX_SYMBOL_NUM) {
j -= MAX_SYMBOL_NUM;
}

if (j == n) {
break;
}

symbol = &buf->buf[j];

if (!symbol->lower && !symbol->upper) {
return IR_MATCH_NEED_MORE_DATA;
}

/* check data phase is exceed or not */
if (key_match_phase(symbol, &ip->attr.b0)
&& key_match_phase(symbol, &ip->attr.b1)) {
return IR_MATCH_NOT_MATCH;
}
}
HI_LOG_DBG("%s->%d, checking burst at(%d)!\n",
__func__, __LINE__, n);
symbol = &buf->buf[n];
if (!symbol->upper && !symbol->lower) {
HI_LOG_DBG("%s->%d, idx:%d, needs more data\n",
__func__, __LINE__, ip->priv);
return IR_MATCH_NEED_MORE_DATA;
}

return IR_MATCH_MATCH;
}
enum IR_MATCH_RESULT sony_burst_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int n;
struct key_attr *symbol = NULL;
unsigned long long minp, maxp;
/* SONY frame burst may constains b0's pluse or b1's pluse
* and space will > 20000.
*/
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
symbol = &buf->buf[n];
minp = ip->attr.b0.minp;
maxp = ip->attr.b1.maxp;
if (((HI_U32)symbol->lower >= minp) && ((HI_U32)symbol->lower <= maxp)
&& ((HI_U32) symbol->upper >= ip->attr.burst.mins)) {
HI_LOG_DBG("%s->%d, idx:%d, frame burst match!\n",
__func__, __LINE__, ip->priv);
return IR_MATCH_MATCH;
} else {
HI_LOG_DBG("%s->%d, idx:%d. burst not match!"
" key[l, u][%d, %d],"
" burst[p, s, f]: [%d, %d, %d]\n",
__func__, __LINE__, ip->priv,
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.burst.pluse,
ip->attr.burst.space,
ip->attr.burst.factor);

return IR_MATCH_NOT_MATCH;
}
}


enum IR_MATCH_RESULT sony_frame_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int ret;

/* header match? */
HI_LOG_DBG("%s->%d, idx:%d, checking header!\n", __func__, __LINE__, ip->priv);
ret = sony_header_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return IR_MATCH_NOT_MATCH;
}
/* check frame symbols */
ret = sony_data_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return ret;
}
/* burst match? */
ret = sony_burst_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return ret;
}

return IR_MATCH_MATCH;
}

/* to see a frame is a full frame or a repeat frame */
enum IR_MATCH_RESULT sony_match(enum IR_MATCH_TYPE type,
struct ir_buffer *buf, struct ir_protocol *ip)
{
struct key_attr *symbol = NULL;

if (ip->priv >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony , private data error!\n");
return IR_MATCH_NOT_MATCH;
}
symbol = &buf->buf[buf->reader];
if (!symbol->upper && !symbol->lower) {
HI_LOG_DBG("%s->%d, idx:%d, key empty!\n", __func__, __LINE__, ip->priv);
return IR_MATCH_NOT_MATCH;
}
switch (type) {
case IR_MTT_HEADER:
return sony_header_match(buf, ip);
case IR_MTT_FRAME:
return sony_frame_match(buf, ip);
case IR_MTT_BURST:
/* fall though */
default:
return IR_MATCH_NOT_MATCH;
}
}
int sony_last_data_parse(struct ir_protocol *ip, struct ir_buffer *rd, struct key_attr *key)
{
struct key_attr *symbol = NULL;
unsigned long long minp, maxp;
unsigned int sony_last_data_cnt = ip->attr.wanna_bits - 1;

symbol = &rd->buf[rd->reader];
HI_LOG_DBG("%s->%d, meets burst, i:%d, ip->attr.wanna_bits:%d, rd->reader:%d!\n",
__func__, __LINE__, sony_last_data_cnt, ip->attr.wanna_bits, rd->reader);
minp = ip->attr.b1.minp;
maxp = ip->attr.b1.maxp;
if (data_fallin((HI_U32)symbol->lower, minp, maxp)) {
HI_LOG_DBG("%s->%d, burst constains bit1!\n", __func__, __LINE__);
if (sony_last_data_cnt < 64) { /* 64 is threshold of lower and upper */
key->lower |= (unsigned long long)(((unsigned long long)1) << sony_last_data_cnt);
} else {
key->upper |= (unsigned long long)(((unsigned long long)1)
<< (sony_last_data_cnt - 64)); /* 64 is threshold of lower and upper */
}
return HI_SUCCESS;
}
minp = ip->attr.b0.minp;
maxp = ip->attr.b0.maxp;
if (data_fallin((HI_U32)symbol->lower, minp, maxp)) {
HI_LOG_DBG("%s->%d, burst constains bit0!\n", __func__, __LINE__);
return HI_SUCCESS;
}
return HI_FAILURE;
}
int sony_data_parse(struct ir_protocol *ip, struct ir_buffer *rd, struct key_attr *key)
{
struct key_attr *symbol = NULL;
HI_U32 bit_cnt = 0;
int ret;
/* data phase */
symbol = ir_next_reader_clr_inc(rd);
HI_LOG_DBG("try parse data(at %d)!\n", rd->reader);
while (symbol != NULL && symbol->upper && symbol->lower && bit_cnt < ip->attr.wanna_bits) {
if (!key_match_phase(symbol, &ip->attr.b0)) {
symbol = ir_next_reader_clr_inc(rd);
bit_cnt++;
continue;
}

if (!key_match_phase(symbol, &ip->attr.b1)) {
if (bit_cnt < 64) { /* 64 is threshold of lower and upper */
key->lower |= (unsigned long long)(((unsigned long long)1) << bit_cnt);
} else {
key->upper |= (unsigned long long)(((unsigned long long)1) << (bit_cnt - 64)); /* 64 is threshold */
}
symbol = ir_next_reader_clr_inc(rd);
bit_cnt++;
continue;
}
/* meats burst. */
if (bit_cnt + 1 == ip->attr.wanna_bits) {
ret = sony_last_data_parse(ip, rd, key);
if (ret == 0) {
bit_cnt++;
break;
}
}
HI_LOG_INFO("SONY : unkown symbol[l, u]: [%d, %d],"
" b0[p, s, f]: [%d, %d, %d],"
" b1[p, s, f]: [%d, %d, %d]. Assume to 0!\n",
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.b0.pluse, ip->attr.b0.space,
ip->attr.b0.factor,
ip->attr.b1.pluse, ip->attr.b1.space,
ip->attr.b1.factor);
bit_cnt++;
symbol = ir_next_reader_clr_inc(rd);
return HI_FAILURE;
}
return HI_SUCCESS;
}
int sony_burst_parse(struct ir_protocol *ip, struct ir_buffer *rd)
{
struct key_attr *symbol = NULL;
unsigned long long mins, maxs;

symbol = ir_reader_inc(rd);
HI_LOG_DBG("try parse burst(at %d)!\n", rd->reader);
mins = ip->attr.burst.mins;
maxs = ip->attr.burst.maxs;
if (symbol && ((!data_fallin((HI_U32)symbol->lower, ip->attr.b0.minp, ip->attr.b0.maxp) &&
!data_fallin((HI_U32)symbol->lower, ip->attr.b1.minp, ip->attr.b1.maxp))
|| (symbol->upper < maxs && !data_fallin((HI_U32)symbol->upper, mins, maxs)))) {
HI_LOG_INFO("SONY : unkown symbol[l, u]: [%d, %d],"
" burst[p, s, f]: [%d, %d, %d].\n",
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.burst.pluse, ip->attr.burst.space,
ip->attr.burst.factor);
return HI_FAILURE;
}

if (symbol->upper > maxs) {
return SONY_FINAL_BURST;
}
return SONY_NORMAL_BURST;
}

int sony_key_parse(struct ir_priv *ir, struct ir_protocol *ip,
struct ir_buffer *rd, struct ir_buffer *wr)
{
struct key_attr key;
int length;
int ret;

/* data phase */
if (EOK != memset_s(&key, sizeof(struct key_attr), 0, sizeof(struct key_attr))) {
HI_LOG_ERR("sony_frame_full_parse key memset_s error!\n");
return HI_FAILURE;
}
length = osal_min((HI_U32)strlen(ip->ir_code_name), (HI_U32)(PROTOCOL_NAME_SZ - 1));
if (EOK != memcpy_s(key.protocol_name, PROTOCOL_NAME_SZ, ip->ir_code_name, length)) {
HI_LOG_ERR("sony_frame_full_parse protocol_name memcpy_s err!\n");
}
key.protocol_name[length + 1] = '\0';
ret = sony_data_parse(ip, rd, &key);
if (ret != 0) {
(HI_VOID)ir_next_reader_clr_inc(rd);
return HI_FAILURE;
}

ret = sony_burst_parse(ip, rd);
if (ret == SONY_FINAL_BURST) {
ir_key_report(&key, IR_NORMAL_FINAL_KEY, ip);
} else if (ret == SONY_NORMAL_BURST) {
ir_key_report(&key, IR_NORMAL_KEY, ip);
} else if (ret != 0) {
/* need clear burst symbol? */
return HI_FAILURE;
}

return HI_SUCCESS;
}
int sony_frame_full_parse(struct ir_priv *ir, struct ir_protocol *ip,
struct ir_buffer *rd, struct ir_buffer *wr)
{
int ret;

if (ip->priv >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony , private data error!\n");
return HI_FAILURE;
}

osal_timer_del(&g_sony_timer[ip->priv]);
HI_LOG_DBG("try parse header(at %d)!\n", rd->reader);
ret = sony_header_match(rd, ip);
if (ret != IR_MATCH_MATCH) {
return HI_FAILURE;
}
/* key parse */
ret = sony_key_parse(ir, ip, rd, wr);
if (ret != HI_SUCCESS) {
return HI_FAILURE;
}
return HI_SUCCESS;
}
EXPORT_SYMBOL(sony_match);
EXPORT_SYMBOL(sony_frame_full_parse);


} else if (ret != 0) {
/* need clear burst symbol? */
return HI_FAILURE;
}

return HI_SUCCESS;
}
int sony_frame_full_parse(struct ir_priv *ir, struct ir_protocol *ip,
struct ir_buffer *rd, struct ir_buffer *wr)
{
int ret;

if (ip->priv >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony , private data error!\n");
return HI_FAILURE;
}

osal_timer_del(&g_sony_timer[ip->priv]);
HI_LOG_DBG("try parse header(at %d)!\n", rd->reader);
ret = sony_header_match(rd, ip);
if (ret != IR_MATCH_MATCH) {
return HI_FAILURE;
}
/* key parse */
ret = sony_key_parse(ir, ip, rd, wr);
if (ret != HI_SUCCESS) {
return HI_FAILURE;
}
return HI_SUCCESS;
}
EXPORT_SYMBOL(sony_match);
EXPORT_SYMBOL(sony_frame_full_parse);

  实际情况并不是,而是高低位相反了,获取的数据位比如是000100100101,但是它解析出来的是101001001000。这些都是用示波器和代码调试测量出来的,知道了原因,就更改一下代码即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
* Description:drv_ir_sony.c
* Author: DPT_BSP
* Create: 2018-12-22
*/

#include "hi_osal.h"
#include "securec.h"
#include "drv_ir_priv.h"
#include "drv_ir_protocol.h"
#include "drv_ir_utils.h"
#include "drv_ir_report.h"
#ifndef __UBOOT__
#include <linux/module.h>
#endif
/* store the max & min value of pluse and space to minx and maxx */
#define mm_ps(phase, minp, maxp, mins, maxs) \
do { \
(minp) = (phase)->minp; \
(maxp) = (phase)->maxp; \
(mins) = (phase)->mins; \
(maxs) = (phase)->maxs; \
} while (0)

#define SONY_REPEAT_INTERVAL_TIME 300 /* The repeat interval is 300ms */
#define SONY_NORMAL_BURST 0
#define SONY_FINAL_BURST 1

static struct key_attr g_sony_last_key[MAX_SONY_INFR_NR];
static osal_timer g_sony_timer[MAX_SONY_INFR_NR];
static void sony_keyup_proc(unsigned long i)
{
struct key_attr *last_key = NULL;
struct ir_priv *ir_local = get_var_ir_local();
if (i >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony keyup timer, i > MAX_SONY_INFR_NR!\n");
return;
}

last_key = &g_sony_last_key[i];
if ((last_key->lower || last_key->upper)
&& last_key->key_stat != KEY_STAT_UP) {
last_key->key_stat = KEY_STAT_UP;
if (ir_local->key_up_event) {
ir_insert_key_tail(ir_local->key_buf, last_key);
osal_wait_wakeup(&(ir_local->read_wait));
}
last_key->lower = last_key->upper = 0;
}
}
void sony_init(void)
{
int i;
int size;

for (i = 0; i < MAX_SONY_INFR_NR; i++) {
osal_timer_init(&g_sony_timer[i]);
g_sony_timer[i].data = (unsigned long)~0;
g_sony_timer[i].handler = sony_keyup_proc;
}

size = MAX_SONY_INFR_NR * sizeof(struct key_attr);
if (EOK != memset_s(g_sony_last_key, size, 0, size)) {
HI_LOG_ERR("sony_last_key memset_s error!\n");
}
}
void sony_exit(void)
{
int i;
for (i = 0; i < MAX_SONY_INFR_NR; i++) {
osal_timer_del(&g_sony_timer[i]);
}
}
#define print_mm_sp(phase, name) \
do { \
hi_dbg_print_str(name); \
hi_dbg_print_s32((phase)->minp); \
hi_dbg_print_s32((phase)->maxp); \
hi_dbg_print_s32((phase)->mins); \
hi_dbg_print_s32((phase)->maxs); \
} while (0)
enum IR_MATCH_RESULT sony_header_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
struct key_attr *symbol = NULL;

symbol = &buf->buf[buf->reader];

if (!key_match_phase(symbol, &ip->attr.header)) {
return IR_MATCH_MATCH;
}
HI_LOG_DBG("%s->%d, header not match! ip at:%p"
" header[p, s, f]: [%d, %d, %d],"
" key[l, u]:[%d, %d]\n",
__func__, __LINE__, ip,
ip->attr.header.pluse,
ip->attr.header.space,
ip->attr.header.factor,
(HI_U32)symbol->lower, (HI_U32)symbol->upper);
print_mm_sp(&ip->attr.header, "header");
return IR_MATCH_NOT_MATCH;
}

enum IR_MATCH_RESULT sony_data_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int n, i, j;
struct key_attr *symbol = NULL;

/* try find burst. */
HI_LOG_DBG("%s->%d,idx:%d header match!\n", __func__, __LINE__, ip->priv);
#if 1
/* check frame symbols */
for (i = 0, j = i + buf->reader + 1; i < 20 ; i++, j++) {
if (j >= MAX_SYMBOL_NUM) {
j -= MAX_SYMBOL_NUM;
}

symbol = &buf->buf[j];

if (!symbol->lower && !symbol->upper) {
if (j - buf->reader < 0){
ip->attr.wanna_bits = j + MAX_SYMBOL_NUM - buf->reader - 1;
ip->attr.burst_offset = j + MAX_SYMBOL_NUM - buf->reader - 1;
} else {
ip->attr.wanna_bits = j- buf->reader - 1;
ip->attr.burst_offset = j - buf->reader - 1;
}
//HI_LOG_ERR("%s->%d, ip->attr.wanna_bits = %d ip->attr.burst_offset = %d \n", __func__, __LINE__, ip->attr.wanna_bits,ip->attr.burst_offset);
break;
}
}

if (ip->attr.wanna_bits == 15){
//15bit
ip->attr.burst.space = 20000;
} else {
//12bit
ip->attr.burst.space = 25000;
}
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
#else
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
/* check frame symbols */
for (i = 0, j = i + buf->reader + 1; i < ip->attr.wanna_bits && j != n;
i++, j++) {
if (j >= MAX_SYMBOL_NUM) {
j -= MAX_SYMBOL_NUM;
}

if (j == n) {
break;
}

symbol = &buf->buf[j];

if (!symbol->lower && !symbol->upper) {
return IR_MATCH_NEED_MORE_DATA;
}

/* check data phase is exceed or not */
if (key_match_phase(symbol, &ip->attr.b0)
&& key_match_phase(symbol, &ip->attr.b1)) {
return IR_MATCH_NOT_MATCH;
}
}
#endif
HI_LOG_DBG("%s->%d, checking burst at(%d)!\n",
__func__, __LINE__, n);
symbol = &buf->buf[n];
if (!symbol->upper && !symbol->lower) {
HI_LOG_DBG("%s->%d, idx:%d, needs more data\n",
__func__, __LINE__, ip->priv);
return IR_MATCH_NEED_MORE_DATA;
}

return IR_MATCH_MATCH;
}
enum IR_MATCH_RESULT sony_burst_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int n;
struct key_attr *symbol = NULL;
unsigned long long minp, maxp;
/* SONY frame burst may constains b0's pluse or b1's pluse
* and space will > 20000.
*/
n = buf->reader + ip->attr.burst_offset;
if (n >= MAX_SYMBOL_NUM) {
n -= MAX_SYMBOL_NUM;
}
symbol = &buf->buf[n];
minp = ip->attr.b0.minp;
maxp = ip->attr.b1.maxp;
if (((HI_U32)symbol->lower >= minp) && ((HI_U32)symbol->lower <= maxp)
&& ((HI_U32) symbol->upper >= ip->attr.burst.mins)) {
HI_LOG_DBG("%s->%d, idx:%d, frame burst match!\n",
__func__, __LINE__, ip->priv);
return IR_MATCH_MATCH;
} else {
HI_LOG_DBG("%s->%d, idx:%d. burst not match!"
" key[l, u][%d, %d],"
" burst[p, s, f]: [%d, %d, %d]\n",
__func__, __LINE__, ip->priv,
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.burst.pluse,
ip->attr.burst.space,
ip->attr.burst.factor);

return IR_MATCH_NOT_MATCH;
}
}


enum IR_MATCH_RESULT sony_frame_match(struct ir_buffer *buf, struct ir_protocol *ip)
{
int ret;

/* header match? */
HI_LOG_DBG("%s->%d, idx:%d, checking header!\n", __func__, __LINE__, ip->priv);
ret = sony_header_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return IR_MATCH_NOT_MATCH;
}
/* check frame symbols */
ret = sony_data_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return ret;
}
/* burst match? */
ret = sony_burst_match(buf, ip);
if (ret != IR_MATCH_MATCH) {
return ret;
}

return IR_MATCH_MATCH;
}

/* to see a frame is a full frame or a repeat frame */
enum IR_MATCH_RESULT sony_match(enum IR_MATCH_TYPE type,
struct ir_buffer *buf, struct ir_protocol *ip)
{
struct key_attr *symbol = NULL;

if (ip->priv >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony , private data error!\n");
return IR_MATCH_NOT_MATCH;
}
symbol = &buf->buf[buf->reader];
if (!symbol->upper && !symbol->lower) {
HI_LOG_DBG("%s->%d, idx:%d, key empty!\n", __func__, __LINE__, ip->priv);
return IR_MATCH_NOT_MATCH;
}
switch (type) {
case IR_MTT_HEADER:
return sony_header_match(buf, ip);
case IR_MTT_FRAME:
return sony_frame_match(buf, ip);
case IR_MTT_BURST:
/* fall though */
default:
return IR_MATCH_NOT_MATCH;
}
}
int sony_last_data_parse(struct ir_protocol *ip, struct ir_buffer *rd, struct key_attr *key)
{
struct key_attr *symbol = NULL;
unsigned long long minp, maxp;
unsigned int sony_last_data_cnt = ip->attr.wanna_bits - 1;

symbol = &rd->buf[rd->reader];
HI_LOG_DBG("%s->%d, meets burst, i:%d, ip->attr.wanna_bits:%d, rd->reader:%d!\n",
__func__, __LINE__, sony_last_data_cnt, ip->attr.wanna_bits, rd->reader);
minp = ip->attr.b1.minp;
maxp = ip->attr.b1.maxp;
if (data_fallin((HI_U32)symbol->lower, minp, maxp)) {
HI_LOG_DBG("%s->%d, burst constains bit1!\n", __func__, __LINE__);
if (sony_last_data_cnt < 64) { /* 64 is threshold of lower and upper */
key->lower |= (unsigned long long)(((unsigned long long)1) << (sony_last_data_cnt-7));
//key->lower |= (unsigned long long)(((unsigned long long)1) << sony_last_data_cnt);
} else {
key->upper |= (unsigned long long)(((unsigned long long)1)
<< (sony_last_data_cnt - 64)); /* 64 is threshold of lower and upper */
}
return HI_SUCCESS;
}
minp = ip->attr.b0.minp;
maxp = ip->attr.b0.maxp;
if (data_fallin((HI_U32)symbol->lower, minp, maxp)) {
HI_LOG_DBG("%s->%d, burst constains bit0!\n", __func__, __LINE__);
return HI_SUCCESS;
}
return HI_FAILURE;
}
int sony_data_parse(struct ir_protocol *ip, struct ir_buffer *rd, struct key_attr *key)
{
struct key_attr *symbol = NULL;
HI_U32 bit_cnt = 0;
int ret;
/*zhouj add*/
int command = 0;
int address = 0;
/*zhouj add*/
/* data phase */
symbol = ir_next_reader_clr_inc(rd);
HI_LOG_DBG("try parse data(at %d)!\n", rd->reader);
while (symbol != NULL && symbol->upper && symbol->lower && bit_cnt < ip->attr.wanna_bits) {
if (!key_match_phase(symbol, &ip->attr.b0)) {
symbol = ir_next_reader_clr_inc(rd);
bit_cnt++;
continue;
}

if (!key_match_phase(symbol, &ip->attr.b1)) {
if (bit_cnt < 64) { /* 64 is threshold of lower and upper */
if(bit_cnt < 7) {
command |= (unsigned long long)(((unsigned long long)1) << bit_cnt);
}else if(7 <= bit_cnt && bit_cnt < 15) {
address |= (unsigned long long)(((unsigned long long)1) << (bit_cnt-7));
}
//key->lower |= (unsigned long long)(((unsigned long long)1) << bit_cnt);
} else {
key->upper |= (unsigned long long)(((unsigned long long)1) << (bit_cnt - 64)); /* 64 is threshold */
}
symbol = ir_next_reader_clr_inc(rd);
bit_cnt++;
continue;
}
/* meats burst. */
if (bit_cnt + 1 == ip->attr.wanna_bits) {
command = command << 16;
//HI_LOG_ERR("%s-----command->0x%x address->0x%x \n", __func__, command,address);
key->lower = command+address;
command = 0;
address = 0;
ret = sony_last_data_parse(ip, rd, key);
if (ret == 0) {
bit_cnt++;
break;
}
}
HI_LOG_INFO("SONY : unkown symbol[l, u]: [%d, %d],"
" b0[p, s, f]: [%d, %d, %d],"
" b1[p, s, f]: [%d, %d, %d]. Assume to 0!\n",
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.b0.pluse, ip->attr.b0.space,
ip->attr.b0.factor,
ip->attr.b1.pluse, ip->attr.b1.space,
ip->attr.b1.factor);
bit_cnt++;
symbol = ir_next_reader_clr_inc(rd);
return HI_FAILURE;
}
return HI_SUCCESS;
}
int sony_burst_parse(struct ir_protocol *ip, struct ir_buffer *rd)
{
struct key_attr *symbol = NULL;
unsigned long long mins, maxs;

symbol = ir_reader_inc(rd);
HI_LOG_DBG("try parse burst(at %d)!\n", rd->reader);
mins = ip->attr.burst.mins;
maxs = ip->attr.burst.maxs;
if (symbol && ((!data_fallin((HI_U32)symbol->lower, ip->attr.b0.minp, ip->attr.b0.maxp) &&
!data_fallin((HI_U32)symbol->lower, ip->attr.b1.minp, ip->attr.b1.maxp))
|| (symbol->upper < maxs && !data_fallin((HI_U32)symbol->upper, mins, maxs)))) {
HI_LOG_INFO("SONY : unkown symbol[l, u]: [%d, %d],"
" burst[p, s, f]: [%d, %d, %d].\n",
(HI_U32)symbol->lower, (HI_U32)symbol->upper,
ip->attr.burst.pluse, ip->attr.burst.space,
ip->attr.burst.factor);
return HI_FAILURE;
}

if (symbol->upper > maxs) {
return SONY_FINAL_BURST;
}
return SONY_NORMAL_BURST;
}

int sony_key_parse(struct ir_priv *ir, struct ir_protocol *ip,
struct ir_buffer *rd, struct ir_buffer *wr)
{
struct key_attr key;
int length;
int ret;

/* data phase */
if (EOK != memset_s(&key, sizeof(struct key_attr), 0, sizeof(struct key_attr))) {
HI_LOG_ERR("sony_frame_full_parse key memset_s error!\n");
return HI_FAILURE;
}
length = osal_min((HI_U32)strlen(ip->ir_code_name), (HI_U32)(PROTOCOL_NAME_SZ - 1));
if (EOK != memcpy_s(key.protocol_name, PROTOCOL_NAME_SZ, ip->ir_code_name, length)) {
HI_LOG_ERR("sony_frame_full_parse protocol_name memcpy_s err!\n");
}
key.protocol_name[length + 1] = '\0';
ret = sony_data_parse(ip, rd, &key);
if (ret != 0) {
(HI_VOID)ir_next_reader_clr_inc(rd);
return HI_FAILURE;
}

ret = sony_burst_parse(ip, rd);
if (ret == SONY_FINAL_BURST) {
ir_key_report(&key, IR_NORMAL_FINAL_KEY, ip);
} else if (ret == SONY_NORMAL_BURST) {
ir_key_report(&key, IR_NORMAL_KEY, ip);
} else if (ret != 0) {
/* need clear burst symbol? */
return HI_FAILURE;
}

return HI_SUCCESS;
}
int sony_frame_full_parse(struct ir_priv *ir, struct ir_protocol *ip,
struct ir_buffer *rd, struct ir_buffer *wr)
{
int ret;

if (ip->priv >= MAX_SONY_INFR_NR) {
HI_LOG_ERR("sony , private data error!\n");
return HI_FAILURE;
}

osal_timer_del(&g_sony_timer[ip->priv]);
HI_LOG_DBG("try parse header(at %d)!\n", rd->reader);
ret = sony_header_match(rd, ip);
if (ret != IR_MATCH_MATCH) {
return HI_FAILURE;
}
/* key parse */
ret = sony_key_parse(ir, ip, rd, wr);
if (ret != HI_SUCCESS) {
return HI_FAILURE;
}
return HI_SUCCESS;
}
EXPORT_SYMBOL(sony_match);
EXPORT_SYMBOL(sony_frame_full_parse);

  这样看起来可能不是很好看明白,这里推荐用beyond compare工具进行对比,就是更改了sony_data_match函数(主要是12位和15位的匹配),还有sony_data_parse函数,这里就不贴出来了。

1.1.2 配置分析

  我们来看一下红外遥控是怎么配置的, 位于./device/hisilicon/bigfish/system/ir_user/key_pars/key.xml,简单看一下配置内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<key_xml>
<etegol-key>
<!-- 00bf -->
<key value="0x00bf00" name="KEY_POWER" /> <!-- -->
<key value="0x01bf00" name="KEY_MUTE" /> <!-- -->
<key value="0x02bf00" name="KEY_1" />
<key value="0x60bf00" name="KEY_HOME" /> <!-- -->
<!-- more...-->
</etegol-key>

<other-key>
<key value="0x020707" name="KEY_POWER" /> <!-- -->
<key value="0x010707" name="KEY_SOURCE" /> <!-- -->
<key value="0x8B0707" name="KEY_MEDIA" />
<!-- more...-->
</other-key>
</key_xml>

  可以看到,这里外层有个标签key_xml,然后里面又分为两个部分,一个是etegol-key,一个是other-key。在里面的配置中包含了一个key标签,这个key标签有两个属性value和name。valus是十六进制值,name是对应的按键名称。其中vaule的值是十六进制值,这里需要拆分来看,前两位是功能码(用户码)。后面的四位是系统地址码,代表着这个遥控的头码,前两位是高八位,后两位是低八位。name是按键名称。注意这里的name和framwork中的keyEvent.java中的定义是不一样的,但是是一一对应的关系。

  简单分析这里的映射关系,首先是linux键值字符型与整型的关系:./device/hisilicon/bigfish/system/ir_user/key_pars/linux_key.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2019. All rights reserved.
* Description: parse key for virtualkeypad
* Author: hisilicon
* Create: 2012-01-01
*/

/* copy from kernel/include/input.h,do not change it */

#ifndef LINUX_KEY_HEADER
#define LINUX_KEY_HEADER

const int LINUX_KEYCODE_NAME_SIZE = 48;
const int LINUX_KEYCODE_ARY_SIZE = 512;

typedef struct linux_keycode_ {
char linux_keycode_name[LINUX_KEYCODE_NAME_SIZE];
unsigned int linux_keycode;
} linux_keycode_ary;
/*
* Keys and buttons
*
* Most of the keys/buttons are modeled after USB HUT 1.12
* (see http://www.usb.org/developers/hidpage).
* Abbreviations in the comments:
* AC - Application Control
* AL - Application Launch Button
* SC - System Control
*/
const linux_keycode_ary g_linuxKeycodeArray[LINUX_KEYCODE_ARY_SIZE] = {
{"KEY_RESERVED", 0},
{"KEY_ESC", 1},
{"KEY_1", 2},
//more ...
{"KEY_HOME", 102},
{"KEY_REC_LIST", 0x284},
{"KEY_WIFI_SETTING", 0x285},
{"KEY_RECALL", 0x2f0},
{"KEY_MIN_INTERESTING", 113},
{"KEY_MAX", 0x2ff},
{"KEY_CNT", 0x300},
};

#endif

  可以看到在g_linuxKeycodeArray数组中自定义的字符串KEY_HOME的整型数据是102,这个字符串就是我们在key.xml中配置的name。接着继续分析这个KEY_HOME的配置。

  • 涉及目录
    • ./device/hisilicon/bigfish/prebuilts/Vendor_0001_Product_0001.kl
    • ./frameworks/native/libs/input/InputEventLabels.cpp(这里Android 9和Android 12的路径不一样,关键在于DEFINE_KEYCODE宏函数处理)
    • ./frameworks/native/include/android/keycodes.h
    • ./frameworks/base/core/res/res/values/attrs.xml
    • ./frameworks/base/core/java/android/view/KeyEvent.java
    • ./device/hisilicon/bigfish/sdk/source/kernel/linux-xx.y/drivers/hid/hid-input.c
    • ./device/hisilicon/bigfish/sdk/source/kernel/linux-xx.y/include/uapi/linux/input-event-codes.h
    • ./bionic/libc/kernel/uapi/linux/input-event-codes.h
        Vendor_0001_Product_0001.kl是本次分析的默认红外加载的键盘映射文件(KeyLayout),用于定义输入设备的按键映射和行为。如果你不知道当前红外默认加载的是哪个kl文件,可以使用 dumpsys input 查看。这里的键码102映射到 Android 系统中的 HOME 键。再比如KEY_WIFI_SETTING,在linux_key.h文件中定义的是0x285,对应的十进制为645,这些键码是唯一的。
1
2
3
4
# more
key 102 HOME
key 645 KEY_WIFI_SETTING
# more

  这里对应的key 645与之后蓝牙使用的KEY_WIFI_SETTING是sdk下的kernel中的input-event-codes.h定义的,当然也可以直接在hid-input.c使用数值进行绑定,而bionic中的input-event-codes.h同步对应可以使得getevent -l 命令获取到当前的key event name。

  在linux_key.h中自定义了一个字串,我们需要在InputEventLabels文件中定义这个字串。

1
2
3
4
5
6
7
8
9
#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
//more
#define KEYCODES_SEQUENCE \
DEFINE_KEYCODE(UNKNOWN), \
DEFINE_KEYCODE(SOFT_LEFT), \
DEFINE_KEYCODE(SOFT_RIGHT), \
DEFINE_KEYCODE(HOME), \ //more
DEFINE_KEYCODE(KEY_WIFI_SETTING)
//more

  这里的处理比如说HOME这个按键,在xml中是KEY_HOME,在InputEventLabels.cpp中是AKEYCODE_HOME。这。它使用#操作符将key参数转换为字符串,同时使用AKEYCODE_##key表示一个在代码中预定义的键码。在keycodes.h定义这个AKEYCODE_HOME,查看keycodes.h,可以看到已经定义了AKEYCODE_HOME枚举。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//.....
/**
* Key codes.
*/
enum {
/** Unknown key code. */
AKEYCODE_UNKNOWN = 0,
/** Soft Left key.
* Usually situated below the display on phones and used as a multi-function
* feature key for selecting a software defined function shown on the bottom left
* of the display. */
AKEYCODE_SOFT_LEFT = 1,
/** Soft Right key.
* Usually situated below the display on phones and used as a multi-function
* feature key for selecting a software defined function shown on the bottom right
* of the display. */
AKEYCODE_SOFT_RIGHT = 2,
/** Home key.
* This key is handled by the framework and is never delivered to applications. */
AKEYCODE_HOME = 3,
//.....
}

  文件attrs.xml中的keycode标签的枚举数组和KeyEvent.java中就是定义静态常量就是我们在framework层响应的keyCode值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class KeyEvent extends InputEvent implements Parcelable {
/** Key code constant: Unknown key code. */
public static final int KEYCODE_UNKNOWN = 0;
/** Key code constant: Soft Left key.
* Usually situated below the display on phones and used as a multi-function
* feature key for selecting a software defined function shown on the bottom left
* of the display. */
public static final int KEYCODE_SOFT_LEFT = 1;
/** Key code constant: Soft Right key.
* Usually situated below the display on phones and used as a multi-function
* feature key for selecting a software defined function shown on the bottom right
* of the display. */
public static final int KEYCODE_SOFT_RIGHT = 2;
/** Key code constant: Home key.
* This key is handled by the framework and is never delivered to applications. */
public static final int KEYCODE_HOME = 3;
//more.....
}

2. 总结

  学会使用工具,找准分析方向,不要畏惧,不要放弃。剩下关于蓝牙的配置可以参考下面的文章。