目录
修改的文件
文件修改说明
runtime.h
Android.mk(在 rild 目录下)
rild.c
Android.mk(在 runtime-ril-port 目录下)
runtime_port.c
如何适配
这个补丁是我加在全志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 的监视。
runtime_port.c
中的 modem_3g_device_table
。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
#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
+#include
+#include
+#include
+#include
+#include
+#define LOG_TAG "RIL"
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+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);
+}
+
+