All of lore.kernel.org
 help / color / mirror / Atom feed
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 v4 5/8] usb: mausb_host: Introduce PAL processing
Date: Fri, 27 Mar 2020 16:26:11 +0100	[thread overview]
Message-ID: <20200327152614.26833-6-vladimir.stankovic@displaylink.com> (raw)
In-Reply-To: <20200327152614.26833-1-vladimir.stankovic@displaylink.com>

Protocol adaptation layer (PAL) implementation has been added to
introduce MA-USB structures and logic.

Signed-off-by: Vladimir Stankovic <vladimir.stankovic@displaylink.com>
---
 drivers/usb/mausb_host/Makefile        |    1 +
 drivers/usb/mausb_host/hcd.c           |  523 ++++++++++-
 drivers/usb/mausb_host/hcd.h           |   11 +
 drivers/usb/mausb_host/hpal.c          | 1094 ++++++++++++++++++++++++
 drivers/usb/mausb_host/hpal.h          |  289 +++++++
 drivers/usb/mausb_host/ma_usb.h        |  869 +++++++++++++++++++
 drivers/usb/mausb_host/mausb_address.h |   26 +
 drivers/usb/mausb_host/mausb_core.c    |   13 +-
 drivers/usb/mausb_host/mausb_event.h   |  224 +++++
 9 files changed, 3040 insertions(+), 10 deletions(-)
 create mode 100644 drivers/usb/mausb_host/hpal.c
 create mode 100644 drivers/usb/mausb_host/hpal.h
 create mode 100644 drivers/usb/mausb_host/ma_usb.h
 create mode 100644 drivers/usb/mausb_host/mausb_address.h
 create mode 100644 drivers/usb/mausb_host/mausb_event.h

diff --git a/drivers/usb/mausb_host/Makefile b/drivers/usb/mausb_host/Makefile
index cce4696682b2..829314b15cbb 100644
--- a/drivers/usb/mausb_host/Makefile
+++ b/drivers/usb/mausb_host/Makefile
@@ -10,5 +10,6 @@ mausb_host-y := mausb_core.o
 mausb_host-y += utils.o
 mausb_host-y += ip_link.o
 mausb_host-y += hcd.o
+mausb_host-y += hpal.o
 
 ccflags-y += -I$(srctree)/$(src)
diff --git a/drivers/usb/mausb_host/hcd.c b/drivers/usb/mausb_host/hcd.c
index b20d1a36ba34..70cb633c39ba 100644
--- a/drivers/usb/mausb_host/hcd.c
+++ b/drivers/usb/mausb_host/hcd.c
@@ -9,6 +9,7 @@
 #include <linux/limits.h>
 #include <linux/module.h>
 
+#include "hpal.h"
 #include "utils.h"
 
 static int mausb_open(struct inode *inode, struct file *file);
@@ -195,6 +196,90 @@ void mausb_deinit_hcd(void)
 	}
 }
 
+void mausb_port_has_changed(const enum mausb_device_type device_type,
+			    const enum mausb_device_speed device_speed,
+			    void *ma_dev)
+{
+	struct usb_hcd *hcd;
+	unsigned long flags = 0;
+	struct mausb_device *dev = ma_dev;
+	u16 port_number = dev->port_number;
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+
+	if (device_type == USB20HUB || device_speed < SUPER_SPEED) {
+		mhcd->hcd_hs_ctx->ma_devs[port_number].port_status |=
+		    USB_PORT_STAT_CONNECTION | (1 <<
+						USB_PORT_FEAT_C_CONNECTION);
+
+		if (device_speed == LOW_SPEED) {
+			mhcd->hcd_hs_ctx->ma_devs[port_number].port_status |=
+			    MAUSB_PORT_20_STATUS_LOW_SPEED;
+			mhcd->hcd_hs_ctx->ma_devs[port_number].dev_speed =
+			    LOW_SPEED;
+		} else if (device_speed == HIGH_SPEED) {
+			mhcd->hcd_hs_ctx->ma_devs[port_number].port_status |=
+			    MAUSB_PORT_20_STATUS_HIGH_SPEED;
+			mhcd->hcd_hs_ctx->ma_devs[port_number].dev_speed =
+			    HIGH_SPEED;
+		}
+
+		hcd = mhcd->hcd_hs_ctx->hcd;
+		mhcd->hcd_hs_ctx->ma_devs[port_number].ma_dev = ma_dev;
+	} else {
+		mhcd->hcd_ss_ctx->ma_devs[port_number].port_status |=
+		    USB_PORT_STAT_CONNECTION | (1 <<
+						USB_PORT_FEAT_C_CONNECTION);
+		mhcd->hcd_ss_ctx->ma_devs[port_number].dev_speed = SUPER_SPEED;
+
+		hcd = mhcd->hcd_ss_ctx->hcd;
+		mhcd->hcd_ss_ctx->ma_devs[port_number].ma_dev = ma_dev;
+	}
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	usb_hcd_poll_rh_status(hcd);
+}
+
+void mausb_hcd_disconnect(const u16 port_number,
+			  const enum mausb_device_type device_type,
+			  const enum mausb_device_speed device_speed)
+{
+	struct usb_hcd *hcd;
+	unsigned long flags = 0;
+
+	if (port_number >= NUMBER_OF_PORTS) {
+		mausb_pr_err("port number out of range, port_number=%x",
+			     port_number);
+		return;
+	}
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+
+	if (device_type == USB20HUB || device_speed < SUPER_SPEED) {
+		mhcd->hcd_hs_ctx->ma_devs[port_number].port_status &=
+			~(USB_PORT_STAT_CONNECTION);
+		mhcd->hcd_hs_ctx->ma_devs[port_number].port_status &=
+			~(USB_PORT_STAT_ENABLE);
+		mhcd->hcd_hs_ctx->ma_devs[port_number].port_status |=
+			(1 << USB_PORT_FEAT_C_CONNECTION);
+		hcd = mhcd->hcd_hs_ctx->hcd;
+	} else {
+		mhcd->hcd_ss_ctx->ma_devs[port_number].port_status &=
+			~(USB_PORT_STAT_CONNECTION);
+		mhcd->hcd_ss_ctx->ma_devs[port_number].port_status &=
+			~(USB_PORT_STAT_ENABLE);
+		mhcd->hcd_ss_ctx->ma_devs[port_number].port_status |=
+			(1 << USB_PORT_FEAT_C_CONNECTION);
+		hcd = mhcd->hcd_ss_ctx->hcd;
+	}
+
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+	if (!hcd)
+		return;
+
+	usb_hcd_poll_rh_status(hcd);
+}
+
 static const char driver_name[] = "MA-USB host controller";
 
 static void mausb_get_hub_descriptor(struct usb_hcd *hcd, u16 type_req,
@@ -235,12 +320,31 @@ static int mausb_hcd_hub_status(struct usb_hcd *hcd, char *buff);
 static int mausb_hcd_reset(struct usb_hcd *hcd);
 static int mausb_hcd_start(struct usb_hcd *hcd);
 static void mausb_hcd_stop(struct usb_hcd *hcd);
+static int mausb_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+				 int status);
+static int mausb_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+				 gfp_t mem_flags);
 static int mausb_hub_update_device(struct usb_hcd *hcd, struct usb_device *dev,
 				   struct usb_tt *tt, gfp_t mem_flags);
 static void mausb_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *dev);
 static int mausb_reset_device(struct usb_hcd *hcd, struct usb_device *dev);
 static int mausb_update_device(struct usb_hcd *hcd, struct usb_device *dev);
 
+static void mausb_print_urb(struct urb *request)
+{
+	mausb_pr_debug("URB: urb=%p, ep_handle=%#x, packet_num=%d, setup_dma=%lld, is_setup_packet=%d, is_ep=%d, is_sg=%d, num_sgs=%d, num_mapped_sgs=%d, status=%d, is_transfer_buffer=%d, transfer_buffer_length=%d, is_transfer_dma=%llu, transfer_flags=%d, is_hcpriv=%d",
+		       request, ((struct mausb_endpoint_ctx *)
+				 request->ep->hcpriv)->ep_handle,
+		       request->number_of_packets, request->setup_dma,
+		       request->setup_packet ? 1 : 0, request->ep ? 1 : 0,
+		       request->sg ? 1 : 0, request->num_sgs,
+		       request->num_mapped_sgs, request->status,
+		       request->transfer_buffer ? 1 : 0,
+		       request->transfer_buffer_length,
+		       request->transfer_dma, request->transfer_flags,
+		       (request->ep && request->ep->hcpriv) ? 1 : 0);
+}
+
 static const struct hc_driver mausb_hc_driver = {
 	.description  =  driver_name,
 	.product_desc = driver_name,
@@ -252,6 +356,9 @@ static const struct hc_driver mausb_hc_driver = {
 	.start = mausb_hcd_start,
 	.stop  = mausb_hcd_stop,
 
+	.urb_enqueue = mausb_hcd_urb_enqueue,
+	.urb_dequeue = mausb_hcd_urb_dequeue,
+
 	.get_frame_number = mausb_hcd_get_frame_number,
 
 	.hub_status_data   = mausb_hcd_hub_status,
@@ -311,6 +418,25 @@ static int get_root_hub_port_number(struct usb_device *dev, u8 *port_number)
 	return 0;
 }
 
+static int usb_to_mausb_device_speed(u8 speed)
+{
+	switch (speed) {
+	case USB_SPEED_LOW:
+		return MA_USB_SPEED_LOW_SPEED;
+	case USB_SPEED_FULL:
+		return MA_USB_SPEED_FULL_SPEED;
+	case USB_SPEED_WIRELESS:
+	case USB_SPEED_HIGH:
+		return MA_USB_SPEED_HIGH_SPEED;
+	case USB_SPEED_SUPER:
+		return MA_USB_SPEED_SUPER_SPEED;
+	case USB_SPEED_SUPER_PLUS:
+		return MA_USB_SPEED_SUPER_SPEED_PLUS;
+	default:
+		return -EINVAL;
+	}
+}
+
 static struct mausb_usb_device_ctx *mausb_find_usb_device(struct mausb_dev
 							*mdevs, void *dev_addr)
 {
@@ -330,6 +456,31 @@ static struct mausb_usb_device_ctx *mausb_find_usb_device(struct mausb_dev
 	return NULL;
 }
 
+static int mausb_insert_usb_device(struct mausb_dev *mdevs,
+				   struct mausb_usb_device_ctx *usb_device)
+{
+	struct rb_node **new_node = &mdevs->usb_devices.rb_node;
+	struct rb_node *parent = NULL;
+	struct mausb_usb_device_ctx *current_usb_device = NULL;
+
+	while (*new_node) {
+		parent = *new_node;
+		current_usb_device = rb_entry(*new_node,
+					      struct mausb_usb_device_ctx,
+					      rb_node);
+
+		if (usb_device->dev_addr < current_usb_device->dev_addr)
+			new_node = &((*new_node)->rb_left);
+		else if (usb_device->dev_addr > current_usb_device->dev_addr)
+			new_node = &((*new_node)->rb_right);
+		else
+			return -EEXIST;
+	}
+	rb_link_node(&usb_device->rb_node, parent, new_node);
+	rb_insert_color(&usb_device->rb_node, &mdevs->usb_devices);
+	return 0;
+}
+
 static int mausb_hcd_get_frame_number(struct usb_hcd *hcd)
 {
 	return 0;
@@ -504,6 +655,123 @@ static int mausb_hcd_hub_control(struct usb_hcd *hcd, u16 type_req,
 	return retval;
 }
 
+static int mausb_validate_urb(struct urb *urb)
+{
+	if (!urb) {
+		mausb_pr_err("urb is NULL");
+		return -EINVAL;
+	}
+
+	if (!urb->ep->hcpriv) {
+		mausb_pr_err("urb->ep->hcpriv is NULL");
+		return -EINVAL;
+	}
+
+	if (!urb->ep->enabled) {
+		mausb_pr_err("Endpoint not enabled");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mausb_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+				 gfp_t mem_flags)
+{
+	struct mausb_endpoint_ctx *endpoint_ctx;
+	struct mausb_device	  *ma_dev;
+	struct mausb_urb_ctx	  *urb_ctx;
+	int status = 0;
+
+	if (mausb_validate_urb(urb) < 0) {
+		mausb_pr_err("Hpal urb enqueue failed");
+		return -EPROTO;
+	}
+
+	endpoint_ctx = urb->ep->hcpriv;
+	ma_dev = endpoint_ctx->ma_dev;
+
+	if (atomic_read(&ma_dev->unresponsive_client)) {
+		mausb_pr_err("Client is not responsive anymore - finish urb immediately");
+		return -EHOSTDOWN;
+	}
+
+	urb->hcpriv = hcd;
+
+	mausb_pr_debug("ep_handle=%#x, dev_handle=%#x, urb_reject=%d",
+		       endpoint_ctx->ep_handle, endpoint_ctx->dev_handle,
+		       atomic_read(&urb->reject));
+
+	status = mausb_insert_urb_in_tree(urb, true);
+	if (status) {
+		mausb_pr_err("Hpal urb enqueue failed");
+		return status;
+	}
+
+	atomic_inc(&urb->use_count);
+
+	mausb_print_urb(urb);
+
+	/*
+	 * Masking URB_SHORT_NOT_OK flag as SCSI driver is adding it where it
+	 * should not, so it is breaking the USB drive on the linux
+	 */
+	urb->transfer_flags &= ~URB_SHORT_NOT_OK;
+
+	status = mausb_data_req_enqueue_event(ma_dev, endpoint_ctx->ep_handle,
+					      urb);
+	if (status < 0) {
+		urb_ctx = mausb_unlink_and_delete_urb_from_tree(urb, status);
+		atomic_dec(&urb->use_count);
+		if (urb_ctx) {
+			mausb_uninit_data_iterator(&urb_ctx->iterator);
+			kfree(urb_ctx);
+		}
+	}
+
+	return status;
+}
+
+static int mausb_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+				 int status)
+{
+	struct mausb_endpoint_ctx *endpoint_ctx;
+	struct mausb_device	  *ma_dev;
+	struct mausb_urb_ctx	  *urb_ctx;
+
+	mausb_pr_info("Urb=%p", urb);
+
+	urb_ctx = mausb_unlink_and_delete_urb_from_tree(urb, status);
+	if (!urb_ctx) {
+		mausb_pr_warn("Urb=%p is not in tree", urb);
+		return 0;
+	}
+
+	endpoint_ctx = urb->ep->hcpriv;
+	ma_dev	     = endpoint_ctx->ma_dev;
+
+	queue_work(ma_dev->workq, &urb_ctx->work);
+
+	return 0;
+}
+
+void mausb_hcd_urb_complete(struct urb *urb, u32 actual_length, int status)
+{
+	struct mausb_urb_ctx *urb_ctx =
+		mausb_unlink_and_delete_urb_from_tree(urb, status);
+
+	if (urb_ctx) {
+		mausb_uninit_data_iterator(&urb_ctx->iterator);
+		kfree(urb_ctx);
+
+		urb->status	   = status;
+		urb->actual_length = actual_length;
+
+		atomic_dec(&urb->use_count);
+		usb_hcd_giveback_urb(urb->hcpriv, urb, urb->status);
+		return;
+	}
+}
+
 int mausb_probe(struct device *dev)
 {
 	struct mausb_hcd *mausb_hcd;
@@ -765,8 +1033,10 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
 	u8	port_number;
 	s16	dev_handle;
 	int	status;
+	unsigned long	 flags;
 	struct hub_ctx   *hub  = (struct hub_ctx *)hcd->hcd_priv;
 	struct mausb_dev	    *mdev = NULL;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_device_ctx;
 	struct mausb_endpoint_ctx   *ep_ctx = dev->ep0.hcpriv;
 
@@ -779,6 +1049,16 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
 
 	mdev  = &hub->ma_devs[port_number];
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return;
+	}
+
 	usb_device_ctx = mausb_find_usb_device(mdev, dev);
 	if (!usb_device_ctx) {
 		mausb_pr_warn("device_ctx is not found");
@@ -787,6 +1067,13 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
 
 	dev_handle = usb_device_ctx->dev_handle;
 
+	if (atomic_read(&ma_dev->unresponsive_client)) {
+		mausb_pr_err("Client is not responsive anymore - free usbdevice immediately");
+		dev->ep0.hcpriv = NULL;
+		kfree(ep_ctx);
+		goto free_dev;
+	}
+
 	if (ep_ctx) {
 		dev->ep0.hcpriv = NULL;
 		kfree(ep_ctx);
@@ -795,9 +1082,51 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
 		mausb_pr_warn("ep_ctx is NULL: dev_handle=%#x", dev_handle);
 	}
 
+free_dev:
+	if (atomic_sub_and_test(1, &ma_dev->num_of_usb_devices)) {
+		mausb_pr_info("All usb devices destroyed - proceed with disconnecting");
+		queue_work(ma_dev->workq, &ma_dev->socket_disconnect_work);
+	}
+
 	rb_erase(&usb_device_ctx->rb_node, &mdev->usb_devices);
 	mausb_pr_info("USB device deleted device=%p", usb_device_ctx->dev_addr);
 	kfree(usb_device_ctx);
+
+	if (kref_put(&ma_dev->refcount, mausb_release_ma_dev_async))
+		mausb_clear_hcd_madev(port_number);
+}
+
+static struct mausb_usb_device_ctx *
+mausb_alloc_device_ctx(struct hub_ctx *hub, struct usb_device *dev,
+		       struct mausb_device *ma_dev, u16 port_number,
+		       int *status)
+{
+	struct mausb_usb_device_ctx *usb_device_ctx = NULL;
+
+	usb_device_ctx = kzalloc(sizeof(*usb_device_ctx), GFP_ATOMIC);
+	if (!usb_device_ctx) {
+		*status = -ENOMEM;
+		return NULL;
+	}
+
+	usb_device_ctx->dev_addr   = dev;
+	usb_device_ctx->dev_handle = DEV_HANDLE_NOT_ASSIGNED;
+	usb_device_ctx->addressed  = false;
+
+	if (mausb_insert_usb_device(&hub->ma_devs[port_number],
+				    usb_device_ctx)) {
+		mausb_pr_warn("device_ctx already exists");
+		kfree(usb_device_ctx);
+		*status = -EEXIST;
+		return NULL;
+	}
+
+	kref_get(&ma_dev->refcount);
+	mausb_pr_info("New USB device added device=%p",
+		      usb_device_ctx->dev_addr);
+	atomic_inc(&ma_dev->num_of_usb_devices);
+
+	return usb_device_ctx;
 }
 
 /*
@@ -808,7 +1137,9 @@ static int mausb_address_device(struct usb_hcd *hcd, struct usb_device *dev)
 {
 	u8	port_number;
 	int	status;
+	unsigned long	flags;
 	struct hub_ctx	*hub = (struct hub_ctx *)hcd->hcd_priv;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_device_ctx;
 	struct mausb_endpoint_ctx   *endpoint_ctx;
 
@@ -819,9 +1150,23 @@ static int mausb_address_device(struct usb_hcd *hcd, struct usb_device *dev)
 		return -EINVAL;
 	}
 
-	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
-	if (!usb_device_ctx)
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_warn("MAUSB device not found on port_number=%d",
+			      port_number);
 		return -ENODEV;
+	}
+
+	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
+	if (!usb_device_ctx) {
+		usb_device_ctx = mausb_alloc_device_ctx(hub, dev, ma_dev,
+							port_number, &status);
+		if (!usb_device_ctx)
+			return status;
+	}
 
 	mausb_pr_info("dev_handle=%#x, dev_speed=%#x",
 		      usb_device_ctx->dev_handle, dev->speed);
@@ -852,9 +1197,13 @@ static int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
 {
 	int	status;
 	u8	port_number;
+	struct ma_usb_ephandlereq_desc_ss  descriptor_ss;
+	struct ma_usb_ephandlereq_desc_std descriptor;
 	struct hub_ctx		    *hub = (struct hub_ctx *)hcd->hcd_priv;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_dev_ctx;
 	struct mausb_endpoint_ctx   *endpoint_ctx;
+	unsigned long flags = 0;
 
 	status = get_root_hub_port_number(dev, &port_number);
 	if (status < 0 || port_number >= NUMBER_OF_PORTS) {
@@ -863,6 +1212,16 @@ static int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
 		return 0;
 	}
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return -ENODEV;
+	}
+
 	usb_dev_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
 
 	if (!usb_dev_ctx) {
@@ -876,8 +1235,17 @@ static int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
 
 	endpoint_ctx->dev_handle	= usb_dev_ctx->dev_handle;
 	endpoint_ctx->usb_device_ctx	= usb_dev_ctx;
+	endpoint_ctx->ma_dev		= ma_dev;
 	endpoint->hcpriv		= endpoint_ctx;
 
+	if (dev->speed >= USB_SPEED_SUPER) {
+		mausb_init_superspeed_ep_descriptor(&descriptor_ss,
+						    &endpoint->desc,
+						    &endpoint->ss_ep_comp);
+	} else {
+		mausb_init_standard_ep_descriptor(&descriptor, &endpoint->desc);
+	}
+
 	return 0;
 }
 
@@ -887,8 +1255,10 @@ static int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
 	u8	port_number;
 	int	status;
 	struct hub_ctx		    *hub = (struct hub_ctx *)hcd->hcd_priv;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_dev_ctx;
 	struct mausb_endpoint_ctx   *endpoint_ctx = endpoint->hcpriv;
+	unsigned long flags = 0;
 
 	status = get_root_hub_port_number(dev, &port_number);
 	if (status < 0 || port_number >= NUMBER_OF_PORTS) {
@@ -897,6 +1267,16 @@ static int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
 		return -EINVAL;
 	}
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return -ENODEV;
+	}
+
 	usb_dev_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
 
 	if (!endpoint_ctx) {
@@ -913,6 +1293,70 @@ static int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
 	return 0;
 }
 
+static int mausb_device_assign_dev_handle(struct usb_hcd *hcd,
+					  struct usb_device *dev,
+					  struct hub_ctx *hub,
+					  struct mausb_device *ma_dev,
+					  struct mausb_usb_device_ctx
+					  *usb_device_ctx)
+{
+	u8 port_number;
+	int status;
+	int dev_speed;
+	u16 hub_dev_handle		= 0;
+	u16 parent_hs_hub_dev_handle	= 0;
+	u16 parent_hs_hub_port		= 0;
+	struct usb_device		   *first_hub_device = dev;
+	struct mausb_usb_device_ctx	   *hub_device_ctx;
+	struct mausb_endpoint_ctx	   *endpoint_ctx;
+	struct ma_usb_ephandlereq_desc_std descriptor;
+
+	status = get_root_hub_port_number(dev, &port_number);
+	if (status < 0 || port_number >= NUMBER_OF_PORTS) {
+		mausb_pr_info("port_number out of range, port_number=%x",
+			      port_number);
+		return -EINVAL;
+	}
+
+	while (first_hub_device->parent->parent)
+		first_hub_device = first_hub_device->parent;
+
+	hub_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number],
+					       first_hub_device);
+	if (hub_device_ctx)
+		hub_dev_handle = hub_device_ctx->dev_handle;
+
+	if ((dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL) &&
+	    first_hub_device->speed == USB_SPEED_HIGH) {
+		parent_hs_hub_dev_handle =
+			mausb_find_usb_device(&hub->ma_devs[port_number],
+					      dev->parent)->dev_handle;
+		parent_hs_hub_port = dev->parent->portnum;
+	}
+
+	dev_speed = usb_to_mausb_device_speed(dev->speed);
+	mausb_pr_info("start... mausb_devspeed=%d, route=%#x, port_number=%d",
+		      dev_speed, dev->route, port_number);
+
+	if (dev_speed == -EINVAL) {
+		mausb_pr_err("bad dev_speed");
+		return -EINVAL;
+	}
+
+	endpoint_ctx = kzalloc(sizeof(*endpoint_ctx), GFP_ATOMIC);
+	if (!endpoint_ctx)
+		return -ENOMEM;
+
+	endpoint_ctx->dev_handle     = usb_device_ctx->dev_handle;
+	endpoint_ctx->ma_dev	     = ma_dev;
+	endpoint_ctx->usb_device_ctx = usb_device_ctx;
+	dev->ep0.hcpriv		     = endpoint_ctx;
+
+	mausb_init_standard_ep_descriptor(&descriptor, &dev->ep0.desc);
+
+	return 0;
+}
+
 /*
  * For usb 2.0 logitech camera called multiple times, once during enumeration
  * of device and later after mausb_reset_device. In latter case it is
@@ -923,7 +1367,9 @@ static int mausb_enable_device(struct usb_hcd *hcd, struct usb_device *dev)
 	int status;
 	u8 port_number;
 	struct hub_ctx		    *hub = (struct hub_ctx *)hcd->hcd_priv;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_device_ctx;
+	unsigned long flags;
 
 	status = get_root_hub_port_number(dev, &port_number);
 	if (status < 0 || port_number >= NUMBER_OF_PORTS) {
@@ -932,13 +1378,27 @@ static int mausb_enable_device(struct usb_hcd *hcd, struct usb_device *dev)
 		return -EINVAL;
 	}
 
-	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
-	if (!usb_device_ctx)
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
 		return -ENODEV;
+	}
 
-	mausb_pr_info("Device assigned and addressed usb_device_ctx=%p",
-		      usb_device_ctx);
+	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
+	if (!usb_device_ctx) {
+		usb_device_ctx = mausb_alloc_device_ctx(hub, dev, ma_dev,
+							port_number, &status);
+		if (!usb_device_ctx)
+			return status;
+	}
 
+	if (usb_device_ctx->dev_handle == DEV_HANDLE_NOT_ASSIGNED)
+		return mausb_device_assign_dev_handle(hcd, dev, hub, ma_dev,
+						      usb_device_ctx);
 	return 0;
 }
 
@@ -952,7 +1412,9 @@ static int mausb_update_device(struct usb_hcd *hcd, struct usb_device *dev)
 	u8	port_number = 0;
 	int	status	    = 0;
 	struct hub_ctx		    *hub = (struct hub_ctx *)hcd->hcd_priv;
+	struct mausb_device	    *ma_dev = NULL;
 	struct mausb_usb_device_ctx *usb_device_ctx = NULL;
+	unsigned long flags = 0;
 
 	if (mausb_is_hub_device(dev)) {
 		mausb_pr_warn("Device is hub");
@@ -966,6 +1428,16 @@ static int mausb_update_device(struct usb_hcd *hcd, struct usb_device *dev)
 		return -EINVAL;
 	}
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return -ENODEV;
+	}
+
 	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
 	if (!usb_device_ctx) {
 		mausb_pr_warn("Device not found");
@@ -980,10 +1452,12 @@ static int mausb_hub_update_device(struct usb_hcd *hcd, struct usb_device *dev,
 {
 	int	status;
 	u8	port_number;
+	unsigned long flags;
 	u16 max_exit_latency = 0;
 	u8  mtt = 0;
 	u8  ttt = 0;
 	struct hub_ctx		    *hub = (struct hub_ctx *)hcd->hcd_priv;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_device_ctx;
 
 	if (dev->speed == USB_SPEED_HIGH) {
@@ -998,6 +1472,16 @@ static int mausb_hub_update_device(struct usb_hcd *hcd, struct usb_device *dev,
 		return 0;
 	}
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return -ENODEV;
+	}
+
 	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number],
 					       dev);
 
@@ -1038,10 +1522,12 @@ static void mausb_endpoint_reset(struct usb_hcd *hcd,
 	int is_control;
 	int epnum;
 	int is_out;
+	unsigned long flags;
 	u16	dev_handle;
 	u8	tsp;
 	u8	port_number;
 	struct hub_ctx		    *hub;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_device_ctx;
 	struct usb_device	    *dev;
 	struct mausb_endpoint_ctx   *ep_ctx;
@@ -1064,14 +1550,21 @@ static void mausb_endpoint_reset(struct usb_hcd *hcd,
 	}
 	hub = (struct hub_ctx *)hcd->hcd_priv;
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return;
+	}
+
 	is_control = usb_endpoint_xfer_control(&endpoint->desc);
 	epnum = usb_endpoint_num(&endpoint->desc);
 	is_out = usb_endpoint_dir_out(&endpoint->desc);
 	tsp = (u8)(is_out ? dev->toggle[1] : dev->toggle[0]);
 
-	if (status < 0)
-		return;
-
 	if (status != EUCLEAN) {
 		if (!tsp) {
 			usb_settoggle(dev, epnum, is_out, 0U);
@@ -1099,7 +1592,9 @@ static int mausb_reset_device(struct usb_hcd *hcd, struct usb_device *dev)
 	int status;
 	u8  port_number;
 	u16 dev_handle;
+	unsigned long flags;
 	struct hub_ctx		    *hub;
+	struct mausb_device	    *ma_dev;
 	struct mausb_usb_device_ctx *usb_device_ctx;
 
 	hub = (struct hub_ctx *)hcd->hcd_priv;
@@ -1111,6 +1606,16 @@ static int mausb_reset_device(struct usb_hcd *hcd, struct usb_device *dev)
 		return -EINVAL;
 	}
 
+	spin_lock_irqsave(&mhcd->lock, flags);
+	ma_dev = hub->ma_devs[port_number].ma_dev;
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	if (!ma_dev) {
+		mausb_pr_err("MAUSB device not found on port_number=%d",
+			     port_number);
+		return -ENODEV;
+	}
+
 	usb_device_ctx = mausb_find_usb_device(&hub->ma_devs[port_number], dev);
 
 	if (!usb_device_ctx ||
diff --git a/drivers/usb/mausb_host/hcd.h b/drivers/usb/mausb_host/hcd.h
index cbef70a2f985..d4e9267503d1 100644
--- a/drivers/usb/mausb_host/hcd.h
+++ b/drivers/usb/mausb_host/hcd.h
@@ -15,6 +15,8 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 
+#include "hpal.h"
+
 #define DEVICE_NAME "mausb_host_hcd_dev"
 #define CLASS_NAME "mausb"
 
@@ -65,6 +67,13 @@ struct hub_ctx {
 int mausb_init_hcd(void);
 void mausb_deinit_hcd(void);
 
+void mausb_port_has_changed(const enum mausb_device_type device_type,
+			    const enum mausb_device_speed device_speed,
+			    void *ma_dev);
+void mausb_hcd_disconnect(const u16 port_number,
+			  const enum mausb_device_type device_type,
+			  const enum mausb_device_speed device_speed);
+
 #define PORT_C_MASK \
 		((USB_PORT_STAT_C_CONNECTION \
 		| USB_PORT_STAT_C_ENABLE \
@@ -140,11 +149,13 @@ struct mausb_endpoint_ctx {
 
 struct mausb_urb_ctx {
 	struct urb		*urb;
+	struct mausb_data_iter	iterator;
 	struct rb_node		rb_node;
 	struct work_struct	work;
 };
 
 int mausb_probe(struct device *dev);
+void mausb_hcd_urb_complete(struct urb *urb, u32 actual_length, int status);
 
 void mausb_clear_hcd_madev(u16 port_number);
 
diff --git a/drivers/usb/mausb_host/hpal.c b/drivers/usb/mausb_host/hpal.c
new file mode 100644
index 000000000000..ac86cbc71e36
--- /dev/null
+++ b/drivers/usb/mausb_host/hpal.c
@@ -0,0 +1,1094 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#include "hpal.h"
+
+#include <linux/circ_buf.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/uio.h>
+
+#include "hcd.h"
+#include "utils.h"
+
+struct mss mss;
+
+static int mausb_power_state_cb(struct notifier_block *nb, unsigned long action,
+				void *data);
+static void mausb_execute_urb_dequeue(struct work_struct *dequeue_work);
+static int mausb_start_heartbeat_timer(void);
+
+static inline struct mausb_urb_ctx *__mausb_find_urb_in_tree(struct urb *urb)
+{
+	struct rb_node *node = mhcd->mausb_urbs.rb_node;
+
+	while (node) {
+		struct mausb_urb_ctx *urb_ctx =
+		    rb_entry(node, struct mausb_urb_ctx, rb_node);
+
+		if (urb < urb_ctx->urb)
+			node = urb_ctx->rb_node.rb_left;
+		else if (urb > urb_ctx->urb)
+			node = urb_ctx->rb_node.rb_right;
+		else
+			return urb_ctx;
+	}
+	return NULL;
+}
+
+struct mausb_urb_ctx *mausb_find_urb_in_tree(struct urb *urb)
+{
+	unsigned long flags = 0;
+	struct mausb_urb_ctx *urb_ctx;
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+	urb_ctx =  __mausb_find_urb_in_tree(urb);
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	return urb_ctx;
+}
+
+static int mausb_insert_urb_ctx_in_tree(struct mausb_urb_ctx *urb_ctx)
+{
+	struct rb_node **new_node = &mhcd->mausb_urbs.rb_node;
+	struct rb_node *parent = NULL;
+	struct mausb_urb_ctx *current_urb = NULL;
+
+	while (*new_node) {
+		parent = *new_node;
+		current_urb = rb_entry(*new_node, struct mausb_urb_ctx,
+				       rb_node);
+
+		if (urb_ctx->urb < current_urb->urb)
+			new_node = &((*new_node)->rb_left);
+		else if (urb_ctx->urb > current_urb->urb)
+			new_node = &((*new_node)->rb_right);
+		else
+			return -EEXIST;
+	}
+	rb_link_node(&urb_ctx->rb_node, parent, new_node);
+	rb_insert_color(&urb_ctx->rb_node, &mhcd->mausb_urbs);
+	return 0;
+}
+
+static void mausb_delete_urb_ctx_from_tree(struct mausb_urb_ctx *urb_ctx)
+{
+	rb_erase(&urb_ctx->rb_node, &mhcd->mausb_urbs);
+}
+
+static struct mausb_urb_ctx *mausb_create_urb_ctx(struct urb *urb, int *status)
+{
+	struct mausb_urb_ctx *urb_ctx = NULL;
+
+	if (!urb) {
+		mausb_pr_err("Urb is NULL");
+		*status = -EINVAL;
+		return NULL;
+	}
+
+	urb_ctx = kzalloc(sizeof(*urb_ctx), GFP_ATOMIC);
+	if (!urb_ctx) {
+		*status = -ENOMEM;
+		return NULL;
+	}
+
+	urb_ctx->urb = urb;
+	INIT_WORK(&urb_ctx->work, mausb_execute_urb_dequeue);
+
+	return urb_ctx;
+}
+
+int mausb_insert_urb_in_tree(struct urb *urb, bool link_urb_to_ep)
+{
+	unsigned long flags;
+	int status = 0;
+
+	struct mausb_urb_ctx *urb_ctx = mausb_create_urb_ctx(urb, &status);
+
+	if (!urb_ctx)
+		return status;
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+
+	if (link_urb_to_ep) {
+		status = usb_hcd_link_urb_to_ep(urb->hcpriv, urb);
+		if (status) {
+			spin_unlock_irqrestore(&mhcd->lock, flags);
+			mausb_pr_err("Error %d while linking urb to hcd_endpoint",
+				     status);
+			kfree(urb_ctx);
+			return status;
+		}
+	}
+
+	if (mausb_insert_urb_ctx_in_tree(urb_ctx)) {
+		kfree(urb_ctx);
+		if (link_urb_to_ep)
+			usb_hcd_unlink_urb_from_ep(urb->hcpriv, urb);
+		spin_unlock_irqrestore(&mhcd->lock, flags);
+		mausb_pr_err("Urb_ctx insertion failed");
+		return -EEXIST;
+	}
+
+	mausb_init_data_iterator(&urb_ctx->iterator, urb->transfer_buffer,
+				 urb->transfer_buffer_length, urb->sg,
+				 (unsigned int)urb->num_sgs,
+				 usb_urb_dir_in(urb));
+
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	return 0;
+}
+
+static bool mausb_return_urb_ctx_to_tree(struct mausb_urb_ctx *urb_ctx,
+					 bool link_urb_to_ep)
+{
+	unsigned long flags;
+	int status;
+
+	if (!urb_ctx)
+		return false;
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+	if (link_urb_to_ep) {
+		status = usb_hcd_link_urb_to_ep(urb_ctx->urb->hcpriv,
+						urb_ctx->urb);
+		if (status) {
+			spin_unlock_irqrestore(&mhcd->lock, flags);
+			mausb_pr_err("Error %d while linking urb to hcd_endpoint",
+				     status);
+			return false;
+		}
+	}
+
+	if (mausb_insert_urb_ctx_in_tree(urb_ctx)) {
+		if (link_urb_to_ep)
+			usb_hcd_unlink_urb_from_ep(urb_ctx->urb->hcpriv,
+						   urb_ctx->urb);
+		spin_unlock_irqrestore(&mhcd->lock, flags);
+		mausb_pr_err("Urb_ctx insertion failed");
+		return false;
+	}
+
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	return true;
+}
+
+/*After this function call only valid thing to do with urb is to give it back*/
+struct mausb_urb_ctx *mausb_unlink_and_delete_urb_from_tree(struct urb *urb,
+							    int status)
+{
+	struct mausb_urb_ctx *urb_ctx = NULL;
+	unsigned long flags;
+	int ret;
+
+	if (!urb) {
+		mausb_pr_warn("Urb is NULL");
+		return NULL;
+	}
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+
+	urb_ctx = __mausb_find_urb_in_tree(urb);
+
+	if (!urb_ctx) {
+		mausb_pr_warn("Urb=%p not in tree", urb);
+		spin_unlock_irqrestore(&mhcd->lock, flags);
+		return NULL;
+	}
+
+	ret = usb_hcd_check_unlink_urb(urb->hcpriv, urb, status);
+
+	if (ret == -EIDRM)
+		mausb_pr_warn("Urb=%p is already unlinked", urb);
+	else
+		usb_hcd_unlink_urb_from_ep(urb->hcpriv, urb);
+
+	mausb_delete_urb_ctx_from_tree(urb_ctx);
+
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	mausb_pr_debug("Urb=%p is removed from tree", urb);
+
+	return urb_ctx;
+}
+
+void mausb_release_event_resources(struct mausb_event *event)
+{
+	struct ma_usb_hdr_common *receive_buffer = (struct ma_usb_hdr_common *)
+						    event->data.recv_buf;
+
+	kfree(receive_buffer);
+}
+
+void mausb_complete_urb(struct mausb_event *event)
+{
+	struct urb *urb = (struct urb *)event->data.urb;
+
+	mausb_pr_debug("transfer_size=%d, rem_transfer_size=%d, status=%d",
+		       event->data.transfer_size,
+		       event->data.rem_transfer_size, event->status);
+	mausb_complete_request(urb,
+			       event->data.transfer_size -
+			       event->data.rem_transfer_size,
+			       event->status);
+}
+
+static int mausb_get_first_free_port_number(u16 *port_number)
+{
+	(*port_number) = 0;
+	while ((mhcd->connected_ports & (1 << *port_number)) != 0 &&
+	       *port_number < NUMBER_OF_PORTS)
+		++(*port_number);
+
+	if (*port_number == NUMBER_OF_PORTS)
+		return -EINVAL;
+
+	mhcd->connected_ports |= (1 << *port_number);
+
+	return 0;
+}
+
+static inline void mausb_port_has_changed_event(struct mausb_device *dev,
+						struct mausb_event *event)
+{
+	int status;
+	u16 port_number;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+
+	status = mausb_get_first_free_port_number(&port_number);
+	if (status < 0) {
+		spin_unlock_irqrestore(&mhcd->lock, flags);
+		mausb_pr_err("There is no free port, schedule delete ma_dev");
+		queue_work(dev->workq, &dev->socket_disconnect_work);
+		return;
+	}
+
+	spin_unlock_irqrestore(&mhcd->lock, flags);
+
+	dev->dev_type	   = event->port_changed.dev_type;
+	dev->dev_speed	   = event->port_changed.dev_speed;
+	dev->lse	   = event->port_changed.lse;
+	dev->dev_connected = 1;
+	dev->port_number   = port_number;
+
+	mausb_port_has_changed(event->port_changed.dev_type,
+			       event->port_changed.dev_speed, dev);
+
+	if ((enum mausb_device_type)event->port_changed.dev_type == USB30HUB)
+		mausb_port_has_changed(USB20HUB, HIGH_SPEED, dev);
+}
+
+static void mausb_heartbeat_timer_func(struct timer_list *timer)
+{
+	unsigned long flags = 0;
+	struct mausb_device *dev = NULL;
+
+	if (mausb_start_heartbeat_timer() < 0) {
+		mausb_pr_err("Devices disconnecting - app is unresponsive");
+		spin_lock_irqsave(&mss.lock, flags);
+
+		/* Reset connected clients */
+		mss.client_connected = false;
+		mss.missed_heartbeats = 0;
+
+		list_for_each_entry(dev, &mss.madev_list, list_entry) {
+			mausb_pr_debug("Enqueue heartbeat_work madev_addr=%x",
+				       dev->madev_addr);
+			queue_work(dev->workq, &dev->heartbeat_work);
+		}
+
+		complete(&mss.client_stopped);
+		spin_unlock_irqrestore(&mss.lock, flags);
+	}
+}
+
+void mausb_release_ma_dev_async(struct kref *kref)
+{
+	struct mausb_device *dev = container_of(kref, struct mausb_device,
+						refcount);
+
+	mausb_pr_info("Scheduling work for MAUSB device to be deleted");
+
+	schedule_work(&dev->madev_delete_work);
+}
+
+int mausb_enqueue_event_from_user(u8 madev_addr, u16 num_of_events,
+				  u16 num_of_completed)
+{
+	unsigned long flags;
+	struct mausb_device *dev;
+
+	spin_lock_irqsave(&mss.lock, flags);
+	dev = mausb_get_dev_from_addr_unsafe(madev_addr);
+
+	if (!dev) {
+		spin_unlock_irqrestore(&mss.lock, flags);
+		return -EINVAL;
+	}
+
+	spin_lock(&dev->num_of_user_events_lock);
+	dev->num_of_user_events += num_of_events;
+	dev->num_of_completed_events += num_of_completed;
+	spin_unlock(&dev->num_of_user_events_lock);
+	queue_work(dev->workq, &dev->work);
+	spin_unlock_irqrestore(&mss.lock, flags);
+
+	return 0;
+}
+
+int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
+				 struct urb *request)
+{
+	struct mausb_event mausb_event;
+
+	mausb_event.type   = MAUSB_EVENT_TYPE_SEND_DATA_MSG;
+	mausb_event.status = 0;
+
+	mausb_event.data.transfer_type =
+		mausb_transfer_type_from_usb(&request->ep->desc);
+	mausb_event.data.device_id	= dev->id;
+	mausb_event.data.ep_handle	= ep_handle;
+	mausb_event.data.urb		= (u64)request;
+	mausb_event.data.setup_packet	=
+		(usb_endpoint_xfer_control(&request->ep->desc) &&
+			request->setup_packet);
+	mausb_event.data.transfer_size	= request->transfer_buffer_length;
+	mausb_event.data.direction	= (usb_urb_dir_in(request) ?
+						MAUSB_DATA_MSG_DIRECTION_IN :
+						MAUSB_DATA_MSG_DIRECTION_OUT);
+	mausb_event.data.transfer_size +=
+		((mausb_event.data.direction == MAUSB_DATA_MSG_DIRECTION_OUT &&
+			mausb_event.data.setup_packet) ?
+				MAUSB_CONTROL_SETUP_SIZE : 0);
+	mausb_event.data.rem_transfer_size = mausb_event.data.transfer_size;
+	mausb_event.data.transfer_flags	   = request->transfer_flags;
+	mausb_event.data.transfer_eot	   = false;
+	mausb_event.data.isoch_seg_num	   = (u32)request->number_of_packets;
+	mausb_event.data.recv_buf	   = 0;
+	mausb_event.data.payload_size	   =
+		(usb_endpoint_xfer_isoc(&request->ep->desc) &&
+		 usb_endpoint_dir_out(&request->ep->desc)) ?
+		(request->iso_frame_desc[request->number_of_packets - 1]
+								.offset +
+		 request->iso_frame_desc[request->number_of_packets - 1]
+								.length) : 0;
+
+	if (mausb_event.data.setup_packet) {
+		memcpy(mausb_event.data.hdr_ack, request->setup_packet,
+		       MAUSB_CONTROL_SETUP_SIZE);
+		memcpy(shift_ptr(mausb_event.data.hdr_ack,
+				 MAUSB_CONTROL_SETUP_SIZE),
+		       &request->dev->route, sizeof(request->dev->route));
+	}
+
+	return 0;
+}
+
+void mausb_complete_request(struct urb *urb, u32 actual_length, int status)
+{
+	mausb_hcd_urb_complete(urb, actual_length, status);
+}
+
+int mausb_signal_event(struct mausb_device *dev,
+		       struct mausb_event *event, u64 event_id)
+{
+	unsigned long flags;
+	struct mausb_completion *mausb_completion;
+
+	spin_lock_irqsave(&dev->completion_events_lock, flags);
+	list_for_each_entry(mausb_completion, &dev->completion_events,
+			    list_entry) {
+		if (mausb_completion->event_id == event_id) {
+			memcpy(mausb_completion->mausb_event, event,
+			       sizeof(*event));
+			complete(mausb_completion->completion_event);
+			spin_unlock_irqrestore(&dev->completion_events_lock,
+					       flags);
+			return 0;
+		}
+	}
+	spin_unlock_irqrestore(&dev->completion_events_lock, flags);
+
+	return -ETIMEDOUT;
+}
+
+void mausb_reset_connection_timer(struct mausb_device *dev)
+{
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&dev->connection_timer_lock, flags);
+	dev->receive_failures_num = 0;
+
+	mod_timer(&dev->connection_timer, jiffies + msecs_to_jiffies(1000));
+
+	spin_unlock_irqrestore(&dev->connection_timer_lock, flags);
+}
+
+static int mausb_start_heartbeat_timer(void)
+{
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&mss.lock, flags);
+	if (++mss.missed_heartbeats > MAUSB_MAX_MISSED_HEARTBEATS) {
+		mausb_pr_err("Missed more than %d heartbeats",
+			     MAUSB_MAX_MISSED_HEARTBEATS);
+		spin_unlock_irqrestore(&mss.lock, flags);
+		return -ETIMEDOUT;
+	}
+
+	spin_unlock_irqrestore(&mss.lock, flags);
+	mod_timer(&mss.heartbeat_timer,
+		  jiffies + msecs_to_jiffies(MAUSB_HEARTBEAT_TIMEOUT_MS));
+
+	return 0;
+}
+
+void mausb_reset_heartbeat_cnt(void)
+{
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&mss.lock, flags);
+	mss.missed_heartbeats = 0;
+	spin_unlock_irqrestore(&mss.lock, flags);
+}
+
+static void mausb_execute_urb_dequeue(struct work_struct *dequeue_work)
+{
+	struct mausb_urb_ctx *urb_ctx =
+			container_of(dequeue_work, struct mausb_urb_ctx, work);
+	struct urb		  *urb = urb_ctx->urb;
+	struct mausb_endpoint_ctx *ep_ctx;
+	struct mausb_device	  *ma_dev;
+	struct mausb_event	  mausb_event;
+	int status = 0;
+
+	ep_ctx = urb->ep->hcpriv;
+	ma_dev = ep_ctx->ma_dev;
+
+	if (atomic_read(&ma_dev->unresponsive_client)) {
+		mausb_pr_err("Client is not responsive anymore - finish urb immediately urb=%p, ep_handle=%#x, dev_handle=%#x",
+			     urb, ep_ctx->ep_handle, ep_ctx->dev_handle);
+		goto complete_urb;
+	}
+
+	mausb_pr_debug("urb=%p, ep_handle=%#x, dev_handle=%#x",
+		       urb, ep_ctx->ep_handle, ep_ctx->dev_handle);
+
+	memset(&mausb_event, 0, sizeof(mausb_event));
+
+	mausb_event.type   = MAUSB_EVENT_TYPE_DELETE_DATA_TRANSFER;
+	mausb_event.status = 0;
+
+	mausb_event.data.transfer_type =
+				mausb_transfer_type_from_usb(&urb->ep->desc);
+	mausb_event.data.device_id     = ma_dev->id;
+	mausb_event.data.ep_handle     = ep_ctx->ep_handle;
+	mausb_event.data.urb	       = (u64)urb;
+	mausb_event.data.direction     = (usb_urb_dir_in(urb) ?
+						MAUSB_DATA_MSG_DIRECTION_IN :
+						MAUSB_DATA_MSG_DIRECTION_OUT);
+
+	if (!mausb_return_urb_ctx_to_tree(urb_ctx, false)) {
+		mausb_pr_alert("Failed to insert in tree urb=%p ep_handle=%#x, status=%d",
+			       urb, mausb_event.data.ep_handle, status);
+		goto complete_urb;
+	}
+
+	return;
+
+complete_urb:
+
+	/* Deallocate urb_ctx */
+	mausb_uninit_data_iterator(&urb_ctx->iterator);
+	kfree(urb_ctx);
+
+	urb->status	   = -EPROTO;
+	urb->actual_length = 0;
+	atomic_dec(&urb->use_count);
+	usb_hcd_giveback_urb(urb->hcpriv, urb, urb->status);
+}
+
+void mausb_initialize_mss(void)
+{
+	spin_lock_init(&mss.lock);
+	INIT_LIST_HEAD(&mss.madev_list);
+	INIT_LIST_HEAD(&mss.available_ring_buffers);
+
+	init_completion(&mss.empty);
+	complete(&mss.empty);
+	init_completion(&mss.rings_events.mausb_ring_has_events);
+	atomic_set(&mss.rings_events.mausb_stop_reading_ring_events, 0);
+	mss.deinit_in_progress	= false;
+	mss.ring_buffer_id	= 0;
+	mss.client_connected = false;
+	mss.missed_heartbeats = 0;
+	init_completion(&mss.client_stopped);
+	atomic_set(&mss.num_of_transitions_to_sleep, 0);
+
+	timer_setup(&mss.heartbeat_timer, mausb_heartbeat_timer_func, 0);
+}
+
+void mausb_deinitialize_mss(void)
+{
+	struct mausb_device *dev = NULL;
+	unsigned long flags = 0;
+	unsigned long timeout =
+			msecs_to_jiffies(MAUSB_CLIENT_STOPPED_TIMEOUT_MS);
+
+	spin_lock_irqsave(&mss.lock, flags);
+
+	mss.deinit_in_progress = true;
+
+	list_for_each_entry(dev, &mss.madev_list, list_entry) {
+		mausb_pr_debug("Enqueue mausb_hcd_disconnect_work madev_addr=%x",
+			       dev->madev_addr);
+		queue_work(dev->workq, &dev->hcd_disconnect_work);
+	}
+
+	spin_unlock_irqrestore(&mss.lock, flags);
+
+	wait_for_completion(&mss.empty);
+	mausb_pr_debug("Waiting for completion on disconnect_event ended");
+
+	timeout = wait_for_completion_timeout(&mss.client_stopped, timeout);
+	mausb_pr_info("Remaining time after waiting for stopping client %ld",
+		      timeout);
+}
+
+int mausb_register_power_state_listener(void)
+{
+	mausb_pr_info("Registering power states listener");
+
+	mhcd->power_state_listener.notifier_call = mausb_power_state_cb;
+	return register_pm_notifier(&mhcd->power_state_listener);
+}
+
+void mausb_unregister_power_state_listener(void)
+{
+	mausb_pr_info("Un-registering power states listener");
+
+	unregister_pm_notifier(&mhcd->power_state_listener);
+}
+
+static int mausb_power_state_cb(struct notifier_block *nb, unsigned long action,
+				void *data)
+{
+	unsigned long flags = 0;
+	struct mausb_device *dev = NULL;
+
+	mausb_pr_info("Power state callback action = %ld", action);
+	if (action == PM_SUSPEND_PREPARE || action == PM_HIBERNATION_PREPARE) {
+		/* Stop heartbeat timer */
+		del_timer_sync(&mss.heartbeat_timer);
+		mausb_pr_info("Saving state before sleep");
+		spin_lock_irqsave(&mss.lock, flags);
+		if (!list_empty(&mss.madev_list))
+			atomic_inc(&mss.num_of_transitions_to_sleep);
+
+		list_for_each_entry(dev, &mss.madev_list, list_entry) {
+			mausb_pr_info("Enqueue heartbeat_work madev_addr=%x",
+				      dev->madev_addr);
+			queue_work(dev->workq, &dev->heartbeat_work);
+		}
+
+		spin_unlock_irqrestore(&mss.lock, flags);
+	} else if (action == PM_POST_SUSPEND || action == PM_POST_HIBERNATION) {
+		mausb_reset_heartbeat_cnt();
+		/* Start hearbeat timer */
+		mod_timer(&mss.heartbeat_timer, jiffies +
+			  msecs_to_jiffies(MAUSB_HEARTBEAT_TIMEOUT_MS));
+	}
+	return NOTIFY_OK;
+}
+
+static void mausb_populate_standard_ep_descriptor(struct usb_ep_desc *std_desc,
+						  struct usb_endpoint_descriptor
+						  *usb_std_desc)
+{
+	std_desc->bLength	   = usb_std_desc->bLength;
+	std_desc->bDescriptorType  = usb_std_desc->bDescriptorType;
+	std_desc->bEndpointAddress = usb_std_desc->bEndpointAddress;
+	std_desc->bmAttributes	   = usb_std_desc->bmAttributes;
+	std_desc->wMaxPacketSize   = usb_std_desc->wMaxPacketSize;
+	std_desc->bInterval	   = usb_std_desc->bInterval;
+}
+
+static void
+mausb_populate_superspeed_ep_descriptor(struct usb_ss_ep_comp_desc *ss_desc,
+					struct usb_ss_ep_comp_descriptor*
+					usb_ss_desc)
+{
+	ss_desc->bLength	   = usb_ss_desc->bLength;
+	ss_desc->bDescriptorType   = usb_ss_desc->bDescriptorType;
+	ss_desc->bMaxBurst	   = usb_ss_desc->bMaxBurst;
+	ss_desc->bmAttributes	   = usb_ss_desc->bmAttributes;
+	ss_desc->wBytesPerInterval = usb_ss_desc->wBytesPerInterval;
+}
+
+void
+mausb_init_standard_ep_descriptor(struct ma_usb_ephandlereq_desc_std *std_desc,
+				  struct usb_endpoint_descriptor *usb_std_desc)
+{
+	mausb_populate_standard_ep_descriptor(&std_desc->usb20, usb_std_desc);
+}
+
+void
+mausb_init_superspeed_ep_descriptor(struct ma_usb_ephandlereq_desc_ss *ss_desc,
+				    struct usb_endpoint_descriptor *
+				    usb_std_desc,
+				    struct usb_ss_ep_comp_descriptor *
+				    usb_ss_desc)
+{
+	mausb_populate_standard_ep_descriptor(&ss_desc->usb20, usb_std_desc);
+	mausb_populate_superspeed_ep_descriptor(&ss_desc->usb31, usb_ss_desc);
+}
+
+struct mausb_device *mausb_get_dev_from_addr_unsafe(u8 madev_addr)
+{
+	struct mausb_device *dev = NULL;
+
+	list_for_each_entry(dev, &mss.madev_list, list_entry) {
+		if (dev->madev_addr == madev_addr)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static inline
+struct mausb_ip_ctx *mausb_get_data_channel(struct mausb_device *ma_dev,
+					    enum mausb_channel channel)
+{
+	if (channel >= MAUSB_CHANNEL_MAP_LENGTH)
+		return NULL;
+
+	return ma_dev->channel_map[channel];
+}
+
+int mausb_send_data(struct mausb_device *dev, enum mausb_channel channel_num,
+		    struct mausb_kvec_data_wrapper *data)
+{
+	struct mausb_ip_ctx *channel = mausb_get_data_channel(dev, channel_num);
+	int status = 0;
+
+	if (!channel)
+		return -ECHRNG;
+
+	status = mausb_ip_send(channel, data);
+
+	if (status < 0) {
+		mausb_pr_err("Send failed. Disconnecting... status=%d", status);
+		queue_work(dev->workq, &dev->socket_disconnect_work);
+		queue_work(dev->workq, &dev->hcd_disconnect_work);
+	}
+
+	return status;
+}
+
+int mausb_send_transfer_ack(struct mausb_device *dev, struct mausb_event *event)
+{
+	struct ma_usb_hdr_common *ack_hdr;
+	struct kvec kvec;
+	struct mausb_kvec_data_wrapper data_to_send;
+	enum mausb_channel channel;
+
+	ack_hdr = (struct ma_usb_hdr_common *)(&event->data.hdr_ack);
+
+	data_to_send.kvec	    = &kvec;
+	data_to_send.kvec->iov_base = ack_hdr;
+	data_to_send.kvec->iov_len  = ack_hdr->length;
+	data_to_send.kvec_num	    = 1;
+	data_to_send.length	    = ack_hdr->length;
+
+	channel = mausb_transfer_type_to_channel(event->data.transfer_type);
+	return mausb_send_data(dev, channel, &data_to_send);
+}
+
+int mausb_send_data_msg(struct mausb_device *dev, struct mausb_event *event)
+{
+	struct mausb_urb_ctx *urb_ctx;
+	int status = 0;
+
+	if (event->status != 0) {
+		mausb_pr_err("Event %d failed with status %d",
+			     event->type, event->status);
+		mausb_complete_urb(event);
+		return event->status;
+	}
+
+	urb_ctx = mausb_find_urb_in_tree((struct urb *)event->data.urb);
+
+	if (!urb_ctx) {
+		/* Transfer will be deleted from dequeue task */
+		mausb_pr_warn("Urb is already cancelled for event=%d",
+			      event->type);
+		return status;
+	}
+
+	return status;
+}
+
+int mausb_receive_data_msg(struct mausb_device *dev, struct mausb_event *event)
+{
+	int status = 0;
+	struct mausb_urb_ctx *urb_ctx;
+
+	mausb_pr_debug("Direction=%d", event->data.direction);
+
+	if (!mausb_isoch_data_event(event)) {
+		status = mausb_send_transfer_ack(dev, event);
+		if (status < 0) {
+			mausb_pr_warn("Sending acknowledgment failed");
+			goto cleanup;
+		}
+	}
+
+	urb_ctx = mausb_find_urb_in_tree((struct urb *)event->data.urb);
+
+	if (!urb_ctx)
+		mausb_pr_warn("Urb is already cancelled");
+
+cleanup:
+	mausb_release_event_resources(event);
+	return status;
+}
+
+int mausb_add_data_chunk(void *buffer, u32 buffer_size,
+			 struct list_head *chunks_list)
+{
+	struct mausb_payload_chunk *data_chunk;
+
+	data_chunk = kzalloc(sizeof(*data_chunk), GFP_KERNEL);
+	if (!data_chunk)
+		return -ENOMEM;
+
+	/* Initialize data chunk for MAUSB header and add it to chunks list */
+	INIT_LIST_HEAD(&data_chunk->list_entry);
+
+	data_chunk->kvec.iov_base = buffer;
+	data_chunk->kvec.iov_len  = buffer_size;
+	list_add_tail(&data_chunk->list_entry, chunks_list);
+	return 0;
+}
+
+int mausb_init_data_wrapper(struct mausb_kvec_data_wrapper *data,
+			    struct list_head *chunks_list,
+			    u32 num_of_data_chunks)
+{
+	struct mausb_payload_chunk *data_chunk = NULL;
+	struct mausb_payload_chunk *tmp = NULL;
+	u32 current_kvec = 0;
+
+	data->length = 0;
+	data->kvec = kcalloc(num_of_data_chunks, sizeof(struct kvec),
+			     GFP_KERNEL);
+	if (!data->kvec)
+		return -ENOMEM;
+
+	list_for_each_entry_safe(data_chunk, tmp, chunks_list, list_entry) {
+		data->kvec[current_kvec].iov_base =
+			data_chunk->kvec.iov_base;
+		data->kvec[current_kvec].iov_len =
+		    data_chunk->kvec.iov_len;
+		++data->kvec_num;
+		data->length += data_chunk->kvec.iov_len;
+		++current_kvec;
+	}
+	return 0;
+}
+
+void mausb_cleanup_chunks_list(struct list_head *chunks_list)
+{
+	struct mausb_payload_chunk *data_chunk = NULL;
+	struct mausb_payload_chunk *tmp = NULL;
+
+	list_for_each_entry_safe(data_chunk, tmp, chunks_list, list_entry) {
+		list_del(&data_chunk->list_entry);
+		kfree(data_chunk);
+	}
+}
+
+static int mausb_read_virtual_buffer(struct mausb_data_iter *iterator,
+				     u32 byte_num,
+				     struct list_head *data_chunks_list,
+				     u32 *data_chunks_num)
+{
+	u32 rem_data		= 0;
+	u32 bytes_to_read	= 0;
+	struct mausb_payload_chunk *data_chunk = NULL;
+
+	(*data_chunks_num) = 0;
+
+	if (!data_chunks_list)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(data_chunks_list);
+	rem_data      = iterator->length - iterator->offset;
+	bytes_to_read = min(byte_num, rem_data);
+
+	if (bytes_to_read == 0)
+		return 0;
+
+	data_chunk = kzalloc(sizeof(*data_chunk), GFP_KERNEL);
+
+	if (!data_chunk)
+		return -ENOMEM;
+
+	++(*data_chunks_num);
+
+	data_chunk->kvec.iov_base = (u8 *)(iterator->buffer) + iterator->offset;
+	data_chunk->kvec.iov_len = bytes_to_read;
+	iterator->offset += bytes_to_read;
+
+	list_add_tail(&data_chunk->list_entry, data_chunks_list);
+
+	return 0;
+}
+
+static int mausb_read_scatterlist_buffer(struct mausb_data_iter *iterator,
+					 u32 byte_num,
+					 struct list_head *data_chunks_list,
+					 u32 *data_chunks_num)
+{
+	u32 current_sg_read_num;
+	struct mausb_payload_chunk *data_chunk = NULL;
+
+	(*data_chunks_num) = 0;
+
+	if (!data_chunks_list)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(data_chunks_list);
+
+	while (byte_num) {
+		if (iterator->sg_iter.consumed == iterator->sg_iter.length) {
+			if (!sg_miter_next(&iterator->sg_iter))
+				break;
+			iterator->sg_iter.consumed = 0;
+		}
+
+		data_chunk = kzalloc(sizeof(*data_chunk), GFP_KERNEL);
+		if (!data_chunk) {
+			sg_miter_stop(&iterator->sg_iter);
+			return -ENOMEM;
+		}
+
+		current_sg_read_num = min((size_t)byte_num,
+					  iterator->sg_iter.length -
+					  iterator->sg_iter.consumed);
+
+		data_chunk->kvec.iov_base = (u8 *)iterator->sg_iter.addr +
+				iterator->sg_iter.consumed;
+		data_chunk->kvec.iov_len  = current_sg_read_num;
+
+		++(*data_chunks_num);
+		list_add_tail(&data_chunk->list_entry, data_chunks_list);
+
+		byte_num -= current_sg_read_num;
+		iterator->sg_iter.consumed += current_sg_read_num;
+		data_chunk = NULL;
+	}
+
+	return 0;
+}
+
+static u32 mausb_write_virtual_buffer(struct mausb_data_iter *iterator,
+				      void *buffer, u32 size)
+{
+	u32 rem_space   = 0;
+	u32 write_count = 0;
+
+	if (!buffer || !size)
+		return write_count;
+
+	rem_space   = iterator->length - iterator->offset;
+	write_count = min(size, rem_space);
+
+	if (write_count > 0) {
+		void *location = shift_ptr(iterator->buffer, iterator->offset);
+
+		memcpy(location, buffer, write_count);
+		iterator->offset += write_count;
+	}
+
+	return write_count;
+}
+
+static u32 mausb_write_scatterlist_buffer(struct mausb_data_iter *iterator,
+					  void *buffer, u32 size)
+{
+	u32 current_sg_rem_space;
+	u32 count = 0;
+	u32 total_count = 0;
+	void *location = NULL;
+
+	if (!buffer || !size)
+		return count;
+
+	while (size) {
+		if (iterator->sg_iter.consumed >= iterator->sg_iter.length) {
+			if (!sg_miter_next(&iterator->sg_iter))
+				break;
+			iterator->sg_iter.consumed = 0;
+		}
+
+		current_sg_rem_space = (u32)(iterator->sg_iter.length -
+			iterator->sg_iter.consumed);
+
+		count = min(size, current_sg_rem_space);
+		total_count += count;
+
+		location = shift_ptr(iterator->sg_iter.addr,
+				     iterator->sg_iter.consumed);
+
+		memcpy(location, buffer, count);
+
+		buffer = shift_ptr(buffer, count);
+		size -= count;
+		iterator->sg_iter.consumed += count;
+	}
+
+	return total_count;
+}
+
+int mausb_data_iterator_read(struct mausb_data_iter *iterator,
+			     u32 byte_num,
+			     struct list_head *data_chunks_list,
+			     u32 *data_chunks_num)
+{
+	if (iterator->buffer)
+		return mausb_read_virtual_buffer(iterator, byte_num,
+						 data_chunks_list,
+						 data_chunks_num);
+	else
+		return mausb_read_scatterlist_buffer(iterator, byte_num,
+						     data_chunks_list,
+						     data_chunks_num);
+}
+
+u32 mausb_data_iterator_write(struct mausb_data_iter *iterator, void *buffer,
+			      u32 length)
+{
+	if (iterator->buffer)
+		return mausb_write_virtual_buffer(iterator, buffer, length);
+	else
+		return mausb_write_scatterlist_buffer(iterator, buffer, length);
+}
+
+static inline void mausb_seek_virtual_buffer(struct mausb_data_iter *iterator,
+					     u32 seek_delta)
+{
+	iterator->offset += min(seek_delta, iterator->length -
+					    iterator->offset);
+}
+
+static void mausb_seek_scatterlist_buffer(struct mausb_data_iter *iterator,
+					  u32 seek_delta)
+{
+	u32 rem_bytes_in_current_scatter;
+
+	while (seek_delta) {
+		rem_bytes_in_current_scatter = (u32)(iterator->sg_iter.length -
+						iterator->sg_iter.consumed);
+		if (rem_bytes_in_current_scatter <= seek_delta) {
+			iterator->sg_iter.consumed +=
+			    rem_bytes_in_current_scatter;
+			seek_delta -= rem_bytes_in_current_scatter;
+			if (!sg_miter_next(&iterator->sg_iter))
+				break;
+			iterator->sg_iter.consumed = 0;
+		} else {
+			iterator->sg_iter.consumed += seek_delta;
+			break;
+		}
+	}
+}
+
+void mausb_data_iterator_seek(struct mausb_data_iter *iterator,
+			      u32 seek_delta)
+{
+	if (iterator->buffer)
+		mausb_seek_virtual_buffer(iterator, seek_delta);
+	else
+		mausb_seek_scatterlist_buffer(iterator, seek_delta);
+}
+
+static void mausb_calculate_buffer_length(struct mausb_data_iter *iterator)
+{
+	/* Calculate buffer length */
+	if (iterator->buffer_len > 0) {
+		/* Transfer_buffer_length is populated */
+		iterator->length = iterator->buffer_len;
+	} else if (iterator->sg && iterator->num_sgs != 0) {
+		/* Transfer_buffer_length is not populated */
+		sg_miter_start(&iterator->sg_iter, iterator->sg,
+			       iterator->num_sgs, iterator->flags);
+		while (sg_miter_next(&iterator->sg_iter))
+			iterator->length += (u32)iterator->sg_iter.length;
+		sg_miter_stop(&iterator->sg_iter);
+	} else {
+		iterator->length = 0;
+	}
+}
+
+void mausb_init_data_iterator(struct mausb_data_iter *iterator, void *buffer,
+			      u32 buffer_len, struct scatterlist *sg,
+			      unsigned int num_sgs, bool direction)
+{
+	iterator->offset = 0;
+	iterator->buffer     = buffer;
+	iterator->buffer_len = buffer_len;
+	iterator->length     = 0;
+	iterator->sg	     = sg;
+	iterator->num_sgs    = num_sgs;
+	iterator->sg_started = 0;
+
+	mausb_calculate_buffer_length(iterator);
+
+	if (!buffer && sg && num_sgs != 0) {
+		/* Scatterlist provided */
+		iterator->flags = direction ? SG_MITER_TO_SG : SG_MITER_FROM_SG;
+		sg_miter_start(&iterator->sg_iter, sg, num_sgs,
+			       iterator->flags);
+		iterator->sg_started = 1;
+	}
+}
+
+void mausb_uninit_data_iterator(struct mausb_data_iter *iterator)
+{
+	iterator->offset     = 0;
+	iterator->length     = 0;
+	iterator->buffer     = NULL;
+	iterator->buffer_len = 0;
+
+	if (iterator->sg_started)
+		sg_miter_stop(&iterator->sg_iter);
+
+	iterator->sg_started = 0;
+}
+
+void mausb_reset_data_iterator(struct mausb_data_iter *iterator)
+{
+	iterator->offset = 0;
+	if (iterator->sg_started) {
+		sg_miter_stop(&iterator->sg_iter);
+		iterator->sg_started = 0;
+	}
+
+	if (!iterator->buffer && iterator->sg && iterator->num_sgs != 0) {
+		sg_miter_start(&iterator->sg_iter, iterator->sg,
+			       iterator->num_sgs, iterator->flags);
+		iterator->sg_started = 1;
+	}
+}
+
+u32 mausb_data_iterator_length(struct mausb_data_iter *iterator)
+{
+	return iterator->length;
+}
diff --git a/drivers/usb/mausb_host/hpal.h b/drivers/usb/mausb_host/hpal.h
new file mode 100644
index 000000000000..f184bbc07783
--- /dev/null
+++ b/drivers/usb/mausb_host/hpal.h
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_HPAL_H__
+#define __MAUSB_HPAL_H__
+
+#include <linux/kref.h>
+#include <linux/suspend.h>
+#include <linux/usb.h>
+
+#include "ip_link.h"
+#include "mausb_address.h"
+#include "mausb_event.h"
+
+#define MAUSB_CONTROL_SETUP_SIZE	8
+#define MAUSB_BUSY_RETRIES_COUNT	3
+#define MAUSB_HEARTBEAT_TIMEOUT_MS	1000
+#define MAUSB_CLIENT_STOPPED_TIMEOUT_MS	3000
+
+#define MAUSB_MAX_RECEIVE_FAILURES	3
+#define MAUSB_MAX_MISSED_HEARTBEATS	3
+#define MAUSB_TRANSFER_RESERVED		0
+
+#define MAUSB_CHANNEL_MAP_LENGTH	4
+
+extern struct mss mss;
+extern struct mausb_hcd *mhcd;
+
+enum mausb_isoch_header_format_size {
+	MAUSB_ISOCH_SHORT_FORMAT_SIZE	 = 4,
+	MAUSB_ISOCH_STANDARD_FORMAT_SIZE = 8,
+	MAUSB_ISOCH_LONG_FORMAT_SIZE	 = 12
+};
+
+struct mausb_completion {
+	struct list_head   list_entry;
+	struct completion  *completion_event;
+	struct mausb_event *mausb_event;
+	u64		   event_id;
+};
+
+struct mausb_mss_rings_events {
+	atomic_t	  mausb_stop_reading_ring_events;
+	struct completion mausb_ring_has_events;
+};
+
+struct mss {
+	bool	   deinit_in_progress;
+	spinlock_t lock;	/* Protect mss structure */
+	u64	   ring_buffer_id;
+
+	struct completion empty;
+	struct completion client_stopped;
+	bool		  client_connected;
+	struct timer_list heartbeat_timer;
+	u8		  missed_heartbeats;
+
+	struct list_head  madev_list;
+	atomic_t	  num_of_transitions_to_sleep;
+	struct list_head  available_ring_buffers;
+
+	struct mausb_mss_rings_events	 rings_events;
+	struct mausb_events_notification events[MAUSB_MAX_NUM_OF_MA_DEVS];
+};
+
+struct mausb_device {
+	struct mausb_device_address dev_addr;
+	struct net		    *net_ns;
+	struct list_head	    list_entry;
+
+	struct mausb_ip_ctx *mgmt_channel;
+	struct mausb_ip_ctx *ctrl_channel;
+	struct mausb_ip_ctx *bulk_channel;
+	struct mausb_ip_ctx *isoch_channel;
+	struct mausb_ip_ctx *channel_map[MAUSB_CHANNEL_MAP_LENGTH];
+
+	struct work_struct work;
+	struct work_struct socket_disconnect_work;
+	struct work_struct hcd_disconnect_work;
+	struct work_struct madev_delete_work;
+	struct work_struct ping_work;
+	struct work_struct heartbeat_work;
+	struct workqueue_struct *workq;
+
+	struct kref refcount;
+	/* Set on port change event after cap resp */
+	u8 dev_type;
+	u8 dev_speed;
+	u8 lse;
+	u8 madev_addr;
+	u8 dev_connected;
+	u16 id;
+	u16 port_number;
+
+	u64		event_id;
+	spinlock_t	event_id_lock; /* Lock event ID increments */
+
+	struct list_head completion_events;
+	spinlock_t	 completion_events_lock; /* Lock completion events */
+
+	struct completion user_finished_event;
+	u16		  num_of_user_events;
+	u16		  num_of_completed_events;
+
+	spinlock_t	  num_of_user_events_lock; /* Lock user events count */
+
+	struct timer_list connection_timer;
+	u8		  receive_failures_num;
+	spinlock_t	  connection_timer_lock; /* Lock connection timer */
+
+	atomic_t	  unresponsive_client;
+
+	atomic_t	  num_of_usb_devices;
+};
+
+struct mausb_urb_ctx *mausb_find_urb_in_tree(struct urb *urb);
+struct mausb_urb_ctx *mausb_unlink_and_delete_urb_from_tree(struct urb *urb,
+							    int status);
+struct mausb_device *mausb_get_dev_from_addr_unsafe(u8 madev_addr);
+
+static inline u64 mausb_event_id(struct mausb_device *dev)
+{
+	unsigned long flags;
+	u64 val;
+
+	spin_lock_irqsave(&dev->event_id_lock, flags);
+	val = ++(dev->event_id);
+	spin_unlock_irqrestore(&dev->event_id_lock, flags);
+
+	return val;
+}
+
+int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
+				 struct urb *request);
+int mausb_signal_event(struct mausb_device *dev, struct mausb_event *event,
+		       u64 event_id);
+int mausb_insert_urb_in_tree(struct urb *urb, bool link_urb_to_ep);
+
+static inline void mausb_insert_event(struct mausb_device *dev,
+				      struct mausb_completion *event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->completion_events_lock, flags);
+	list_add_tail(&event->list_entry, &dev->completion_events);
+	spin_unlock_irqrestore(&dev->completion_events_lock, flags);
+}
+
+static inline void mausb_remove_event(struct mausb_device *dev,
+				      struct mausb_completion *event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->completion_events_lock, flags);
+	list_del(&event->list_entry);
+	spin_unlock_irqrestore(&dev->completion_events_lock, flags);
+}
+
+void mausb_release_ma_dev_async(struct kref *kref);
+void mausb_complete_request(struct urb *urb, u32 actual_length, int status);
+void mausb_complete_urb(struct mausb_event *event);
+void mausb_reset_connection_timer(struct mausb_device *dev);
+void mausb_reset_heartbeat_cnt(void);
+void mausb_release_event_resources(struct mausb_event  *event);
+void mausb_initialize_mss(void);
+void mausb_deinitialize_mss(void);
+int mausb_register_power_state_listener(void);
+void mausb_unregister_power_state_listener(void);
+
+void mausb_init_standard_ep_descriptor(struct ma_usb_ephandlereq_desc_std *
+				       std_desc,
+				       struct usb_endpoint_descriptor *
+				       usb_std_desc);
+void mausb_init_superspeed_ep_descriptor(struct ma_usb_ephandlereq_desc_ss *
+					 ss_desc,
+					 struct usb_endpoint_descriptor *
+					 usb_std_desc,
+					 struct usb_ss_ep_comp_descriptor *
+					 usb_ss_desc);
+
+int mausb_send_data(struct mausb_device *dev, enum mausb_channel channel_num,
+		    struct mausb_kvec_data_wrapper *data);
+
+int mausb_send_transfer_ack(struct mausb_device *dev,
+			    struct mausb_event *event);
+
+int mausb_send_data_msg(struct mausb_device *dev, struct mausb_event *event);
+
+int mausb_receive_data_msg(struct mausb_device *dev, struct mausb_event *event);
+
+int mausb_add_data_chunk(void *buffer, u32 buffer_size,
+			 struct list_head *chunks_list);
+
+int mausb_init_data_wrapper(struct mausb_kvec_data_wrapper *data,
+			    struct list_head *chunks_list,
+			    u32 num_of_data_chunks);
+
+void mausb_cleanup_chunks_list(struct list_head *chunks_list);
+
+static inline bool mausb_ctrl_transfer(struct ma_usb_hdr_common *hdr)
+{
+	return (hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK) ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL;
+}
+
+static inline bool mausb_isoch_transfer(struct ma_usb_hdr_common *hdr)
+{
+	return (hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK) ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH;
+}
+
+static inline bool mausb_ctrl_data_event(struct mausb_event *event)
+{
+	return event->data.transfer_type ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL;
+}
+
+static inline bool mausb_isoch_data_event(struct mausb_event *event)
+{
+	return event->data.transfer_type ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH;
+}
+
+/* usb to mausb transfer type */
+static inline
+u8 mausb_transfer_type_from_usb(struct usb_endpoint_descriptor *epd)
+{
+	return (u8)usb_endpoint_type(epd) << 3;
+}
+
+static inline u8 mausb_transfer_type_from_hdr(struct ma_usb_hdr_common *hdr)
+{
+	return hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK;
+}
+
+static inline
+enum mausb_channel mausb_transfer_type_to_channel(u8 transfer_type)
+{
+	return transfer_type >> 3;
+}
+
+struct mausb_data_iter {
+	u32 length;
+
+	void *buffer;
+	u32  buffer_len;
+	u32  offset;
+
+	struct scatterlist	*sg;
+	struct sg_mapping_iter	sg_iter;
+	bool		sg_started;
+	unsigned int	num_sgs;
+	unsigned int	flags;
+};
+
+struct mausb_payload_chunk {
+	struct list_head list_entry;
+	struct kvec	 kvec;
+};
+
+int mausb_data_iterator_read(struct mausb_data_iter *iterator,
+			     u32 byte_num,
+			     struct list_head *data_chunks_list,
+			     u32 *data_chunks_num);
+
+u32 mausb_data_iterator_length(struct mausb_data_iter *iterator);
+u32 mausb_data_iterator_write(struct mausb_data_iter *iterator, void *buffer,
+			      u32 length);
+
+void mausb_init_data_iterator(struct mausb_data_iter *iterator,
+			      void *buffer, u32 buffer_len,
+			      struct scatterlist *sg, unsigned int num_sgs,
+			      bool direction);
+void mausb_reset_data_iterator(struct mausb_data_iter *iterator);
+void mausb_uninit_data_iterator(struct mausb_data_iter *iterator);
+void mausb_data_iterator_seek(struct mausb_data_iter *iterator, u32 seek_delta);
+
+static inline unsigned int mausb_get_page_order(unsigned int num_of_elems,
+						unsigned int elem_size)
+{
+	unsigned int num_of_pages = DIV_ROUND_UP(num_of_elems * elem_size,
+						 PAGE_SIZE);
+	unsigned int order = (unsigned int)ilog2(num_of_pages) +
+					(is_power_of_2(num_of_pages) ? 0 : 1);
+	return order;
+}
+
+#endif /* __MAUSB_HPAL_H__ */
diff --git a/drivers/usb/mausb_host/ma_usb.h b/drivers/usb/mausb_host/ma_usb.h
new file mode 100644
index 000000000000..65f6229c0dfe
--- /dev/null
+++ b/drivers/usb/mausb_host/ma_usb.h
@@ -0,0 +1,869 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_MA_USB_H__
+#define __MAUSB_MA_USB_H__
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <types.h>
+#endif /* __KERNEL__ */
+
+#define MA_USB_SET_FIELD_(_m_, _v) __mausb_set_field(MA_USB_##_m_##_MASK, _v)
+#define MA_USB_GET_FIELD_(_m_, _v) __mausb_get_field(MA_USB_##_m_##_MASK, _v)
+#define MA_USB_SET_FIELD(_m_, _v) __mausb_set_field(MA_USB_##_m_##_MASK, \
+						    MA_USB_##_v)
+#define MA_USB_GET_FIELD(_m_, _v) __mausb_get_field(MA_USB_##_m_##_MASK, \
+						    MA_USB_##_v)
+
+#define MA_USB_MGMT_TOKEN_RESERVED  0
+#define MA_USB_MGMT_TOKEN_MIN       1
+#define MA_USB_MGMT_TOKEN_MAX       ((1 << 10) - 1)
+
+#define MA_USB_DATA_EPS_UNASSIGNED  0
+#define MA_USB_DATA_EPS_ACTIVE      1
+#define MA_USB_DATA_EPS_INACTIVE    2
+#define MA_USB_DATA_EPS_HALTED      3
+
+#define MA_USB_DATA_TFLAGS_ARQ      1
+#define MA_USB_DATA_TFLAGS_NEG      2
+#define MA_USB_DATA_TFLAGS_EOT      4
+#define MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL   0
+#define MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH  8
+#define MA_USB_DATA_TFLAGS_TRANSFER_TYPE_BULK   16
+#define MA_USB_DATA_TFLAGS_TRANSFER_TYPE_INTR   24
+
+#define MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK   0x18
+
+#define MA_USB_DATA_IFLAGS_MTD_VALID      1
+#define MA_USB_DATA_IFLAGS_HDR_FMT_SHORT  0
+#define MA_USB_DATA_IFLAGS_HDR_FMT_STD    2
+#define MA_USB_DATA_IFLAGS_HDR_FMT_LONG   4
+#define MA_USB_DATA_IFLAGS_IRS_FMT_STD    0
+#define MA_USB_DATA_IFLAGS_IRS_FMT_LONG   2
+#define MA_USB_DATA_IFLAGS_ASAP           8
+
+#define MA_USB_DATA_IFLAGS_FMT_MASK       0x6
+
+/* version */
+
+#define MA_USB_HDR_VERSION_1_0      0
+
+/* flags */
+
+#define MA_USB_HDR_FLAGS_HOST       1
+#define MA_USB_HDR_FLAGS_RETRY      2
+#define MA_USB_HDR_FLAGS_TIMESTAMP  4
+#define MA_USB_HDR_FLAGS_RESERVED   8
+#define MA_USB_HDR_FLAG(_f) MA_USB_HDR_FLAGS_##_f
+
+/* type and subtype */
+
+#define MA_USB_HDR_TYPE_TYPE_MASK     0xC0
+#define MA_USB_HDR_TYPE_SUBTYPE_MASK  0x3F
+
+#define MA_USB_HDR_TYPE_TYPE_MANAGEMENT 0
+#define MA_USB_HDR_TYPE_TYPE_CONTROL    1
+#define MA_USB_HDR_TYPE_TYPE_DATA       2
+
+/* Management subtypes */
+
+#define _MA_USB_HDR_TYPE_MANAGEMENT_REQ(_s) \
+	MA_USB_SET_FIELD_(HDR_TYPE_SUBTYPE, (_s) * 2)
+#define _MA_USB_HDR_TYPE_MANAGEMENT_RESP(_s) \
+	MA_USB_SET_FIELD_(HDR_TYPE_SUBTYPE, (_s) * 2 + 1)
+
+#define MA_USB_HDR_TYPE_MANAGEMENT_REQ(_s) \
+	_MA_USB_HDR_TYPE_MANAGEMENT_REQ(MA_USB_HDR_TYPE_SUBTYPE_##_s)
+#define MA_USB_HDR_TYPE_MANAGEMENT_RESP(_s) \
+	_MA_USB_HDR_TYPE_MANAGEMENT_RESP(MA_USB_HDR_TYPE_SUBTYPE_##_s)
+
+#define MA_USB_HDR_TYPE_SUBTYPE_CAP               0
+#define MA_USB_HDR_TYPE_SUBTYPE_USBDEVHANDLE      1
+#define MA_USB_HDR_TYPE_SUBTYPE_EPHANDLE          2
+#define MA_USB_HDR_TYPE_SUBTYPE_EPACTIVATE        3
+#define MA_USB_HDR_TYPE_SUBTYPE_EPINACTIVATE      4
+#define MA_USB_HDR_TYPE_SUBTYPE_EPRESET           5
+#define MA_USB_HDR_TYPE_SUBTYPE_CLEARTRANSFERS    6
+#define MA_USB_HDR_TYPE_SUBTYPE_EPHANDLEDELETE    7
+#define MA_USB_HDR_TYPE_SUBTYPE_DEVRESET          8
+#define MA_USB_HDR_TYPE_SUBTYPE_MODIFYEP0         9
+#define MA_USB_HDR_TYPE_SUBTYPE_SETUSBDEVADDR     10
+#define MA_USB_HDR_TYPE_SUBTYPE_UPDATEDEV         11
+#define MA_USB_HDR_TYPE_SUBTYPE_USBDEVDISCONNECT  12
+#define MA_USB_HDR_TYPE_SUBTYPE_USBSUSPEND        13
+#define MA_USB_HDR_TYPE_SUBTYPE_USBRESUME         14
+#define MA_USB_HDR_TYPE_SUBTYPE_REMOTEWAKE        15
+#define MA_USB_HDR_TYPE_SUBTYPE_PING              16
+#define MA_USB_HDR_TYPE_SUBTYPE_DEVDISCONNECT     17
+#define MA_USB_HDR_TYPE_SUBTYPE_DEVINITDISCONNECT 18
+#define MA_USB_HDR_TYPE_SUBTYPE_SYNCH             19
+#define MA_USB_HDR_TYPE_SUBTYPE_CANCELTRANSFER    20
+#define MA_USB_HDR_TYPE_SUBTYPE_EPOPENSTREAM      21
+#define MA_USB_HDR_TYPE_SUBTYPE_EPCLOSESTREAM     22
+#define MA_USB_HDR_TYPE_SUBTYPE_USBDEVRESET       23
+#define MA_USB_HDR_TYPE_SUBTYPE_DEVNOTIFICATION   24
+#define MA_USB_HDR_TYPE_SUBTYPE_EPSETKEEPALIVE    25
+#define MA_USB_HDR_TYPE_SUBTYPE_GETPORTBW         26
+#define MA_USB_HDR_TYPE_SUBTYPE_SLEEP             27
+#define MA_USB_HDR_TYPE_SUBTYPE_WAKE              28
+#define MA_USB_HDR_TYPE_SUBTYPE_VENDORSPECIFIC    31 /* Reserved */
+
+/* Data subtypes */
+
+#define _MA_USB_HDR_TYPE_DATA_REQ(_s) ({ \
+	typeof(_s) (s) = (_s); \
+	MA_USB_SET_FIELD(HDR_TYPE_TYPE, HDR_TYPE_TYPE_DATA) | \
+	MA_USB_SET_FIELD_(HDR_TYPE_SUBTYPE, (s) * 2 \
+	+ ((s) > 0 ? 1 : 0)); })
+#define _MA_USB_HDR_TYPE_DATA_RESP(_s) ({ \
+	typeof(_s) (s) = (_s); \
+	MA_USB_SET_FIELD(HDR_TYPE_TYPE, HDR_TYPE_TYPE_DATA) | \
+	MA_USB_SET_FIELD_(HDR_TYPE_SUBTYPE, (s) * 2 + 1 \
+	+ ((s) > 0 ? 1 : 0)); })
+#define _MA_USB_HDR_TYPE_DATA_ACK(_s) ( \
+	MA_USB_SET_FIELD(HDR_TYPE_TYPE, HDR_TYPE_TYPE_DATA) | \
+	MA_USB_SET_FIELD_(HDR_TYPE_SUBTYPE, (_s) * 2 + 2))
+
+#define MA_USB_HDR_TYPE_DATA_REQ(_s) \
+	_MA_USB_HDR_TYPE_DATA_REQ(MA_USB_HDR_TYPE_SUBTYPE_##_s)
+#define MA_USB_HDR_TYPE_DATA_RESP(_s) \
+	_MA_USB_HDR_TYPE_DATA_RESP(MA_USB_HDR_TYPE_SUBTYPE_##_s)
+#define MA_USB_HDR_TYPE_DATA_ACK(_s) \
+	_MA_USB_HDR_TYPE_DATA_ACK(MA_USB_HDR_TYPE_SUBTYPE_##_s)
+
+#define MA_USB_HDR_TYPE_SUBTYPE_TRANSFER          0
+#define MA_USB_HDR_TYPE_SUBTYPE_ISOCHTRANSFER     1
+
+/* EP/Device Handle */
+
+#define MA_USB_DEVICE_HANDLE_RESERVED   0
+
+#define MA_USB_EP_HANDLE_D_MASK     0x0001
+#define MA_USB_EP_HANDLE_EP_N_MASK  0x001e
+#define MA_USB_EP_HANDLE_ADDR_MASK  0x0fe0
+#define MA_USB_EP_HANDLE_BUS_N_MASK 0xf000
+
+#define MA_USB_EP_HANDLE(_b, _a, _e, _d) ( \
+	MA_USB_SET_FIELD_(EP_HANDLE_BUS_N, _b)  | \
+	MA_USB_SET_FIELD_(EP_HANDLE_ADDR, _a)   | \
+	MA_USB_SET_FIELD_(EP_HANDLE_EP_N, _e)   | \
+	MA_USB_SET_FIELD_(EP_HANDLE_D, _d))
+
+#define MA_USB_EP_HANDLE_BUS_N_VIRTUAL  15
+#define MA_USB_EP_HANDLE_ADDR_DEFAULT   0
+#define MA_USB_EP_HANDLE_EP_N_DEFAULT   0
+#define MA_USB_EP_HANDLE_D_OUT          0	/* See USB2.0 9.3, Table 9-2 */
+#define MA_USB_EP_HANDLE_D_IN           1	/* See USB2.0 9.3, Table 9-2 */
+
+/* Status codes */
+
+#define MA_USB_HDR_STATUS_UNSUCCESSFUL                  -128
+#define MA_USB_HDR_STATUS_INVALID_MA_USB_SESSION_STATE  -127
+#define MA_USB_HDR_STATUS_INVALID_DEVICE_HANDLE         -126
+#define MA_USB_HDR_STATUS_INVALID_EP_HANDLE             -125
+#define MA_USB_HDR_STATUS_INVALID_EP_HANDLE_STATE       -124
+#define MA_USB_HDR_STATUS_INVALID_REQUEST               -123
+#define MA_USB_HDR_STATUS_MISSING_SEQUENCE_NUMBER       -122
+#define MA_USB_HDR_STATUS_TRANSFER_PENDING              -121
+#define MA_USB_HDR_STATUS_TRANSFER_EP_STALL             -120
+#define MA_USB_HDR_STATUS_TRANSFER_SIZE_ERROR           -119
+#define MA_USB_HDR_STATUS_TRANSFER_DATA_BUFFER_ERROR    -118
+#define MA_USB_HDR_STATUS_TRANSFER_BABBLE_DETECTED      -117
+#define MA_USB_HDR_STATUS_TRANSFER_TRANSACTION_ERROR    -116
+#define MA_USB_HDR_STATUS_TRANSFER_SHORT_TRANSFER       -115
+#define MA_USB_HDR_STATUS_TRANSFER_CANCELED             -114
+#define MA_USB_HDR_STATUS_INSUFICIENT_RESOURCES         -113
+#define MA_USB_HDR_STATUS_NOT_SUFFICIENT_BANDWIDTH      -112
+#define MA_USB_HDR_STATUS_INTERNAL_ERROR                -111
+#define MA_USB_HDR_STATUS_DATA_OVERRUN                  -110
+#define MA_USB_HDR_STATUS_DEVICE_NOT_ACCESSED           -109
+#define MA_USB_HDR_STATUS_BUFFER_OVERRUN                -108
+#define MA_USB_HDR_STATUS_BUSY                          -107
+#define MA_USB_HDR_STATUS_DROPPED_PACKET                -106
+#define MA_USB_HDR_STATUS_ISOCH_TIME_EXPIRED            -105
+#define MA_USB_HDR_STATUS_ISOCH_TIME_INVALID            -104
+#define MA_USB_HDR_STATUS_NO_USB_PING_RESPONSE          -103
+#define MA_USB_HDR_STATUS_NOT_SUPPORTED                 -102
+#define MA_USB_HDR_STATUS_REQUEST_DENIED                -101
+#define MA_USB_HDR_STATUS_MISSING_REQUEST_ID            -100
+#define MA_USB_HDR_STATUS_SUCCESS                       0	/* Reserved */
+#define MA_USB_HDR_STATUS_NO_ERROR MA_USB_HDR_STATUS_SUCCESS	/* Reserved */
+
+/* Speed values */
+
+#define MA_USB_SPEED_LOW_SPEED         0
+#define MA_USB_SPEED_FULL_SPEED        1
+#define MA_USB_SPEED_HIGH_SPEED        2
+#define MA_USB_SPEED_SUPER_SPEED       3
+#define MA_USB_SPEED_SUPER_SPEED_PLUS  4
+
+/* capreq extra hdr */
+
+#define MA_USB_CAPREQ_DESC_SYNCHRONIZATION_LENGTH\
+	(sizeof(struct ma_usb_desc) +\
+	sizeof(struct ma_usb_capreq_desc_synchronization))
+#define MA_USB_CAPREQ_DESC_LINK_SLEEP_LENGTH\
+	(sizeof(struct ma_usb_desc) +\
+	sizeof(struct ma_usb_capreq_desc_link_sleep))
+
+#define MA_USB_CAPREQ_LENGTH\
+	(sizeof(struct ma_usb_hdr_common) +\
+	sizeof(struct ma_usb_hdr_capreq) +\
+	MA_USB_CAPREQ_DESC_SYNCHRONIZATION_LENGTH +\
+	MA_USB_CAPREQ_DESC_LINK_SLEEP_LENGTH)
+
+/* capreq desc types */
+
+#define MA_USB_CAPREQ_DESC_TYPE_SYNCHRONIZATION 3
+#define MA_USB_CAPREQ_DESC_TYPE_LINK_SLEEP      5
+
+/* capresp descriptors */
+
+#define MA_USB_CAPRESP_DESC_TYPE_SPEED            0
+#define MA_USB_CAPRESP_DESC_TYPE_P_MANAGED_OUT    1
+#define MA_USB_CAPRESP_DESC_TYPE_ISOCHRONOUS      2
+#define MA_USB_CAPRESP_DESC_TYPE_SYNCHRONIZATION  3
+#define MA_USB_CAPRESP_DESC_TYPE_CONTAINER_ID     4
+#define MA_USB_CAPRESP_DESC_TYPE_LINK_SLEEP       5
+#define MA_USB_CAPRESP_DESC_TYPE_HUB_LATENCY      6
+
+/* Request ID and sequence number values */
+
+#define MA_USB_TRANSFER_RESERVED      0
+#define MA_USB_TRANSFER_REQID_MIN     0
+#define MA_USB_TRANSFER_REQID_MAX     ((1 <<  8) - 1)
+#define MA_USB_TRANSFER_SEQN_MIN      0
+#define MA_USB_TRANSFER_SEQN_MAX      ((1 << 24) - 2)
+#define MA_USB_TRANSFER_SEQN_INVALID  ((1 << 24) - 1)
+
+#define MA_USB_ISOCH_SFLAGS_FRAGMENT      0x1
+#define MA_USB_ISOCH_SFLAGS_LAST_FRAGMENT 0x2
+
+#define MAUSB_MAX_MGMT_SIZE 50
+
+#define MAUSB_TRANSFER_HDR_SIZE (u32)(sizeof(struct ma_usb_hdr_common) +\
+				      sizeof(struct ma_usb_hdr_transfer))
+
+#define MAUSB_ISOCH_TRANSFER_HDR_SIZE (u16)(sizeof(struct ma_usb_hdr_common) +\
+			sizeof(struct ma_usb_hdr_isochtransfer) +\
+			sizeof(struct ma_usb_hdr_isochtransfer_optional))
+
+#define MAX_ISOCH_ASAP_PACKET_SIZE (150000 /* Network MTU */ -\
+	MAUSB_ISOCH_TRANSFER_HDR_SIZE - 20 /* IP header size */ -\
+	8 /* UDP header size*/)
+
+#define shift_ptr(ptr, offset) ((u8 *)(ptr) + (offset))
+
+/* USB descriptor */
+struct ma_usb_desc {
+	u8 length;
+	u8 type;
+	u8 value[0];
+} __packed;
+
+struct ma_usb_ep_handle {
+	u16 d		:1,
+	    ep_n	:4,
+	    addr	:7,
+	    bus_n	:4;
+};
+
+struct ma_usb_hdr_mgmt {
+	u32 status	:8,
+	    token	:10,  /* requestor originator allocated */
+	    reserved	:14;
+} __aligned(4);
+
+struct ma_usb_hdr_ctrl {	/* used in all req/resp/conf operations */
+	s8 status;
+	u8 link_type;
+	union {
+		u8 tid;	/* ieee 802.11 */
+	} connection_id;
+} __aligned(4);
+
+struct ma_usb_hdr_data {
+	s8 status;
+	u8 eps		:2,
+	   t_flags	:6;
+	union {
+		u16 stream_id;
+		struct {
+			u16 headers	:12,
+			    i_flags	:4;
+		};
+	};
+} __aligned(4);
+
+struct ma_usb_hdr_common {
+	u8 version	:4,
+	   flags	:4;
+	u8  type;
+	u16 length;
+	union {
+		u16 dev;
+		u16 epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u8 dev_addr;
+	u8 ssid;
+	union {
+		s8 status;
+		struct ma_usb_hdr_mgmt mgmt;
+		struct ma_usb_hdr_ctrl ctrl;
+		struct ma_usb_hdr_data data;
+	};
+} __aligned(4);
+
+/* capreq extra hdr */
+
+struct ma_usb_hdr_capreq {
+	u32 out_mgmt_reqs	:12,
+	    reserved		:20;
+} __aligned(4);
+
+struct ma_usb_capreq_desc_synchronization {
+	u8 media_time_available	:1,
+	   reserved		:7;
+} __packed;
+
+struct ma_usb_capreq_desc_link_sleep {
+	u8 link_sleep_capable	:1,
+	   reserved		:7;
+} __packed;
+
+/* capresp extra hdr */
+
+struct ma_usb_hdr_capresp {
+	u16 endpoints;
+	u8 devices;
+	u8 streams		:5,
+	   dev_type		:3;
+	u32 descs		:8,
+	    descs_length	:24;
+	u16 out_transfer_reqs;
+	u16 out_mgmt_reqs	:12,
+	    reserved		:4;
+} __aligned(4);
+
+struct ma_usb_capresp_desc_speed {
+	u8 reserved1		:4,
+		speed		:4;
+	u8 reserved2		:4,
+	   lse			:2,	/* USB3.1 8.5.6.7, Table 8-22 */
+	   reserved3		:2;
+} __packed;
+
+struct ma_usb_capresp_desc_p_managed_out {
+	u8 elastic_buffer		:1,
+	   drop_notification		:1,
+	   reserved			:6;
+} __packed;
+
+struct ma_usb_capresp_desc_isochronous {
+	u8 payload_dword_aligned	:1,
+	   reserved			:7;
+} __packed;
+
+struct ma_usb_capresp_desc_synchronization {
+	u8 media_time_available	:1,
+	   time_stamp_required	:1,/* hubs need this set */
+	   reserved		:6;
+} __packed;
+
+struct ma_usb_capresp_desc_container_id {
+	u8 container_id[16];	/* UUID IETF RFC 4122 */
+} __packed;
+
+struct ma_usb_capresp_desc_link_sleep {
+	u8 link_sleep_capable	:1,
+	   reserved		:7;
+} __packed;
+
+struct ma_usb_capresp_desc_hub_latency {
+	u16 latency;		/* USB3.1 */
+} __packed;
+
+/* usbdevhandlereq extra hdr */
+struct ma_usb_hdr_usbdevhandlereq {
+	u32 route_string	:20,
+	    speed		:4,
+	    reserved1		:8;
+	u16 hub_dev_handle;
+	u16 reserved2;
+	u16 parent_hs_hub_dev_handle;
+	u16 parent_hs_hub_port		:4,
+	    mtt				:1,	/* USB2.0 11.14, 11.14.1.3 */
+	    lse				:2,	/* USB3.1 8.5.6.7, Table 8-22 */
+	    reserved3			:9;
+} __aligned(4);
+
+/* usbdevhandleresp extra hdr */
+struct ma_usb_hdr_usbdevhandleresp {
+	u16 dev_handle;
+	u16 reserved;
+} __aligned(4);
+
+/* ephandlereq extra hdr */
+struct ma_usb_hdr_ephandlereq {
+	u32 ep_descs		:5,
+	    ep_desc_size	:6,
+	    reserved		:21;
+} __aligned(4);
+
+/*
+ * Restricted USB2.0 ep desc limited to 6 bytes, isolating further changes.
+ * See USB2.0 9.6.6, Table 9-13
+ */
+struct usb_ep_desc {
+	u8 bLength;
+	/* USB2.0 9.4, Table 9-5 (5) usb/ch9.h: USB_DT_ENDPOINT */
+	u8 bDescriptorType;
+	u8  bEndpointAddress;
+	u8  bmAttributes;
+	__le16 wMaxPacketSize;
+	u8  bInterval;
+} __packed;
+
+/*
+ * Restricted USB3.1 ep comp desc isolating further changes in usb/ch9.h
+ * See USB3.1 9.6.7, Table 9-26
+ */
+struct usb_ss_ep_comp_desc {
+	u8 bLength;
+	/* USB3.1 9.4, Table 9-6 (48) usb/ch9.h: USB_DT_SS_ENDPOINT_COMP */
+	u8  bDescriptorType;
+	u8  bMaxBurst;
+	u8  bmAttributes;
+	__le16 wBytesPerInterval;
+} __packed;
+
+/*
+ * USB3.1 ss_plus_isoch_ep_comp_desc
+ * See USB3.1 9.6.8, Table 9-27
+ */
+struct usb_ss_plus_isoch_ep_comp_desc {
+	u8 bLength;
+	/* USB3.1 9.4, Table 9-6 (49) usb/ch9.h: not yet defined! */
+	u8 bDescriptorType;
+	u16 wReserved;
+	u32 dwBytesPerInterval;
+} __packed;
+
+struct ma_usb_ephandlereq_desc_std {
+	struct usb_ep_desc usb20;
+} __aligned(4);
+
+struct ma_usb_ephandlereq_desc_ss {
+	struct usb_ep_desc	   usb20;
+	struct usb_ss_ep_comp_desc usb31;
+} __aligned(4);
+
+struct ma_usb_ephandlereq_desc_ss_plus {
+	struct usb_ep_desc		      usb20;
+	struct usb_ss_ep_comp_desc	      usb31;
+	struct usb_ss_plus_isoch_ep_comp_desc usb31_isoch;
+} __aligned(4);
+
+struct ma_usb_dev_context {
+	struct usb_ep_desc usb;
+};
+
+/* ephandleresp extra hdr */
+struct ma_usb_hdr_ephandleresp {
+	u32 ep_descs :5,
+	    reserved :27;
+} __aligned(4);
+
+/* ephandleresp descriptor */
+struct ma_usb_ephandleresp_desc {
+	union {
+		struct ma_usb_ep_handle eph;
+		u16		epv;
+	} ep_handle;
+	u16 d		:1,	/* non-control or non-OUT */
+	    isoch	:1,
+	    l_managed	:1,	/* control or non-isoch OUT */
+	    invalid	:1,
+	    reserved1	:12;
+	u16 ccu;		/* control or non-isoch OUT */
+	u16 reserved2;
+	u32 buffer_size;	/* control or OUT */
+	u16 isoch_prog_delay;	/* in us. */
+	u16 isoch_resp_delay;	/* in us. */
+} __aligned(4);
+
+/* epactivatereq extra hdr */
+struct ma_usb_hdr_epactivatereq {
+	u32 ep_handles	:5,
+	    reserved	:27;
+	union {
+		u16		epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* epactivateresp extra hdr */
+struct ma_usb_hdr_epactivateresp {
+	u32 ep_errors	:5,
+	    reserved	:27;
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* epinactivatereq extra hdr */
+struct ma_usb_hdr_epinactivatereq {
+	u32 ep_handles	:5,
+	    suspend	:1,
+	    reserved	:26;
+	union {
+		u16		epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* epinactivateresp extra hdr */
+struct ma_usb_hdr_epinactivateresp {
+	u32 ep_errors	:5,
+	    reserved	:27;
+	union {
+		u16		epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* epresetreq extra hdr */
+struct ma_usb_hdr_epresetreq {
+	u32 ep_reset_blocks	:5,
+	    reserved		:27;
+} __aligned(4);
+
+/* epresetreq reset block */
+struct ma_usb_epresetreq_block {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u16 tsp		:1,
+	    reserved	:15;
+} __aligned(4);
+
+/* epresetresp extra hdr */
+struct ma_usb_hdr_epresetresp {
+	u32 ep_errors	:5,
+	    reserved	:27;
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* cleartransfersreq extra hdr */
+struct ma_usb_hdr_cleartransfersreq {
+	u32 info_blocks	:8,
+	    reserved	:24;
+} __aligned(4);
+
+/* cleartransfersreq info block */
+struct ma_usb_cleartransfersreq_block {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u16 stream_id; /* ss stream eps only */
+	u32 start_req_id	:8,
+	    reserved		:24;
+} __aligned(4);
+
+/* cleartransfersresp extra hdr */
+struct ma_usb_hdr_cleartransfersresp {
+	u32 status_blocks	:8,
+	    reserved		:24;
+} __aligned(4);
+
+/* cleartransfersresp status block */
+struct ma_usb_cleartransfersresp_block {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u16 stream_id;	/* ss stream eps only */
+	u32 cancel_success	:1,
+	    partial_delivery	:1,
+	    reserved		:30;
+	u32 last_req_id		:8,
+	    delivered_seq_n	:24;	/* OUT w/partial_delivery only */
+	u32 delivered_byte_offset;	/* OUT w/partial_delivery only */
+} __aligned(4);
+
+/* ephandledeletereq extra hdr */
+struct ma_usb_hdr_ephandledeletereq {
+	u32 ep_handles	:5,
+	    reserved	:27;
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* ephandledeleteresp extra hdr */
+struct ma_usb_hdr_ephandledeleteresp {
+	u32 ep_errors	:5,
+	    reserved	:27;
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle[0];
+} __aligned(4);
+
+/* modifyep0req extra hdr */
+struct ma_usb_hdr_modifyep0req {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u16 max_packet_size;
+} __aligned(4);
+
+/*
+ * modifyep0resp extra hdr
+ * Only if req ep0 handle addr was 0 and req dev is in the addressed state
+ * or  if req ep0 handle addr != 0 and req dev is in default state
+ */
+struct ma_usb_hdr_modifyep0resp {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+
+	u16 reserved;
+} __aligned(4);
+
+/* setusbdevaddrreq extra hdr */
+struct ma_usb_hdr_setusbdevaddrreq {
+	u16 response_timeout;	/* in ms. */
+	u16 reserved;
+} __aligned(4);
+
+/* setusbdevaddrresp extra hdr */
+struct ma_usb_hdr_setusbdevaddrresp {
+	u32 addr	:7,
+	    reserved	:25;
+} __aligned(4);
+
+/* updatedevreq extra hdr */
+struct ma_usb_hdr_updatedevreq {
+	u16 max_exit_latency;	/* hubs only */
+	u8 hub		:1,
+	   ports	:4,
+	   mtt		:1,
+	   ttt		:2;
+	u8 integrated_hub_latency	:1,
+	   reserved			:7;
+} __aligned(4);
+
+/*
+ * USB2.0 dev desc, isolating further changes in usb/ch9.h
+ * See USB2.0 9.6.6, Table 9-13
+ */
+struct usb_dev_desc {
+	u8 bLength;
+	/*
+	 * USB2.0 9.4, Table 9-5 (1)
+	 * usb/ch9.h: USB_DT_DEVICE
+	 */
+	u8 bDescriptorType;
+	__le16 bcdUSB;
+	u8  bDeviceClass;
+	u8  bDeviceSubClass;
+	u8  bDeviceProtocol;
+	u8  bMaxPacketSize0;
+	__le16 idVendor;
+	__le16 idProduct;
+	__le16 bcdDevice;
+	u8  iManufacturer;
+	u8  iProduct;
+	u8  iSerialNumber;
+	u8  bNumConfigurations;
+} __packed;
+
+struct ma_usb_updatedevreq_desc {
+	struct usb_dev_desc usb20;
+} __aligned(4);
+
+/* remotewakereq extra hdr */
+struct ma_usb_hdr_remotewakereq {
+	u32 resumed  :1,
+		 reserved :31;
+} __aligned(4);
+
+/* synchreq/resp extra hdr */
+struct ma_usb_hdr_synch {
+	u32 mtd_valid		:1,	/* MA-USB1.0b 6.5.1.8, Table 66 */
+	    resp_required	:1,
+	    reserved		:30;
+	union {
+		u32 timestamp;		/* MA-USB1.0b 6.5.1.11 */
+		struct {
+			u32 delta		:13,
+			    bus_interval	:19;
+		};			/* MA-USB1.0b 6.6.1, Table 69 */
+	};
+	u32 mtd;			/* MA-USB1.0b 6.5.1.12 */
+} __aligned(4);
+
+/* canceltransferreq extra hdr */
+struct ma_usb_hdr_canceltransferreq {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u16 stream_id;
+	u32 req_id	  :8,
+		 reserved :24;
+} __aligned(4);
+
+/* canceltransferresp extra hdr */
+struct ma_usb_hdr_canceltransferresp {
+	union {
+		u16			epv;
+		struct ma_usb_ep_handle eph;
+	} handle;
+	u16 stream_id;
+	u32 req_id		:8,
+	    cancel_status	:3,
+	    reserved1		:21;
+	u32 delivered_seq_n	:24,
+	    reserved2		:8;
+	u32 delivered_byte_offset;
+} __aligned(4);
+
+/* transferreq/resp/ack extra hdr */
+struct ma_usb_hdr_transfer {
+	u32 seq_n	:24,
+	    req_id	:8;
+	union {
+		u32 rem_size_credit;
+		/* ISOCH aliased fields added for convenience. */
+		struct {
+			u32 presentation_time	:20,
+			    segments		:12;
+		};
+	};
+} __aligned(4);
+
+/* isochtransferreq/resp extra hdr */
+struct ma_usb_hdr_isochtransfer {
+	u32 seq_n		:24,
+	    req_id		:8;
+	u32 presentation_time	:20,
+	    segments		:12;
+} __aligned(4);
+
+/* isochtransferreq/resp optional hdr */
+struct ma_usb_hdr_isochtransfer_optional {
+	union {
+		u32 timestamp;	/* MA-USB1.0b 6.5.1.11 */
+		struct {
+			u32 delta		:13,
+			    bus_interval	:19;
+		};		/* MA-USB1.0b 6.6.1, Table 69 */
+	};
+	u32 mtd;		/* MA-USB1.0b 6.5.1.12 */
+} __aligned(4);
+
+/* isochdatablock hdrs */
+
+struct ma_usb_hdr_isochdatablock_short {
+	u16 block_length;
+	u16 segment_number	:12,
+	    s_flags		:4;
+} __aligned(4);
+
+struct ma_usb_hdr_isochdatablock_std {
+	u16 block_length;
+	u16 segment_number	:12,
+	    s_flags		:4;
+	u16 segment_length;
+	u16 fragment_offset;
+} __aligned(4);
+
+struct ma_usb_hdr_isochdatablock_long {
+	u16 block_length;
+	u16 segment_number	:12,
+	    s_flags		:4;
+	u32 segment_length;
+	u32 fragment_offset;
+} __aligned(4);
+
+/* isochreadsizeblock hdrs */
+
+struct ma_usb_hdr_isochreadsizeblock_std {
+	u32 service_intervals		:12,
+	    max_segment_length		:20;
+} __aligned(4);
+
+struct ma_usb_hdr_isochreadsizeblock_long {
+	u32 service_intervals		:12,
+	    reserved			:20;
+	u32 max_segment_length;
+} __aligned(4);
+
+static inline int __mausb_set_field(int m, int v)
+{
+	return ((~((m) - 1) & (m)) * (v)) & (m);
+}
+
+static inline int __mausb_get_field(int m, int v)
+{
+	return ((v) & (m)) / (~((m) - 1) & (m));
+}
+
+static inline bool mausb_is_management_hdr_type(int hdr_type)
+{
+	return MA_USB_GET_FIELD_(HDR_TYPE_TYPE, hdr_type)
+			== MA_USB_HDR_TYPE_TYPE_MANAGEMENT;
+}
+
+static inline bool mausb_is_data_hdr_type(int hdr_type)
+{
+	return MA_USB_GET_FIELD_(HDR_TYPE_TYPE, hdr_type)
+			== MA_USB_HDR_TYPE_TYPE_DATA;
+}
+
+static inline bool mausb_is_management_resp_hdr_type(int hdr_resp_type)
+{
+	return mausb_is_management_hdr_type(hdr_resp_type) &&
+			(MA_USB_GET_FIELD_(HDR_TYPE_SUBTYPE, hdr_resp_type) & 1)
+			!= 0;
+}
+
+static inline
+struct ma_usb_hdr_transfer *
+mausb_get_data_transfer_hdr(struct ma_usb_hdr_common *hdr)
+{
+	return (struct ma_usb_hdr_transfer *)shift_ptr(hdr, sizeof(*hdr));
+}
+
+static inline
+struct ma_usb_hdr_isochtransfer *
+mausb_get_isochtransfer_hdr(struct ma_usb_hdr_common *hdr)
+{
+	return (struct ma_usb_hdr_isochtransfer *)shift_ptr(hdr, sizeof(*hdr));
+}
+
+static inline
+struct ma_usb_hdr_isochtransfer_optional *
+mausb_hdr_isochtransfer_optional_hdr(struct ma_usb_hdr_common *hdr)
+{
+	return (struct ma_usb_hdr_isochtransfer_optional *)
+			shift_ptr(hdr, sizeof(struct ma_usb_hdr_common) +
+				       sizeof(struct ma_usb_hdr_isochtransfer));
+}
+
+#endif	/* __MAUSB_MA_USB_H__ */
diff --git a/drivers/usb/mausb_host/mausb_address.h b/drivers/usb/mausb_host/mausb_address.h
new file mode 100644
index 000000000000..1a75482740ea
--- /dev/null
+++ b/drivers/usb/mausb_host/mausb_address.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_MAUSB_ADDRESS_H__
+#define __MAUSB_MAUSB_ADDRESS_H__
+
+#include <linux/inet.h>
+#include <linux/types.h>
+
+struct mausb_device_address {
+	u8 link_type;
+	struct {
+		char address[INET6_ADDRSTRLEN];
+		u8 number_of_ports;
+		struct {
+			u16 management;
+			u16 control;
+			u16 bulk;
+			u16 interrupt;
+			u16 isochronous;
+		} port;
+	} ip;
+};
+
+#endif /* __MAUSB_MAUSB_ADDRESS_H__ */
diff --git a/drivers/usb/mausb_host/mausb_core.c b/drivers/usb/mausb_host/mausb_core.c
index 3ce90c29f6de..8730590126ea 100644
--- a/drivers/usb/mausb_host/mausb_core.c
+++ b/drivers/usb/mausb_host/mausb_core.c
@@ -12,6 +12,7 @@
 #include <linux/net.h>
 
 #include "hcd.h"
+#include "hpal.h"
 #include "utils.h"
 
 MODULE_LICENSE("GPL");
@@ -75,12 +76,20 @@ static int mausb_host_init(void)
 	if (status < 0)
 		goto cleanup;
 
-	status = mausb_create_dev();
+	status = mausb_register_power_state_listener();
 	if (status < 0)
 		goto cleanup_hcd;
 
+	status = mausb_create_dev();
+	if (status < 0)
+		goto unregister_power_state_listener;
+
+	mausb_initialize_mss();
+
 	return 0;
 
+unregister_power_state_listener:
+	mausb_unregister_power_state_listener();
 cleanup_hcd:
 	mausb_deinit_hcd();
 cleanup:
@@ -91,6 +100,8 @@ static int mausb_host_init(void)
 static void mausb_host_exit(void)
 {
 	mausb_pr_info("Module unloading started...");
+	mausb_unregister_power_state_listener();
+	mausb_deinitialize_mss();
 	mausb_deinit_hcd();
 	mausb_cleanup_dev(1);
 	mausb_pr_info("Module unloaded. Version=%s", MAUSB_DRIVER_VERSION);
diff --git a/drivers/usb/mausb_host/mausb_event.h b/drivers/usb/mausb_host/mausb_event.h
new file mode 100644
index 000000000000..636c07b5f2be
--- /dev/null
+++ b/drivers/usb/mausb_host/mausb_event.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_MAUSB_EVENT_H__
+#define __MAUSB_MAUSB_EVENT_H__
+
+#include "ma_usb.h"
+
+#define MAUSB_MAX_NUM_OF_MA_DEVS			15
+#define MAUSB_RING_BUFFER_SIZE				1024
+#define MAUSB_MAX_DATA_IN_REQ_SIZE			28
+
+#define MAUSB_EVENT_TYPE_DEV_RESET			1u
+#define MAUSB_EVENT_TYPE_USB_DEV_HANDLE			2u
+#define MAUSB_EVENT_TYPE_EP_HANDLE			3u
+#define MAUSB_EVENT_TYPE_EP_HANDLE_ACTIVATE		4u
+#define MAUSB_EVENT_TYPE_EP_HANDLE_INACTIVATE		5u
+#define MAUSB_EVENT_TYPE_EP_HANDLE_RESET		6u
+#define MAUSB_EVENT_TYPE_EP_HANDLE_DELETE		7u
+#define MAUSB_EVENT_TYPE_MODIFY_EP0			8u
+#define MAUSB_EVENT_TYPE_SET_USB_DEV_ADDRESS		9u
+#define MAUSB_EVENT_TYPE_UPDATE_DEV			10u
+#define MAUSB_EVENT_TYPE_USB_DEV_DISCONNECT		11u
+#define MAUSB_EVENT_TYPE_PING				12u
+#define MAUSB_EVENT_TYPE_DEV_DISCONNECT			13u
+#define MAUSB_EVENT_TYPE_USB_DEV_RESET			14u
+#define MAUSB_EVENT_TYPE_CANCEL_TRANSFER		15u
+
+#define MAUSB_EVENT_TYPE_PORT_CHANGED			80u
+#define MAUSB_EVENT_TYPE_SEND_MGMT_MSG			81u
+#define MAUSB_EVENT_TYPE_SEND_DATA_MSG			82u
+#define MAUSB_EVENT_TYPE_RECEIVED_MGMT_MSG		83u
+#define MAUSB_EVENT_TYPE_RECEIVED_DATA_MSG		84u
+#define MAUSB_EVENT_TYPE_URB_COMPLETE			85u
+#define MAUSB_EVENT_TYPE_SEND_ACK			86u
+#define MAUSB_EVENT_TYPE_ITERATOR_RESET			87u
+#define MAUSB_EVENT_TYPE_ITERATOR_SEEK			88u
+#define MAUSB_EVENT_TYPE_DELETE_DATA_TRANSFER		89u
+#define MAUSB_EVENT_TYPE_DELETE_MA_DEV			90u
+#define MAUSB_EVENT_TYPE_USER_FINISHED			91u
+#define MAUSB_EVENT_TYPE_RELEASE_EVENT_RESOURCES	92u
+#define MAUSB_EVENT_TYPE_NETWORK_DISCONNECTED		93u
+#define MAUSB_EVENT_TYPE_MGMT_REQUEST_TIMED_OUT		94u
+
+#define MAUSB_EVENT_TYPE_NONE				255u
+
+#define MAUSB_DATA_MSG_DIRECTION_OUT			0
+#define MAUSB_DATA_MSG_DIRECTION_IN			1
+#define MAUSB_DATA_MSG_CONTROL MAUSB_DATA_MSG_DIRECTION_OUT
+
+struct mausb_devhandle {
+	u64 event_id;
+	u32 route_string;
+	u16 hub_dev_handle;
+	u16 parent_hs_hub_dev_handle;
+	u16 parent_hs_hub_port;
+	u16 mtt;
+	/* dev_handle assigned in user */
+	u16 dev_handle;
+	u8  device_speed;
+	u8  lse;
+};
+
+struct mausb_ephandle {
+	u64 event_id;
+	u16 device_handle;
+	u16 descriptor_size;
+	/* ep_handle assigned in user */
+	u16 ep_handle;
+	char	 descriptor[sizeof(struct ma_usb_ephandlereq_desc_ss)];
+};
+
+struct mausb_epactivate {
+	u64 event_id;
+	u16 device_handle;
+	u16 ep_handle;
+};
+
+struct mausb_epinactivate {
+	u64 event_id;
+	u16 device_handle;
+	u16 ep_handle;
+};
+
+struct mausb_epreset {
+	u64 event_id;
+	u16 device_handle;
+	u16 ep_handle;
+	u8  tsp;
+};
+
+struct mausb_epdelete {
+	u64 event_id;
+	u16 device_handle;
+	u16 ep_handle;
+};
+
+struct mausb_updatedev {
+	u64 event_id;
+	u16 device_handle;
+	u16 max_exit_latency;
+	struct ma_usb_updatedevreq_desc update_descriptor;
+	u8  hub;
+	u8  number_of_ports;
+	u8  mtt;
+	u8  ttt;
+	u8  integrated_hub_latency;
+};
+
+struct mausb_usbdevreset {
+	u64 event_id;
+	u16 device_handle;
+};
+
+struct mausb_modifyep0 {
+	u64 event_id;
+	u16 device_handle;
+	u16 ep_handle;
+	__le16 max_packet_size;
+};
+
+struct mausb_setusbdevaddress {
+	u64 event_id;
+	u16 device_handle;
+	u16 response_timeout;
+};
+
+struct mausb_usbdevdisconnect {
+	u16 device_handle;
+};
+
+struct mausb_canceltransfer {
+	u64 urb;
+	u16 device_handle;
+	u16 ep_handle;
+};
+
+struct mausb_mgmt_hdr {
+	__aligned(4) char hdr[MAUSB_MAX_MGMT_SIZE];
+};
+
+struct mausb_mgmt_req_timedout {
+	u64 event_id;
+};
+
+struct mausb_delete_ma_dev {
+	u64 event_id;
+	u16 device_id;
+};
+
+/* TODO split mgmt_event to generic send mgmt req and specific requests */
+struct mausb_mgmt_event {
+	union {
+		struct mausb_devhandle		dev_handle;
+		struct mausb_ephandle		ep_handle;
+		struct mausb_epactivate		ep_activate;
+		struct mausb_epinactivate	ep_inactivate;
+		struct mausb_epreset		ep_reset;
+		struct mausb_epdelete		ep_delete;
+		struct mausb_modifyep0		modify_ep0;
+		struct mausb_setusbdevaddress	set_usb_dev_address;
+		struct mausb_updatedev		update_dev;
+		struct mausb_usbdevreset	usb_dev_reset;
+		struct mausb_usbdevdisconnect	usb_dev_disconnect;
+		struct mausb_canceltransfer	cancel_transfer;
+		struct mausb_mgmt_hdr		mgmt_hdr;
+		struct mausb_mgmt_req_timedout	mgmt_req_timedout;
+		struct mausb_delete_ma_dev	delete_ma_dev;
+	};
+};
+
+struct mausb_data_event {
+	u64 urb;
+	u64 recv_buf;
+	u32 iterator_seek_delta;
+	u32 transfer_size;
+	u32 rem_transfer_size;
+	u32 transfer_flags;
+	u32 isoch_seg_num;
+	u32 req_id;
+	u32 payload_size;
+	s32 status;
+
+	__aligned(4) char hdr[MAUSB_TRANSFER_HDR_SIZE];
+	__aligned(4) char hdr_ack[MAUSB_TRANSFER_HDR_SIZE];
+
+	u16 device_id;
+	u16 ep_handle;
+	u16 packet_size;
+	u8  setup_packet;
+	u8  direction;
+	u8  transfer_type;
+	u8  first_control_packet;
+	u8  transfer_eot;
+	u8  mausb_address;
+	u8  mausb_ssid;
+};
+
+struct mausb_port_changed_event {
+	u8 port;
+	u8 dev_type;
+	u8 dev_speed;
+	u8 lse;
+};
+
+struct mausb_event {
+	union {
+		struct mausb_mgmt_event		mgmt;
+		struct mausb_data_event		data;
+		struct mausb_port_changed_event port_changed;
+	};
+	s32 status;
+	u8 type;
+	u8 madev_addr;
+};
+
+struct mausb_events_notification {
+	u16 num_of_events;
+	u16 num_of_completed_events;
+	u8  madev_addr;
+};
+
+#endif /* __MAUSB_MAUSB_EVENT_H__ */
-- 
2.17.1


  parent reply	other threads:[~2020-03-27 15:26 UTC|newest]

Thread overview: 65+ 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   ` vladimir.stankovic [this message]
2020-03-27 16:35     ` [PATCH v4 5/8] usb: mausb_host: Introduce PAL processing Alan Stern
2020-03-28  3:56     ` kbuild test robot
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-03-28 10:35       ` kbuild test robot
2020-04-04 16:07     ` 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     ` [PATCH v5 2/8] usb: mausb_host: Add link layer implementation vladimir.stankovic
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=20200327152614.26833-6-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.