这个补丁是我加在全志A40 4.4上面的做模块动态适配的 , 毋庸置疑 后面的Android 版本也是适用的 , 比如rockchip 也是没问题的 只是我懒得搞了而已。
调试4G模块非常简单 只是说早期模块经常切换 , 换了还得换固件 , 固件其实只是更换了so库而已。因为kernel driver 已经对vid/pid进行了适配。
这个补丁是直接在hal 层rild 做的vid/pid 然后选择so库文件的。
这个补丁主要修改了 Android RIL (Radio Interface Layer) 的部分代码,以支持动态切换不同的 3G/4G 模块。
修改的文件
android/hardware/ril/include/runtime/runtime.h
android/hardware/ril/rild/Android.mk
android/hardware/ril/rild/rild.c
android/hardware/ril/runtime-ril-port/Android.mk
android/hardware/ril/runtime-ril-port/runtime_port.c
文件修改说明
runtime.h
这是一个新文件,定义了一些函数和变量,用于启动 uevent 监视器,获取当前的 3G 端口设备,数据和类型。
Android.mk
(在 rild 目录下)
在这个 makefile 文件中,添加了 libruntime-ril-port
到 LOCAL_SHARED_LIBRARIES
,这样 rild 就可以链接到这个新的库。
rild.c
这个文件中的修改主要是在 rild 的主函数中,添加了对 3G 模块类型的检测,并根据检测到的模块类型,动态地设置 RIL 库的路径。此外,还添加了对 uevent 的监视,当检测到 3G 模块的变化时,会重新启动 rild。
Android.mk
(在 runtime-ril-port 目录下)
这是一个新文件,用于编译 runtime_port.c
,生成 libruntime-ril-port
库。
runtime_port.c
这是一个新文件,实现了在 runtime.h
中定义的函数。这些函数主要用于检测当前的 3G 模块类型,以及启动对 uevent 的监视。
如何适配
- 将这个补丁应用到你的 Android 源码树中。
- 根据你的 3G 模块的特性,修改
runtime_port.c
中的modem_3g_device_table
。 - 编译并刷入你的 Android 系统。
- 当你的设备启动时,rild 会自动检测当前的 3G 模块类型,并加载相应的 RIL 库。
diff --git a/android/hardware/ril/include/runtime/runtime.h b/android/hardware/ril/include/runtime/runtime.h new file mode 100755 index 0000000000..c381b4f2f8 --- /dev/null +++ b/android/hardware/ril/include/runtime/runtime.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + */ + +#ifndef RUNTIME_H +#define RUNTIME_H + +extern int start_uevent_monitor(void); +extern const char *runtime_3g_port_device(void); +extern const char *runtime_3g_port_data(void); +extern int runtime_3g_port_type(void); +enum { + ME909S_MODEM = 0, + U9300C_MODEM, + EC20_MODEM, + EM8000_MODEM, + UNKNOWN_MODEM, +}; + +extern int current_modem_type; + +#endif diff --git a/android/hardware/ril/rild/Android.mk b/android/hardware/ril/rild/Android.mk index d8ca6d368d..83c0a1a130 100755 --- a/android/hardware/ril/rild/Android.mk +++ b/android/hardware/ril/rild/Android.mk @@ -13,7 +13,8 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ libril \ - libdl + libdl \ + libruntime-ril-port # temporary hack for broken vendor rils #LOCAL_WHOLE_STATIC_LIBRARIES := \ diff --git a/android/hardware/ril/rild/rild.c b/android/hardware/ril/rild/rild.c index 4a555f275c..e79cd3cb71 100755 --- a/android/hardware/ril/rild/rild.c +++ b/android/hardware/ril/rild/rild.c @@ -36,10 +36,19 @@ #include "hardware/qemu_pipe.h" #include "radio_monitor.h" - +#include <runtime/runtime.h> #define LIB_PATH_PROPERTY "rild.libpath" #define LIB_ARGS_PROPERTY "rild.libargs" #define MAX_LIB_ARGS 16 +#define MAX_POLL_DEVICE_CNT 8 + + + + +#define REFERENCE_RIL_ME909S_PATH "/system/lib/libreference_me909s-ril.so" +#define REFERENCE_RIL_U9300C_PATH "/system/lib/libreference_u9300c-ril.so" +#define REFERENCE_RIL_EC20_PATH "/system/lib/libreference_ec20-ril.so" +#define REFERENCE_RIL_EM8000_PATH "/system/lib/libreference_em8000-ril.so" static void usage(const char *argv0) { @@ -64,6 +73,7 @@ static struct RIL_Env s_rilEnv = { RIL_onUnsolicitedResponse, RIL_requestTimedCallback }; +static int s_poll_device_cnt = 0; extern void RIL_startEventLoop(); @@ -109,44 +119,21 @@ int main(int argc, char **argv) char libPath[PROPERTY_VALUE_MAX]; unsigned char hasLibArgs = 0; int ret = 0; + int modem_type = UNKNOWN_MODEM; int i; char platform[PROPERTY_VALUE_MAX] = {0}; //is telephony platform? if(property_get("ro.sw.embeded.telephony", platform, NULL)){ if(strcmp(platform, "true")) { - RLOGI("platform: wifi-only"); + RLOGI("platform: wifi-only --1"); radio_monitor(); }else{ - RLOGI("platform: telephony"); + RLOGI("platform: telephony --2"); } } -#if 0 - umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); - for (i = 1; i < argc ;) { - if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) { - rilLibPath = argv[i + 1]; - i += 2; - } else if (0 == strcmp(argv[i], "--")) { - i++; - hasLibArgs = 1; - break; - } else { - usage(argv[0]); - } - } - if (rilLibPath == NULL) { - if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) { - // No lib sepcified on the command line, and nothing set in props. - // Assume "no-ril" case. - goto done; - } else { - rilLibPath = libPath; - } - } -#else ret = property_get(LIB_PATH_PROPERTY, libPath, NULL); if (ret <= 0) { /* nothing to do */ @@ -174,9 +161,62 @@ int main(int argc, char **argv) RLOGD("err: get rilLibPath failed\n"); goto done; } + ///$shh$20180906$add$Dynamic switching module$ + //Wait for device ready. + // if (rilLibPath == NULL) { + while(UNKNOWN_MODEM == modem_type){ + modem_type = runtime_3g_port_type(); + ALOGD("111 -Couldn't find proper modem, retrying..."); + s_poll_device_cnt++; + if (s_poll_device_cnt > MAX_POLL_DEVICE_CNT){ + /* + *Maybe no device right now, start to monitor + *hotplug event later. + */ + start_uevent_monitor(); + goto done; + } + sleep(5); + } + //} -#endif - RLOGD("\nrilLibPath = %s\n\n", rilLibPath); + start_uevent_monitor(); + + switch (modem_type){ + case ME909S_MODEM: + { + rilLibPath = REFERENCE_RIL_ME909S_PATH; + break; + } + case U9300C_MODEM: + { + rilLibPath = REFERENCE_RIL_U9300C_PATH; + break; + } + case EC20_MODEM: + { + rilLibPath = REFERENCE_RIL_EC20_PATH; + break; + } + case EM8000_MODEM: + { + rilLibPath = REFERENCE_RIL_EM8000_PATH; + printf(""); + break; + } + + if (rilLibPath == NULL) { + if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) { + // No lib sepcified on the command line, and nothing set in props. + // Assume "no-ril" case. + goto done; + } else { + rilLibPath = libPath; + } + } + } + RLOGD("shh->rilLibPath:%s,modem_type=%d",rilLibPath,modem_type); + ///$shh$20180906$add$Dynamic switching module$ /* special override when in the emulator */ #if 0 //ignore this by SW diff --git a/android/hardware/ril/runtime-ril-port/Android.mk b/android/hardware/ril/runtime-ril-port/Android.mk new file mode 100755 index 0000000000..fdf21f4844 --- /dev/null +++ b/android/hardware/ril/runtime-ril-port/Android.mk @@ -0,0 +1,19 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + runtime_port.c + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils + +LOCAL_CFLAGS := + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE:= libruntime-ril-port + + +include $(BUILD_SHARED_LIBRARY) diff --git a/android/hardware/ril/runtime-ril-port/runtime_port.c b/android/hardware/ril/runtime-ril-port/runtime_port.c new file mode 100755 index 0000000000..f7682c7df1 --- /dev/null +++ b/android/hardware/ril/runtime-ril-port/runtime_port.c @@ -0,0 +1,452 @@ +/* + * 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. + */ + +/* + * Copyright 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <linux/netlink.h> + +#include <signal.h> +#include <unistd.h> +#include <runtime/runtime.h> + +int current_modem_type = UNKNOWN_MODEM; + +#define FAKE_PORT "/dev/ttyFAKEPort" +/* Rild need a fake port to pass continue init job, + * return a fake port make it runable. + * Or the system will enter 15s in early suspend. + */ + +struct modem_3g_device { + const char *idVendor; + const char *idProduct; + const char *deviceport; /* sending AT command */ + const char *dataport; /* sending 3g data */ + const char *name; + const int type; +}; + +#define PATH_SIZE 1024 +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +static const char *USB_DIR_BASE = "/sys/bus/usb/devices/"; + +static struct modem_3g_device modem_3g_device_table[] = { + + { + .name = "ME909S_MODEM", + .idVendor = "12d1", + .idProduct = "15c1", + .deviceport = "/dev/ttyUSB0", + .dataport = "/dev/ttyUSB2", + .type = ME909S_MODEM, + }, + + + { + .name = "U9300C_MODEM", + .idVendor = "1c9e", + .idProduct = "9b3c", + .deviceport = "/dev/ttyUSB1", + .dataport = "/dev/ttyUSB2", + .type = U9300C_MODEM, + }, + { + .name = "EC20_MODEM", + .idVendor = "2c7c", + .idProduct = "0125", + .deviceport = "/dev/ttyUSB0", + .dataport = "/dev/ttyUSB2", + .type = EC20_MODEM, + }, + { + .name = "EM8000_MODEM", + .idVendor = "19d2", + .idProduct = "0532", + .deviceport = "/dev/ttyUSB0", + .dataport = "/dev/ttyUSB2", + .type = EM8000_MODEM, + }, +}; + +/* -------------------------------------------------------------- */ + +#define DEBUG_UEVENT 0 +#define UEVENT_PARAMS_MAX 32 + +enum uevent_action { action_add, action_remove, action_change }; + +struct uevent { + char *path; + enum uevent_action action; + char *subsystem; + char *param[UEVENT_PARAMS_MAX]; + unsigned int seqnum; +}; + +static void dump_uevent(struct uevent *event); + +int readfile(char *path, char *content, size_t size) +{ + int ret; + FILE *f; + f = fopen(path, "r"); + if (f == NULL) + return -1; + + ret = fread(content, 1, size, f); + fclose(f); + return ret; +} + +int is_device_equal(struct modem_3g_device *device, + const char *idv, const char *idp) +{ + long pvid = 0xffff, ppid = 0xffff; + long t_vid, t_pid; + if (device == NULL) + return 0; + t_vid = strtol(device->idVendor, NULL, 16); + t_pid = strtol(device->idProduct, NULL, 16); + pvid = strtol(idv, NULL, 16); + ppid = strtol(idp, NULL, 16); + + return (t_vid == pvid && t_pid == ppid); +} + +struct modem_3g_device * +find_devices_in_table(const char *idvendor, const char *idproduct) +{ + int i; + int size = ARRAY_SIZE(modem_3g_device_table); + struct modem_3g_device *device; + + for (i = 0; i < size; i++) { + device = &modem_3g_device_table[i]; + + if (is_device_equal(device, idvendor, idproduct)) { + ALOGI("Runtime 3G port found matched device with " + "Name:%s idVendor:%s idProduct:%s", + device->name, device->idVendor, device->idProduct); + + return device; + } + } + + return NULL; +} + +struct modem_3g_device *find_matched_device(void) +{ + struct dirent *dent; + DIR *usbdir; + struct modem_3g_device *device = NULL; + char *path, *path2; + char idvendor[64]; + char idproduct[64]; + int ret, i; + + path = malloc(PATH_SIZE); + if (!path) + return NULL; + + path2 = malloc(PATH_SIZE); + if (!path2) { + free(path); + return NULL; + } + + usbdir = opendir(USB_DIR_BASE); + if (usbdir == NULL) { + free(path); + free(path2); + return NULL; + } + + memset(path, 0, PATH_SIZE); + memset(path2, 0, PATH_SIZE); + + while ((dent = readdir(usbdir)) != NULL) { + if (strcmp(dent->d_name, ".") == 0 + || strcmp(dent->d_name, "..") == 0) + continue; + memset(idvendor, 0, sizeof(idvendor)); + memset(idproduct, 0, sizeof(idproduct)); + path = strcpy(path, USB_DIR_BASE); + path = strcat(path, dent->d_name); + strcpy(path2, path); + path = strcat(path, "/idVendor"); + path2 = strcat(path2, "/idProduct"); + + ret = readfile(path, idvendor, 4); + if (ret <= 0) + continue; + ret = readfile(path2, idproduct, 4); + if (ret <= 0) + continue; + device = find_devices_in_table(idvendor, idproduct); + if (device != NULL) + goto out; + } + + if (device == NULL) + ALOGI("Runtime 3G can't find supported modem"); +out: + closedir(usbdir); + free(path); + free(path2); + + return device; +} + + +const char *runtime_3g_port_device(void) +{ + struct modem_3g_device *device; + device = find_matched_device(); + if (device == NULL) + return FAKE_PORT; + + /* Set gobal modem type. */ + current_modem_type = device->type; + + ALOGI("Current modem type = %d", current_modem_type); + + return device->deviceport; +} + +const char *runtime_3g_port_data(void) +{ + struct modem_3g_device *device; + + device = find_matched_device(); + if (device == NULL) + return FAKE_PORT; + return device->dataport; +} + +int runtime_3g_port_type(void) +{ + struct modem_3g_device *device; + int type = UNKNOWN_MODEM; + if (UNKNOWN_MODEM == current_modem_type){ + if (NULL != (device = find_matched_device())){ + /* Set gobal modem type. */ + type = device->type; + } + }else{ + type = current_modem_type; + } + + ALOGI("Current modem type = %d", type); + + return type; +} + +static void free_uevent(struct uevent *event) +{ + int i; + free(event->path); + free(event->subsystem); + for (i = 0; i < UEVENT_PARAMS_MAX; i++) { + if (!event->param[i]) + break; + free(event->param[i]); + } + free(event); +} + +static int dispatch_uevent(struct uevent *event) +{ + /* if it's a usb tty event in our table. make the rild reboot. */ + int i; + int ret; + for (i = 0; i < UEVENT_PARAMS_MAX; i++) { + if (!event->param[i]) + break; + if (strncmp(event->param[i], "PRODUCT=", 8) == 0) { + char vbuf[5], pbuf[5]; + ret = sscanf(event->param[i], + "PRODUCT=%4s/%4s/", vbuf, pbuf); + if (ret < 0) + return -1; + if (find_devices_in_table(vbuf, pbuf)) + alarm(1); + /* Restart in 1 second, since USB usually have + * many devices, this avoid rild restart too + * many times. */ + } + } + return 0; +} + +int process_uevent_message(int sock) +{ + char buffer[64 * 1024]; + char *s = buffer, *p; + char *end; + int count, param_idx = 0, ret; + struct uevent *event; + count = recv(sock, buffer, sizeof(buffer), 0); + if (count < 0) { + ALOGE("Error receiving uevent (%s)", strerror(errno)); + return -errno; + } + event = malloc(sizeof(struct uevent)); + if (!event) { + ALOGE("Error allcating memroy (%s)", strerror(errno)); + return -errno; + } + memset(event, 0, sizeof(struct uevent)); + + end = s + count; + + for (p = s; *p != '@'; p++) + ; + p++; + event->path = strdup(p); + s += strlen(s) + 1; + + while (s < end) { + if (!strncmp(s, "ACTION=", strlen("ACTION="))) { + char *a = s + strlen("ACTION="); + if (!strcmp(a, "add")) + event->action = action_add; + else if (!strcmp(a, "change")) + event->action = action_change; + else if (!strcmp(a, "remove")) + event->action = action_remove; + } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM="))) + event->seqnum = atoi(s + strlen("SEQNUM=")); + else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM="))) + event->subsystem = strdup(s + strlen("SUBSYSTEM=")); + else + event->param[param_idx++] = strdup(s); + s += strlen(s) + 1; + } + + ret = dispatch_uevent(event); +#if DEBUG_UEVENT + dump_uevent(event); +#endif + free_uevent(event); + return ret; +} + +static void dump_uevent(struct uevent *event) +{ + int i; + + ALOGD("[UEVENT] Sq: %u S: %s A: %d P: %s", + event->seqnum, event->subsystem, event->action, event->path); + for (i = 0; i < UEVENT_PARAMS_MAX; i++) { + if (!event->param[i]) + break; + ALOGD("%s", event->param[i]); + } +} + +void restart_rild(int p) +{ + ALOGI("3G Modem changed,RILD will restart..."); + exit(-1); +} + +void *usb_tty_monitor_thread(void *arg) +{ + struct sockaddr_nl nladdr; + struct pollfd pollfds[2]; + int uevent_sock; + int ret, max = 0; + int uevent_sz = 64 * 1024; + int timeout = -1; + struct sigaction timeoutsigact; + + ALOGI("3G modem monitor thread is start"); + + timeoutsigact.sa_handler = restart_rild; + sigemptyset(&timeoutsigact.sa_mask); + sigaddset(&timeoutsigact.sa_mask, SIGALRM); + sigaction(SIGALRM, &timeoutsigact, 0); + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = getpid(); + nladdr.nl_groups = 0xffffffff; + + uevent_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (uevent_sock < 0) { + ALOGE(" Netlink socket faild, usb monitor exiting..."); + return NULL; + } + + if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz, + sizeof(uevent_sz)) < 0) { + ALOGE("Unable to set uevent socket options: %s", strerror(errno)); + return NULL; + } + + if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { + ALOGE("Unable to bind uevent socket: %s", strerror(errno)); + return NULL; + } + pollfds[0].fd = uevent_sock; + pollfds[0].events = POLLIN; + + ret = fcntl(uevent_sock,F_SETFL, O_NONBLOCK); + if (ret < 0) + ALOGE("Error on fcntl:%s", strerror(errno)); + + while (1) { + ret = poll(pollfds, 1, timeout); + + switch (ret) { + case 0: + ALOGD("poll timeout"); + continue; + case -1: + ALOGD("poll error:%s", strerror(errno)); + break; + + default: + if (pollfds[0].revents & POLLIN) + process_uevent_message(uevent_sock); + } + } + + close(uevent_sock); +} + +int start_uevent_monitor(void) +{ + pthread_t pth_uevent_monitor; + return pthread_create(&pth_uevent_monitor, NULL, + usb_tty_monitor_thread, NULL); +} + +