rk3288 android7.1.2 4g模块调试(三)
前言当前我们公司使用多个4g模块,为了方便android系统的使用,所以添加的多4g模块的适配,这种方式在可以根据接的4g模块的uid与pid,指定接入4g模块的ril库和at指令端口,完成4g模块的拨号工作。1、移植多4g模块适配代码到hardware目录下hardware/ril/runtime-ril-port/runtime_port.c/** Licensed under the Apa
前言
当前我们公司使用多个4g模块,为了方便android系统的使用,所以添加的多4g模块的适配,这种方式在可以根据接的4g模块的uid与pid,指定接入4g模块的ril库和at指令端口,完成4g模块的拨号工作。
1、移植多4g模块适配代码到hardware目录下
hardware/ril/runtime-ril-port/runtime_port.c
/*
* 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 = "Huawei-EM770",
.idVendor = "12d1",
.idProduct = "1001",
.deviceport = "/dev/ttyUSB0",
.dataport = "/dev/ttyUSB0",
.type = HUAWEI_MODEM,
},
{
.name = "Huawei-EM770W",
.idVendor = "12d1",
.idProduct = "1404",
.deviceport = "/dev/ttyUSB2",
.dataport = "/dev/ttyUSB0",
.type = HUAWEI_MODEM,
},
{
.name = "Huawei-E180",
.idVendor = "12d1",
.idProduct = "1003",
.deviceport = "/dev/ttyUSB1",
.dataport = "/dev/ttyUSB0",
.type = HUAWEI_MODEM,
},
{
.name = "Huawei-EM750",
.idVendor = "12d1",
.idProduct = "1413",
.deviceport = "/dev/ttyUSB3",
.dataport = "/dev/ttyUSB0",
.type = HUAWEI_MODEM,
},
{
.name = "InnoComm-Amazon1",
.idVendor = "1519",
.idProduct = "1001",
.deviceport = "/dev/ttyACM3",
.dataport = "/dev/ttyACM0",
.type = AMAZON_MODEM,
},
{
.name = "InnoComm-Amazon1",
.idVendor = "1519",
.idProduct = "0020",
.deviceport = "/dev/ttyACM3",
.dataport = "/dev/ttyACM0",
.type = AMAZON_MODEM,
},
{
.name = "ZTE-MF220",
.idVendor = "19d2",
.idProduct = "0145",
.deviceport = "/dev/ttyUSB2",
.dataport = "/dev/ttyUSB4",
.type = ZTE_MODEM,
},
{
.name = "ZTE-ME3630",
.idVendor = "19d2",
.idProduct = "1476",
.deviceport = "/dev/ttyUSB3",
.type = ZTE_ME3630,
},
{
.name = "SIMCOM-SIM7600",
.idVendor = "1E0E",
.idProduct = "9001",
.deviceport = "/dev/ttyUSB3",
.type = SIMCOM_SIM7600,
},
{
.name = "Huawei-ME909s",
.idVendor = "12d1",
.idProduct = "15c1",
.deviceport = "/dev/ttyUSB5",
.type = HUAWEI_ME909S,
},
};
/* -------------------------------------------------------------- */
#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);
}
hardware/ril/runtime-ril-port/Android.mk
# 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)
hardware/ril/include/runtime/runtime.h
#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 {
HUAWEI_MODEM = 0,
AMAZON_MODEM,
ZTE_MODEM,
ZTE_ME3630,
SIMCOM_SIM7600,
HUAWEI_ME909S,
UNKNOWN_MODEM,
};
extern int current_modem_type;
#endif
hardware/ril/rild/Android.mk
libril \
- libdl
+ libdl \
+ libruntime-ril-port
runtime_port.c文件主要添加了一些4g模块标志、usb设备节点信息及一些加载4g ril库时的处理函数,具体rild服务启动调用ril库将在rild.c中调用。
2、修改rild ril库及AT指令端口配置方式
修改ril库名称,每个4g模块单独对应一个ril库
hardware/ril/rild/rild.c
+#define REFERENCE_RIL_DEF_PATH "/system/lib/libreference-ril.so"
+#define REFERENCE_RIL_ZTE_PATH "/system/lib/libreference-ril-zte.so"
+#define REFERENCE_RIL_ZTE_ME3630_PATH "/system/lib/libreference-ril-me3630.so"
+#define REFERENCE_RIL_SIMCOM_SIM7600CE_PATH "/system/lib/libreference-ril-sim7600ce.so"
+#define REFERENCE_RIL_HUAWEI_ME909S_PATH "/system/lib/libreference-ril-me909s.so"
调用runtime_port.c中的函数,通过usb 设备的vid与pid,确定当前接入的4g模块,根据4g模块类型,指定系统中调用的ril库
@@ -153,7 +160,7 @@ int main(int argc, char **argv) {
const RIL_RadioFunctions *funcs;
char libPath[PROPERTY_VALUE_MAX];
unsigned char hasLibArgs = 0;
-
+ int modem_type = UNKNOWN_MODEM;
int i;
const char *clientId = NULL;
RLOGD("**RIL Daemon Started**");
@@ -186,6 +193,46 @@ int main(int argc, char **argv) {
strlcat(rild, clientId, MAX_SOCKET_NAME_LENGTH);
RIL_setRilSocketName(rild);
}
+ //Wait for device ready.
+ if (rilLibPath == NULL) {
+ while(UNKNOWN_MODEM == modem_type){
+ modem_type = runtime_3g_port_type();
+ ALOGD("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);
+ }
+ }
+
+ start_uevent_monitor();
+
+ switch (modem_type){
+ case ZTE_MODEM:
+ case ZTE_ME3630:
+ rilLibPath = REFERENCE_RIL_ZTE_ME3630_PATH;
+ break;
+
+ case SIMCOM_SIM7600:
+ rilLibPath = REFERENCE_RIL_SIMCOM_SIM7600CE_PATH;
+ break;
+
+ case HUAWEI_ME909S:
+ rilLibPath = REFERENCE_RIL_HUAWEI_ME909S_PATH;
+ break;
+
+ case HUAWEI_MODEM:
+ case AMAZON_MODEM:
+ default:
+ rilLibPath = REFERENCE_RIL_DEF_PATH;
+ break;
+ }
关闭系统模块ril库路径获取方式
@@ -198,7 +245,7 @@ int main(int argc, char **argv) {
}
/* special override when in the emulator */
-#if 1
+#if 0
{
static char* arg_overrides[5];
static char arg_device[32];
@@ -317,7 +364,7 @@ int main(int argc, char **argv) {
}
OpenLib:
#endif
- switchUser();
+ //switchUser();
总结
使用此方式,可以实现一个系统多个4g模块适配工作,在更换4g模块时,无需在次编译android系统,若有新的模块添加,可以按照上面me3630模块添加方式进行操作。
更多推荐
所有评论(0)