1094332d3Sopenharmony_ci/* 2094332d3Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 3094332d3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4094332d3Sopenharmony_ci * you may not use this file except in compliance with the License. 5094332d3Sopenharmony_ci * You may obtain a copy of the License at 6094332d3Sopenharmony_ci * 7094332d3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8094332d3Sopenharmony_ci * 9094332d3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10094332d3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11094332d3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12094332d3Sopenharmony_ci * See the License for the specific language governing permissions and 13094332d3Sopenharmony_ci * limitations under the License. 14094332d3Sopenharmony_ci */ 15094332d3Sopenharmony_ci#include "ddk_uevent_handle.h" 16094332d3Sopenharmony_ci 17094332d3Sopenharmony_ci#include <linux/netlink.h> 18094332d3Sopenharmony_ci#include <pthread.h> 19094332d3Sopenharmony_ci#include <string.h> 20094332d3Sopenharmony_ci#include <sys/socket.h> 21094332d3Sopenharmony_ci#include <sys/types.h> 22094332d3Sopenharmony_ci#include <unistd.h> 23094332d3Sopenharmony_ci 24094332d3Sopenharmony_ci#include "ddk_pnp_listener_mgr.h" 25094332d3Sopenharmony_ci#include "hdf_base.h" 26094332d3Sopenharmony_ci#include "hdf_log.h" 27094332d3Sopenharmony_ci#include "securec.h" 28094332d3Sopenharmony_ci#include "usbfn_uevent_handle.h" 29094332d3Sopenharmony_ci#include "usbd_wrapper.h" 30094332d3Sopenharmony_ci 31094332d3Sopenharmony_ci#define UEVENT_MSG_LEN 2048 32094332d3Sopenharmony_ci#define UEVENT_SOCKET_GROUPS 0xffffffff 33094332d3Sopenharmony_ci#define UEVENT_SOCKET_BUFF_SIZE (64 * 1024) 34094332d3Sopenharmony_ci#define TIMEVAL_SECOND 0 35094332d3Sopenharmony_ci#define TIMEVAL_USECOND (100 * 1000) 36094332d3Sopenharmony_ci 37094332d3Sopenharmony_ci#define HDF_LOG_TAG usbfn_uevent 38094332d3Sopenharmony_ci 39094332d3Sopenharmony_cichar *g_gadgetEventPath = "invalid_path"; 40094332d3Sopenharmony_ci 41094332d3Sopenharmony_cistruct UsbFnUeventInfo { 42094332d3Sopenharmony_ci const char *devPath; 43094332d3Sopenharmony_ci const char *subSystem; 44094332d3Sopenharmony_ci const char *usbState; 45094332d3Sopenharmony_ci const char *dualRoleMode; 46094332d3Sopenharmony_ci}; 47094332d3Sopenharmony_ci 48094332d3Sopenharmony_cistatic void UsbFnDispatchUevent(const struct UsbFnUeventInfo *info) 49094332d3Sopenharmony_ci{ 50094332d3Sopenharmony_ci bool isGadgetConnect = strcmp(info->devPath, g_gadgetEventPath) == 0; 51094332d3Sopenharmony_ci isGadgetConnect = (isGadgetConnect && strcmp(info->usbState, "CONNECTED") == 0); 52094332d3Sopenharmony_ci if (isGadgetConnect) { 53094332d3Sopenharmony_ci DdkListenerMgrNotifyAll(NULL, USB_PNP_DRIVER_GADGET_ADD); 54094332d3Sopenharmony_ci return; 55094332d3Sopenharmony_ci } 56094332d3Sopenharmony_ci 57094332d3Sopenharmony_ci bool isGadgetDisconnect = strcmp(info->devPath, g_gadgetEventPath) == 0; 58094332d3Sopenharmony_ci isGadgetDisconnect = (isGadgetDisconnect && strcmp(info->usbState, "DISCONNECTED") == 0); 59094332d3Sopenharmony_ci if (isGadgetDisconnect) { 60094332d3Sopenharmony_ci DdkListenerMgrNotifyAll(NULL, USB_PNP_DRIVER_GADGET_REMOVE); 61094332d3Sopenharmony_ci return; 62094332d3Sopenharmony_ci } 63094332d3Sopenharmony_ci 64094332d3Sopenharmony_ci bool isPort2Device = strcmp(info->subSystem, "dual_role_usb") == 0; 65094332d3Sopenharmony_ci isPort2Device = (isPort2Device && strcmp(info->dualRoleMode, "ufp") == 0); 66094332d3Sopenharmony_ci if (isPort2Device) { 67094332d3Sopenharmony_ci DdkListenerMgrNotifyAll(NULL, USB_PNP_DRIVER_PORT_DEVICE); 68094332d3Sopenharmony_ci return; 69094332d3Sopenharmony_ci } 70094332d3Sopenharmony_ci 71094332d3Sopenharmony_ci bool isPort2Host = strcmp(info->subSystem, "dual_role_usb") == 0; 72094332d3Sopenharmony_ci isPort2Host = (isPort2Host && strcmp(info->dualRoleMode, "dfp") == 0); 73094332d3Sopenharmony_ci if (isPort2Host) { 74094332d3Sopenharmony_ci DdkListenerMgrNotifyAll(NULL, USB_PNP_DRIVER_PORT_HOST); 75094332d3Sopenharmony_ci return; 76094332d3Sopenharmony_ci } 77094332d3Sopenharmony_ci} 78094332d3Sopenharmony_ci 79094332d3Sopenharmony_civoid UsbFnHandleUevent(const char msg[], ssize_t rcvLen) 80094332d3Sopenharmony_ci{ 81094332d3Sopenharmony_ci struct UsbFnUeventInfo info = { 82094332d3Sopenharmony_ci .devPath = "", 83094332d3Sopenharmony_ci .subSystem = "", 84094332d3Sopenharmony_ci .usbState = "", 85094332d3Sopenharmony_ci .dualRoleMode = "", 86094332d3Sopenharmony_ci }; 87094332d3Sopenharmony_ci 88094332d3Sopenharmony_ci const char *msgTmp = msg; 89094332d3Sopenharmony_ci while (*msgTmp && (msgTmp - msg < rcvLen)) { 90094332d3Sopenharmony_ci if (strncmp(msgTmp, "DEVPATH=", strlen("DEVPATH=")) == 0) { 91094332d3Sopenharmony_ci msgTmp += strlen("DEVPATH="); 92094332d3Sopenharmony_ci info.devPath = msgTmp; 93094332d3Sopenharmony_ci } else if (strncmp(msgTmp, "SUBSYSTEM=", strlen("SUBSYSTEM=")) == 0 && 94094332d3Sopenharmony_ci strlen(info.subSystem) == 0) { // some uevent has more than one SUBSYSTEM property 95094332d3Sopenharmony_ci msgTmp += strlen("SUBSYSTEM="); 96094332d3Sopenharmony_ci info.subSystem = msgTmp; 97094332d3Sopenharmony_ci } else if (strncmp(msgTmp, "USB_STATE=", strlen("USB_STATE=")) == 0) { 98094332d3Sopenharmony_ci msgTmp += strlen("USB_STATE="); 99094332d3Sopenharmony_ci info.usbState = msgTmp; 100094332d3Sopenharmony_ci } else if (strncmp(msgTmp, "DUAL_ROLE_MODE=", strlen("DUAL_ROLE_MODE=")) == 0) { 101094332d3Sopenharmony_ci msgTmp += strlen("DUAL_ROLE_MODE="); 102094332d3Sopenharmony_ci info.dualRoleMode = msgTmp; 103094332d3Sopenharmony_ci } 104094332d3Sopenharmony_ci msgTmp += strlen(msgTmp) + 1; // 1 is a skip character '\0' 105094332d3Sopenharmony_ci } 106094332d3Sopenharmony_ci 107094332d3Sopenharmony_ci UsbFnDispatchUevent(&info); 108094332d3Sopenharmony_ci return; 109094332d3Sopenharmony_ci} 110094332d3Sopenharmony_ci 111094332d3Sopenharmony_ciint32_t UsbFnUeventInit(const char *gadgetEventPath) 112094332d3Sopenharmony_ci{ 113094332d3Sopenharmony_ci if (gadgetEventPath == NULL) { 114094332d3Sopenharmony_ci HDF_LOGE("%{puiblic}s invalid param", __func__); 115094332d3Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 116094332d3Sopenharmony_ci } 117094332d3Sopenharmony_ci 118094332d3Sopenharmony_ci g_gadgetEventPath = (char *)gadgetEventPath; 119094332d3Sopenharmony_ci return HDF_SUCCESS; 120094332d3Sopenharmony_ci}