linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing
@ 2020-02-26  9:58 Vladimir Stankovic
  2020-02-26 12:35 ` Oliver Neukum
  2020-02-26 14:19 ` Oliver Neukum
  0 siblings, 2 replies; 4+ messages in thread
From: Vladimir Stankovic @ 2020-02-26  9:58 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb, mausb-host-devel

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          | 1095 ++++++++++++++++++++++++
  drivers/usb/mausb_host/hpal.h          |  289 +++++++
  drivers/usb/mausb_host/ma_usb.h        |  869 +++++++++++++++++++
  drivers/usb/mausb_host/mausb_address.h |   34 +
  drivers/usb/mausb_host/mausb_event.h   |  224 +++++
  drivers/usb/mausb_host/mausb_host.c    |   13 +-
  9 files changed, 3049 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 855947376f71..0ebd79f8e2ef 100644
--- a/drivers/usb/mausb_host/Makefile
+++ b/drivers/usb/mausb_host/Makefile
@@ -10,6 +10,7 @@ mausb_host-y := mausb_host.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)
  ccflags-y += -g
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..d5a4d17d4d4d
--- /dev/null
+++ b/drivers/usb/mausb_host/hpal.c
@@ -0,0 +1,1095 @@
+// 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_irqsave(&dev->num_of_user_events_lock, flags);
+	dev->num_of_user_events += num_of_events;
+	dev->num_of_completed_events += num_of_completed;
+	spin_unlock_irqrestore(&dev->num_of_user_events_lock, flags);
+	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..613ac77ce6f4
--- /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 "mausb_address.h"
+#include "mausb_event.h"
+#include "ip_link.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..922a075c198e
--- /dev/null
+++ b/drivers/usb/mausb_host/mausb_address.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_MAUSB_ADDRESS_H__
+#define __MAUSB_MAUSB_ADDRESS_H__
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <types.h>
+#endif /* __KERNEL__ */
+
+#define ADDR_LEN 16
+
+struct mausb_device_address {
+	u8 link_type;
+	struct {
+		union {
+			char	ip4[ADDR_LEN];
+			u8	ip6[ADDR_LEN];
+		} address;
+		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_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__ */
diff --git a/drivers/usb/mausb_host/mausb_host.c 
b/drivers/usb/mausb_host/mausb_host.c
index 3ce90c29f6de..8730590126ea 100644
--- a/drivers/usb/mausb_host/mausb_host.c
+++ b/drivers/usb/mausb_host/mausb_host.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);
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing
  2020-02-26  9:58 [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing Vladimir Stankovic
@ 2020-02-26 12:35 ` Oliver Neukum
  2020-02-27  8:50   ` [External] " Vladimir Stankovic
  2020-02-26 14:19 ` Oliver Neukum
  1 sibling, 1 reply; 4+ messages in thread
From: Oliver Neukum @ 2020-02-26 12:35 UTC (permalink / raw)
  To: Vladimir Stankovic, Greg KH; +Cc: linux-kernel, linux-usb, mausb-host-devel

Am Mittwoch, den 26.02.2020, 09:58 +0000 schrieb Vladimir Stankovic

+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);

You save the flags.

+       dev = mausb_get_dev_from_addr_unsafe(madev_addr);
+
+       if (!dev) {
+               spin_unlock_irqrestore(&mss.lock, flags);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&dev->num_of_user_events_lock, flags);

You overwrite the flags.

+       dev->num_of_user_events += num_of_events;
+       dev->num_of_completed_events += num_of_completed;
+       spin_unlock_irqrestore(&dev->num_of_user_events_lock, flags);

Your restore the flags.

+       queue_work(dev->workq, &dev->work);
+       spin_unlock_irqrestore(&mss.lock, flags);

You restore the overwritten flags.

This cannot be right.

	Regards
		Oliver


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing
  2020-02-26  9:58 [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing Vladimir Stankovic
  2020-02-26 12:35 ` Oliver Neukum
@ 2020-02-26 14:19 ` Oliver Neukum
  1 sibling, 0 replies; 4+ messages in thread
From: Oliver Neukum @ 2020-02-26 14:19 UTC (permalink / raw)
  To: Vladimir Stankovic, Greg KH; +Cc: linux-kernel, linux-usb, mausb-host-devel

Hi,

+       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;

This is extremely drastic and will break drivers. Which driver causes
the problems?

	Regards
		Oliver



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [External] Re: [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing
  2020-02-26 12:35 ` Oliver Neukum
@ 2020-02-27  8:50   ` Vladimir Stankovic
  0 siblings, 0 replies; 4+ messages in thread
From: Vladimir Stankovic @ 2020-02-27  8:50 UTC (permalink / raw)
  To: Oliver Neukum, Greg KH; +Cc: linux-kernel, linux-usb, mausb-host-devel

On 26.2.20. 13:35, Oliver Neukum wrote:
> Am Mittwoch, den 26.02.2020, 09:58 +0000 schrieb Vladimir Stankovic
> 
> +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);
> 
> You save the flags.
> 
> +       dev = mausb_get_dev_from_addr_unsafe(madev_addr);
> +
> +       if (!dev) {
> +               spin_unlock_irqrestore(&mss.lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       spin_lock_irqsave(&dev->num_of_user_events_lock, flags);
> 
> You overwrite the flags.
> 
> +       dev->num_of_user_events += num_of_events;
> +       dev->num_of_completed_events += num_of_completed;
> +       spin_unlock_irqrestore(&dev->num_of_user_events_lock, flags);
> 
> Your restore the flags.
> 
> +       queue_work(dev->workq, &dev->work);
> +       spin_unlock_irqrestore(&mss.lock, flags);
> 
> You restore the overwritten flags.
> 
> This cannot be right.
> 
> 	Regards
> 		Oliver
> 
You're right. We'll address this issue.

-- 
Regards,
Vladimir.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-02-27  8:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-26  9:58 [PATCH v2 5/8] usb: mausb_host: Introduce PAL processing Vladimir Stankovic
2020-02-26 12:35 ` Oliver Neukum
2020-02-27  8:50   ` [External] " Vladimir Stankovic
2020-02-26 14:19 ` Oliver Neukum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).