/* * Copyright (c) 2017 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief TP Keyboard driver for Actions SoC */ #define ir_protocol_param_init #define capture_param_init #include #include #include #include #include #include "IR_context.h" struct capture_handle cp_handle; static int capture_acts_rate_check(u32_t code_rate, u32_t carrier_rate) { if((code_rate - carrier_rate) * (code_rate - carrier_rate) > 4) return -1; return 0; } static int capture_acts_lc_length(u32_t code) { u32_t lc_num = 0; u32_t temp_val = 0; while(code) { temp_val = code & 1; code = code >> 1; if((code & 1) != temp_val) lc_num++; } return lc_num; } static int capture_acts_halfcode_compare(uint32_t code, uint32_t cp, u32_t threshold) { int temp_val = 0; u32_t threshold_val = 0; temp_val = (code & 0x7fff) - (cp & 0x7fff); threshold_val = (cp&0x7fff)*threshold/100; if(temp_val * temp_val > threshold_val * threshold_val) return -EIO; return 0; } static int capture_acts_lead_check(u32_t *data, u32_t bit_length, u32_t code, u32_t threshold) { u32_t lc_num, temp_val, lc_length; u32_t irpro_buf[32]; memset(irpro_buf, 0, 32); lc_num = 0; while(code) { irpro_buf[lc_num] = irpro_buf[lc_num] + 1; temp_val = code & 1; code = code >> 1; if((code & 1) != temp_val) lc_num++; } for(int j = 0; j < lc_num; j++) { lc_length = irpro_buf[lc_num - 1 - j] * bit_length; temp_val = data[j] & 0x7fff; if(j == (lc_num - 1)) { if(temp_val > (lc_length + threshold*bit_length/100)) return temp_val -lc_length - threshold*bit_length/200; } if((temp_val - lc_length) * (temp_val - lc_length) > (threshold*bit_length/100)*(threshold*bit_length/100)) return -2; } return 0; } static int capture_acts_code_compare(uint32_t code_pre, uint32_t code_post, uint32_t cp_pre, uint32_t cp_post, u32_t threshold) { int temp_val = 0; u32_t threshold_val = 0; if((code_pre & 0x8000) != (cp_pre & 0x8000)) return -EIO; if((code_post & 0x8000) != (cp_post & 0x8000)) return -EIO; temp_val = (code_pre & 0x7fff) - (cp_pre & 0x7fff); threshold_val = (cp_pre&0x7fff)*threshold/100; if(temp_val * temp_val > threshold_val * threshold_val) return -EIO; threshold_val = (cp_post&0x7fff)*threshold/100; if(code_post < (cp_post + threshold_val))//belong to a complete message return 0; temp_val = (code_post & 0x7fff) - (cp_post & 0x7fff) - (cp_post & 0x7fff)*threshold/200;//post including a next message return temp_val; } static int capture_acts_cv(u32_t *data, u32_t offset, ir_receive_param_t *param, u32_t threshold, u32_t leader_hc, u32_t *decode) { int data_pre, data_post; uint32_t code_off; int temp_val, temp_data; uint32_t code0_pre, code0_post, code1_pre, code1_post; uint32_t tr0_pre, tr0_post, tr1_pre, tr1_post; int cp_result[4]; bool code1_discriminate = false; code0_pre = (param->ir_0_code & 0x8000) | ((param->ir_0_code & 0x7f00) >> 8) * param->code_bit_length; code0_post = (param->ir_0_code & 0x80) << 8 | (param->ir_0_code & 0x7f) * param->code_bit_length; code1_pre = (param->ir_1_code & 0x8000) | ((param->ir_1_code & 0x7f00) >> 8) * param->code_bit_length; code1_post = (param->ir_1_code & 0x80) << 8 | (param->ir_1_code & 0x7f) * param->code_bit_length; if(param->ir_trc_loc) { tr0_pre = (param->ir_tr0_code & 0x8000) | ((param->ir_tr0_code & 0x7f00) >> 8) * param->code_bit_length; tr0_post = (param->ir_tr0_code & 0x80) << 8 | (param->ir_tr0_code & 0x7f) * param->code_bit_length; tr1_pre = (param->ir_tr1_code & 0x8000) | ((param->ir_tr1_code & 0x7f00) >> 8) * param->code_bit_length; tr1_post = (param->ir_tr1_code & 0x80) << 8 | (param->ir_tr1_code & 0x7f) * param->code_bit_length; } code_off = decode[0] = decode[1] = 0; if(leader_hc) { offset = offset - 1; data_pre = (data[offset] & 0x8000) | leader_hc; } else data_pre = data[offset];// a complete message including data_pre | data_ post data_post = data[offset + 1]; for(int j = offset; j < 99; j++) { code_off++; if(data[j] == 0) break; if(((data[j] & 0x8000) == 0) && ((data[j] & 0x7fff) > param->ir_max_code)) break; if(code_off > param->ir_dc_length + 1) return -3; if(code_off > param->ir_dc_length) continue; if(j > offset) data_post = data[j + 1]; temp_val = capture_acts_code_compare(data_pre, data_post, code0_pre, code0_post, threshold); if(temp_val > 0) { cp_result[0] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, code0_pre, threshold); cp_result[1] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, code1_pre, threshold); cp_result[2] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, tr0_pre, threshold); cp_result[3] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, tr1_pre, threshold); if(cp_result[3]&&cp_result[2]&&cp_result[1]&&cp_result[0]) temp_val = -5; } if(temp_val != 0) { temp_data = capture_acts_code_compare(data_pre, data_post, code1_pre, code1_post, threshold); if(temp_data > 0) { cp_result[0] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, code0_pre, threshold); cp_result[1] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, code1_pre, threshold); cp_result[2] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, tr0_pre, threshold); cp_result[3] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, tr1_pre, threshold); if(cp_result[3]&&cp_result[2]&&cp_result[1]&&cp_result[0]) temp_data = -5; } if(temp_data >= 0) { temp_val = temp_data; code1_discriminate = true; } } if(temp_val >= 0) { if(code1_discriminate) { if(param->ir_dc_length - code_off > 32) decode[1] |= 1 << (param->ir_dc_length - code_off - 32); else decode[0] |= 1 << (param->ir_dc_length - code_off); } code1_discriminate = false; } if(temp_val > 0) {//compare status and including next message data_pre = (data_post & 0x8000) | temp_val; continue; } else if(temp_val == 0) {//campare status j++; data_pre = data[j + 1]; continue; } if(param->ir_trc_loc) { temp_val = capture_acts_code_compare(data_pre, data_post, tr0_pre, tr0_post, threshold); if(temp_val > 0) { cp_result[0] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, code0_pre, threshold); cp_result[1] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, code1_pre, threshold); cp_result[2] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, tr0_pre, threshold); cp_result[3] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_val, tr1_pre, threshold); if(cp_result[3]&&cp_result[2]&&cp_result[1]&&cp_result[0]) temp_val = -5; } if(temp_val != 0) { temp_data = capture_acts_code_compare(data_pre, data_post, tr1_pre, tr1_post, threshold); if(temp_data > 0) { cp_result[0] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, code0_pre, threshold); cp_result[1] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, code1_pre, threshold); cp_result[2] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, tr0_pre, threshold); cp_result[3] = capture_acts_halfcode_compare((data_post & 0x8000) | temp_data, tr1_pre, threshold); if(cp_result[3]&&cp_result[2]&&cp_result[1]&&cp_result[0]) temp_data = -5; } if(temp_data >= 0) { temp_val = temp_data; code1_discriminate = true; } } if(temp_val >= 0) { if(code1_discriminate) { if(param->ir_dc_length - code_off > 32) decode[1] |= 1 << (param->ir_dc_length - code_off - 32); else decode[0] |= 1 << (param->ir_dc_length - code_off); } code1_discriminate = false; } if(temp_val > 0) {//compare status and including next message data_pre = (data_post & 0x8000) | temp_val; continue; } else if(temp_val == 0) {//campare status j++; data_pre = data[j + 1]; continue; } } return -3; } if(decode[1]) printk("decode:0x%x%x\n", decode[1], decode[0]); else printk("decode:0x%x\n", decode[0]); return 0; } static int capture_acts_Tf(u32_t *data, u32_t Tf, u32_t lc_bit_length, u32_t threshold) { int data_val, temp_val; int j = 0; temp_val = 0; for(j = 0; j < 100; j++) { data_val = data[j] & 0x7fff; temp_val += data_val/10; if(data_val == 0) break; if(((data[j] & 0x8000) == 0) && ((data[j] & 0x7fff) > lc_bit_length)) break; } for(; j < 100; j++) { data_val = data[j] & 0x8000; if(data_val != 0) { break; } data_val = data[j] & 0x7fff; if(data_val == 0) temp_val += 3277/3; else temp_val += data_val/10; } if(temp_val < Tf - Tf*threshold/100) return -4; return 0; } static u32_t capture_acts_ic(u32_t *decode, ir_receive_param_t *param) { u32_t data[2]; data[0] = ((decode[0] >> param->ir_ic_co) | (decode[1] << (32 - param->ir_ic_co)))¶m->ir_ic_mask; data[1] = (decode[0] >> param->ir_ic_ico)¶m->ir_ic_mask; if(data[0] & data[1]) return -5; return 0; } static int capture_acts_discriminate(struct capture_data *data, u32_t *decode) { u32_t irpro_param1, irpro_param2, irpro_param3; int i, result; u32_t leader_hc; result = 0; for(i = 0; i < Protocols_MAX; i++) { irpro_param3 = ir_protocol_param[i].ir_threshold_val; /* rate check */ if(ir_protocol_param[i].ir_cr_check_en) { if(capture_acts_rate_check(ir_protocol_param[i].ir_cr_rate , data->carrier_rate)) { result = -1; continue; } } /* lead check */ if(ir_protocol_param[i].ir_lc_check_en) { irpro_param1 = ir_protocol_param[i].ir_lc_bit_length; irpro_param2 = ir_protocol_param[i].ir_lc_code; leader_hc = capture_acts_lead_check(data->capture_data, irpro_param1, irpro_param2, irpro_param3); if(leader_hc < 0) { result = -2; continue; } } /* code check */ if(ir_protocol_param[i].ir_cv_check_en) { irpro_param1 = capture_acts_lc_length(ir_protocol_param[i].ir_lc_code); result = capture_acts_cv(data->capture_data, irpro_param1, &ir_protocol_param[i], irpro_param3, leader_hc, decode); if(result == -3) { continue; } } /* Tf check */ if(ir_protocol_param[i].ir_Tf_check_en) { irpro_param1 = ir_protocol_param[i].ir_Tf_length; if(capture_acts_Tf(data->capture_data, irpro_param1, ir_protocol_param[i].ir_max_code, irpro_param3)) { result = -4; continue; } } /* ir inverse code check */ if(ir_protocol_param[i].ir_ic_check_en) { irpro_param1 = capture_acts_lc_length(ir_protocol_param[i].ir_lc_code); if(capture_acts_ic(decode, &ir_protocol_param[i])) { result = -5; continue; } } break; } if(i < Protocols_MAX) return i; else return result; } static int capture_acts_protocol(int ret) { u32_t protocol; switch(ret) { case PWM_IR_6122: protocol = IR_uPD6121; printk("IR protocol is nec\n"); break; case PWM_IR_9012: protocol = IR_9012; printk("IR protocol is 9012\n"); break; case PWM_IR_RC6: protocol = IR_RC6_dat1; printk("IR protocol is RC6\n"); break; case PWM_IR_50462: protocol = IR_50462; printk("IR protocol is 50462\n"); break; case PWM_IR_M50560: protocol = IR_M50560_dat1; printk("IR protocol is 50560\n"); break; case PWM_IR_RC5X: protocol = IR_RC5; printk("IR protocol is rc5x\n"); break; case PWM_IR_7461: protocol = IR_7461; printk("IR protocol is 7461\n"); break; case PWM_IR_3004: protocol = IR_3004; printk("IR protocol is 3004\n"); break; case PWM_IR_RCA: protocol = IR_RCA; printk("IR protocol is RCA\n"); break; default: printk("can not find right protocol: %d\n", ret); return -ENOTSUP; } return protocol; } static void capture_data_dump(struct capture_data *data) { printk("rate:%dkhz\n", data->carrier_rate); for(int i = 0;i < 100;i++) { data->capture_data[i] = (data->capture_data[i] & 0x8000) | ((data->capture_data[i] & 0x7fff)/3);//cycle to us if(i%10 == 9) { printk("%d0%d\n", ((data->capture_data[i] & 0x8000) >> 15), (data->capture_data[i] & 0x7fff)); continue; } printk("%d0%d ", ((data->capture_data[i] & 0x8000) >> 15), (data->capture_data[i] & 0x7fff)); } } void capture_notify_callback(struct device *dev, struct input_value *val) { struct capture_handle * handle = &cp_handle; struct input_value report_val; uint32_t decode_data[2] = {0x11,0x22}; struct capture_data data; int result; data.capture_data = val->ir.protocol.data; data.carrier_rate = val->ir.protocol.carry_rate; capture_data_dump(&data); result = capture_acts_discriminate(&data, decode_data); result = capture_acts_protocol(result); report_val.ir.protocol.mode = result; report_val.ir.protocol.data = decode_data; handle->capture_notify(NULL, &report_val); } struct capture_handle * capture_device_open(capture_notify_cb cb, char * dev_name) { struct capture_handle * handle = &cp_handle; if(handle == NULL) { printk("capture device in mem_malloc failed need %d bytes ",(int)sizeof(struct capture_handle)); return NULL; } handle->input_dev = (struct device *)device_get_binding(dev_name); if (!handle->input_dev) { printk("cannot found capture dev %s\n",dev_name); return NULL; } input_dev_enable(handle->input_dev); input_dev_register_notify(handle->input_dev, capture_notify_callback); handle->capture_notify = cb; return handle; } void capture_device_close(void * handle) { struct capture_handle * capture = &cp_handle; input_dev_unregister_notify(capture->input_dev, capture->capture_notify); input_dev_disable(capture->input_dev); } void capture_device_abort_cb(void * handle) { struct capture_handle * capture = &cp_handle; input_dev_unregister_notify(capture->input_dev, capture->capture_notify); } void capture_device_enable_cb(void * handle) { struct capture_handle * capture = &cp_handle; input_dev_register_notify(capture->input_dev, capture->capture_notify); }