12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2014 Samsung Electronics Co., Ltd.
- *
- * 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 "sec_cmd.h"
- #include "sec_input.h"
- #include "sec_tsp_log.h"
- struct class *tsp_sec_class;
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- __visible_for_testing struct sec_cmd_data *kunit_sec;
- EXPORT_SYMBOL(kunit_sec);
- #else
- #define __visible_for_testing static
- #endif
- const char *str_power_state[3] = { "OFF", "LP", "ON" };
- const char *str_use_case[CHECK_ALL + 1] = {
- "NONE", // 0
- "OFF", // 1 CHECK_POWEROFF
- "LP", // 2 CHECK_LPMODE
- "LP/OFF", // 3 CHECK_POWEROFF | CHECK_LPMODE
- "ON", // 4 CHECK_POWERON
- "ON/OFF", // 5 CHECK_POWEROFF | CHECK_POWERON
- "ON/LP", // 6 CHECK_ON_LP
- "ON/LP/OFF", // 7 CHECK_ALL
- };
- #ifdef USE_SEC_CMD_QUEUE
- static void cmd_store_function(struct sec_cmd_data *data);
- void sec_cmd_execution(struct sec_cmd_data *data, bool lock)
- {
- if (lock)
- mutex_lock(&data->fs_lock);
- /* check lock */
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 1);
- mutex_unlock(&data->cmd_lock);
- data->cmd_state = SEC_CMD_STATUS_RUNNING;
- cmd_store_function(data);
- if (lock)
- mutex_unlock(&data->fs_lock);
- }
- #endif
- void sec_cmd_set_cmd_exit(struct sec_cmd_data *data)
- {
- #ifdef USE_SEC_CMD_QUEUE
- mutex_lock(&data->fifo_lock);
- if (kfifo_len(&data->cmd_queue)) {
- pr_info("%s: %s %s: do next cmd, left cmd[%d]\n", dev_name(data->fac_dev), SECLOG, __func__,
- (int)(kfifo_len(&data->cmd_queue) / sizeof(struct command)));
- mutex_unlock(&data->fifo_lock);
- sec_cmd_execution(data, false);
- } else {
- mutex_unlock(&data->fifo_lock);
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 0);
- mutex_unlock(&data->cmd_lock);
- }
- if (data->wait_cmd_result_done)
- complete_all(&data->cmd_result_done);
- #else
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 0);
- mutex_unlock(&data->cmd_lock);
- #endif
- }
- EXPORT_SYMBOL(sec_cmd_set_cmd_exit);
- #ifdef USE_SEC_CMD_QUEUE
- static void cmd_exit_work(struct work_struct *work)
- {
- struct sec_cmd_data *data = container_of(work, struct sec_cmd_data, cmd_work.work);
- sec_cmd_execution(data, true);
- }
- #endif
- void sec_cmd_set_default_result(struct sec_cmd_data *data)
- {
- char *delim = ":";
- memset(data->cmd_result, 0x00, SEC_CMD_RESULT_STR_LEN_EXPAND);
- memcpy(data->cmd_result, data->cmd, SEC_CMD_STR_LEN);
- strlcat(data->cmd_result, delim, SEC_CMD_RESULT_STR_LEN_EXPAND);
- }
- EXPORT_SYMBOL(sec_cmd_set_default_result);
- void sec_cmd_set_cmd_result_all(struct sec_cmd_data *data, char *buff, int len, char *item)
- {
- char *delim1 = " ";
- char *delim2 = ":";
- int cmd_result_len;
- cmd_result_len = (int)strlen(data->cmd_result_all) + len + 2 + (int)strlen(item);
- if (cmd_result_len >= SEC_CMD_RESULT_STR_LEN) {
- pr_err("%s: %s %s: cmd length is over (%d)!!", dev_name(data->fac_dev), SECLOG, __func__, cmd_result_len);
- return;
- }
- data->item_count++;
- strlcat(data->cmd_result_all, delim1, sizeof(data->cmd_result_all));
- strlcat(data->cmd_result_all, item, sizeof(data->cmd_result_all));
- strlcat(data->cmd_result_all, delim2, sizeof(data->cmd_result_all));
- strlcat(data->cmd_result_all, buff, sizeof(data->cmd_result_all));
- }
- EXPORT_SYMBOL(sec_cmd_set_cmd_result_all);
- void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff, int len)
- {
- if (strlen(buff) >= (unsigned int)SEC_CMD_RESULT_STR_LEN_EXPAND) {
- pr_err("%s %s: cmd length is over (%d)!!", SECLOG, __func__, (int)strlen(buff));
- strlcat(data->cmd_result, "NG", SEC_CMD_RESULT_STR_LEN_EXPAND);
- return;
- }
- data->cmd_result_expand = (int)strlen(buff) / SEC_CMD_RESULT_STR_LEN;
- data->cmd_result_expand_count = 0;
- strlcat(data->cmd_result, buff, SEC_CMD_RESULT_STR_LEN_EXPAND);
- }
- EXPORT_SYMBOL(sec_cmd_set_cmd_result);
- void sec_cmd_check_store_condition(struct sec_cmd_data *data, struct sec_cmd *sec_cmd_ptr)
- {
- struct sec_ts_plat_data *plat_data = data->dev->platform_data;
- int prev_result_len = 0;
- pr_info("%s %s power_state:%s, check_power:%s%s, wait_result:%d\n",
- dev_name(data->fac_dev), SECLOG, str_power_state[atomic_read(&plat_data->power_state)],
- str_use_case[sec_cmd_ptr->cmd_use_cases],
- sec_cmd_ptr->cmd_func_forced ? "(force func)" : "",
- sec_cmd_ptr->wait_read_result);
- sec_cmd_set_default_result(data);
- prev_result_len = (int)strlen(data->cmd_result);
- if (sec_input_cmp_ic_status(data->dev, sec_cmd_ptr->cmd_use_cases)) {
- sec_cmd_ptr->cmd_func(data);
- } else {
- if (sec_cmd_ptr->cmd_func_forced)
- sec_cmd_ptr->cmd_func_forced(data);
- else
- goto CMD_NG;
- }
- if (prev_result_len == (int)strlen(data->cmd_result)) {
- if ((data->cmd_state == SEC_CMD_STATUS_WAITING) || (data->cmd_state == SEC_CMD_STATUS_OK))
- strlcat(data->cmd_result, "OK", SEC_CMD_RESULT_STR_LEN_EXPAND);
- else if (data->cmd_state == SEC_CMD_STATUS_NOT_APPLICABLE)
- strlcat(data->cmd_result, "NA", SEC_CMD_RESULT_STR_LEN_EXPAND);
- else
- strlcat(data->cmd_result, "NG", SEC_CMD_RESULT_STR_LEN_EXPAND);
- }
- if (sec_cmd_ptr->wait_read_result == EXIT_RESULT) {
- data->cmd_state = SEC_CMD_STATUS_WAITING;
- sec_cmd_set_cmd_exit(data);
- }
- return;
- CMD_NG:
- data->cmd_state = SEC_CMD_STATUS_FAIL;
- strlcat(data->cmd_result, "NG", SEC_CMD_RESULT_STR_LEN_EXPAND);
- if (sec_cmd_ptr->wait_read_result == EXIT_RESULT)
- sec_cmd_set_cmd_exit(data);
- }
- #ifndef USE_SEC_CMD_QUEUE
- __visible_for_testing ssize_t cmd_store(struct device *dev,
- struct device_attribute *devattr, const char *buf, size_t count)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- char *cur, *start, *end;
- char buff[SEC_CMD_STR_LEN] = { 0 };
- int len, i;
- struct sec_cmd *sec_cmd_ptr = NULL;
- char delim = ',';
- bool cmd_found = false;
- int param_cnt = 0;
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return -EINVAL;
- }
- if (strnlen(buf, SEC_CMD_STR_LEN) >= SEC_CMD_STR_LEN) {
- pr_err("%s: %s %s: cmd length(strlen(buf)) is over (%d,%s)!!\n",
- dev_name(data->fac_dev), SECLOG, __func__, (int)strlen(buf), buf);
- return -EINVAL;
- }
- if (count >= (unsigned int)SEC_CMD_STR_LEN) {
- pr_err("%s: %s %s: cmd length(count) is over (%d,%s)!!\n",
- dev_name(data->fac_dev), SECLOG, __func__, (unsigned int)count, buf);
- return -EINVAL;
- }
- if (atomic_read(&data->cmd_is_running)) {
- pr_err("%s: %s %s: other cmd is running.\n", dev_name(data->fac_dev), SECLOG, __func__);
- return -EBUSY;
- }
- /* check lock */
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 1);
- mutex_unlock(&data->cmd_lock);
- data->cmd_state = SEC_CMD_STATUS_RUNNING;
- for (i = 0; i < ARRAY_SIZE(data->cmd_param); i++)
- data->cmd_param[i] = 0;
- len = (int)count;
- if (*(buf + len - 1) == '\n')
- len--;
- memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd));
- memcpy(data->cmd, buf, len);
- cur = strchr(buf, (int)delim);
- if (cur)
- memcpy(buff, buf, cur - buf);
- else
- memcpy(buff, buf, len);
- pr_debug("%s: %s %s: COMMAND = %s\n", dev_name(data->fac_dev), SECLOG, __func__, buff);
- /* find command */
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
- if (!sec_cmd_ptr->not_support_cmds) {
- cmd_found = true;
- break;
- }
- pr_err("%s: %s %s: [%s] is in not_support_cmds list\n", dev_name(data->fac_dev), SECLOG, __func__, buff);
- }
- }
- check_not_support_cmd:
- /* set not_support_cmd */
- if (!cmd_found) {
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name,
- SEC_CMD_STR_LEN))
- break;
- }
- }
- /* parsing parameters */
- if (cur && cmd_found) {
- cur++;
- start = cur;
- memset(buff, 0x00, ARRAY_SIZE(buff));
- do {
- if (*cur == delim || cur - buf == len) {
- end = cur;
- memcpy(buff, start, end - start);
- *(buff + strnlen(buff, ARRAY_SIZE(buff))) = '\0';
- if (kstrtoint(buff, 10, data->cmd_param + param_cnt) < 0) {
- pr_err("%s: %s %s: error to parse parameter\n",
- dev_name(data->fac_dev), SECLOG, __func__);
- cmd_found = false;
- goto check_not_support_cmd;
- }
- start = cur + 1;
- memset(buff, 0x00, ARRAY_SIZE(buff));
- param_cnt++;
- }
- cur++;
- } while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM));
- }
- if (cmd_found) {
- char dbuff[13];
- char tdbuff[13 * SEC_CMD_PARAM_NUM] = { 0 };
- for (i = 0; i < param_cnt; i++) {
- snprintf(dbuff, sizeof(dbuff), "%d ", data->cmd_param[i]);
- strlcat(tdbuff, dbuff, sizeof(tdbuff));
- }
- if (param_cnt == 0)
- snprintf(tdbuff, sizeof(tdbuff), "none");
- pr_info("%s: %s %s: cmd = %s param = %s\n", dev_name(data->fac_dev), SECLOG, __func__, sec_cmd_ptr->cmd_name, tdbuff);
- } else {
- pr_info("%s: %s %s: cmd = %s(%s)\n", dev_name(data->fac_dev), SECLOG, __func__, buff, sec_cmd_ptr->cmd_name);
- }
- if (sec_cmd_ptr->cmd_use_cases)
- sec_cmd_check_store_condition(data, sec_cmd_ptr);
- else
- sec_cmd_ptr->cmd_func(data);
- return count;
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_store);
- #endif
- #else /* defined USE_SEC_CMD_QUEUE */
- static void cmd_store_function(struct sec_cmd_data *data)
- {
- char *cur, *start, *end;
- char buff[SEC_CMD_STR_LEN] = { 0 };
- int len, i;
- struct sec_cmd *sec_cmd_ptr = NULL;
- char delim = ',';
- bool cmd_found = false;
- int param_cnt = 0;
- int ret;
- const char *buf;
- size_t count;
- struct command cmd = {{0}};
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return;
- }
- mutex_lock(&data->fifo_lock);
- if (kfifo_len(&data->cmd_queue)) {
- ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command));
- if (!ret) {
- pr_err("%s: %s %s: kfifo_out failed, it seems empty, ret=%d\n", dev_name(data->fac_dev), SECLOG, __func__, ret);
- mutex_unlock(&data->fifo_lock);
- return;
- }
- } else {
- pr_err("%s: %s %s: left cmd is nothing\n", dev_name(data->fac_dev), SECLOG, __func__);
- mutex_unlock(&data->fifo_lock);
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 0);
- mutex_unlock(&data->cmd_lock);
- return;
- }
- mutex_unlock(&data->fifo_lock);
- buf = cmd.cmd;
- count = strlen(buf);
- for (i = 0; i < (int)ARRAY_SIZE(data->cmd_param); i++)
- data->cmd_param[i] = 0;
- len = (int)count;
- if (*(buf + len - 1) == '\n')
- len--;
- memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd));
- memcpy(data->cmd, buf, len);
- cur = strchr(buf, (int)delim);
- if (cur)
- memcpy(buff, buf, cur - buf);
- else
- memcpy(buff, buf, len);
- pr_debug("%s: %s %s: COMMAND : %s\n", dev_name(data->fac_dev), SECLOG, __func__, buff);
- /* find command */
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
- if (!sec_cmd_ptr->not_support_cmds) {
- cmd_found = true;
- break;
- }
- pr_err("%s: %s %s: [%s] is in not_support_cmds list\n", dev_name(data->fac_dev), SECLOG, __func__, buff);
- }
- }
- check_not_support_cmd:
- /* set not_support_cmd */
- if (!cmd_found) {
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name,
- SEC_CMD_STR_LEN))
- break;
- }
- }
- /* parsing parameters */
- if (cur && cmd_found) {
- cur++;
- start = cur;
- memset(buff, 0x00, ARRAY_SIZE(buff));
- do {
- if (*cur == delim || cur - buf == len) {
- end = cur;
- memcpy(buff, start, end - start);
- *(buff + strnlen(buff, ARRAY_SIZE(buff))) = '\0';
- if (kstrtoint(buff, 10, data->cmd_param + param_cnt) < 0) {
- pr_err("%s: %s %s: error to parse parameter\n",
- dev_name(data->fac_dev), SECLOG, __func__);
- cmd_found = false;
- goto check_not_support_cmd;
- }
- start = cur + 1;
- memset(buff, 0x00, ARRAY_SIZE(buff));
- param_cnt++;
- }
- cur++;
- } while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM));
- }
- if (cmd_found) {
- char dbuff[13];
- char tdbuff[13 * SEC_CMD_PARAM_NUM] = { 0 };
- for (i = 0; i < param_cnt; i++) {
- snprintf(dbuff, sizeof(dbuff), "%d ", data->cmd_param[i]);
- strlcat(tdbuff, dbuff, sizeof(tdbuff));
- }
- if (param_cnt == 0)
- snprintf(tdbuff, sizeof(tdbuff), "none");
- pr_info("%s: %s %s: cmd = %s param = %s\n", dev_name(data->fac_dev), SECLOG, __func__, sec_cmd_ptr->cmd_name, tdbuff);
- } else {
- pr_info("%s: %s %s: cmd = %s(%s)\n", dev_name(data->fac_dev), SECLOG, __func__, buff, sec_cmd_ptr->cmd_name);
- }
- if (sec_cmd_ptr->cmd_use_cases)
- sec_cmd_check_store_condition(data, sec_cmd_ptr);
- else
- sec_cmd_ptr->cmd_func(data);
- if (cmd_found && sec_cmd_ptr->cmd_log) {
- char tbuf[32];
- unsigned long long t;
- unsigned long nanosec_rem;
- memset(tbuf, 0x00, sizeof(tbuf));
- t = local_clock();
- nanosec_rem = do_div(t, 1000000000);
- snprintf(tbuf, sizeof(tbuf), "[r:%lu.%06lu]",
- (unsigned long)t,
- nanosec_rem / 1000);
- #if IS_ENABLED(CONFIG_SEC_DEBUG_TSP_LOG)
- sec_debug_tsp_command_history(tbuf);
- #endif
- }
- }
- __visible_for_testing ssize_t cmd_store(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- struct command cmd = {{0}};
- struct sec_cmd *sec_cmd_ptr = NULL;
- int queue_size;
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return -EINVAL;
- }
- if (strnlen(buf, SEC_CMD_STR_LEN) >= SEC_CMD_STR_LEN) {
- pr_err("%s: %s %s: cmd length(strlen(buf)) is over (%d,%s)!!\n",
- dev_name(data->fac_dev), SECLOG, __func__, (int)strlen(buf), buf);
- return -EINVAL;
- }
- if (count >= (unsigned int)SEC_CMD_STR_LEN) {
- pr_err("%s: %s %s: cmd length(count) is over (%d,%s)!!\n",
- dev_name(data->fac_dev), SECLOG, __func__, (unsigned int)count, buf);
- return -EINVAL;
- }
- if (strnlen(buf, SEC_CMD_STR_LEN) == 0) {
- pr_err("%s: %s %s: cmd length is zero (%d,%s) count(%ld)!!\n",
- dev_name(data->fac_dev), SECLOG, __func__, (int)strlen(buf), buf, count);
- return -EINVAL;
- }
- strncpy(cmd.cmd, buf, count);
- if (data->wait_cmd_result_done) {
- int ret;
- mutex_lock(&data->wait_lock);
- if (!data->cmd_result_done.done)
- pr_info("%s: %s %s: %s - waiting prev cmd...\n", dev_name(data->fac_dev), SECLOG, __func__, cmd.cmd);
- ret = wait_for_completion_interruptible_timeout(&data->cmd_result_done, msecs_to_jiffies(2000));
- if (ret <= 0)
- pr_err("%s: %s %s: completion %d\n", dev_name(data->fac_dev), SECLOG, __func__, ret);
- reinit_completion(&data->cmd_result_done);
- mutex_unlock(&data->wait_lock);
- }
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (!strncmp(cmd.cmd, sec_cmd_ptr->cmd_name, strlen(sec_cmd_ptr->cmd_name))) {
- if (sec_cmd_ptr->cmd_log) {
- char task_info[40];
- char tbuf[32];
- unsigned long long t;
- unsigned long nanosec_rem;
- memset(tbuf, 0x00, sizeof(tbuf));
- t = local_clock();
- nanosec_rem = do_div(t, 1000000000);
- snprintf(tbuf, sizeof(tbuf), "[q:%lu.%06lu]",
- (unsigned long)t,
- nanosec_rem / 1000);
- snprintf(task_info, 40, "\n[%d:%s:%s]", current->pid, current->comm, dev_name(data->fac_dev));
- #if IS_ENABLED(CONFIG_SEC_DEBUG_TSP_LOG)
- sec_debug_tsp_command_history(task_info);
- sec_debug_tsp_command_history(cmd.cmd);
- sec_debug_tsp_command_history(tbuf);
- #endif
- }
- break;
- }
- }
- mutex_lock(&data->fifo_lock);
- queue_size = (kfifo_len(&data->cmd_queue) / sizeof(struct command));
- if (kfifo_avail(&data->cmd_queue) && (queue_size < SEC_CMD_MAX_QUEUE)) {
- kfifo_in(&data->cmd_queue, &cmd, sizeof(struct command));
- pr_info("%s: %s %s: push cmd: %s\n", dev_name(data->fac_dev), SECLOG, __func__, cmd.cmd);
- } else {
- pr_err("%s: %s %s: cmd_queue is full!!\n", dev_name(data->fac_dev), SECLOG, __func__);
- kfifo_reset(&data->cmd_queue);
- pr_err("%s: %s %s: cmd_queue is reset!!\n", dev_name(data->fac_dev), SECLOG, __func__);
- mutex_unlock(&data->fifo_lock);
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 0);
- mutex_unlock(&data->cmd_lock);
- if (data->wait_cmd_result_done)
- complete_all(&data->cmd_result_done);
- return -ENOSPC;
- }
- if (atomic_read(&data->cmd_is_running)) {
- pr_err("%s: %s %s: other cmd is running. Wait until previous cmd is done[%d]\n",
- dev_name(data->fac_dev), SECLOG, __func__, (int)(kfifo_len(&data->cmd_queue) / sizeof(struct command)));
- mutex_unlock(&data->fifo_lock);
- return count;
- }
- mutex_unlock(&data->fifo_lock);
- sec_cmd_execution(data, true);
- return count;
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_store);
- #endif
- #endif
- __visible_for_testing ssize_t cmd_status_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- char buff[16] = { 0 };
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return -EINVAL;
- }
- if (data->cmd_state == SEC_CMD_STATUS_WAITING)
- snprintf(buff, sizeof(buff), "WAITING");
- else if (data->cmd_state == SEC_CMD_STATUS_RUNNING)
- snprintf(buff, sizeof(buff), "RUNNING");
- else if (data->cmd_state == SEC_CMD_STATUS_OK)
- snprintf(buff, sizeof(buff), "OK");
- else if (data->cmd_state == SEC_CMD_STATUS_FAIL)
- snprintf(buff, sizeof(buff), "FAIL");
- else if (data->cmd_state == SEC_CMD_STATUS_EXPAND)
- snprintf(buff, sizeof(buff), "EXPAND");
- else if (data->cmd_state == SEC_CMD_STATUS_NOT_APPLICABLE)
- snprintf(buff, sizeof(buff), "NOT_APPLICABLE");
- pr_debug("%s: %s %s: %d, %s\n", dev_name(data->fac_dev), SECLOG, __func__, data->cmd_state, buff);
- return snprintf(buf, sizeof(buff), "%s\n", buff);
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_status_show);
- #endif
- __visible_for_testing ssize_t cmd_status_all_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- char buff[16] = { 0 };
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return -EINVAL;
- }
- if (data->cmd_all_factory_state == SEC_CMD_STATUS_WAITING)
- snprintf(buff, sizeof(buff), "WAITING");
- else if (data->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING)
- snprintf(buff, sizeof(buff), "RUNNING");
- else if (data->cmd_all_factory_state == SEC_CMD_STATUS_OK)
- snprintf(buff, sizeof(buff), "OK");
- else if (data->cmd_all_factory_state == SEC_CMD_STATUS_FAIL)
- snprintf(buff, sizeof(buff), "FAIL");
- else if (data->cmd_state == SEC_CMD_STATUS_EXPAND)
- snprintf(buff, sizeof(buff), "EXPAND");
- else if (data->cmd_all_factory_state == SEC_CMD_STATUS_NOT_APPLICABLE)
- snprintf(buff, sizeof(buff), "NOT_APPLICABLE");
- pr_debug("%s: %s %s: %d, %s\n", dev_name(data->fac_dev), SECLOG, __func__, data->cmd_all_factory_state, buff);
- return snprintf(buf, sizeof(buff), "%s\n", buff);
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_status_all_show);
- #endif
- __visible_for_testing ssize_t cmd_result_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- int size;
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return -EINVAL;
- }
- size = snprintf(buf, SEC_CMD_RESULT_STR_LEN, "%s\n",
- data->cmd_result + (SEC_CMD_RESULT_STR_LEN - 1) * data->cmd_result_expand_count);
- if (data->cmd_result_expand_count != data->cmd_result_expand) {
- data->cmd_state = SEC_CMD_STATUS_EXPAND;
- data->cmd_result_expand_count++;
- } else {
- data->cmd_state = SEC_CMD_STATUS_WAITING;
- }
- pr_info("%s: %s %s: %s\n", dev_name(data->fac_dev), SECLOG, __func__, buf);
- sec_cmd_set_cmd_exit(data);
- return size;
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_result_show);
- #endif
- __visible_for_testing ssize_t cmd_result_all_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- int size;
- if (!data) {
- pr_err("%s %s: No platform data found\n", SECLOG, __func__);
- return -EINVAL;
- }
- data->cmd_state = SEC_CMD_STATUS_WAITING;
- pr_info("%s: %s %s: %d, %s\n", dev_name(data->fac_dev), SECLOG, __func__, data->item_count, data->cmd_result_all);
- size = snprintf(buf, SEC_CMD_RESULT_STR_LEN, "%d%s\n", data->item_count, data->cmd_result_all);
- sec_cmd_set_cmd_exit(data);
- data->item_count = 0;
- memset(data->cmd_result_all, 0x00, SEC_CMD_RESULT_STR_LEN);
- return size;
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_result_all_show);
- #endif
- __visible_for_testing ssize_t cmd_list_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct sec_cmd_data *data = dev_get_drvdata(dev);
- struct sec_cmd *sec_cmd_ptr = NULL;
- char *buffer;
- char buffer_name[SEC_CMD_STR_LEN];
- int ret = 0;
- buffer = kzalloc(data->cmd_buffer_size + 30, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
- snprintf(buffer, 30, "++factory command list++\n");
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (sec_cmd_ptr->not_support_cmds)
- continue;
- if (strncmp(sec_cmd_ptr->cmd_name, "not_support_cmd", 15)) {
- snprintf(buffer_name, SEC_CMD_STR_LEN, "%s\n", sec_cmd_ptr->cmd_name);
- strlcat(buffer, buffer_name, data->cmd_buffer_size + 30);
- }
- }
- ret = snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buffer);
- kfree(buffer);
- return ret;
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(cmd_list_show);
- #endif
- static DEVICE_ATTR(cmd, 0220, NULL, cmd_store);
- static DEVICE_ATTR_RO(cmd_status);
- static DEVICE_ATTR_RO(cmd_status_all);
- static DEVICE_ATTR_RO(cmd_result);
- static DEVICE_ATTR_RO(cmd_result_all);
- static DEVICE_ATTR_RO(cmd_list);
- static struct attribute *sec_fac_attrs[] = {
- &dev_attr_cmd.attr,
- &dev_attr_cmd_status.attr,
- &dev_attr_cmd_status_all.attr,
- &dev_attr_cmd_result.attr,
- &dev_attr_cmd_result_all.attr,
- &dev_attr_cmd_list.attr,
- NULL,
- };
- static struct attribute_group sec_fac_attr_group = {
- .attrs = sec_fac_attrs,
- };
- static ssize_t prox_power_off_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct sec_cmd_data *sec = dev_get_drvdata(dev);
- struct sec_ts_plat_data *plat_data = sec->dev->platform_data;
- input_info(true, sec->dev, "%s: %d\n", __func__, plat_data->prox_power_off);
- return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", plat_data->prox_power_off);
- }
- static ssize_t prox_power_off_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct sec_cmd_data *sec = dev_get_drvdata(dev);
- struct sec_ts_plat_data *plat_data = sec->dev->platform_data;
- long data;
- int ret;
- ret = kstrtol(buf, 10, &data);
- if (ret < 0)
- return ret;
- input_info(true, sec->dev, "%s: %ld\n", __func__, data);
- plat_data->prox_power_off = data;
- return count;
- }
- static ssize_t support_feature_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct sec_cmd_data *sec = dev_get_drvdata(dev);
- struct sec_ts_plat_data *plat_data = sec->dev->platform_data;
- u32 feature = 0;
- if (plat_data->enable_settings_aot)
- feature |= INPUT_FEATURE_ENABLE_SETTINGS_AOT;
- if (plat_data->support_vrr)
- feature |= INPUT_FEATURE_ENABLE_VRR;
- if (plat_data->support_open_short_test)
- feature |= INPUT_FEATURE_SUPPORT_OPEN_SHORT_TEST;
- if (plat_data->support_mis_calibration_test)
- feature |= INPUT_FEATURE_SUPPORT_MIS_CALIBRATION_TEST;
- if (plat_data->support_wireless_tx)
- feature |= INPUT_FEATURE_SUPPORT_WIRELESS_TX;
- if (plat_data->enable_sysinput_enabled)
- feature |= INPUT_FEATURE_ENABLE_SYSINPUT_ENABLED;
- if (plat_data->prox_lp_scan_enabled)
- feature |= INPUT_FEATURE_ENABLE_PROX_LP_SCAN_ENABLED;
- if (plat_data->support_input_monitor)
- feature |= INPUT_FEATURE_SUPPORT_INPUT_MONITOR;
- if (plat_data->support_rawdata_motion_aivf)
- feature |= INPUT_FEATURE_SUPPORT_MOTION_AIVF;
- if (plat_data->support_rawdata_motion_palm)
- feature |= INPUT_FEATURE_SUPPORT_MOTION_PALM;
- input_info(true, sec->dev, "%s: %d%s%s%s%s%s%s%s%s%s%s%s\n",
- __func__, feature,
- feature & INPUT_FEATURE_ENABLE_SETTINGS_AOT ? " aot" : "",
- feature & INPUT_FEATURE_ENABLE_PRESSURE ? " pressure" : "",
- feature & INPUT_FEATURE_ENABLE_VRR ? " vrr" : "",
- feature & INPUT_FEATURE_SUPPORT_OPEN_SHORT_TEST ? " openshort" : "",
- feature & INPUT_FEATURE_SUPPORT_MIS_CALIBRATION_TEST ? " miscal" : "",
- feature & INPUT_FEATURE_SUPPORT_WIRELESS_TX ? " wirelesstx" : "",
- feature & INPUT_FEATURE_SUPPORT_INPUT_MONITOR ? " inputmonitor" : "",
- feature & INPUT_FEATURE_ENABLE_SYSINPUT_ENABLED ? " SE" : "",
- feature & INPUT_FEATURE_ENABLE_PROX_LP_SCAN_ENABLED ? " LPSCAN" : "",
- feature & INPUT_FEATURE_SUPPORT_MOTION_AIVF ? " AIVF" : "",
- feature & INPUT_FEATURE_SUPPORT_MOTION_PALM ? " PALM" : "");
- return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", feature);
- }
- static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct sec_cmd_data *sec = dev_get_drvdata(dev);
- struct sec_ts_plat_data *plat_data = sec->dev->platform_data;
- if (!plat_data->enable_sysinput_enabled)
- return -EINVAL;
- input_info(true, sec->dev, "%s: enabled %d\n", __func__, atomic_read(&plat_data->enabled));
- return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", atomic_read(&plat_data->enabled));
- }
- ssize_t sec_cmd_enabled_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- return enabled_show(dev, attr, buf);
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(sec_cmd_enabled_show);
- #endif
- static ssize_t enabled_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct sec_cmd_data *sec = dev_get_drvdata(dev);
- struct sec_ts_plat_data *plat_data = sec->dev->platform_data;
- int buff[2];
- int ret;
- if (!plat_data->enable_sysinput_enabled)
- return -EINVAL;
- ret = sscanf(buf, "%d,%d", &buff[0], &buff[1]);
- if (ret != 2) {
- input_err(true, sec->dev,
- "%s: failed read params [%d]\n", __func__, ret);
- return -EINVAL;
- }
- if (buff[0] == DISPLAY_STATE_ON && buff[1] == DISPLAY_EVENT_LATE) {
- input_info(true, sec->dev, "%s: DISPLAY_STATE_ON\n", __func__);
- if (atomic_read(&plat_data->enabled)) {
- input_err(true, sec->dev, "%s: device already enabled\n", __func__);
- goto out;
- }
- ret = sec_input_enable_device(plat_data->dev);
- } else if (buff[0] == DISPLAY_STATE_OFF && buff[1] == DISPLAY_EVENT_EARLY) {
- input_info(true, sec->dev, "%s: DISPLAY_STATE_OFF\n", __func__);
- if (!atomic_read(&plat_data->enabled)) {
- input_err(true, sec->dev, "%s: device already disabled\n", __func__);
- goto out;
- }
- ret = sec_input_disable_device(plat_data->dev);
- } else if (buff[0] == DISPLAY_STATE_FORCE_ON) {
- input_info(true, sec->dev, "%s: DISPLAY_STATE_FORCE_ON\n", __func__);
- if (atomic_read(&plat_data->enabled)) {
- input_err(true, sec->dev, "%s: device already enabled\n", __func__);
- goto out;
- }
- ret = sec_input_enable_device(plat_data->dev);
- } else if (buff[0] == DISPLAY_STATE_FORCE_OFF || buff[0] == DISPLAY_STATE_LPM_OFF) {
- input_info(true, sec->dev, "%s: %s\n", __func__, buff[0] == DISPLAY_STATE_FORCE_OFF ?
- "DISPLAY_STATE_FORCE_OFF" : "DISPLAY_STATE_LPM_OFF");
- if (!atomic_read(&plat_data->enabled)) {
- input_err(true, sec->dev, "%s: device already disabled\n", __func__);
- goto out;
- }
- ret = sec_input_disable_device(plat_data->dev);
- }
- if (ret)
- return ret;
- out:
- return count;
- }
- ssize_t sec_cmd_enabled_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
- {
- return enabled_store(dev, attr, buf, count);
- }
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- EXPORT_SYMBOL_KUNIT(sec_cmd_enabled_store);
- #endif
- static DEVICE_ATTR_RW(prox_power_off);
- static DEVICE_ATTR_RO(support_feature);
- static DEVICE_ATTR_RW(enabled);
- static struct attribute *sec_fac_common_attrs[] = {
- &dev_attr_prox_power_off.attr,
- &dev_attr_support_feature.attr,
- &dev_attr_enabled.attr,
- NULL,
- };
- static struct attribute_group sec_fac_common_attr_group = {
- .attrs = sec_fac_common_attrs,
- };
- static void sec_cmd_parse_dt_not_support_cmds(struct sec_cmd_data *data)
- {
- struct device *dev;
- struct device_node *np;
- struct sec_cmd *sec_cmd_ptr = NULL;
- int count = 0;
- int ii = 0;
- int ret = 0;
- if (data->dev)
- dev = data->dev;
- else
- return;
- if (dev->of_node)
- np = dev->of_node;
- else
- return;
- count = of_property_count_strings(np, "sec_cmd,not_support_cmds");
- for (ii = 0; ii < count; ii++) {
- const char *buff;
- ret = of_property_read_string_index(np, "sec_cmd,not_support_cmds", ii, &buff);
- if (ret < 0 || strlen(buff) <= 0) {
- input_err(true, dev, "%s: failed get sec_cmd,not_support_cmds: %d, %lu\n", __func__, ret, strlen(buff));
- return;
- }
- list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
- if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
- sec_cmd_ptr->not_support_cmds = true;
- }
- }
- input_info(true, dev, "%s: sec_cmd,not_support_cmds(%d): %s\n", __func__, ii, buff);
- }
- }
- int sec_cmd_init(struct sec_cmd_data *data, struct device *dev, struct sec_cmd *cmds,
- int len, int devt, struct attribute_group *vendor_attr_group)
- {
- const char *dev_name;
- int ret, i;
- INIT_LIST_HEAD(&data->cmd_list_head);
- data->cmd_buffer_size = 0;
- for (i = 0; i < len; i++) {
- list_add_tail(&cmds[i].list, &data->cmd_list_head);
- if (cmds[i].cmd_name)
- data->cmd_buffer_size += strlen(cmds[i].cmd_name) + 1;
- }
- mutex_init(&data->cmd_lock);
- mutex_init(&data->fs_lock);
- mutex_lock(&data->cmd_lock);
- atomic_set(&data->cmd_is_running, 0);
- mutex_unlock(&data->cmd_lock);
- data->cmd_result = kzalloc(SEC_CMD_RESULT_STR_LEN_EXPAND, GFP_KERNEL);
- if (!data->cmd_result)
- goto err_alloc_cmd_result;
- if (!IS_ERR_OR_NULL(dev))
- data->dev = dev;
- #ifdef USE_SEC_CMD_QUEUE
- if (kfifo_alloc(&data->cmd_queue,
- SEC_CMD_MAX_QUEUE * sizeof(struct command), GFP_KERNEL)) {
- pr_err("%s %s: failed to alloc queue for cmd\n", SECLOG, __func__);
- goto err_alloc_queue;
- }
- mutex_init(&data->fifo_lock);
- mutex_init(&data->wait_lock);
- init_completion(&data->cmd_result_done);
- complete_all(&data->cmd_result_done);
- INIT_DELAYED_WORK(&data->cmd_work, cmd_exit_work);
- #endif
- switch (devt) {
- case SEC_CLASS_DEVT_TSP:
- dev_name = SEC_CLASS_DEV_NAME_TSP;
- break;
- case SEC_CLASS_DEVT_TSP1:
- dev_name = SEC_CLASS_DEV_NAME_TSP1;
- break;
- case SEC_CLASS_DEVT_TSP2:
- dev_name = SEC_CLASS_DEV_NAME_TSP2;
- break;
- case SEC_CLASS_DEVT_TKEY:
- dev_name = SEC_CLASS_DEV_NAME_TKEY;
- break;
- case SEC_CLASS_DEVT_WACOM:
- dev_name = SEC_CLASS_DEV_NAME_WACOM;
- break;
- case SEC_CLASS_DEVT_SIDEKEY:
- dev_name = SEC_CLASS_DEV_NAME_SIDEKEY;
- break;
- default:
- pr_err("%s %s: not defined devt=%d\n", SECLOG, __func__, devt);
- goto err_get_dev_name;
- }
- #if IS_ENABLED(CONFIG_DRV_SAMSUNG)
- data->fac_dev = sec_device_create(data, dev_name);
- #else
- tsp_sec_class = class_create(THIS_MODULE, dev_name);
- if (IS_ERR(tsp_sec_class)) {
- pr_err("%s %s: Failed to create class(sec) %ld\n", SECLOG, __func__, PTR_ERR(tsp_sec_class));
- return PTR_ERR(tsp_sec_class);
- }
- data->fac_dev = device_create(tsp_sec_class, NULL, devt, data, "%s", dev_name);
- #endif
- if (IS_ERR(data->fac_dev)) {
- pr_err("%s %s: failed to create device for the sysfs\n", SECLOG, __func__);
- goto err_sysfs_device;
- }
- dev_set_drvdata(data->fac_dev, data);
- sec_cmd_parse_dt_not_support_cmds(data);
- ret = sysfs_create_group(&data->fac_dev->kobj, &sec_fac_attr_group);
- if (ret < 0) {
- pr_err("%s %s: failed to create sysfs group\n", SECLOG, __func__);
- goto err_sysfs_group;
- }
- pr_info("%s: %s create sec_fac_attr_group: done\n", SECLOG, __func__);
- if (!IS_ERR_OR_NULL(vendor_attr_group)) {
- ret = sysfs_create_group(&data->fac_dev->kobj, vendor_attr_group);
- if (ret < 0) {
- pr_err("%s %s: failed to create sysfs group\n", SECLOG, __func__);
- goto err_vendor_sysfs_group;
- }
- data->vendor_attr_group = vendor_attr_group;
- pr_info("%s: %s create vendor_attr_group: done\n", SECLOG, __func__);
- }
- if (!IS_ERR_OR_NULL(dev)) {
- /* if you do not use sec_ts_plat_data, should invoke sec_cmd_init_without_platdata */
- struct sec_ts_plat_data *plat_data = dev->platform_data;
- plat_data->sec = data;
- ret = sysfs_create_group(&data->fac_dev->kobj, &sec_fac_common_attr_group);
- if (ret < 0) {
- pr_err("%s %s: failed to create sec_fac_common_attr_group\n", SECLOG, __func__);
- goto err_common_sysfs_group;
- }
- pr_info("%s: %s create sec_fac_common_attr_group: done\n", SECLOG, __func__);
- }
- pr_info("%s: %s %s: done\n", dev_name, SECLOG, __func__);
- sec_cmd_send_event_to_user(data, NULL, "RESULT=PROBE_DONE");
- return 0;
- err_common_sysfs_group:
- if (!IS_ERR_OR_NULL(data->vendor_attr_group))
- sysfs_remove_group(&data->fac_dev->kobj, data->vendor_attr_group);
- err_vendor_sysfs_group:
- sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group);
- err_sysfs_group:
- #if IS_ENABLED(CONFIG_DRV_SAMSUNG)
- sec_device_destroy(data->fac_dev->devt);
- #else
- device_destroy(tsp_sec_class, devt);
- #endif
- err_sysfs_device:
- err_get_dev_name:
- #ifdef USE_SEC_CMD_QUEUE
- mutex_destroy(&data->fifo_lock);
- kfifo_free(&data->cmd_queue);
- mutex_destroy(&data->wait_lock);
- err_alloc_queue:
- #endif
- kfree(data->cmd_result);
- err_alloc_cmd_result:
- mutex_destroy(&data->cmd_lock);
- list_del(&data->cmd_list_head);
- return -ENODEV;
- }
- EXPORT_SYMBOL(sec_cmd_init);
- /*
- * sec_cmd_init_without_platdata
- *
- * If device driver doesn't use sec_ts_plat_data as platform_data, you should init cmds with this function.
- * and should make sysfs like sec_fac_common_attrs on device driver side
- */
- int sec_cmd_init_without_platdata(struct sec_cmd_data *data, struct sec_cmd *cmds,
- int len, int devt, struct attribute_group *vendor_attr_group)
- {
- return sec_cmd_init(data, NULL, cmds, len, devt, vendor_attr_group);
- }
- EXPORT_SYMBOL(sec_cmd_init_without_platdata);
- void sec_cmd_exit(struct sec_cmd_data *data, int devt)
- {
- #ifdef USE_SEC_CMD_QUEUE
- struct command cmd = {{0}};
- int ret;
- #endif
- pr_info("%s: %s %s\n", dev_name(data->fac_dev), SECLOG, __func__);
- if (!IS_ERR_OR_NULL(data->fac_dev))
- sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_common_attr_group);
- if (!IS_ERR_OR_NULL(data->vendor_attr_group))
- sysfs_remove_group(&data->fac_dev->kobj, data->vendor_attr_group);
- sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group);
- dev_set_drvdata(data->fac_dev, NULL);
- #if IS_ENABLED(CONFIG_DRV_SAMSUNG)
- sec_device_destroy(data->fac_dev->devt);
- #else
- device_destroy(tsp_sec_class, devt);
- #endif
- #ifdef USE_SEC_CMD_QUEUE
- mutex_lock(&data->fifo_lock);
- while (kfifo_len(&data->cmd_queue)) {
- ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command));
- if (!ret)
- pr_err("%s %s: kfifo_out failed, it seems empty, ret=%d\n", SECLOG, __func__, ret);
- pr_info("%s %s: remove pending commands: %s", SECLOG, __func__, cmd.cmd);
- }
- mutex_unlock(&data->fifo_lock);
- mutex_destroy(&data->fifo_lock);
- kfifo_free(&data->cmd_queue);
- mutex_destroy(&data->wait_lock);
- cancel_delayed_work_sync(&data->cmd_work);
- flush_delayed_work(&data->cmd_work);
- #endif
- if (!IS_ERR_OR_NULL(data->dev)) {
- struct sec_ts_plat_data *plat_data = data->dev->platform_data;
- plat_data->sec = NULL;
- }
- data->fac_dev = NULL;
- kfree(data->cmd_result);
- mutex_destroy(&data->cmd_lock);
- list_del(&data->cmd_list_head);
- }
- EXPORT_SYMBOL(sec_cmd_exit);
- void sec_cmd_send_event_to_user(struct sec_cmd_data *data, char *test, char *result)
- {
- char *event[5];
- char timestamp[32];
- char feature[32];
- char stest[32];
- char sresult[64];
- ktime_t calltime;
- u64 realtime;
- int curr_time;
- char *eol = "\0";
- if (!data || !data->fac_dev)
- return;
- calltime = ktime_get();
- realtime = ktime_to_ns(calltime);
- do_div(realtime, NSEC_PER_USEC);
- curr_time = realtime / USEC_PER_MSEC;
- snprintf(timestamp, 32, "TIMESTAMP=%d", curr_time);
- strncat(timestamp, eol, 1);
- snprintf(feature, 32, "FEATURE=TSP");
- strncat(feature, eol, 1);
- if (!test)
- snprintf(stest, 32, "TEST=NULL");
- else
- snprintf(stest, 32, "%s", test);
- strncat(stest, eol, 1);
- if (!result)
- snprintf(sresult, 64, "RESULT=NULL");
- else
- snprintf(sresult, 64, "%s", result);
- strncat(sresult, eol, 1);
- pr_info("%s: %s %s: time:%s, feature:%s, test:%s, result:%s\n",
- dev_name(data->fac_dev), SECLOG, __func__, timestamp, feature, stest, sresult);
- event[0] = timestamp;
- event[1] = feature;
- event[2] = stest;
- event[3] = sresult;
- event[4] = NULL;
- kobject_uevent_env(&data->fac_dev->kobj, KOBJ_CHANGE, event);
- }
- EXPORT_SYMBOL(sec_cmd_send_event_to_user);
- void sec_cmd_send_status_uevent(struct sec_cmd_data *data, enum sec_cmd_status_uevent_type type, int value)
- {
- char test[32] = { 0 };
- char result[32] = { 0 };
- switch (type) {
- case STATUS_TYPE_WET:
- snprintf(test, sizeof(test), "STATUS=WET");
- break;
- case STATUS_TYPE_NOISE:
- snprintf(test, sizeof(test), "STATUS=NOISE");
- break;
- case STATUS_TYPE_FREQ:
- snprintf(test, sizeof(test), "STATUS=FREQ");
- break;
- default:
- pr_info("%s: %s %s: undefined type %d\n",
- dev_name(data->fac_dev), SECLOG, __func__, type);
- return;
- }
- snprintf(result, sizeof(result), "VALUE=%d", value);
- sec_cmd_send_event_to_user(data, test, result);
- }
- EXPORT_SYMBOL(sec_cmd_send_status_uevent);
- void sec_cmd_send_gesture_uevent(struct sec_cmd_data *data, int type, int x, int y)
- {
- struct sec_ts_plat_data *plat_data;
- char test[32] = { 0 };
- char result[32] = { 0 };
- if (!data->dev)
- return;
- plat_data = data->dev->platform_data;
- if (IS_ERR_OR_NULL(plat_data))
- return;
- snprintf(test, sizeof(test), "GESTURE=%d", type);
- snprintf(result, sizeof(result), "POS=%d,%d", x, y);
- sec_cmd_send_event_to_user(data, test, result);
- }
- EXPORT_SYMBOL(sec_cmd_send_gesture_uevent);
- MODULE_DESCRIPTION("Samsung input command");
- MODULE_LICENSE("GPL");
|