From: vladimir.stankovic@displaylink.com
To: gregkh@linuxfoundation.org
Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
mausb-host-devel@displaylink.com
Subject: [PATCH v5 2/8] usb: mausb_host: Add link layer implementation
Date: Sat, 25 Apr 2020 11:19:48 +0200 [thread overview]
Message-ID: <20200425091954.1610-3-vladimir.stankovic@displaylink.com> (raw)
In-Reply-To: <20200425091954.1610-1-vladimir.stankovic@displaylink.com>
Implemented link layer using kernel sockets. Link layer
manages network communication and provides interface for upper
layers of MA-USB stack.
Signed-off-by: Vladimir Stankovic <vladimir.stankovic@displaylink.com>
---
drivers/usb/mausb_host/Makefile | 1 +
drivers/usb/mausb_host/ip_link.c | 374 +++++++++++++++++++++++++++++++
drivers/usb/mausb_host/ip_link.h | 87 +++++++
3 files changed, 462 insertions(+)
create mode 100644 drivers/usb/mausb_host/ip_link.c
create mode 100644 drivers/usb/mausb_host/ip_link.h
diff --git a/drivers/usb/mausb_host/Makefile b/drivers/usb/mausb_host/Makefile
index 2e353fa0958b..19445b73b50b 100644
--- a/drivers/usb/mausb_host/Makefile
+++ b/drivers/usb/mausb_host/Makefile
@@ -8,5 +8,6 @@
obj-$(CONFIG_HOST_MAUSB) += mausb_host.o
mausb_host-y := mausb_core.o
mausb_host-y += utils.o
+mausb_host-y += ip_link.o
ccflags-y += -I$(srctree)/$(src)
diff --git a/drivers/usb/mausb_host/ip_link.c b/drivers/usb/mausb_host/ip_link.c
new file mode 100644
index 000000000000..49b592c02210
--- /dev/null
+++ b/drivers/usb/mausb_host/ip_link.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#include "ip_link.h"
+
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/workqueue.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+
+#include "utils.h"
+
+static void __mausb_ip_connect(struct work_struct *work);
+static int __mausb_ip_recv(struct mausb_ip_ctx *ip_ctx);
+static void __mausb_ip_recv_work(struct work_struct *work);
+static inline void __mausb_ip_recv_ctx_clear(struct mausb_ip_recv_ctx
+ *recv_ctx);
+static inline void __mausb_ip_recv_ctx_free(struct mausb_ip_recv_ctx
+ *recv_ctx);
+
+int mausb_init_ip_ctx(struct mausb_ip_ctx **ip_ctx,
+ struct net *net_ns,
+ char ip_addr[INET6_ADDRSTRLEN],
+ u16 port, void *context,
+ void (*fn_callback)(void *ctx, enum mausb_channel channel,
+ enum mausb_link_action act,
+ int status, void *data),
+ enum mausb_channel channel)
+{
+ struct mausb_ip_ctx *ctx;
+
+ *ip_ctx = kzalloc(sizeof(**ip_ctx), GFP_ATOMIC);
+ if (!*ip_ctx)
+ return -ENOMEM;
+
+ ctx = *ip_ctx;
+ ctx->client_socket = NULL;
+ __mausb_ip_recv_ctx_clear(&ctx->recv_ctx);
+
+ if (in4_pton(ip_addr, -1,
+ (u8 *)&ctx->dev_addr_in.sa_in.sin_addr.s_addr, -1,
+ NULL) == 1) {
+ ctx->dev_addr_in.sa_in.sin_family = AF_INET;
+ ctx->dev_addr_in.sa_in.sin_port = htons(port);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (in6_pton(ip_addr, -1,
+ (u8 *)&ctx->dev_addr_in.sa_in6.sin6_addr.in6_u, -1,
+ NULL) == 1) {
+ ctx->dev_addr_in.sa_in6.sin6_family = AF_INET6;
+ ctx->dev_addr_in.sa_in6.sin6_port = htons(port);
+#endif
+ } else {
+ mausb_pr_err("Invalid IP address received: address=%s",
+ ip_addr);
+ kfree(ctx);
+ return -EINVAL;
+ }
+
+ ctx->net_ns = net_ns;
+
+ if (channel == MAUSB_ISOCH_CHANNEL)
+ ctx->udp = true;
+
+ ctx->connect_workq = alloc_ordered_workqueue("connect_workq",
+ WQ_MEM_RECLAIM);
+ if (!ctx->connect_workq) {
+ kfree(ctx);
+ return -ENOMEM;
+ }
+
+ ctx->recv_workq = alloc_ordered_workqueue("recv_workq", WQ_MEM_RECLAIM);
+ if (!ctx->recv_workq) {
+ destroy_workqueue(ctx->connect_workq);
+ kfree(ctx);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&ctx->connect_work, __mausb_ip_connect);
+ INIT_WORK(&ctx->recv_work, __mausb_ip_recv_work);
+
+ ctx->channel = channel;
+ ctx->ctx = context;
+ ctx->fn_callback = fn_callback;
+
+ return 0;
+}
+
+void mausb_destroy_ip_ctx(struct mausb_ip_ctx *ip_ctx)
+{
+ if (!ip_ctx)
+ return;
+
+ if (ip_ctx->connect_workq) {
+ flush_workqueue(ip_ctx->connect_workq);
+ destroy_workqueue(ip_ctx->connect_workq);
+ }
+
+ if (ip_ctx->recv_workq) {
+ flush_workqueue(ip_ctx->recv_workq);
+ destroy_workqueue(ip_ctx->recv_workq);
+ }
+ if (ip_ctx->client_socket)
+ sock_release(ip_ctx->client_socket);
+ __mausb_ip_recv_ctx_free(&ip_ctx->recv_ctx);
+
+ kfree(ip_ctx);
+}
+
+static void __mausb_ip_set_options(struct socket *sock, bool udp)
+{
+ u32 optval = 0;
+ unsigned int optlen = sizeof(optval);
+ int status = 0;
+ struct __kernel_sock_timeval timeo = {.tv_sec = 0, .tv_usec = 500000U };
+ struct __kernel_sock_timeval send_timeo = {.tv_sec = 1, .tv_usec = 0 };
+
+ if (!udp) {
+ optval = 1;
+ status = kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&optval, optlen);
+ if (status < 0)
+ mausb_pr_warn("Failed to set tcp no delay option: status=%d",
+ status);
+ }
+
+ status = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO_NEW,
+ (char *)&timeo, sizeof(timeo));
+ if (status < 0)
+ mausb_pr_warn("Failed to set recv timeout option: status=%d",
+ status);
+
+ status = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO_NEW,
+ (char *)&send_timeo, sizeof(send_timeo));
+ if (status < 0)
+ mausb_pr_warn("Failed to set snd timeout option: status=%d",
+ status);
+
+ optval = MAUSB_LINK_BUFF_SIZE;
+ status = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ (char *)&optval, optlen);
+ if (status < 0)
+ mausb_pr_warn("Failed to set recv buffer size: status=%d",
+ status);
+
+ optval = MAUSB_LINK_BUFF_SIZE;
+ status = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+ (char *)&optval, optlen);
+ if (status < 0)
+ mausb_pr_warn("Failed to set send buffer size: status=%d",
+ status);
+
+ optval = MAUSB_LINK_TOS_LEVEL_EF;
+ status = kernel_setsockopt(sock, IPPROTO_IP, IP_TOS,
+ (char *)&optval, optlen);
+ if (status < 0)
+ mausb_pr_warn("Failed to set QOS: status=%d", status);
+}
+
+static void __mausb_ip_connect(struct work_struct *work)
+{
+ int status = 0;
+ struct sockaddr *sa;
+ int sa_size;
+ struct mausb_ip_ctx *ip_ctx = container_of(work, struct mausb_ip_ctx,
+ connect_work);
+ unsigned short int family = ip_ctx->dev_addr_in.sa_in.sin_family;
+
+ if (!ip_ctx->udp) {
+ status = sock_create_kern(ip_ctx->net_ns, family, SOCK_STREAM,
+ IPPROTO_TCP, &ip_ctx->client_socket);
+ if (status < 0) {
+ mausb_pr_err("Failed to create socket: status=%d",
+ status);
+ goto callback;
+ }
+ } else {
+ status = sock_create_kern(ip_ctx->net_ns, family, SOCK_DGRAM,
+ IPPROTO_UDP, &ip_ctx->client_socket);
+ if (status < 0) {
+ mausb_pr_err("Failed to create socket: status=%d",
+ status);
+ goto callback;
+ }
+ }
+
+ __mausb_ip_set_options((struct socket *)ip_ctx->client_socket,
+ ip_ctx->udp);
+
+ if (family == AF_INET) {
+ sa = (struct sockaddr *)&ip_ctx->dev_addr_in.sa_in;
+ sa_size = sizeof(ip_ctx->dev_addr_in.sa_in);
+ mausb_pr_info("Connecting to %pI4:%d, status=%d",
+ &ip_ctx->dev_addr_in.sa_in.sin_addr,
+ htons(ip_ctx->dev_addr_in.sa_in.sin_port),
+ status);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (family == AF_INET6) {
+ sa = (struct sockaddr *)&ip_ctx->dev_addr_in.sa_in6;
+ sa_size = sizeof(ip_ctx->dev_addr_in.sa_in6);
+ mausb_pr_info("Connecting to %pI6c:%d, status=%d",
+ &ip_ctx->dev_addr_in.sa_in6.sin6_addr,
+ htons(ip_ctx->dev_addr_in.sa_in6.sin6_port),
+ status);
+#endif
+ } else {
+ mausb_pr_err("Wrong network family provided");
+ status = -EINVAL;
+ goto callback;
+ }
+
+ status = kernel_connect(ip_ctx->client_socket, sa, sa_size, O_RDWR);
+ if (status < 0) {
+ mausb_pr_err("Failed to connect to host, status=%d", status);
+ goto clear_socket;
+ }
+
+ queue_work(ip_ctx->recv_workq, &ip_ctx->recv_work);
+
+ goto callback;
+
+clear_socket:
+ sock_release(ip_ctx->client_socket);
+ ip_ctx->client_socket = NULL;
+callback:
+ ip_ctx->fn_callback(ip_ctx->ctx, ip_ctx->channel, MAUSB_LINK_CONNECT,
+ status, NULL);
+}
+
+void mausb_ip_connect_async(struct mausb_ip_ctx *ip_ctx)
+{
+ queue_work(ip_ctx->connect_workq, &ip_ctx->connect_work);
+}
+
+int mausb_ip_disconnect(struct mausb_ip_ctx *ip_ctx)
+{
+ if (ip_ctx && ip_ctx->client_socket)
+ return kernel_sock_shutdown(ip_ctx->client_socket, SHUT_RDWR);
+ return 0;
+}
+
+int mausb_ip_send(struct mausb_ip_ctx *ip_ctx,
+ struct mausb_kvec_data_wrapper *wrapper)
+{
+ struct msghdr msghd;
+
+ if (!ip_ctx) {
+ mausb_pr_alert("Socket ctx is NULL!");
+ return -EINVAL;
+ }
+
+ memset(&msghd, 0, sizeof(msghd));
+ msghd.msg_flags = MSG_WAITALL;
+
+ return kernel_sendmsg(ip_ctx->client_socket, &msghd, wrapper->kvec,
+ wrapper->kvec_num, wrapper->length);
+}
+
+static inline void __mausb_ip_recv_ctx_clear(struct mausb_ip_recv_ctx *recv_ctx)
+{
+ recv_ctx->buffer = NULL;
+ recv_ctx->left = 0;
+ recv_ctx->received = 0;
+}
+
+static inline void __mausb_ip_recv_ctx_free(struct mausb_ip_recv_ctx *recv_ctx)
+{
+ kfree(recv_ctx->buffer);
+ __mausb_ip_recv_ctx_clear(recv_ctx);
+}
+
+static int __mausb_ip_recv(struct mausb_ip_ctx *ip_ctx)
+{
+ struct msghdr msghd;
+ struct kvec vec;
+ int status;
+ bool peek = true;
+ unsigned int optval = 1;
+ struct socket *client_socket = (struct socket *)ip_ctx->client_socket;
+
+ /* receive with timeout of 0.5s */
+ while (true) {
+ memset(&msghd, 0, sizeof(msghd));
+ if (peek) {
+ vec.iov_base = ip_ctx->recv_ctx.common_hdr;
+ vec.iov_len = sizeof(ip_ctx->recv_ctx.common_hdr);
+ msghd.msg_flags = MSG_PEEK;
+ } else {
+ vec.iov_base =
+ ip_ctx->recv_ctx.buffer +
+ ip_ctx->recv_ctx.received;
+ vec.iov_len = ip_ctx->recv_ctx.left;
+ msghd.msg_flags = MSG_WAITALL;
+ }
+
+ if (!ip_ctx->udp) {
+ status = kernel_setsockopt(client_socket, IPPROTO_TCP,
+ TCP_QUICKACK,
+ (char *)&optval,
+ sizeof(optval));
+ if (status != 0) {
+ mausb_pr_warn("Setting TCP_QUICKACK failed, status=%d",
+ status);
+ }
+ }
+
+ status = kernel_recvmsg(client_socket, &msghd, &vec, 1,
+ vec.iov_len, (int)msghd.msg_flags);
+ if (status == -EAGAIN) {
+ return -EAGAIN;
+ } else if (status <= 0) {
+ mausb_pr_warn("kernel_recvmsg, status=%d", status);
+
+ __mausb_ip_recv_ctx_free(&ip_ctx->recv_ctx);
+ ip_ctx->fn_callback(ip_ctx->ctx, ip_ctx->channel,
+ MAUSB_LINK_RECV, status, NULL);
+ return status;
+ }
+
+ mausb_pr_debug("kernel_recvmsg, status=%d", status);
+
+ if (peek) {
+ if ((unsigned int)status <
+ sizeof(ip_ctx->recv_ctx.common_hdr))
+ return -EAGAIN;
+ /* length field of mausb_common_hdr */
+ ip_ctx->recv_ctx.left =
+ *(u16 *)(&ip_ctx->recv_ctx.common_hdr[2]);
+ ip_ctx->recv_ctx.received = 0;
+ ip_ctx->recv_ctx.buffer =
+ kzalloc(ip_ctx->recv_ctx.left, GFP_KERNEL);
+ peek = false;
+ if (!ip_ctx->recv_ctx.buffer) {
+ ip_ctx->fn_callback(ip_ctx->ctx,
+ ip_ctx->channel,
+ MAUSB_LINK_RECV,
+ -ENOMEM, NULL);
+ return -ENOMEM;
+ }
+ } else {
+ if (status < ip_ctx->recv_ctx.left) {
+ ip_ctx->recv_ctx.left -= (u16)status;
+ ip_ctx->recv_ctx.received += (u16)status;
+ } else {
+ ip_ctx->fn_callback(ip_ctx->ctx,
+ ip_ctx->channel,
+ MAUSB_LINK_RECV, status,
+ ip_ctx->recv_ctx.buffer);
+ __mausb_ip_recv_ctx_clear(&ip_ctx->recv_ctx);
+ peek = true;
+ }
+ }
+ }
+
+ return status;
+}
+
+static void __mausb_ip_recv_work(struct work_struct *work)
+{
+ struct mausb_ip_ctx *ip_ctx = container_of(work, struct mausb_ip_ctx,
+ recv_work);
+ int status = __mausb_ip_recv(ip_ctx);
+
+ if (status <= 0 && status != -EAGAIN)
+ return;
+
+ queue_work(ip_ctx->recv_workq, &ip_ctx->recv_work);
+}
diff --git a/drivers/usb/mausb_host/ip_link.h b/drivers/usb/mausb_host/ip_link.h
new file mode 100644
index 000000000000..5946151e4e4e
--- /dev/null
+++ b/drivers/usb/mausb_host/ip_link.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_IP_LINK_H__
+#define __MAUSB_IP_LINK_H__
+
+#include <linux/inet.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <net/net_namespace.h>
+
+#define MAUSB_LINK_BUFF_SIZE 16777216
+#define MAUSB_LINK_TOS_LEVEL_EF 0xB8
+
+enum mausb_link_action {
+ MAUSB_LINK_CONNECT = 0,
+ MAUSB_LINK_DISCONNECT = 1,
+ MAUSB_LINK_RECV = 2,
+ MAUSB_LINK_SEND = 3
+};
+
+enum mausb_channel {
+ MAUSB_CTRL_CHANNEL = 0,
+ MAUSB_ISOCH_CHANNEL = 1,
+ MAUSB_BULK_CHANNEL = 2,
+ MAUSB_INTR_CHANNEL = 3,
+ MAUSB_MGMT_CHANNEL = 4
+};
+
+struct mausb_kvec_data_wrapper {
+ struct kvec *kvec;
+ u32 kvec_num;
+ u32 length;
+};
+
+struct mausb_ip_recv_ctx {
+ u16 left;
+ u16 received;
+ char *buffer;
+ char common_hdr[12] __aligned(4);
+};
+
+struct mausb_ip_ctx {
+ struct socket *client_socket;
+ union {
+ struct sockaddr_in sa_in;
+#if IS_ENABLED(CONFIG_IPV6)
+ struct sockaddr_in6 sa_in6;
+#endif
+ } dev_addr_in;
+ struct net *net_ns;
+ bool udp;
+
+ /* Queues to schedule rx work */
+ struct workqueue_struct *recv_workq;
+ struct workqueue_struct *connect_workq;
+ struct work_struct recv_work;
+ struct work_struct connect_work;
+
+ struct mausb_ip_recv_ctx recv_ctx; /* recv buffer */
+
+ enum mausb_channel channel;
+ void *ctx;
+ /* callback should store task into hpal queue */
+ void (*fn_callback)(void *ctx, enum mausb_channel channel,
+ enum mausb_link_action act, int status, void *data);
+};
+
+int mausb_init_ip_ctx(struct mausb_ip_ctx **ip_ctx,
+ struct net *net_ns,
+ char ip_addr[INET6_ADDRSTRLEN],
+ u16 port,
+ void *ctx,
+ void (*ctx_callback)(void *ctx,
+ enum mausb_channel channel,
+ enum mausb_link_action act,
+ int status, void *data),
+ enum mausb_channel channel);
+int mausb_ip_disconnect(struct mausb_ip_ctx *ip_ctx);
+int mausb_ip_send(struct mausb_ip_ctx *ip_ctx,
+ struct mausb_kvec_data_wrapper *wrapper);
+
+void mausb_destroy_ip_ctx(struct mausb_ip_ctx *ip_ctx);
+void mausb_ip_connect_async(struct mausb_ip_ctx *ip_ctx);
+
+#endif /* __MAUSB_IP_LINK_H__ */
--
2.17.1
next prev parent reply other threads:[~2020-04-25 9:20 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-12 14:42 [PATCH v3 0/8] Add MA USB Host driver Vladimir Stankovic
2020-03-27 15:26 ` [PATCH v4 " vladimir.stankovic
2020-03-27 15:26 ` [PATCH v4 1/8] usb: Add MA-USB Host kernel module vladimir.stankovic
2020-03-27 16:25 ` Alan Stern
2020-03-27 15:26 ` [PATCH v4 2/8] usb: mausb_host: Add link layer implementation vladimir.stankovic
2020-03-27 15:26 ` [PATCH v4 3/8] usb: mausb_host: HCD initialization vladimir.stankovic
2020-03-27 15:26 ` [PATCH v4 4/8] usb: mausb_host: Implement initial hub handlers vladimir.stankovic
2020-03-27 16:37 ` Alan Stern
2020-04-13 15:16 ` Vladimir Stankovic
2020-03-27 15:26 ` [PATCH v4 5/8] usb: mausb_host: Introduce PAL processing vladimir.stankovic
2020-03-27 16:35 ` Alan Stern
2020-03-28 3:56 ` kbuild test robot
2020-03-27 15:26 ` [PATCH v4 6/8] usb: mausb_host: Add logic for PAL-to-PAL communication vladimir.stankovic
2020-03-27 15:26 ` [PATCH v4 7/8] usb: mausb_host: MA-USB PAL events processing vladimir.stankovic
2020-03-28 10:35 ` kbuild test robot
2020-04-04 16:07 ` kbuild test robot
2020-03-27 15:26 ` [PATCH v4 8/8] usb: mausb_host: Process MA-USB data packets vladimir.stankovic
2020-04-25 9:19 ` [PATCH v5 0/8] Add MA USB Host driver vladimir.stankovic
2020-04-25 9:19 ` [PATCH v5 1/8] usb: Add MA-USB Host kernel module vladimir.stankovic
2020-04-28 11:03 ` Greg KH
2020-04-25 9:19 ` vladimir.stankovic [this message]
2020-04-25 9:19 ` [PATCH v5 3/8] usb: mausb_host: HCD initialization vladimir.stankovic
2020-04-28 11:07 ` Greg KH
2020-04-25 9:19 ` [PATCH v5 4/8] usb: mausb_host: Implement initial hub handlers vladimir.stankovic
2020-04-25 9:19 ` [PATCH v5 5/8] usb: mausb_host: Introduce PAL processing vladimir.stankovic
2020-04-26 0:32 ` Alan Stern
2020-04-26 12:32 ` Vladimir Stankovic
2020-04-26 14:31 ` Alan Stern
2020-04-26 14:45 ` [External] " Vladimir Stankovic
2020-04-26 20:56 ` Alan Stern
2020-04-30 14:37 ` Vladimir Stankovic
2020-04-30 15:18 ` Alan Stern
2020-04-30 15:34 ` Vladimir Stankovic
2020-04-30 15:41 ` Alan Stern
2020-04-25 9:19 ` [PATCH v5 6/8] usb: mausb_host: Add logic for PAL-to-PAL communication vladimir.stankovic
2020-04-25 9:19 ` [PATCH v5 7/8] usb: mausb_host: MA-USB PAL events processing vladimir.stankovic
2020-04-28 11:08 ` Greg KH
2020-04-25 9:19 ` [PATCH v5 8/8] usb: mausb_host: Process MA-USB data packets vladimir.stankovic
2020-04-28 11:04 ` [PATCH v5 0/8] Add MA USB Host driver Greg KH
2020-04-30 16:51 ` [External] " Vladimir Stankovic
2020-04-30 20:02 ` Greg KH
2020-05-15 13:04 ` Vladimir Stankovic
2020-05-29 12:48 ` Pavel Machek
2020-05-15 12:34 ` [PATCH v6 " Vladimir Stankovic
2020-05-15 12:34 ` [PATCH v6 1/8] usb: Add MA-USB Host kernel module Vladimir Stankovic
2020-05-15 13:01 ` Greg KH
2020-06-11 18:20 ` Vladimir Stankovic
2020-05-15 13:02 ` Greg KH
2020-06-11 18:19 ` [External] " Vladimir Stankovic
2020-05-15 12:34 ` [PATCH v6 2/8] usb: mausb_host: Add link layer implementation Vladimir Stankovic
2020-05-15 12:34 ` [PATCH v6 3/8] usb: mausb_host: HCD initialization Vladimir Stankovic
2020-05-15 13:03 ` Greg KH
2020-06-11 18:19 ` Vladimir Stankovic
2020-05-15 13:07 ` Greg KH
2020-06-11 18:18 ` [External] " Vladimir Stankovic
2020-06-18 8:18 ` Greg KH
2020-05-15 12:34 ` [PATCH v6 4/8] usb: mausb_host: Implement initial hub handlers Vladimir Stankovic
2020-05-15 12:34 ` [PATCH v6 5/8] usb: mausb_host: Introduce PAL processing Vladimir Stankovic
2020-05-15 12:35 ` [PATCH v6 6/8] usb: mausb_host: Add logic for PAL-to-PAL communication Vladimir Stankovic
2020-05-15 12:35 ` [PATCH v6 7/8] usb: mausb_host: MA-USB PAL events processing Vladimir Stankovic
2020-05-15 12:35 ` [PATCH v6 8/8] usb: mausb_host: Process MA-USB data packets Vladimir Stankovic
2020-05-15 13:08 ` [PATCH v6 0/8] Add MA USB Host driver Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200425091954.1610-3-vladimir.stankovic@displaylink.com \
--to=vladimir.stankovic@displaylink.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mausb-host-devel@displaylink.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).