secdp_bigdata.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2021 Samsung Electronics Co., Ltd.
  4. * http://www.samsung.com
  5. *
  6. * DP bigdata
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/slab.h>
  15. #include <linux/secdp_bigdata.h>
  16. #define EDID_BUF_SIZE 512
  17. #define ERR_DATA_BUF_SIZE 1024
  18. #define COL_NAME_SIZE 20
  19. enum DP_ITEM_TYPE {
  20. INT = 1,
  21. HEX = 2,
  22. STR = 4,
  23. CHR = 8,
  24. ERR = 16,
  25. };
  26. enum DP_STATUS {
  27. STATUS_NO_CONNECTION,
  28. STATUS_CONNECTION,
  29. STATUS_ERROR_OCCURRED,
  30. };
  31. struct bd_item_info {
  32. char name[COL_NAME_SIZE];
  33. char type;
  34. void *data;
  35. int str_max_len;
  36. };
  37. struct bd_error_data {
  38. int limit;
  39. int count;
  40. };
  41. static char err_data_buf[ERR_DATA_BUF_SIZE];
  42. static struct bd_item_info item_to_column[BD_ITEM_MAX];
  43. static enum DP_STATUS dp_status;
  44. static void secdp_bigdata_save_data(void);
  45. static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...);
  46. static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit);
  47. static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val);
  48. static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val);
  49. static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val);
  50. static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val);
  51. ssize_t _secdp_bigdata_show(struct class *class,
  52. struct class_attribute *attr, char *buf)
  53. {
  54. if (dp_status == STATUS_NO_CONNECTION)
  55. return 0;
  56. return scnprintf(buf, ERR_DATA_BUF_SIZE, "%s", err_data_buf);
  57. }
  58. ssize_t _secdp_bigdata_store(struct class *dev,
  59. struct class_attribute *attr, const char *buf, size_t size)
  60. {
  61. if ((buf[0] | 0x20) == 'c')
  62. dp_status = STATUS_NO_CONNECTION;
  63. return size;
  64. }
  65. void secdp_bigdata_init(struct class *dp_class)
  66. {
  67. secdp_bigdata_init_item(BD_LINK_CONFIGURE, "LINK_CFG", CHR);
  68. secdp_bigdata_init_item(BD_ADAPTER_HWID, "ADT_HWID", HEX);
  69. secdp_bigdata_init_item(BD_ADAPTER_FWVER, "ADT_FWVER", HEX);
  70. secdp_bigdata_init_item(BD_ADAPTER_TYPE, "ADT_TYPE", STR, 20);
  71. secdp_bigdata_init_item(BD_MAX_LANE_COUNT, "MLANE_CNT", INT);
  72. secdp_bigdata_init_item(BD_MAX_LINK_RATE, "MLINK_RATE", INT);
  73. secdp_bigdata_init_item(BD_CUR_LANE_COUNT, "CLANE_CNT", INT);
  74. secdp_bigdata_init_item(BD_CUR_LINK_RATE, "CLINK_RATE", INT);
  75. secdp_bigdata_init_item(BD_HDCP_VER, "HDCP_VER", STR, 10);
  76. secdp_bigdata_init_item(BD_ORIENTATION, "ORIENTATION", STR, 10);
  77. secdp_bigdata_init_item(BD_RESOLUTION, "RESOLUTION", STR, 20);
  78. secdp_bigdata_init_item(BD_EDID, "EDID", STR, EDID_BUF_SIZE);
  79. secdp_bigdata_init_item(BD_ADT_VID, "ADT_VID", HEX);
  80. secdp_bigdata_init_item(BD_ADT_PID, "ADT_PID", HEX);
  81. secdp_bigdata_init_item(BD_DP_MODE, "DP_MODE", STR, 10);
  82. secdp_bigdata_init_item(BD_SINK_NAME, "SINK_NAME", STR, 14);
  83. secdp_bigdata_init_item(BD_AUD_CH, "AUD_CH", INT);
  84. secdp_bigdata_init_item(BD_AUD_FREQ, "AUD_FREQ", INT);
  85. secdp_bigdata_init_item(BD_AUD_BIT, "AUD_BIT", INT);
  86. secdp_bigdata_init_error(ERR_AUX, "ERR_AUX", 3);
  87. secdp_bigdata_init_error(ERR_EDID, "ERR_EDID", 1);
  88. secdp_bigdata_init_error(ERR_HDCP_AUTH, "ERR_HDCP", 5);
  89. secdp_bigdata_init_error(ERR_LINK_TRAIN, "ERR_LT_TRAIN", 1);
  90. secdp_bigdata_init_error(ERR_INF_IRQHPD, "ERR_INF_IRQHPD", 10);
  91. }
  92. static void secdp_bigdata_init_item_str(enum DP_BD_ITEM_LIST item, char *val, int max_len)
  93. {
  94. kfree(item_to_column[item].data);
  95. item_to_column[item].data = kzalloc(max_len + 1, GFP_KERNEL);
  96. if (!item_to_column[item].data)
  97. return;
  98. item_to_column[item].str_max_len = max_len;
  99. strlcpy((char *)item_to_column[item].data, val, max_len + 1);
  100. }
  101. static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...)
  102. {
  103. va_list vl;
  104. va_start(vl, type);
  105. strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
  106. item_to_column[item].type = type;
  107. switch (type) {
  108. case INT:
  109. case HEX:
  110. secdp_bigdata_save_item_int(item, -1);
  111. break;
  112. case STR:
  113. secdp_bigdata_init_item_str(item, "X", (int)va_arg(vl, int));
  114. break;
  115. case CHR:
  116. secdp_bigdata_save_item_char(item, 'X');
  117. break;
  118. default:
  119. break;
  120. }
  121. va_end(vl);
  122. }
  123. static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit)
  124. {
  125. struct bd_error_data *err = kzalloc(sizeof(struct bd_error_data), GFP_KERNEL);
  126. if (err)
  127. err->limit = err_limit;
  128. strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
  129. item_to_column[item].type = ERR;
  130. item_to_column[item].data = err;
  131. }
  132. static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val)
  133. {
  134. if (!item_to_column[item].data) {
  135. item_to_column[item].data = kzalloc(sizeof(int), GFP_KERNEL);
  136. if (!item_to_column[item].data)
  137. return;
  138. }
  139. *((int *)item_to_column[item].data) = val;
  140. }
  141. static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val)
  142. {
  143. secdp_bigdata_save_item_int(item, val);
  144. }
  145. static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val)
  146. {
  147. if (!item_to_column[item].data) {
  148. item_to_column[item].data = kzalloc(sizeof(char), GFP_KERNEL);
  149. if (!item_to_column[item].data)
  150. return;
  151. }
  152. *((char *)item_to_column[item].data) = val;
  153. }
  154. static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val)
  155. {
  156. if (!item_to_column[item].data || !val)
  157. return;
  158. if (item == BD_EDID && val[0] != 'X') {
  159. int ret = 0;
  160. int i;
  161. int ext_blk_cnt = val[0x7e] ? 1 : 0;
  162. int edid_size = 128 * (ext_blk_cnt + 1);
  163. for (i = 0; i < edid_size; i++) {
  164. ret += scnprintf(((char *)item_to_column[item].data) + ret,
  165. EDID_BUF_SIZE + 1 - ret, "%02x",
  166. val[i]);
  167. }
  168. } else {
  169. strlcpy((char *)item_to_column[item].data, val,
  170. item_to_column[item].str_max_len + 1);
  171. }
  172. }
  173. void secdp_bigdata_save_item(enum DP_BD_ITEM_LIST item, ...)
  174. {
  175. va_list vl;
  176. if (item >= BD_ITEM_MAX || item < 0)
  177. return;
  178. va_start(vl, item);
  179. switch (item_to_column[item].type) {
  180. case INT:
  181. secdp_bigdata_save_item_hex(item, (int)va_arg(vl, int));
  182. break;
  183. case HEX:
  184. secdp_bigdata_save_item_int(item, (int)va_arg(vl, int));
  185. break;
  186. case STR:
  187. secdp_bigdata_save_item_str(item, (char *)va_arg(vl, char *));
  188. break;
  189. case CHR:
  190. secdp_bigdata_save_item_char(item, (char)va_arg(vl, int));
  191. break;
  192. default:
  193. break;
  194. }
  195. va_end(vl);
  196. }
  197. void secdp_bigdata_inc_error_cnt(enum DP_BD_ITEM_LIST err)
  198. {
  199. if (err >= BD_ITEM_MAX || err < 0)
  200. return;
  201. if (item_to_column[err].data && item_to_column[err].type == ERR)
  202. ((struct bd_error_data *)item_to_column[err].data)->count++;
  203. }
  204. void secdp_bigdata_clr_error_cnt(enum DP_BD_ITEM_LIST err)
  205. {
  206. if (err >= BD_ITEM_MAX || err < 0)
  207. return;
  208. if (item_to_column[err].data && item_to_column[err].type == ERR)
  209. ((struct bd_error_data *)item_to_column[err].data)->count = 0;
  210. }
  211. static void secdp_bigdata_save_data(void)
  212. {
  213. int i;
  214. int ret = 0;
  215. for (i = 0; i < BD_ITEM_MAX; i++) {
  216. switch (item_to_column[i].type) {
  217. case INT:
  218. ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
  219. "\"%s\":\"%d\",",
  220. item_to_column[i].name,
  221. (item_to_column[i].data != NULL) ?
  222. *((int *)item_to_column[i].data) : -1);
  223. break;
  224. case HEX:
  225. ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
  226. "\"%s\":\"0x%x\",",
  227. item_to_column[i].name,
  228. (item_to_column[i].data != NULL) ?
  229. *((int *)item_to_column[i].data) : -1);
  230. break;
  231. case STR:
  232. ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
  233. "\"%s\":\"%s\",",
  234. item_to_column[i].name,
  235. (item_to_column[i].data != NULL) ?
  236. (char *)item_to_column[i].data : "X");
  237. break;
  238. case CHR:
  239. ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
  240. "\"%s\":\"%c\",",
  241. item_to_column[i].name,
  242. (item_to_column[i].data != NULL) ?
  243. *((char *)item_to_column[i].data) : 'X');
  244. break;
  245. case ERR:
  246. ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
  247. "\"%s\":\"%d\",",
  248. item_to_column[i].name,
  249. (item_to_column[i].data != NULL) ?
  250. ((struct bd_error_data *)item_to_column[i].data)->count : 0);
  251. break;
  252. default:
  253. break;
  254. }
  255. }
  256. if (ret > 0)
  257. err_data_buf[ret - 1] = '\n';
  258. }
  259. static int secdp_bigdata_check_err(void)
  260. {
  261. int i;
  262. struct bd_error_data *e_data;
  263. for (i = 0; i < BD_ITEM_MAX; i++) {
  264. if (item_to_column[i].type == ERR) {
  265. e_data = item_to_column[i].data;
  266. if (e_data != NULL && e_data->count >= e_data->limit)
  267. return 1;
  268. }
  269. }
  270. return 0;
  271. }
  272. void secdp_bigdata_connection(void)
  273. {
  274. int i;
  275. if (dp_status != STATUS_ERROR_OCCURRED)
  276. dp_status = STATUS_CONNECTION;
  277. for (i = 0; i < BD_ITEM_MAX; i++) {
  278. switch (item_to_column[i].type) {
  279. case INT:
  280. case HEX:
  281. secdp_bigdata_save_item_int(i, -1);
  282. break;
  283. case STR:
  284. secdp_bigdata_save_item_str(i, "X");
  285. break;
  286. case CHR:
  287. secdp_bigdata_save_item_char(i, 'X');
  288. break;
  289. case ERR:
  290. secdp_bigdata_clr_error_cnt(i);
  291. break;
  292. default:
  293. break;
  294. }
  295. }
  296. }
  297. void secdp_bigdata_disconnection(void)
  298. {
  299. if (secdp_bigdata_check_err()) {
  300. dp_status = STATUS_ERROR_OCCURRED;
  301. secdp_bigdata_save_data();
  302. }
  303. if (dp_status != STATUS_ERROR_OCCURRED)
  304. secdp_bigdata_save_data();
  305. }