/*
* 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 <stdlib.h>
#include <libudev.h>
#include <pthread.h>
#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);
评论