123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2017-2021 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * DP bigdata
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/secdp_bigdata.h>
- #define EDID_BUF_SIZE 512
- #define ERR_DATA_BUF_SIZE 1024
- #define COL_NAME_SIZE 20
- enum DP_ITEM_TYPE {
- INT = 1,
- HEX = 2,
- STR = 4,
- CHR = 8,
- ERR = 16,
- };
- enum DP_STATUS {
- STATUS_NO_CONNECTION,
- STATUS_CONNECTION,
- STATUS_ERROR_OCCURRED,
- };
- struct bd_item_info {
- char name[COL_NAME_SIZE];
- char type;
- void *data;
- int str_max_len;
- };
- struct bd_error_data {
- int limit;
- int count;
- };
- static char err_data_buf[ERR_DATA_BUF_SIZE];
- static struct bd_item_info item_to_column[BD_ITEM_MAX];
- static enum DP_STATUS dp_status;
- static void secdp_bigdata_save_data(void);
- static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...);
- static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit);
- static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val);
- static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val);
- static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val);
- static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val);
- ssize_t _secdp_bigdata_show(struct class *class,
- struct class_attribute *attr, char *buf)
- {
- if (dp_status == STATUS_NO_CONNECTION)
- return 0;
- return scnprintf(buf, ERR_DATA_BUF_SIZE, "%s", err_data_buf);
- }
- ssize_t _secdp_bigdata_store(struct class *dev,
- struct class_attribute *attr, const char *buf, size_t size)
- {
- if ((buf[0] | 0x20) == 'c')
- dp_status = STATUS_NO_CONNECTION;
- return size;
- }
- void secdp_bigdata_init(struct class *dp_class)
- {
- secdp_bigdata_init_item(BD_LINK_CONFIGURE, "LINK_CFG", CHR);
- secdp_bigdata_init_item(BD_ADAPTER_HWID, "ADT_HWID", HEX);
- secdp_bigdata_init_item(BD_ADAPTER_FWVER, "ADT_FWVER", HEX);
- secdp_bigdata_init_item(BD_ADAPTER_TYPE, "ADT_TYPE", STR, 20);
- secdp_bigdata_init_item(BD_MAX_LANE_COUNT, "MLANE_CNT", INT);
- secdp_bigdata_init_item(BD_MAX_LINK_RATE, "MLINK_RATE", INT);
- secdp_bigdata_init_item(BD_CUR_LANE_COUNT, "CLANE_CNT", INT);
- secdp_bigdata_init_item(BD_CUR_LINK_RATE, "CLINK_RATE", INT);
- secdp_bigdata_init_item(BD_HDCP_VER, "HDCP_VER", STR, 10);
- secdp_bigdata_init_item(BD_ORIENTATION, "ORIENTATION", STR, 10);
- secdp_bigdata_init_item(BD_RESOLUTION, "RESOLUTION", STR, 20);
- secdp_bigdata_init_item(BD_EDID, "EDID", STR, EDID_BUF_SIZE);
- secdp_bigdata_init_item(BD_ADT_VID, "ADT_VID", HEX);
- secdp_bigdata_init_item(BD_ADT_PID, "ADT_PID", HEX);
- secdp_bigdata_init_item(BD_DP_MODE, "DP_MODE", STR, 10);
- secdp_bigdata_init_item(BD_SINK_NAME, "SINK_NAME", STR, 14);
- secdp_bigdata_init_item(BD_AUD_CH, "AUD_CH", INT);
- secdp_bigdata_init_item(BD_AUD_FREQ, "AUD_FREQ", INT);
- secdp_bigdata_init_item(BD_AUD_BIT, "AUD_BIT", INT);
- secdp_bigdata_init_error(ERR_AUX, "ERR_AUX", 3);
- secdp_bigdata_init_error(ERR_EDID, "ERR_EDID", 1);
- secdp_bigdata_init_error(ERR_HDCP_AUTH, "ERR_HDCP", 5);
- secdp_bigdata_init_error(ERR_LINK_TRAIN, "ERR_LT_TRAIN", 1);
- secdp_bigdata_init_error(ERR_INF_IRQHPD, "ERR_INF_IRQHPD", 10);
- }
- static void secdp_bigdata_init_item_str(enum DP_BD_ITEM_LIST item, char *val, int max_len)
- {
- kfree(item_to_column[item].data);
- item_to_column[item].data = kzalloc(max_len + 1, GFP_KERNEL);
- if (!item_to_column[item].data)
- return;
- item_to_column[item].str_max_len = max_len;
- strlcpy((char *)item_to_column[item].data, val, max_len + 1);
- }
- static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...)
- {
- va_list vl;
- va_start(vl, type);
- strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
- item_to_column[item].type = type;
- switch (type) {
- case INT:
- case HEX:
- secdp_bigdata_save_item_int(item, -1);
- break;
- case STR:
- secdp_bigdata_init_item_str(item, "X", (int)va_arg(vl, int));
- break;
- case CHR:
- secdp_bigdata_save_item_char(item, 'X');
- break;
- default:
- break;
- }
- va_end(vl);
- }
- static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit)
- {
- struct bd_error_data *err = kzalloc(sizeof(struct bd_error_data), GFP_KERNEL);
- if (err)
- err->limit = err_limit;
- strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
- item_to_column[item].type = ERR;
- item_to_column[item].data = err;
- }
- static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val)
- {
- if (!item_to_column[item].data) {
- item_to_column[item].data = kzalloc(sizeof(int), GFP_KERNEL);
- if (!item_to_column[item].data)
- return;
- }
- *((int *)item_to_column[item].data) = val;
- }
- static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val)
- {
- secdp_bigdata_save_item_int(item, val);
- }
- static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val)
- {
- if (!item_to_column[item].data) {
- item_to_column[item].data = kzalloc(sizeof(char), GFP_KERNEL);
- if (!item_to_column[item].data)
- return;
- }
- *((char *)item_to_column[item].data) = val;
- }
- static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val)
- {
- if (!item_to_column[item].data || !val)
- return;
- if (item == BD_EDID && val[0] != 'X') {
- int ret = 0;
- int i;
- int ext_blk_cnt = val[0x7e] ? 1 : 0;
- int edid_size = 128 * (ext_blk_cnt + 1);
- for (i = 0; i < edid_size; i++) {
- ret += scnprintf(((char *)item_to_column[item].data) + ret,
- EDID_BUF_SIZE + 1 - ret, "%02x",
- val[i]);
- }
- } else {
- strlcpy((char *)item_to_column[item].data, val,
- item_to_column[item].str_max_len + 1);
- }
- }
- void secdp_bigdata_save_item(enum DP_BD_ITEM_LIST item, ...)
- {
- va_list vl;
- if (item >= BD_ITEM_MAX || item < 0)
- return;
- va_start(vl, item);
- switch (item_to_column[item].type) {
- case INT:
- secdp_bigdata_save_item_hex(item, (int)va_arg(vl, int));
- break;
- case HEX:
- secdp_bigdata_save_item_int(item, (int)va_arg(vl, int));
- break;
- case STR:
- secdp_bigdata_save_item_str(item, (char *)va_arg(vl, char *));
- break;
- case CHR:
- secdp_bigdata_save_item_char(item, (char)va_arg(vl, int));
- break;
- default:
- break;
- }
- va_end(vl);
- }
- void secdp_bigdata_inc_error_cnt(enum DP_BD_ITEM_LIST err)
- {
- if (err >= BD_ITEM_MAX || err < 0)
- return;
- if (item_to_column[err].data && item_to_column[err].type == ERR)
- ((struct bd_error_data *)item_to_column[err].data)->count++;
- }
- void secdp_bigdata_clr_error_cnt(enum DP_BD_ITEM_LIST err)
- {
- if (err >= BD_ITEM_MAX || err < 0)
- return;
- if (item_to_column[err].data && item_to_column[err].type == ERR)
- ((struct bd_error_data *)item_to_column[err].data)->count = 0;
- }
- static void secdp_bigdata_save_data(void)
- {
- int i;
- int ret = 0;
- for (i = 0; i < BD_ITEM_MAX; i++) {
- switch (item_to_column[i].type) {
- case INT:
- ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
- "\"%s\":\"%d\",",
- item_to_column[i].name,
- (item_to_column[i].data != NULL) ?
- *((int *)item_to_column[i].data) : -1);
- break;
- case HEX:
- ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
- "\"%s\":\"0x%x\",",
- item_to_column[i].name,
- (item_to_column[i].data != NULL) ?
- *((int *)item_to_column[i].data) : -1);
- break;
- case STR:
- ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
- "\"%s\":\"%s\",",
- item_to_column[i].name,
- (item_to_column[i].data != NULL) ?
- (char *)item_to_column[i].data : "X");
- break;
- case CHR:
- ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
- "\"%s\":\"%c\",",
- item_to_column[i].name,
- (item_to_column[i].data != NULL) ?
- *((char *)item_to_column[i].data) : 'X');
- break;
- case ERR:
- ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
- "\"%s\":\"%d\",",
- item_to_column[i].name,
- (item_to_column[i].data != NULL) ?
- ((struct bd_error_data *)item_to_column[i].data)->count : 0);
- break;
- default:
- break;
- }
- }
- if (ret > 0)
- err_data_buf[ret - 1] = '\n';
- }
- static int secdp_bigdata_check_err(void)
- {
- int i;
- struct bd_error_data *e_data;
- for (i = 0; i < BD_ITEM_MAX; i++) {
- if (item_to_column[i].type == ERR) {
- e_data = item_to_column[i].data;
- if (e_data != NULL && e_data->count >= e_data->limit)
- return 1;
- }
- }
- return 0;
- }
- void secdp_bigdata_connection(void)
- {
- int i;
- if (dp_status != STATUS_ERROR_OCCURRED)
- dp_status = STATUS_CONNECTION;
- for (i = 0; i < BD_ITEM_MAX; i++) {
- switch (item_to_column[i].type) {
- case INT:
- case HEX:
- secdp_bigdata_save_item_int(i, -1);
- break;
- case STR:
- secdp_bigdata_save_item_str(i, "X");
- break;
- case CHR:
- secdp_bigdata_save_item_char(i, 'X');
- break;
- case ERR:
- secdp_bigdata_clr_error_cnt(i);
- break;
- default:
- break;
- }
- }
- }
- void secdp_bigdata_disconnection(void)
- {
- if (secdp_bigdata_check_err()) {
- dp_status = STATUS_ERROR_OCCURRED;
- secdp_bigdata_save_data();
- }
- if (dp_status != STATUS_ERROR_OCCURRED)
- secdp_bigdata_save_data();
- }
|