/* * cyttsp5_test_device_access_api.c * Parade TrueTouch(TM) Standard Product V5 Device Access API test module. * For use with Parade touchscreen controllers. * Supported parts include: * CYTMA5XX * CYTMA448 * CYTMA445A * CYTT21XXX * CYTT31XXX * * Copyright (C) 2015 Parade Technologies * Copyright (C) 2012-2015 Cypress Semiconductor * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2, and only version 2, as published by the * Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Contact Parade Technologies at www.paradetech.com * */ #include #include #include #define BUFFER_SIZE 256 #define COMMAND_GET_SYSTEM_INFO 2 #define COMMAND_SUSPEND_SCANNING 3 #define COMMAND_RESUME_SCANNING 4 #define COMMAND_GET_PARAMETER 5 #define COMMAND_SET_PARAMETER 6 #define PARAMETER_ACTIVE_DISTANCE_2 0x0B struct tt_output_report { __le16 reg_address; __le16 length; u8 report_id; u8 reserved; u8 command; u8 parameters[0]; } __packed; struct tt_input_report { __le16 length; u8 report_id; u8 reserved; u8 command; u8 return_data[0]; } __packed; static int prepare_tt_output_report(struct tt_output_report *out, u16 length, u8 command) { put_unaligned_le16(0x04, &out->reg_address); put_unaligned_le16(5 + length, &out->length); out->report_id = 0x2f; out->reserved = 0x00; out->command = command; return 7 + length; } static int check_and_parse_tt_input_report(struct tt_input_report *in, u16 *length, u8 *command) { if (in->report_id != 0x1f) return -EINVAL; *length = get_unaligned_le16(&in->length); *command = in->command & 0x7f; return 0; } static int prepare_get_system_info_report(u8 *buf) { struct tt_output_report *out = (struct tt_output_report *)buf; return prepare_tt_output_report(out, 0, COMMAND_GET_SYSTEM_INFO); } static int check_get_system_info_response(u8 *buf, u16 read_length) { struct tt_input_report *in = (struct tt_input_report *)buf; u16 length = 0; u8 command = 0; if (read_length != 51) return -EINVAL; if (check_and_parse_tt_input_report(in, &length, &command) || command != COMMAND_GET_SYSTEM_INFO || length != 51) return -EINVAL; pr_info("PIP Major Version: %d\n", in->return_data[0]); pr_info("PIP Minor Version: %d\n", in->return_data[1]); pr_info("Touch Firmware Product Id: %d\n", get_unaligned_le16(&in->return_data[2])); pr_info("Touch Firmware Major Version: %d\n", in->return_data[4]); pr_info("Touch Firmware Minor Version: %d\n", in->return_data[5]); pr_info("Touch Firmware Internal Revision Control Number: %d\n", get_unaligned_le32(&in->return_data[6])); pr_info("Customer Specified Firmware/Configuration Version: %d\n", get_unaligned_le16(&in->return_data[10])); pr_info("Bootloader Major Version: %d\n", in->return_data[12]); pr_info("Bootloader Minor Version: %d\n", in->return_data[13]); pr_info("Family ID: 0x%02x\n", in->return_data[14]); pr_info("Revision ID: 0x%02x\n", in->return_data[15]); pr_info("Silicon ID: 0x%02x\n", get_unaligned_le16(&in->return_data[16])); pr_info("Parade Manufacturing ID[0]: 0x%02x\n", in->return_data[18]); pr_info("Parade Manufacturing ID[1]: 0x%02x\n", in->return_data[19]); pr_info("Parade Manufacturing ID[2]: 0x%02x\n", in->return_data[20]); pr_info("Parade Manufacturing ID[3]: 0x%02x\n", in->return_data[21]); pr_info("Parade Manufacturing ID[4]: 0x%02x\n", in->return_data[22]); pr_info("Parade Manufacturing ID[5]: 0x%02x\n", in->return_data[23]); pr_info("Parade Manufacturing ID[6]: 0x%02x\n", in->return_data[24]); pr_info("Parade Manufacturing ID[7]: 0x%02x\n", in->return_data[25]); pr_info("POST Result Code: 0x%02x\n", get_unaligned_le16(&in->return_data[26])); pr_info("Number of X Electrodes: %d\n", in->return_data[28]); pr_info("Number of Y Electrodes: %d\n", in->return_data[29]); pr_info("Panel X Axis Length: %d\n", get_unaligned_le16(&in->return_data[30])); pr_info("Panel Y Axis Length: %d\n", get_unaligned_le16(&in->return_data[32])); pr_info("Panel X Axis Resolution: %d\n", get_unaligned_le16(&in->return_data[34])); pr_info("Panel Y Axis Resolution: %d\n", get_unaligned_le16(&in->return_data[36])); pr_info("Panel Pressure Resolution: %d\n", get_unaligned_le16(&in->return_data[38])); pr_info("X_ORG: %d\n", in->return_data[40]); pr_info("Y_ORG: %d\n", in->return_data[41]); pr_info("Panel ID: %d\n", in->return_data[42]); pr_info("Buttons: 0x%02x\n", in->return_data[43]); pr_info("BAL SELF MC: 0x%02x\n", in->return_data[44]); pr_info("Max Number of Touch Records per Refresh Cycle: %d\n", in->return_data[45]); return 0; } static int prepare_get_parameter_report(u8 *buf, u8 parameter_id) { struct tt_output_report *out = (struct tt_output_report *)buf; out->parameters[0] = parameter_id; return prepare_tt_output_report(out, 1, COMMAND_GET_PARAMETER); } static int check_get_parameter_response(u8 *buf, u16 read_length, u32 *parameter_value) { struct tt_input_report *in = (struct tt_input_report *)buf; u16 length = 0; u8 command = 0; u32 param_value = 0; u8 param_id; u8 param_size = 0; if (read_length != 8 && read_length != 9 && read_length != 11) return -EINVAL; if (check_and_parse_tt_input_report(in, &length, &command) || command != COMMAND_GET_PARAMETER || (length != 8 && length != 9 && length != 11)) return -EINVAL; param_id = in->return_data[0]; param_size = in->return_data[1]; if (param_size == 1) param_value = in->return_data[2]; else if (param_size == 2) param_value = get_unaligned_le16(&in->return_data[2]); else if (param_size == 4) param_value = get_unaligned_le32(&in->return_data[2]); else return -EINVAL; pr_info("%s: Parameter ID: 0x%02x Value: 0x%02x\n", __func__, param_id, param_value); if (parameter_value) *parameter_value = param_value; return 0; } static int prepare_set_parameter_report(u8 *buf, u8 parameter_id, u8 parameter_size, u32 parameter_value) { struct tt_output_report *out = (struct tt_output_report *)buf; out->parameters[0] = parameter_id; out->parameters[1] = parameter_size; if (parameter_size == 1) out->parameters[2] = (u8)parameter_value; else if (parameter_size == 2) put_unaligned_le16(parameter_value, &out->parameters[2]); else if (parameter_size == 4) put_unaligned_le32(parameter_value, &out->parameters[2]); else return -EINVAL; return prepare_tt_output_report(out, 2 + parameter_size, COMMAND_SET_PARAMETER); } static int check_set_parameter_response(u8 *buf, u16 read_length) { struct tt_input_report *in = (struct tt_input_report *)buf; u16 length = 0; u8 command = 0; u8 param_id; u8 param_size = 0; if (read_length != 7) return -EINVAL; if (check_and_parse_tt_input_report(in, &length, &command) || command != COMMAND_SET_PARAMETER || length != 7) return -EINVAL; param_id = in->return_data[0]; param_size = in->return_data[1]; pr_info("%s: Parameter ID: 0x%02x Size: 0x%02x\n", __func__, param_id, param_size); return 0; } static int prepare_suspend_scanning_report(u8 *buf) { struct tt_output_report *out = (struct tt_output_report *)buf; return prepare_tt_output_report(out, 0, COMMAND_SUSPEND_SCANNING); } static int check_suspend_scanning_response(u8 *buf, u16 read_length) { struct tt_input_report *in = (struct tt_input_report *)buf; u16 length = 0; u8 command = 0; if (read_length != 5) return -EINVAL; if (check_and_parse_tt_input_report(in, &length, &command) || command != COMMAND_SUSPEND_SCANNING || length != 5) return -EINVAL; return 0; } static int prepare_resume_scanning_report(u8 *buf) { struct tt_output_report *out = (struct tt_output_report *)buf; return prepare_tt_output_report(out, 0, COMMAND_RESUME_SCANNING); } static int check_resume_scanning_response(u8 *buf, u16 read_length) { struct tt_input_report *in = (struct tt_input_report *)buf; u16 length = 0; u8 command = 0; if (read_length != 5) return -EINVAL; if (check_and_parse_tt_input_report(in, &length, &command) || command != COMMAND_RESUME_SCANNING || length != 5) return -EINVAL; return 0; } void cyttsp5_user_command_async_cont(const char *core_name, u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf, u16 actual_read_length, int rc) { if (rc) { pr_err("%s: suspend scan fails\n", __func__); goto exit; } rc = check_suspend_scanning_response(read_buf, actual_read_length); if (rc) { pr_err("%s: check suspend scanning response fails\n", __func__); goto exit; } pr_info("%s: suspend scanning succeeds\n", __func__); exit: return; } /* Read and write buffers */ static u8 write_buf[BUFFER_SIZE]; static u8 read_buf[BUFFER_SIZE]; static uint active_distance; module_param(active_distance, uint, 0); static int __init cyttsp5_test_device_access_api_init(void) { u32 initial_active_distance; u16 actual_read_len; int write_len; int rc; pr_info("%s: Enter\n", __func__); /* CASE 1: Run get system information */ write_len = prepare_get_system_info_report(write_buf); rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf), read_buf, write_len, write_buf, &actual_read_len); if (rc) goto exit; rc = check_get_system_info_response(read_buf, actual_read_len); if (rc) goto exit; /* CASE 2: Run get parameter (Active distance) */ write_len = prepare_get_parameter_report(write_buf, PARAMETER_ACTIVE_DISTANCE_2); rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf), read_buf, write_len, write_buf, &actual_read_len); if (rc) goto exit; rc = check_get_parameter_response(read_buf, actual_read_len, &initial_active_distance); if (rc) goto exit; pr_info("%s: Initial Active Distance: %d\n", __func__, initial_active_distance); /* CASE 3: Run set parameter (Active distance) */ write_len = prepare_set_parameter_report(write_buf, PARAMETER_ACTIVE_DISTANCE_2, 1, active_distance); rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf), read_buf, write_len, write_buf, &actual_read_len); if (rc) goto exit; rc = check_set_parameter_response(read_buf, actual_read_len); if (rc) goto exit; pr_info("%s: Active Distance set to %d\n", __func__, active_distance); /* CASE 4: Run get parameter (Active distance) */ write_len = prepare_get_parameter_report(write_buf, PARAMETER_ACTIVE_DISTANCE_2); rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf), read_buf, write_len, write_buf, &actual_read_len); if (rc) goto exit; rc = check_get_parameter_response(read_buf, actual_read_len, &active_distance); if (rc) goto exit; pr_info("%s: New Active Distance: %d\n", __func__, active_distance); /* CASE 5: Run suspend scanning asynchronously */ write_len = prepare_suspend_scanning_report(write_buf); preempt_disable(); rc = cyttsp5_device_access_user_command_async(NULL, sizeof(read_buf), read_buf, write_len, write_buf, cyttsp5_user_command_async_cont); preempt_enable(); if (rc) goto exit; exit: return rc; } module_init(cyttsp5_test_device_access_api_init); static void __exit cyttsp5_test_device_access_api_exit(void) { u16 actual_read_len; int write_len; int rc; /* CASE 6: Run resume scanning */ write_len = prepare_resume_scanning_report(write_buf); rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf), read_buf, write_len, write_buf, &actual_read_len); if (rc) goto exit; rc = check_resume_scanning_response(read_buf, actual_read_len); if (rc) goto exit; pr_info("%s: resume scanning succeeds\n", __func__); exit: return; } module_exit(cyttsp5_test_device_access_api_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Device Access Driver API Tester"); MODULE_AUTHOR("Parade Technologies ");