[LEDE-DEV] [PATCH 1/2] uqmi: add support for MBIM devices with QMI service
Bjørn Mork
bjorn at mork.no
Sat Aug 20 17:01:09 PDT 2016
Many Qualcomm based devices offer a QMI service when running in MBIM
mode. This is useful for a number of requests which have no MBIM
counterpart.
This implementation is very basic, simply wrapping the QMI requests
in an MBIM command. It is up to the user to make sure that the MBIM
command sequence is valid, using a mix of umbim and uqmi requests.
umbim must be used to send "OPEN" before uqmi can issue any MBIM
requests. Example:
1. use umbim to open the session, using the '-n' option:
$ umbim -d /dev/cdc-wdm0 -n caps
devicetype: 0003 - remote
cellularclass: 0001
voiceclass: 0001 - no-voice
simclass: 0002
dataclass: 003C
smscaps: 0003
controlcaps: 0001
maxsessions: 0008
deviceid: 0145820007xxxxx
firmwareinfo: SWI9X30C_02.08.02.00
hardwareinfo: EM7455
2. use uqmi to send an MBIM request, using the '-m' option:
$ uqmi -m -d /dev/cdc-wdm0 --get-serving-system
{
"registration": "registered",
"plmn_mcc": 242,
"plmn_mnc": 1,
"plmn_description": "TELENOR",
"roaming": false
}
3. use umbim to close the open session, using the '-t X' option:
$ umbim -d /dev/cdc-wdm0 -t 2 caps
devicetype: 0003 - remote
cellularclass: 0001
voiceclass: 0001 - no-voice
simclass: 0002
dataclass: 003C
smscaps: 0003
controlcaps: 0001
maxsessions: 0008
deviceid: 0145820007xxxxx
firmwareinfo: SWI9X30C_02.08.02.00
hardwareinfo: EM7455
Signed-off-by: Bjørn Mork <bjorn at mork.no>
---
CMakeLists.txt | 2 +-
dev.c | 52 +++++++++++++++++++++++++++++++++++++++-------------
main.c | 7 ++++++-
mbim.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
mbim.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
uqmi.h | 2 ++
6 files changed, 154 insertions(+), 15 deletions(-)
create mode 100644 mbim.c
create mode 100644 mbim.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1304415a11b0..9e23a1a1ba8b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations -Wno-
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
-SET(SOURCES main.c dev.c commands.c qmi-message.c)
+SET(SOURCES main.c dev.c commands.c qmi-message.c mbim.c)
INCLUDE(FindPkgConfig)
PKG_CHECK_MODULES(JSONC json-c)
diff --git a/dev.c b/dev.c
index c25900bb9f4a..d65299e1c25d 100644
--- a/dev.c
+++ b/dev.c
@@ -27,6 +27,7 @@
#include "uqmi.h"
#include "qmi-errors.h"
#include "qmi-errors.c"
+#include "mbim.h"
bool cancel_all_requests = false;
@@ -36,10 +37,13 @@ static const uint8_t qmi_services[__QMI_SERVICE_LAST] = {
};
#undef __qmi_service
-static union {
- char buf[512];
- struct qmi_msg msg;
-} msgbuf;
+static struct {
+ struct mbim_command_message mbim;
+ union {
+ char buf[512];
+ struct qmi_msg msg;
+ } u;
+} __attribute__((packed)) msgbuf;
#ifdef DEBUG_PACKET
void dump_packet(const char *prefix, void *ptr, int len)
@@ -124,20 +128,35 @@ static void qmi_notify_read(struct ustream *us, int bytes)
char *buf;
int len, msg_len;
+
while (1) {
buf = ustream_get_read_buf(us, &len);
if (!buf || !len)
return;
- if (len < offsetof(struct qmi_msg, flags))
- return;
+ dump_packet("Received packet", buf, len);
+ if (qmi->is_mbim) {
+ struct mbim_command_message *mbim = (void *) buf;
+
+ if (len < sizeof(*mbim))
+ return;
+ msg = (struct qmi_msg *) (buf + sizeof(*mbim));
+ msg_len = le32toh(mbim->header.length);
+ if (!is_mbim_qmi(mbim)) {
+ /* must consume other MBIM packets */
+ ustream_consume(us, msg_len);
+ return;
+ }
+ } else {
+ if (len < offsetof(struct qmi_msg, flags))
+ return;
+ msg = (struct qmi_msg *) buf;
+ msg_len = le16_to_cpu(msg->qmux.len) + 1;
+ }
- msg = (struct qmi_msg *) buf;
- msg_len = le16_to_cpu(msg->qmux.len) + 1;
if (len < msg_len)
return;
- dump_packet("Received packet", msg, msg_len);
qmi_process_msg(qmi, msg);
ustream_consume(us, msg_len);
}
@@ -147,6 +166,7 @@ int qmi_request_start(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_m
{
int len = qmi_complete_request_message(msg);
uint16_t tid;
+ char *buf = (void *) msg;
memset(req, 0, sizeof(*req));
req->ret = -1;
@@ -170,8 +190,14 @@ int qmi_request_start(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_m
req->pending = true;
list_add(&req->list, &qmi->req);
- dump_packet("Send packet", msg, len);
- ustream_write(&qmi->sf.stream, (void *) msg, len, false);
+ if (qmi->is_mbim) {
+ buf -= sizeof(struct mbim_command_message);
+ mbim_qmi_cmd((struct mbim_command_message *) buf, len, tid);
+ len += sizeof(struct mbim_command_message);
+ }
+
+ dump_packet("Send packet", buf, len);
+ ustream_write(&qmi->sf.stream, buf, len, false);
return 0;
}
@@ -234,7 +260,7 @@ int qmi_service_connect(struct qmi_dev *qmi, QmiService svc, int client_id)
};
struct qmi_connect_request req;
int idx = qmi_get_service_idx(svc);
- struct qmi_msg *msg = &msgbuf.msg;
+ struct qmi_msg *msg = &msgbuf.u.msg;
if (idx < 0)
return -1;
@@ -273,7 +299,7 @@ static void __qmi_service_disconnect(struct qmi_dev *qmi, int idx)
)
};
struct qmi_request req;
- struct qmi_msg *msg = &msgbuf.msg;
+ struct qmi_msg *msg = &msgbuf.u.msg;
qmi->service_connected &= ~(1 << idx);
qmi->service_data[idx].client_id = -1;
diff --git a/main.c b/main.c
index 028c3a9bb11e..c798b6d42a70 100644
--- a/main.c
+++ b/main.c
@@ -43,6 +43,7 @@ static const struct option uqmi_getopt[] = {
{ "device", required_argument, NULL, 'd' },
{ "keep-client-id", required_argument, NULL, 'k' },
{ "release-client-id", required_argument, NULL, 'r' },
+ { "device-is-mbim", no_argument, NULL, 'm' },
{ NULL, 0, NULL, 0 }
};
#undef __uqmi_command
@@ -55,6 +56,7 @@ static int usage(const char *progname)
" --device=NAME, -d NAME: Set device name to NAME (required)\n"
" --keep-client-id <name>: Keep Client ID for service <name>\n"
" --release-client-id <name>: Release Client ID after exiting\n"
+ " --device-is-mbim, -m NAME is an MBIM device with EXT_QMUX support\n"
"\n"
"Services: dms, nas, pds, wds, wms\n"
"\n"
@@ -108,7 +110,7 @@ int main(int argc, char **argv)
signal(SIGINT, handle_exit_signal);
signal(SIGTERM, handle_exit_signal);
- while ((ch = getopt_long(argc, argv, "d:k:s", uqmi_getopt, NULL)) != -1) {
+ while ((ch = getopt_long(argc, argv, "d:k:sm", uqmi_getopt, NULL)) != -1) {
int cmd_opt = CMD_OPT(ch);
if (ch < 0 && cmd_opt >= 0 && cmd_opt < __UQMI_COMMAND_LAST) {
@@ -129,6 +131,9 @@ int main(int argc, char **argv)
case 's':
single_line = true;
break;
+ case 'm':
+ dev.is_mbim = true;
+ break;
default:
return usage(argv[0]);
}
diff --git a/mbim.c b/mbim.c
new file mode 100644
index 000000000000..861554c8efde
--- /dev/null
+++ b/mbim.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Bjørn Mork <bjorn at mork.no>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <stdio.h>
+
+#include "mbim.h"
+
+static const uint8_t qmiuuid[16] = { 0xd1, 0xa3, 0x0b, 0xc2, 0xf9, 0x7a, 0x6e, 0x43,
+ 0xbf, 0x65, 0xc7, 0xe2, 0x4f, 0xb0, 0xf0, 0xd3 };
+
+bool is_mbim_qmi(struct mbim_command_message *msg)
+{
+ return msg->header.type == htole32(MBIM_MESSAGE_TYPE_COMMAND_DONE) &&
+ msg->command_id == htole32(MBIM_CID_QMI_MSG) &&
+ !msg->command_type && /* actually 'status' here */
+ !memcmp(msg->service_id, qmiuuid, 16);
+ }
+
+void mbim_qmi_cmd(struct mbim_command_message *msg, int len, uint16_t tid)
+{
+ msg->header.type = htole32(MBIM_MESSAGE_TYPE_COMMAND);
+ msg->header.length = sizeof(*msg) + len;
+ msg->header.transaction_id = htole32(tid);
+ msg->fragment_header.total = 1;
+ msg->fragment_header.current = 0;
+ memcpy(msg->service_id, qmiuuid, 16);
+ msg->command_id = htole32(MBIM_CID_QMI_MSG);
+ msg->command_type = htole32(MBIM_MESSAGE_COMMAND_TYPE_SET);
+ msg->buffer_length = len;
+}
diff --git a/mbim.h b/mbim.h
new file mode 100644
index 000000000000..60337a5c0f61
--- /dev/null
+++ b/mbim.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 John Crispin <blogic at openwrt.org>
+ * Copyright (C) 2016 Bjørn Mork <bjorn at mork.no>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MBIM_H__
+#define _MBIM_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define MBIM_MESSAGE_TYPE_COMMAND 0x00000003
+#define MBIM_MESSAGE_TYPE_COMMAND_DONE 0x80000003
+#define MBIM_MESSAGE_COMMAND_TYPE_SET 1
+#define MBIM_CID_QMI_MSG 1
+
+struct mbim_message_header {
+ uint32_t type;
+ uint32_t length;
+ uint32_t transaction_id;
+} __attribute__((packed));
+
+struct mbim_fragment_header {
+ uint32_t total;
+ uint32_t current;
+} __attribute__((packed));
+
+struct mbim_command_message {
+ struct mbim_message_header header;
+ struct mbim_fragment_header fragment_header;
+ uint8_t service_id[16];
+ uint32_t command_id;
+ uint32_t command_type;
+ uint32_t buffer_length;
+} __attribute__((packed));
+
+bool is_mbim_qmi(struct mbim_command_message *msg);
+void mbim_qmi_cmd(struct mbim_command_message *msg, int len, uint16_t tid);
+
+#endif
diff --git a/uqmi.h b/uqmi.h
index 5cd3bff06e9a..299997754100 100644
--- a/uqmi.h
+++ b/uqmi.h
@@ -87,6 +87,8 @@ struct qmi_dev {
uint32_t service_release_cid;
uint8_t ctl_tid;
+
+ bool is_mbim;
};
struct qmi_request {
--
2.9.3
More information about the Lede-dev
mailing list