* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "hdf_hid_adapter.h"
#include <securec.h>
#include "event_hub.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "osal_mem.h"
#include "osal_timer.h"
#ifdef CONFIG_DFX_ZEROHUNG
#include <dfx/hung_wp_screen.h>
#endif
#define TIMER_INTERVAL 500
#define REPEAT_VALUE 2
#define MEMCPY_CHECK_RETURN(ret) do { \
if ((ret) != 0) { \
HDF_LOGE("%s: memcpy failed, line %d", __func__, __LINE__); \
return; \
} \
} while (0)
InputDevice *cachedHid[MAX_INPUT_DEV_NUM];
HidInfo *g_cachedInfo[MAX_INPUT_DEV_NUM];
uint32_t g_kbdcode = 0;
OsalTimer g_timer;
static bool HaveHidCache(void)
{
if (cachedHid[0] == NULL) {
return false;
}
return true;
}
static void LoadCachedHid(void)
{
int32_t i = 0;
int32_t ret;
if (!HaveHidCache()) {
HDF_LOGI("%s: exit", __func__);
return;
}
while (i < MAX_INPUT_DEV_NUM && cachedHid[i] != NULL) {
ret = RegisterInputDevice(cachedHid[i]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: add %s failed", __func__, cachedHid[i]->devName);
}
cachedHid[i] = NULL;
i++;
}
}
static int cachedPosId(void)
{
int32_t id = 0;
while (id < MAX_INPUT_DEV_NUM) {
if (g_cachedInfo[id] == NULL) {
return id;
}
id++;
}
return HDF_FAILURE;
}
void SendInfoToHdf(HidInfo *info)
{
int ret;
int32_t id = cachedPosId();
if (id == HDF_FAILURE) {
HDF_LOGE("%s: cached hid info failed", __func__);
return;
}
g_cachedInfo[id] = (HidInfo *)OsalMemAlloc(sizeof(HidInfo));
if (g_cachedInfo[id] == NULL) {
HDF_LOGE("%s: malloc failed", __func__);
return;
}
ret = memcpy_s(g_cachedInfo[id], sizeof(HidInfo), info, sizeof(HidInfo));
if (ret != 0) {
HDF_LOGE("%s: memcpy failed", __func__);
OsalMemFree(g_cachedInfo[id]);
g_cachedInfo[id] = NULL;
return;
}
}
static void FreeCachedInfo(void)
{
int32_t id = 0;
while (id < MAX_INPUT_DEV_NUM) {
if (g_cachedInfo[id] != NULL) {
OsalMemFree(g_cachedInfo[id]);
g_cachedInfo[id] = NULL;
}
id++;
}
}
static int32_t SetInputDevAbsAttr(InputDevice *inputDev, const HidInfo *info)
{
int32_t ret;
int i;
for (i = 0; i < BITS_TO_LONG(ABS_CNT); i++) {
if (inputDev->abilitySet.absCode[i] != 0) {
ret = memcpy_s(inputDev->attrSet.axisInfo, sizeof(AbsAttr) * ABS_CNT,
info->axisInfo, sizeof(AbsAttr) * ABS_CNT);
return ret;
}
}
return HDF_SUCCESS;
}
static void GetInfoFromCache(InputDevice *inputDev, const HidInfo *info)
{
uint32_t len;
int32_t ret;
len = sizeof(unsigned long);
ret = memcpy_s(inputDev->abilitySet.devProp, len * BITS_TO_LONG(INPUT_PROP_CNT),
info->devProp, len * BITS_TO_LONG(INPUT_PROP_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.eventType, len * BITS_TO_LONG(EV_CNT),
info->eventType, len * BITS_TO_LONG(EV_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.absCode, len * BITS_TO_LONG(ABS_CNT),
info->absCode, len * BITS_TO_LONG(ABS_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.relCode, len * BITS_TO_LONG(REL_CNT),
info->relCode, len * BITS_TO_LONG(REL_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.keyCode, len * BITS_TO_LONG(KEY_CNT),
info->keyCode, len * BITS_TO_LONG(KEY_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.ledCode, len * BITS_TO_LONG(LED_CNT),
info->ledCode, len * BITS_TO_LONG(LED_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.miscCode, len * BITS_TO_LONG(MSC_CNT),
info->miscCode, len * BITS_TO_LONG(MSC_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.soundCode, len * BITS_TO_LONG(SND_CNT),
info->soundCode, len * BITS_TO_LONG(SND_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.forceCode, len * BITS_TO_LONG(FF_CNT),
info->forceCode, len * BITS_TO_LONG(FF_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = memcpy_s(inputDev->abilitySet.switchCode, len * BITS_TO_LONG(SW_CNT),
info->switchCode, len * BITS_TO_LONG(SW_CNT));
MEMCPY_CHECK_RETURN(ret);
ret = SetInputDevAbsAttr(inputDev, info);
MEMCPY_CHECK_RETURN(ret);
inputDev->attrSet.id.busType = info->bustype;
inputDev->attrSet.id.vendor = info->vendor;
inputDev->attrSet.id.product = info->product;
inputDev->attrSet.id.version = info->version;
}
static void SetInputDevAbility(InputDevice *inputDev)
{
HidInfo *info = NULL;
int32_t id = 0;
while (id < MAX_INPUT_DEV_NUM) {
if (g_cachedInfo[id] != NULL && !strcmp(inputDev->devName, g_cachedInfo[id]->devName)) {
info = g_cachedInfo[id];
break;
}
id++;
}
if (id == MAX_INPUT_DEV_NUM || info == NULL) {
HDF_LOGE("%s: match cached info failed", __func__);
return;
}
GetInfoFromCache(inputDev, info);
FreeCachedInfo();
}
static InputDevice* HidConstructInputDev(HidInfo *info)
{
InputDevice *inputDev = (InputDevice *)OsalMemAlloc(sizeof(InputDevice));
if (inputDev == NULL) {
HDF_LOGE("%s: instance input device failed", __func__);
return NULL;
}
(void)memset_s(inputDev, sizeof(InputDevice), 0, sizeof(InputDevice));
inputDev->devType = info->devType;
inputDev->devName = info->devName;
SetInputDevAbility(inputDev);
return inputDev;
}
static void DoRegisterInputDev(InputDevice* inputDev)
{
int32_t ret;
ret = RegisterInputDevice(inputDev);
if (ret != HDF_SUCCESS) {
OsalMemFree(inputDev);
return;
}
}
static void CacheHid(InputDevice* inputDev)
{
int32_t i = 0;
while ((i < MAX_INPUT_DEV_NUM) && (cachedHid[i] != NULL)) {
i++;
}
if (i < MAX_INPUT_DEV_NUM) {
cachedHid[i] = inputDev;
return;
} else {
HDF_LOGE("%s: cached hid device failed", __func__);
}
}
static bool InputDriverLoaded(void)
{
InputManager* g_inputManager = GetInputManager();
if ((g_inputManager != NULL) && (g_inputManager->initialized != false)) {
return true;
}
return false;
}
void* HidRegisterHdfInputDev(HidInfo *info)
{
InputDevice* inputDev = HidConstructInputDev(info);
if (inputDev == NULL) {
HDF_LOGE("%s: hid construct input Dev failed", __func__);
return NULL;
}
if (InputDriverLoaded()) {
DoRegisterInputDev(inputDev);
} else {
CacheHid(inputDev);
}
return inputDev;
}
void HidUnregisterHdfInputDev(const void *inputDev)
{
if (inputDev == NULL) {
HDF_LOGE("%s: inputDev is null", __func__);
return;
}
UnregisterInputDevice((InputDevice *)inputDev);
}
static void TimerFunc(uintptr_t arg)
{
InputDevice *device = (InputDevice *)arg;
PushOnePackage(device, EV_KEY, g_kbdcode, REPEAT_VALUE);
PushOnePackage(device, 0, 0, SYN_CONFIG);
}
static void RepateEvent(const InputDevice *device)
{
int32_t ret;
static int32_t flag = 0;
if (flag == 1) {
(void)OsalTimerDelete(&g_timer);
}
ret = OsalTimerCreate(&g_timer, TIMER_INTERVAL, TimerFunc, (uintptr_t)device);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: create timer failed, ret = %d", __func__, ret);
return;
}
ret = OsalTimerStartLoop(&g_timer);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: start timer failed, ret = %d", __func__, ret);
return;
}
flag = 1;
}
void HidReportEvent(const void *inputDev, uint32_t type, uint32_t code, int32_t value)
{
#ifdef CONFIG_DFX_ZEROHUNG
if (type == EV_KEY && code == KEY_POWER)
hung_wp_screen_powerkey_ncb(value);
#endif
InputDevice *device = (InputDevice *)inputDev;
PushOnePackage(device, type, code, value);
if (type == EV_KEY && KEY_RESERVED < code && code < KEY_MAX && value == 0 && code == g_kbdcode) {
OsalTimerDelete(&g_timer);
g_kbdcode = 0;
}
if (type == EV_KEY && KEY_RESERVED < code && code < KEY_MAX && value == 1 &&
device->devType == INDEV_TYPE_KEYBOARD) {
g_kbdcode = code;
RepateEvent(device);
}
}
static int32_t HdfHIDDriverInit(struct HdfDeviceObject *device)
{
(void)device;
static bool cachedHidRegistered = false;
if (!cachedHidRegistered) {
cachedHidRegistered = true;
LoadCachedHid();
}
return HDF_SUCCESS;
}
static int32_t HidGetDevType(InputDevice *inputDev, struct HdfSBuf *reply)
{
uint32_t devType = inputDev->devType;
HDF_LOGI("%s: enter, devType is %u", __func__, devType);
bool ret = HdfSbufWriteUint32(reply, devType);
if (!ret) {
HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t HidGetDeviceStrInfo(InputDevice *inputDev, int32_t cmd, struct HdfSBuf *reply)
{
const char *info = NULL;
if (inputDev == NULL) {
HDF_LOGE("%s: parameter invalid", __func__);
return HDF_ERR_INVALID_PARAM;
}
switch (cmd) {
case GET_CHIP_NAME:
info = "null";
break;
case GET_VENDOR_NAME:
info = "null";
break;
case GET_CHIP_INFO:
info = "null";
break;
default:
info = NULL;
break;
}
bool ret = HdfSbufWriteString(reply, info);
if (!ret) {
HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__);
return HDF_FAILURE;
}
HDF_LOGI("%s: cmd is %d, the info is %s", __func__, cmd, info);
return HDF_SUCCESS;
}
static int32_t HidGetDeviceAttr(InputDevice *inputDev, struct HdfSBuf *reply)
{
int32_t ret;
if (inputDev == NULL) {
return HDF_FAILURE;
}
ret = strncpy_s(inputDev->attrSet.devName, DEV_NAME_LEN, inputDev->devName, strlen(inputDev->devName));
if (ret != 0) {
HDF_LOGE("%s: copy name from inputDev failed, ret = %d", __func__, ret);
return HDF_FAILURE;
}
if (!HdfSbufWriteBuffer(reply, &inputDev->attrSet, sizeof(DevAttr))) {
HDF_LOGE("%s: sbuf write dev attr failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t HidGetDeviceAbility(InputDevice *inputDev, struct HdfSBuf *reply)
{
if (inputDev == NULL) {
return HDF_FAILURE;
}
if (!HdfSbufWriteBuffer(reply, &inputDev->abilitySet, sizeof(DevAbility))) {
HDF_LOGE("%s: sbuf write dev ability failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t HdfHIDDispatch(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
(void)cmd;
int32_t ret;
InputDevice *inputDev = NULL;
if (client == NULL || data == NULL || reply == NULL) {
HDF_LOGE("%s: param is null", __func__);
return HDF_FAILURE;
}
inputDev = (InputDevice *)client->device->priv;
if (inputDev == NULL) {
HDF_LOGE("%s: inputDev is null", __func__);
return HDF_FAILURE;
}
HDF_LOGI("%s: cmd = %d", __func__, cmd);
switch (cmd) {
case GET_DEV_TYPE:
ret = HidGetDevType(inputDev, reply);
break;
case GET_CHIP_NAME:
case GET_VENDOR_NAME:
case GET_CHIP_INFO:
ret = HidGetDeviceStrInfo(inputDev, cmd, reply);
break;
case GET_DEV_ATTR:
ret = HidGetDeviceAttr(inputDev, reply);
break;
case GET_DEV_ABILITY:
ret = HidGetDeviceAbility(inputDev, reply);
break;
default:
ret = HDF_SUCCESS;
HDF_LOGE("%s: cmd unknown, cmd = 0x%x", __func__, cmd);
break;
}
return ret;
}
static int32_t HdfHIDDriverBind(struct HdfDeviceObject *device)
{
if (device == NULL) {
return HDF_ERR_INVALID_PARAM;
}
static struct IDeviceIoService hidService = {
.Dispatch = HdfHIDDispatch,
};
device->service = &hidService;
return HDF_SUCCESS;
}
static void HdfHIDDriverRelease(struct HdfDeviceObject *device)
{
FreeCachedInfo();
if (device == NULL) {
HDF_LOGE("%s: device is null", __func__);
return;
}
}
struct HdfDriverEntry g_hdfHIDEntry = {
.moduleVersion = 1,
.moduleName = "HDF_HID",
.Bind = HdfHIDDriverBind,
.Init = HdfHIDDriverInit,
.Release = HdfHIDDriverRelease,
};
HDF_INIT(g_hdfHIDEntry);