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 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模块添加方式进行操作。

猜你喜欢

转载自blog.csdn.net/qq_32645109/article/details/121372501
今日推荐