init
This commit is contained in:
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
Copyright 2025 Quectel Wireless Solutions Co.,Ltd
|
||||
|
||||
Quectel hereby grants customers of Quectel a license to use, modify,
|
||||
distribute and publish the Software in binary form provided that
|
||||
customers shall have no right to reverse engineer, reverse assemble,
|
||||
decompile or reduce to source code form any portion of the Software.
|
||||
Under no circumstances may customers modify, demonstrate, use, deliver
|
||||
or disclose any portion of the Software in source code form.
|
||||
*/
|
||||
|
||||
#include "QMIThread.h"
|
||||
|
||||
static size_t ql_fread(const char *filename, void *buf, size_t size) {
|
||||
FILE *fp = fopen(filename , "r");
|
||||
size_t n = 0;
|
||||
|
||||
memset(buf, 0x00, size);
|
||||
|
||||
if (fp) {
|
||||
n = fread(buf, 1, size, fp);
|
||||
if (n <= 0 || n == size) {
|
||||
dbg_time("warnning: fail to fread(%s), fread=%zu, buf_size=%zu: (%s)", filename, n, size, strerror(errno));
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return n > 0 ? n : 0;
|
||||
}
|
||||
|
||||
static size_t ql_fwrite(const char *filename, const void *buf, size_t size) {
|
||||
FILE *fp = fopen(filename , "w");
|
||||
size_t n = 0;
|
||||
|
||||
if (fp) {
|
||||
n = fwrite(buf, 1, size, fp);
|
||||
if (n != size) {
|
||||
dbg_time("warnning: fail to fwrite(%s), fwrite=%zu, buf_size=%zu: (%s)", filename, n, size, strerror(errno));
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return n > 0 ? n : 0;
|
||||
}
|
||||
|
||||
int ql_bridge_mode_detect(PROFILE_T *profile) {
|
||||
const char *ifname = profile->qmapnet_adapter[0] ? profile->qmapnet_adapter : profile->usbnet_adapter;
|
||||
const char *driver;
|
||||
char bridge_mode[128];
|
||||
char bridge_ipv4[128];
|
||||
char ipv4[128];
|
||||
char buf[64];
|
||||
size_t n;
|
||||
int in_bridge = 0;
|
||||
|
||||
driver = profile->driver_name;
|
||||
snprintf(bridge_mode, sizeof(bridge_mode), "/sys/class/net/%s/bridge_mode", ifname);
|
||||
snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/class/net/%s/bridge_ipv4", ifname);
|
||||
|
||||
if (access(bridge_ipv4, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", bridge_mode, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(bridge_mode, sizeof(bridge_mode), "/sys/module/%s/parameters/bridge_mode", driver);
|
||||
snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/module/%s/parameters/bridge_ipv4", driver);
|
||||
|
||||
if (access(bridge_mode, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", bridge_mode, errno, strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
n = ql_fread(bridge_mode, buf, sizeof(buf));
|
||||
if (n > 0) {
|
||||
in_bridge = (buf[0] != '0');
|
||||
}
|
||||
if (!in_bridge)
|
||||
return 0;
|
||||
|
||||
memset(ipv4, 0, sizeof(ipv4));
|
||||
|
||||
if (strstr(bridge_ipv4, "/sys/class/net/") || profile->qmap_mode == 0 || profile->qmap_mode == 1) {
|
||||
snprintf(ipv4, sizeof(ipv4), "0x%x", profile->ipv4.Address);
|
||||
dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
|
||||
ql_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
|
||||
}
|
||||
else {
|
||||
snprintf(ipv4, sizeof(ipv4), "0x%x:%d", profile->ipv4.Address, profile->muxid);
|
||||
dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
|
||||
ql_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
|
||||
}
|
||||
|
||||
return in_bridge;
|
||||
}
|
||||
|
||||
int ql_enable_qmi_wwan_rawip_mode(PROFILE_T *profile) {
|
||||
char filename[256];
|
||||
char buf[4];
|
||||
size_t n;
|
||||
FILE *fp;
|
||||
|
||||
if (!qmidev_is_qmiwwan(profile->qmichannel))
|
||||
return 0;
|
||||
|
||||
snprintf(filename, sizeof(filename), "/sys/class/net/%s/qmi/rawip", profile->usbnet_adapter);
|
||||
n = ql_fread(filename, buf, sizeof(buf));
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
if (buf[0] == '1' || buf[0] == 'Y')
|
||||
return 0;
|
||||
|
||||
fp = fopen(filename , "w");
|
||||
if (fp == NULL) {
|
||||
dbg_time("Fail to fopen(%s, \"w\"), errno: %d (%s)", filename, errno, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf[0] = 'Y';
|
||||
n = fwrite(buf, 1, 1, fp);
|
||||
if (n != 1) {
|
||||
dbg_time("Fail to fwrite(%s), errno: %d (%s)", filename, errno, strerror(errno));
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ql_driver_type_detect(PROFILE_T *profile) {
|
||||
if (qmidev_is_gobinet(profile->qmichannel)) {
|
||||
profile->qmi_ops = &gobi_qmidev_ops;
|
||||
}
|
||||
else {
|
||||
profile->qmi_ops = &qmiwwan_qmidev_ops;
|
||||
}
|
||||
qmidev_send = profile->qmi_ops->send;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ql_set_driver_bridge_mode(PROFILE_T *profile) {
|
||||
char enable[16];
|
||||
char filename[256];
|
||||
|
||||
if(profile->qmap_mode)
|
||||
snprintf(filename, sizeof(filename), "/sys/class/net/%s/bridge_mode", profile->qmapnet_adapter);
|
||||
else
|
||||
snprintf(filename, sizeof(filename), "/sys/class/net/%s/bridge_mode", profile->usbnet_adapter);
|
||||
snprintf(enable, sizeof(enable), "%02d\n", profile->enable_bridge);
|
||||
ql_fwrite(filename, enable, sizeof(enable));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QRTR
|
||||
static int ql_create_or_detect_rmnet_data(PROFILE_T *profile) {
|
||||
char tmp[128];
|
||||
int muxid = 0, qmap_version = 0;
|
||||
|
||||
if (access("/sys/module/rmnet_data", F_OK) != 0 /* spf11.x */
|
||||
&& access("/sys/module/rmnet_core", F_OK) != 0 /* spf12.x */) {
|
||||
dbg_time("rmnet_data/rmnet_core driver is not support!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "/sys/class/net/%s", profile->qmapnet_adapter);
|
||||
if (access(tmp, F_OK) && errno == ENOENT) {
|
||||
uint32_t ul_agg_cnt = 0, ul_agg_size = 0;
|
||||
|
||||
if (profile->hardware_interface == HARDWARE_USB) {
|
||||
ul_agg_cnt = 11;
|
||||
ul_agg_size = 4096; //sdx modem may only support 4096
|
||||
}
|
||||
rtrmnet_ctl_new_vnd(profile->usbnet_adapter, profile->qmapnet_adapter,
|
||||
profile->muxid, profile->qmap_version, ul_agg_cnt, ul_agg_size);
|
||||
}
|
||||
|
||||
if (access(tmp, F_OK) && errno == ENOENT) {
|
||||
dbg_time("Fail to detect %s", profile->qmapnet_adapter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rtrmnet_ctl_get_vnd(profile->qmapnet_adapter, &muxid, &qmap_version);
|
||||
if (qmap_version != profile->qmap_version || muxid != profile->muxid) {
|
||||
dbg_time("wrong qmap_version: %d - %d, muxid: %d - %d",
|
||||
qmap_version, profile->qmap_version, muxid, profile->muxid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ql_qmi_qmap_mode_detect(PROFILE_T *profile) {
|
||||
char buf[128];
|
||||
int n;
|
||||
struct {
|
||||
char filename[255 * 2];
|
||||
char linkname[255 * 2];
|
||||
} *pl;
|
||||
|
||||
pl = (typeof(pl)) malloc(sizeof(*pl));
|
||||
|
||||
snprintf(pl->linkname, sizeof(pl->linkname), "/sys/class/net/%s/device/driver", profile->usbnet_adapter);
|
||||
n = readlink(pl->linkname, pl->filename, sizeof(pl->filename));
|
||||
pl->filename[n] = '\0';
|
||||
while (pl->filename[n] != '/')
|
||||
n--;
|
||||
strncpy(profile->driver_name, &pl->filename[n+1], sizeof(profile->driver_name) - 1);
|
||||
|
||||
ql_get_driver_rmnet_info(profile, &profile->rmnet_info);
|
||||
if (profile->rmnet_info.size) {
|
||||
profile->qmap_mode = profile->rmnet_info.qmap_mode;
|
||||
if (profile->qmap_mode) {
|
||||
int offset_id = (profile->muxid == 0)? profile->pdp - 1 : profile->muxid - 0x81;
|
||||
|
||||
if (profile->qmap_mode == 1)
|
||||
offset_id = 0;
|
||||
profile->muxid = profile->rmnet_info.mux_id[offset_id];
|
||||
strncpy(profile->qmapnet_adapter, profile->rmnet_info.ifname[offset_id], sizeof(profile->qmapnet_adapter) - 1);
|
||||
profile->qmap_size = profile->rmnet_info.rx_urb_size;
|
||||
profile->qmap_version = profile->rmnet_info.qmap_version;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QRTR
|
||||
if (!strcmp(profile->qmapnet_adapter, "use_rmnet_data")) {
|
||||
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "%.16s_%d",
|
||||
profile->usbnet_adapter, profile->pdp);
|
||||
ql_create_or_detect_rmnet_data(profile);
|
||||
}
|
||||
#endif
|
||||
|
||||
goto _out;
|
||||
}
|
||||
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_mode", profile->usbnet_adapter);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/module/%s/parameters/qmap_mode", profile->driver_name);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/device/driver/module/parameters/qmap_mode", profile->usbnet_adapter);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!access(pl->filename, R_OK)) {
|
||||
n = ql_fread(pl->filename, buf, sizeof(buf));
|
||||
if (n > 0) {
|
||||
profile->qmap_mode = atoi(buf);
|
||||
|
||||
if (profile->qmap_mode > 1) {
|
||||
if(!profile->muxid)
|
||||
profile->muxid = profile->pdp + 0x80; //muxis is 0x8X for PDN-X
|
||||
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter),
|
||||
"%.16s.%d", profile->usbnet_adapter, profile->muxid - 0x80);
|
||||
} if (profile->qmap_mode == 1) {
|
||||
profile->muxid = 0x81;
|
||||
strncpy(profile->qmapnet_adapter, profile->usbnet_adapter, sizeof(profile->qmapnet_adapter));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (qmidev_is_qmiwwan(profile->qmichannel)) {
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/qmimux%d", profile->pdp - 1);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
|
||||
}
|
||||
goto _out;
|
||||
}
|
||||
|
||||
//upstream Kernel Style QMAP qmi_wwan.c
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
|
||||
n = ql_fread(pl->filename, buf, sizeof(buf));
|
||||
if (n >= 5) {
|
||||
dbg_time("If use QMAP by /sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
|
||||
#if 1
|
||||
dbg_time("Please set mtu of wwan0 >= max dl qmap packet size");
|
||||
#else
|
||||
dbg_time("File:%s Line:%d Please make sure add next patch to qmi_wwan.c", __func__, __LINE__);
|
||||
/*
|
||||
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
||||
index 74bebbd..db8a777 100644
|
||||
--- a/drivers/net/usb/qmi_wwan.c
|
||||
+++ b/drivers/net/usb/qmi_wwan.c
|
||||
@@ -379,6 +379,24 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c
|
||||
if (!ret) {
|
||||
info->flags |= QMI_WWAN_FLAG_MUX;
|
||||
ret = len;
|
||||
+#if 1 //Add by Quectel
|
||||
+ if (le16_to_cpu(dev->udev->descriptor.idVendor) == 0x2c7c) {
|
||||
+ int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct);
|
||||
+
|
||||
+ if (idProduct == 0x0121 || idProduct == 0x0125 || idProduct == 0x0435) //MDM9x07
|
||||
+ dev->rx_urb_size = 4*1024;
|
||||
+ else if (idProduct == 0x0306) //MDM9x40
|
||||
+ dev->rx_urb_size = 16*1024;
|
||||
+ else if (idProduct == 0x0512) //SDX20
|
||||
+ dev->rx_urb_size = 32*1024;
|
||||
+ else if (idProduct == 0x0620) //SDX24
|
||||
+ dev->rx_urb_size = 32*1024;
|
||||
+ else if (idProduct == 0x0800) //SDX55
|
||||
+ dev->rx_urb_size = 32*1024;
|
||||
+ else
|
||||
+ dev->rx_urb_size = 32*1024;
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
err:
|
||||
rtnl_unlock();
|
||||
*/
|
||||
#endif
|
||||
profile->qmap_mode = n/5; //0x11\n0x22\n0x33\n
|
||||
if (profile->qmap_mode > 1) {
|
||||
//PDN-X map to qmimux-X
|
||||
if(!profile->muxid) {
|
||||
profile->muxid = (buf[5*(profile->pdp - 1) + 2] - '0')*16 + (buf[5*(profile->pdp - 1) + 3] - '0');
|
||||
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "qmimux%d", profile->pdp - 1);
|
||||
} else {
|
||||
profile->muxid = (buf[5*(profile->muxid - 0x81) + 2] - '0')*16 + (buf[5*(profile->muxid - 0x81) + 3] - '0');
|
||||
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "qmimux%d", profile->muxid - 0x81);
|
||||
}
|
||||
} else if (profile->qmap_mode == 1) {
|
||||
profile->muxid = (buf[5*0 + 2] - '0')*16 + (buf[5*0 + 3] - '0');
|
||||
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter),
|
||||
"qmimux%d", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_out:
|
||||
if (profile->qmap_mode) {
|
||||
if (profile->qmap_size == 0) {
|
||||
profile->qmap_size = 16*1024;
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_size", profile->usbnet_adapter);
|
||||
if (!access(pl->filename, R_OK)) {
|
||||
size_t n;
|
||||
char buf[32];
|
||||
n = ql_fread(pl->filename, buf, sizeof(buf));
|
||||
if (n > 0) {
|
||||
profile->qmap_size = atoi(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->qmap_version == 0) {
|
||||
profile->qmap_version = WDA_DL_DATA_AGG_QMAP_ENABLED;
|
||||
}
|
||||
|
||||
dbg_time("qmap_mode = %d, qmap_version = %d, qmap_size = %d, muxid = 0x%02x, qmap_netcard = %s",
|
||||
profile->qmap_mode, profile->qmap_version, profile->qmap_size, profile->muxid, profile->qmapnet_adapter);
|
||||
}
|
||||
ql_set_driver_bridge_mode(profile);
|
||||
free(pl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ql_mbim_usb_vlan_mode_detect(PROFILE_T *profile) {
|
||||
char tmp[128];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "/sys/class/net/%s.%d", profile->usbnet_adapter, profile->pdp);
|
||||
if (!access(tmp, F_OK)) {
|
||||
profile->qmap_mode = 4;
|
||||
profile->muxid = profile->pdp;
|
||||
no_trunc_strncpy(profile->qmapnet_adapter, tmp + strlen("/sys/class/net/"), sizeof(profile->qmapnet_adapter) - 1);
|
||||
|
||||
dbg_time("mbim_qmap_mode = %d, vlan_id = 0x%02x, qmap_netcard = %s",
|
||||
profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ql_mbim_mhi_qmap_mode_detect(PROFILE_T *profile) {
|
||||
ql_get_driver_rmnet_info(profile, &profile->rmnet_info);
|
||||
if (profile->rmnet_info.size) {
|
||||
profile->qmap_mode = profile->rmnet_info.qmap_mode;
|
||||
if (profile->qmap_mode) {
|
||||
int offset_id = profile->pdp - 1;
|
||||
|
||||
if (profile->qmap_mode == 1)
|
||||
offset_id = 0;
|
||||
profile->muxid = profile->pdp;
|
||||
strcpy(profile->qmapnet_adapter, profile->rmnet_info.ifname[offset_id]);
|
||||
profile->qmap_size = profile->rmnet_info.rx_urb_size;
|
||||
profile->qmap_version = profile->rmnet_info.qmap_version;
|
||||
|
||||
dbg_time("mbim_qmap_mode = %d, vlan_id = 0x%02x, qmap_netcard = %s",
|
||||
profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
|
||||
}
|
||||
|
||||
goto _out;
|
||||
}
|
||||
|
||||
_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ql_qmap_mode_detect(PROFILE_T *profile) {
|
||||
if (profile->software_interface == SOFTWARE_MBIM) {
|
||||
if (profile->hardware_interface == HARDWARE_USB)
|
||||
return ql_mbim_usb_vlan_mode_detect(profile);
|
||||
else if (profile->hardware_interface == HARDWARE_PCIE)
|
||||
return ql_mbim_mhi_qmap_mode_detect(profile);
|
||||
} else if (profile->software_interface == SOFTWARE_QMI) {
|
||||
return ql_qmi_qmap_mode_detect(profile);
|
||||
}
|
||||
#ifdef CONFIG_QRTR
|
||||
else if (profile->software_interface == SOFTWARE_QRTR) {
|
||||
profile->qmap_mode = 1;
|
||||
profile->qmap_version = WDA_DL_DATA_AGG_QMAP_V5_ENABLED;
|
||||
profile->qmap_size = 15*1024;
|
||||
profile->muxid = 0x80 | profile->pdp;
|
||||
|
||||
if (!strcmp(profile->driver_name, "mhi_netdev")) {
|
||||
char linkname[64];
|
||||
char filename[128];
|
||||
int n;
|
||||
|
||||
snprintf(linkname, sizeof(linkname), "/sys/class/net/%s/device", profile->usbnet_adapter);
|
||||
n = readlink(linkname, filename, sizeof(filename));
|
||||
if (n > 0) {
|
||||
//../../../0308_00.01.00_IP_HW0
|
||||
filename[n] = '\0';
|
||||
if (strstr(filename, "_IP_HW0") && strstr(filename+n, "0303_")) //EG18
|
||||
profile->qmap_version = WDA_DL_DATA_AGG_QMAP_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "rmnet_data%d",
|
||||
profile->pdp);
|
||||
return ql_create_or_detect_rmnet_data(profile);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user