| /* |
| * Copyright (C) 2021 Huawei Device Co., Ltd. |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "hril_hdf.h" |
| |
| #include |
| #include |
| #include |
| |
| #include "dfx_signal_handler.h" |
| #include "parameter.h" |
| |
| #include "modem_adapter.h" |
| #include "telephony_log_c.h" |
| |
| #define RIL_VENDOR_LIB_PATH "persist.sys.radio.vendorlib.path" |
| #define BASE_HEX 16 |
| |
| static struct HRilReport g_reportOps = { |
| OnCallReport, |
| OnDataReport, |
| OnModemReport, |
| OnNetworkReport, |
| OnSimReport, |
| OnSmsReport, |
| OnTimerCallback |
| }; |
| |
| static int32_t GetVendorLibPath(char *path) |
| { |
| int32_t code = GetParameter(RIL_VENDOR_LIB_PATH, "", path, PARAMETER_SIZE); |
| if (code <= 0) { |
| TELEPHONY_LOGE("Failed to get vendor library path through system properties. err:%{public}d", code); |
| return HDF_FAILURE; |
| } |
| return HDF_SUCCESS; |
| } |
| |
| static UsbDeviceInfo *GetPresetInformation(const char *vId, const char *pId) |
| { |
| char *out = NULL; |
| UsbDeviceInfo *uDevInfo = NULL; |
| int32_t idVendor = (int32_t)strtol(vId, &out, BASE_HEX); |
| int32_t idProduct = (int32_t)strtol(pId, &out, BASE_HEX); |
| for (uint32_t i = 0; i < sizeof(g_usbModemVendorInfo) / sizeof(UsbDeviceInfo); i++) { |
| if (g_usbModemVendorInfo[i].idVendor == idVendor && g_usbModemVendorInfo[i].idProduct == idProduct) { |
| TELEPHONY_LOGI("list index:%{public}d", i); |
| uDevInfo = &g_usbModemVendorInfo[i]; |
| break; |
| } |
| } |
| return uDevInfo; |
| } |
| |
| static UsbDeviceInfo *GetUsbDeviceInfo(void) |
| { |
| struct udev *udev; |
| struct udev_enumerate *enumerate; |
| struct udev_list_entry *devices, *dev_list_entry; |
| struct udev_device *dev; |
| UsbDeviceInfo *uDevInfo = NULL; |
| |
| udev = udev_new(); |
| if (udev == NULL) { |
| TELEPHONY_LOGE("Can't create udev"); |
| return uDevInfo; |
| } |
| enumerate = udev_enumerate_new(udev); |
| if (enumerate == NULL) { |
| TELEPHONY_LOGE("Can't create enumerate"); |
| return uDevInfo; |
| } |
| udev_enumerate_add_match_subsystem(enumerate, "tty"); |
| udev_enumerate_scan_devices(enumerate); |
| devices = udev_enumerate_get_list_entry(enumerate); |
| udev_list_entry_foreach(dev_list_entry, devices) { |
| const char *path = udev_list_entry_get_name(dev_list_entry); |
| if (path == NULL) { |
| continue; |
| } |
| dev = udev_device_new_from_syspath(udev, path); |
| if (dev == NULL) { |
| continue; |
| } |
| dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); |
| if (!dev) { |
| TELEPHONY_LOGE("Unable to find parent usb device."); |
| return uDevInfo; |
| } |
| const char *cIdVendor = udev_device_get_sysattr_value(dev, "idVendor"); |
| const char *cIdProduct = udev_device_get_sysattr_value(dev, "idProduct"); |
| uDevInfo = GetPresetInformation(cIdVendor, cIdProduct); |
| udev_device_unref(dev); |
| if (uDevInfo != NULL) { |
| break; |
| } |
| } |
| udev_enumerate_unref(enumerate); |
| udev_unref(udev); |
| return uDevInfo; |
| } |
| |
| static void LoadVendor(void) |
| { |
| const char *rilLibPath = NULL; |
| char vendorLibPath[PARAMETER_SIZE] = {0}; |
| // Pointer to ril init function in vendor ril |
| const HRilOps *(*rilInitOps)(const struct HRilReport *) = NULL; |
| // functions returned by ril init function in vendor ril |
| const HRilOps *ops = NULL; |
| |
| UsbDeviceInfo *uDevInfo = GetUsbDeviceInfo(); |
| if (GetVendorLibPath(vendorLibPath) == HDF_SUCCESS) { |
| rilLibPath = vendorLibPath; |
| } else if (uDevInfo != NULL) { |
| rilLibPath = uDevInfo->libPath; |
| } else { |
| TELEPHONY_LOGI("use default vendor lib."); |
| rilLibPath = g_usbModemVendorInfo[DEFAULT_MODE_INDEX].libPath; |
| } |
| if (rilLibPath == NULL) { |
| TELEPHONY_LOGE("dynamic library path is empty"); |
| return; |
| } |
| |
| TELEPHONY_LOGI("RilInit LoadVendor start with rilLibPath:%{public}s", rilLibPath); |
| g_dlHandle = dlopen(rilLibPath, RTLD_NOW); |
| if (g_dlHandle == NULL) { |
| TELEPHONY_LOGE("dlopen %{public}s is fail. %{public}s", rilLibPath, dlerror()); |
| return; |
| } |
| rilInitOps = (const HRilOps *(*)(const struct HRilReport *))dlsym(g_dlHandle, "RilInitOps"); |
| if (rilInitOps == NULL) { |
| dlclose(g_dlHandle); |
| TELEPHONY_LOGE("RilInit not defined or exported"); |
| return; |
| } |
| ops = rilInitOps(&g_reportOps); |
| HRilRegOps(ops); |
| TELEPHONY_LOGI("HRilRegOps completed"); |
| } |
| |
| // 用来处理用户态发下来的消息 |
| static int32_t RilAdapterDispatch( |
| struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) |
| { |
| int32_t ret; |
| static pthread_mutex_t dispatchMutex = PTHREAD_MUTEX_INITIALIZER; |
| pthread_mutex_lock(&dispatchMutex); |
| TELEPHONY_LOGI("RilAdapterDispatch cmd:%{public}d", cmd); |
| ret = DispatchRequest(cmd, data); |
| pthread_mutex_unlock(&dispatchMutex); |
| return ret; |
| } |
| |
| static struct IDeviceIoService g_rilAdapterService = { |
| .Dispatch = RilAdapterDispatch, |
| .Open = NULL, |
| .Release = NULL, |
| }; |
| |
| //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架 |
| static int32_t RilAdapterBind(struct HdfDeviceObject *device) |
| { |
| if (device == NULL) { |
| return HDF_ERR_INVALID_OBJECT; |
| } |
| device->service = &g_rilAdapterService; |
| return HDF_SUCCESS; |
| } |
| |
| // 驱动自身业务初始的接口 |
| static int32_t RilAdapterInit(struct HdfDeviceObject *device) |
| { |
| if (device == NULL) { |
| return HDF_ERR_INVALID_OBJECT; |
| } |
| DFX_InstallSignalHandler(); |
| struct HdfSBuf *sbuf = HdfSbufTypedObtain(SBUF_IPC); |
| if (sbuf == NULL) { |
| TELEPHONY_LOGE("HdfSampleDriverBind, failed to obtain ipc sbuf"); |
| return HDF_ERR_INVALID_OBJECT; |
| } |
| if (!HdfSbufWriteString(sbuf, "string")) { |
| TELEPHONY_LOGE("HdfSampleDriverBind, failed to write string to ipc sbuf"); |
| HdfSbufRecycle(sbuf); |
| return HDF_FAILURE; |
| } |
| if (sbuf != NULL) { |
| HdfSbufRecycle(sbuf); |
| } |
| TELEPHONY_LOGI("sbuf IPC obtain success!"); |
| LoadVendor(); |
| return HDF_SUCCESS; |
| } |
| |
| // 驱动资源释放的接口 |
| static void RilAdapterRelease(struct HdfDeviceObject *device) |
| { |
| if (device == NULL) { |
| return; |
| } |
| dlclose(g_dlHandle); |
| } |
| |
| //驱动入口注册到HDF框架,这里配置的moduleName是找到Telephony模块与RIL进行通信的一个关键配置 |
| struct HdfDriverEntry g_rilAdapterDevEntry = { |
| .moduleVersion = 1, |
| .moduleName = "hril_hdf", |
| .Bind = RilAdapterBind, |
| .Init = RilAdapterInit, |
| .Release = RilAdapterRelease, |
| }; |
| // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 |
| HDF_INIT(g_rilAdapterDevEntry); |