lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200515123502.12099-6-vladimir.stankovic@displaylink.com>
Date:   Fri, 15 May 2020 14:34:59 +0200
From:   Vladimir Stankovic <vladimir.stankovic@...playlink.com>
To:     gregkh@...uxfoundation.org
Cc:     linux-kernel@...r.kernel.org, linux-usb@...r.kernel.org,
        mausb-host-devel@...playlink.com
Subject: [PATCH v6 5/8] usb: mausb_host: Introduce PAL processing

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

Signed-off-by: Vladimir Stankovic <vladimir.stankovic@...playlink.com>
---
 drivers/usb/host/mausb/Makefile        |    1 +
 drivers/usb/host/mausb/hcd.c           |  516 ++++++++++-
 drivers/usb/host/mausb/hcd.h           |   13 +-
 drivers/usb/host/mausb/hpal.c          | 1092 ++++++++++++++++++++++++
 drivers/usb/host/mausb/hpal.h          |  289 +++++++
 drivers/usb/host/mausb/ma_usb.h        |  869 +++++++++++++++++++
 drivers/usb/host/mausb/mausb_address.h |   26 +
 drivers/usb/host/mausb/mausb_core.c    |   11 +
 drivers/usb/host/mausb/mausb_event.h   |  224 +++++
 9 files changed, 3032 insertions(+), 9 deletions(-)
 create mode 100644 drivers/usb/host/mausb/hpal.c
 create mode 100644 drivers/usb/host/mausb/hpal.h
 create mode 100644 drivers/usb/host/mausb/ma_usb.h
 create mode 100644 drivers/usb/host/mausb/mausb_address.h
 create mode 100644 drivers/usb/host/mausb/mausb_event.h

diff --git a/drivers/usb/host/mausb/Makefile b/drivers/usb/host/mausb/Makefile
index 4d655cb7fab4..0f9b9be38907 100644
--- a/drivers/usb/host/mausb/Makefile
+++ b/drivers/usb/host/mausb/Makefile
@@ -10,3 +10,4 @@ mausb_host-y := mausb_core.o
 mausb_host-y += utils.o
 mausb_host-y += ip_link.o
 mausb_host-y += hcd.o
+mausb_host-y += hpal.o
diff --git a/drivers/usb/host/mausb/hcd.c b/drivers/usb/host/mausb/hcd.c
index 41b88b6f97b1..26d582ee06e9 100644
--- a/drivers/usb/host/mausb/hcd.c
+++ b/drivers/usb/host/mausb/hcd.c
@@ -132,6 +132,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) {
+		dev_err(mausb_host_dev.this_device, "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,
@@ -168,11 +252,30 @@ static int mausb_hcd_hub_control(struct usb_hcd *hcd, u16 type_req,
 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 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 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)
+{
+	dev_vdbg(&request->dev->dev, "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,
@@ -183,6 +286,9 @@ static const struct hc_driver mausb_hc_driver = {
 	.reset = mausb_hcd_reset,
 	.start = mausb_hcd_start,
 
+	.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,
@@ -239,6 +345,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)
 {
@@ -258,6 +383,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;
@@ -430,6 +580,118 @@ 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) {
+		dev_err(mausb_host_dev.this_device, "urb is NULL");
+		return -EINVAL;
+	}
+
+	if (!urb->ep->hcpriv) {
+		dev_err(mausb_host_dev.this_device, "urb->ep->hcpriv is NULL");
+		return -EINVAL;
+	}
+
+	if (!urb->ep->enabled) {
+		dev_err(mausb_host_dev.this_device, "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) {
+		dev_err(&urb->dev->dev, "Hpal urb enqueue failed");
+		return -EPROTO;
+	}
+
+	endpoint_ctx = urb->ep->hcpriv;
+	ma_dev = endpoint_ctx->ma_dev;
+
+	if (atomic_read(&ma_dev->unresponsive_client)) {
+		dev_err(&urb->dev->dev, "Client is not responsive anymore - finish urb immediately");
+		return -EHOSTDOWN;
+	}
+
+	urb->hcpriv = hcd;
+
+	dev_vdbg(&urb->dev->dev, "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) {
+		dev_err(&urb->dev->dev, "Hpal urb enqueue failed");
+		return status;
+	}
+
+	atomic_inc(&urb->use_count);
+
+	mausb_print_urb(urb);
+
+	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;
+
+	dev_info(&urb->dev->dev, "Urb=%p", urb);
+
+	urb_ctx = mausb_unlink_and_delete_urb_from_tree(urb, status);
+	if (!urb_ctx) {
+		dev_warn(mausb_host_dev.this_device, "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;
@@ -693,8 +955,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;
 
@@ -707,6 +971,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) {
+		dev_err(mausb_host_dev.this_device, "MAUSB device not found on port_number=%d",
+			port_number);
+		return;
+	}
+
 	usb_device_ctx = mausb_find_usb_device(mdev, dev);
 	if (!usb_device_ctx) {
 		dev_warn(mausb_host_dev.this_device, "device_ctx is not found");
@@ -715,6 +989,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)) {
+		dev_err(mausb_host_dev.this_device, "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);
@@ -723,17 +1004,61 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
 			 dev_handle);
 	}
 
+free_dev:
+	if (atomic_sub_and_test(1, &ma_dev->num_of_usb_devices)) {
+		dev_info(mausb_host_dev.this_device, "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);
 	dev_info(mausb_host_dev.this_device, "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)) {
+		dev_warn(&dev->dev, "device_ctx already exists");
+		kfree(usb_device_ctx);
+		*status = -EEXIST;
+		return NULL;
+	}
+
+	kref_get(&ma_dev->refcount);
+	dev_info(&dev->dev, "New USB device added device=%p",
+		 usb_device_ctx->dev_addr);
+	atomic_inc(&ma_dev->num_of_usb_devices);
+
+	return usb_device_ctx;
 }
 
 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;
 
@@ -744,9 +1069,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) {
+		dev_warn(&dev->dev, "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;
+	}
 
 	dev_info(&dev->dev, "dev_handle=%#x, dev_speed=%#x",
 		 usb_device_ctx->dev_handle, dev->speed);
@@ -777,9 +1116,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) {
@@ -788,6 +1131,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) {
+		dev_err(&dev->dev, "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) {
 		dev_warn(&dev->dev, "Device not found");
@@ -800,8 +1153,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;
 }
 
@@ -811,8 +1173,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) {
@@ -821,6 +1185,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) {
+		dev_err(&dev->dev, "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) {
@@ -837,12 +1211,78 @@ 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) {
+		dev_dbg(mausb_host_dev.this_device, "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);
+	dev_info(mausb_host_dev.this_device, "start... mausb_devspeed=%d, route=%#x, port_number=%d",
+		 dev_speed, dev->route, port_number);
+
+	if (dev_speed == -EINVAL) {
+		dev_err(mausb_host_dev.this_device, "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;
+}
+
 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) {
@@ -851,13 +1291,30 @@ 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) {
+		dev_err(mausb_host_dev.this_device, "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;
+	}
 
 	dev_info(mausb_host_dev.this_device, "Device assigned and addressed usb_device_ctx=%p",
 		 usb_device_ctx);
 
+	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;
 }
 
@@ -871,7 +1328,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)) {
 		dev_warn(mausb_host_dev.this_device, "Device is hub");
@@ -885,6 +1344,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) {
+		dev_err(mausb_host_dev.this_device, "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) {
 		dev_warn(mausb_host_dev.this_device, "Device not found");
@@ -899,10 +1368,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) {
@@ -917,6 +1388,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) {
+		dev_err(mausb_host_dev.this_device, "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);
 
@@ -940,10 +1421,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;
@@ -964,14 +1447,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) {
+		dev_err(&dev->dev, "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);
@@ -994,7 +1484,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;
@@ -1006,6 +1498,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) {
+		dev_err(mausb_host_dev.this_device, "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/host/mausb/hcd.h b/drivers/usb/host/mausb/hcd.h
index c0818edc0266..7a20264aaa35 100644
--- a/drivers/usb/host/mausb/hcd.h
+++ b/drivers/usb/host/mausb/hcd.h
@@ -9,13 +9,13 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 
+#include "hpal.h"
+
 #define DEVICE_NAME "mausb_host_hcd"
 #define CLASS_NAME "mausb"
 
 #define NUMBER_OF_PORTS		15
-
 #define MAX_USB_DEVICE_DEPTH	6
-
 #define RESPONSE_TIMEOUT	5000
 
 enum mausb_device_type {
@@ -59,6 +59,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 \
@@ -134,11 +141,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/host/mausb/hpal.c b/drivers/usb/host/mausb/hpal.c
new file mode 100644
index 000000000000..5368c500a320
--- /dev/null
+++ b/drivers/usb/host/mausb/hpal.c
@@ -0,0 +1,1092 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#include "hpal.h"
+
+#include <linux/circ_buf.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) {
+		dev_err(mausb_host_dev.this_device, "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);
+			dev_err(mausb_host_dev.this_device, "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);
+		dev_err(mausb_host_dev.this_device, "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);
+			dev_err(mausb_host_dev.this_device, "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);
+		dev_err(mausb_host_dev.this_device, "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) {
+		dev_warn(mausb_host_dev.this_device, "URB is NULL");
+		return NULL;
+	}
+
+	spin_lock_irqsave(&mhcd->lock, flags);
+
+	urb_ctx = __mausb_find_urb_in_tree(urb);
+
+	if (!urb_ctx) {
+		dev_warn(mausb_host_dev.this_device, "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)
+		dev_warn(&urb->dev->dev, "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);
+
+	dev_vdbg(&urb->dev->dev, "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;
+
+	dev_vdbg(mausb_host_dev.this_device, "URB complete request, 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);
+		dev_err(mausb_host_dev.this_device, "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) {
+		dev_err(mausb_host_dev.this_device, "App is unresponsive - disconnecting devices");
+		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) {
+			dev_vdbg(mausb_host_dev.this_device, "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);
+
+	dev_info(mausb_host_dev.this_device, "Scheduling work for MAUSB device to be deleted");
+
+	schedule_work(&dev->madev_delete_work);
+}
+
+int mausb_enqueue_event_from_user(u8 madev_addr, u16 num_of_events,
+				  u16 num_of_completed)
+{
+	unsigned long flags;
+	struct mausb_device *dev;
+
+	spin_lock_irqsave(&mss.lock, flags);
+	dev = mausb_get_dev_from_addr_unsafe(madev_addr);
+
+	if (!dev) {
+		spin_unlock_irqrestore(&mss.lock, flags);
+		return -EINVAL;
+	}
+
+	spin_lock(&dev->num_of_user_events_lock);
+	dev->num_of_user_events += num_of_events;
+	dev->num_of_completed_events += num_of_completed;
+	spin_unlock(&dev->num_of_user_events_lock);
+	queue_work(dev->workq, &dev->work);
+	spin_unlock_irqrestore(&mss.lock, flags);
+
+	return 0;
+}
+
+int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
+				 struct urb *request)
+{
+	struct mausb_event mausb_event;
+
+	mausb_event.type   = MAUSB_EVENT_TYPE_SEND_DATA_MSG;
+	mausb_event.status = 0;
+
+	mausb_event.data.transfer_type =
+		mausb_transfer_type_from_usb(&request->ep->desc);
+	mausb_event.data.device_id	= dev->id;
+	mausb_event.data.ep_handle	= ep_handle;
+	mausb_event.data.urb		= (uintptr_t)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) {
+		dev_err(mausb_host_dev.this_device, "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)) {
+		dev_err(mausb_host_dev.this_device, "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;
+	}
+
+	dev_vdbg(mausb_host_dev.this_device, "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	       = (uintptr_t)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)) {
+		dev_alert(mausb_host_dev.this_device, "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) {
+		dev_dbg(mausb_host_dev.this_device, "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);
+	dev_dbg(mausb_host_dev.this_device, "Waiting for completion on disconnect_event ended");
+
+	timeout = wait_for_completion_timeout(&mss.client_stopped, timeout);
+	dev_info(mausb_host_dev.this_device, "Remaining time after waiting for stopping client %ld",
+		 timeout);
+}
+
+int mausb_register_power_state_listener(void)
+{
+	dev_info(mausb_host_dev.this_device, "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)
+{
+	dev_info(mausb_host_dev.this_device, "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;
+
+	dev_info(mausb_host_dev.this_device, "Power state callback action = %ld",
+		 action);
+	if (action == PM_SUSPEND_PREPARE || action == PM_HIBERNATION_PREPARE) {
+		/* Stop heartbeat timer */
+		del_timer_sync(&mss.heartbeat_timer);
+		dev_info(mausb_host_dev.this_device, "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) {
+			dev_info(mausb_host_dev.this_device, "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) {
+		dev_err(mausb_host_dev.this_device, "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) {
+		dev_err(mausb_host_dev.this_device, "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 */
+		dev_warn(mausb_host_dev.this_device, "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;
+
+	dev_vdbg(mausb_host_dev.this_device, "Direction=%d",
+		 event->data.direction);
+
+	if (!mausb_isoch_data_event(event)) {
+		status = mausb_send_transfer_ack(dev, event);
+		if (status < 0) {
+			dev_warn(mausb_host_dev.this_device, "Sending acknowledgment failed");
+			goto cleanup;
+		}
+	}
+
+	urb_ctx = mausb_find_urb_in_tree((struct urb *)event->data.urb);
+
+	if (!urb_ctx)
+		dev_warn(mausb_host_dev.this_device, "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 = false;
+
+	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 = true;
+	}
+}
+
+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 = false;
+}
+
+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 = false;
+	}
+
+	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 = true;
+	}
+}
+
+u32 mausb_data_iterator_length(struct mausb_data_iter *iterator)
+{
+	return iterator->length;
+}
diff --git a/drivers/usb/host/mausb/hpal.h b/drivers/usb/host/mausb/hpal.h
new file mode 100644
index 000000000000..f184bbc07783
--- /dev/null
+++ b/drivers/usb/host/mausb/hpal.h
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_HPAL_H__
+#define __MAUSB_HPAL_H__
+
+#include <linux/kref.h>
+#include <linux/suspend.h>
+#include <linux/usb.h>
+
+#include "ip_link.h"
+#include "mausb_address.h"
+#include "mausb_event.h"
+
+#define MAUSB_CONTROL_SETUP_SIZE	8
+#define MAUSB_BUSY_RETRIES_COUNT	3
+#define MAUSB_HEARTBEAT_TIMEOUT_MS	1000
+#define MAUSB_CLIENT_STOPPED_TIMEOUT_MS	3000
+
+#define MAUSB_MAX_RECEIVE_FAILURES	3
+#define MAUSB_MAX_MISSED_HEARTBEATS	3
+#define MAUSB_TRANSFER_RESERVED		0
+
+#define MAUSB_CHANNEL_MAP_LENGTH	4
+
+extern struct mss mss;
+extern struct mausb_hcd *mhcd;
+
+enum mausb_isoch_header_format_size {
+	MAUSB_ISOCH_SHORT_FORMAT_SIZE	 = 4,
+	MAUSB_ISOCH_STANDARD_FORMAT_SIZE = 8,
+	MAUSB_ISOCH_LONG_FORMAT_SIZE	 = 12
+};
+
+struct mausb_completion {
+	struct list_head   list_entry;
+	struct completion  *completion_event;
+	struct mausb_event *mausb_event;
+	u64		   event_id;
+};
+
+struct mausb_mss_rings_events {
+	atomic_t	  mausb_stop_reading_ring_events;
+	struct completion mausb_ring_has_events;
+};
+
+struct mss {
+	bool	   deinit_in_progress;
+	spinlock_t lock;	/* Protect mss structure */
+	u64	   ring_buffer_id;
+
+	struct completion empty;
+	struct completion client_stopped;
+	bool		  client_connected;
+	struct timer_list heartbeat_timer;
+	u8		  missed_heartbeats;
+
+	struct list_head  madev_list;
+	atomic_t	  num_of_transitions_to_sleep;
+	struct list_head  available_ring_buffers;
+
+	struct mausb_mss_rings_events	 rings_events;
+	struct mausb_events_notification events[MAUSB_MAX_NUM_OF_MA_DEVS];
+};
+
+struct mausb_device {
+	struct mausb_device_address dev_addr;
+	struct net		    *net_ns;
+	struct list_head	    list_entry;
+
+	struct mausb_ip_ctx *mgmt_channel;
+	struct mausb_ip_ctx *ctrl_channel;
+	struct mausb_ip_ctx *bulk_channel;
+	struct mausb_ip_ctx *isoch_channel;
+	struct mausb_ip_ctx *channel_map[MAUSB_CHANNEL_MAP_LENGTH];
+
+	struct work_struct work;
+	struct work_struct socket_disconnect_work;
+	struct work_struct hcd_disconnect_work;
+	struct work_struct madev_delete_work;
+	struct work_struct ping_work;
+	struct work_struct heartbeat_work;
+	struct workqueue_struct *workq;
+
+	struct kref refcount;
+	/* Set on port change event after cap resp */
+	u8 dev_type;
+	u8 dev_speed;
+	u8 lse;
+	u8 madev_addr;
+	u8 dev_connected;
+	u16 id;
+	u16 port_number;
+
+	u64		event_id;
+	spinlock_t	event_id_lock; /* Lock event ID increments */
+
+	struct list_head completion_events;
+	spinlock_t	 completion_events_lock; /* Lock completion events */
+
+	struct completion user_finished_event;
+	u16		  num_of_user_events;
+	u16		  num_of_completed_events;
+
+	spinlock_t	  num_of_user_events_lock; /* Lock user events count */
+
+	struct timer_list connection_timer;
+	u8		  receive_failures_num;
+	spinlock_t	  connection_timer_lock; /* Lock connection timer */
+
+	atomic_t	  unresponsive_client;
+
+	atomic_t	  num_of_usb_devices;
+};
+
+struct mausb_urb_ctx *mausb_find_urb_in_tree(struct urb *urb);
+struct mausb_urb_ctx *mausb_unlink_and_delete_urb_from_tree(struct urb *urb,
+							    int status);
+struct mausb_device *mausb_get_dev_from_addr_unsafe(u8 madev_addr);
+
+static inline u64 mausb_event_id(struct mausb_device *dev)
+{
+	unsigned long flags;
+	u64 val;
+
+	spin_lock_irqsave(&dev->event_id_lock, flags);
+	val = ++(dev->event_id);
+	spin_unlock_irqrestore(&dev->event_id_lock, flags);
+
+	return val;
+}
+
+int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
+				 struct urb *request);
+int mausb_signal_event(struct mausb_device *dev, struct mausb_event *event,
+		       u64 event_id);
+int mausb_insert_urb_in_tree(struct urb *urb, bool link_urb_to_ep);
+
+static inline void mausb_insert_event(struct mausb_device *dev,
+				      struct mausb_completion *event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->completion_events_lock, flags);
+	list_add_tail(&event->list_entry, &dev->completion_events);
+	spin_unlock_irqrestore(&dev->completion_events_lock, flags);
+}
+
+static inline void mausb_remove_event(struct mausb_device *dev,
+				      struct mausb_completion *event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->completion_events_lock, flags);
+	list_del(&event->list_entry);
+	spin_unlock_irqrestore(&dev->completion_events_lock, flags);
+}
+
+void mausb_release_ma_dev_async(struct kref *kref);
+void mausb_complete_request(struct urb *urb, u32 actual_length, int status);
+void mausb_complete_urb(struct mausb_event *event);
+void mausb_reset_connection_timer(struct mausb_device *dev);
+void mausb_reset_heartbeat_cnt(void);
+void mausb_release_event_resources(struct mausb_event  *event);
+void mausb_initialize_mss(void);
+void mausb_deinitialize_mss(void);
+int mausb_register_power_state_listener(void);
+void mausb_unregister_power_state_listener(void);
+
+void mausb_init_standard_ep_descriptor(struct ma_usb_ephandlereq_desc_std *
+				       std_desc,
+				       struct usb_endpoint_descriptor *
+				       usb_std_desc);
+void mausb_init_superspeed_ep_descriptor(struct ma_usb_ephandlereq_desc_ss *
+					 ss_desc,
+					 struct usb_endpoint_descriptor *
+					 usb_std_desc,
+					 struct usb_ss_ep_comp_descriptor *
+					 usb_ss_desc);
+
+int mausb_send_data(struct mausb_device *dev, enum mausb_channel channel_num,
+		    struct mausb_kvec_data_wrapper *data);
+
+int mausb_send_transfer_ack(struct mausb_device *dev,
+			    struct mausb_event *event);
+
+int mausb_send_data_msg(struct mausb_device *dev, struct mausb_event *event);
+
+int mausb_receive_data_msg(struct mausb_device *dev, struct mausb_event *event);
+
+int mausb_add_data_chunk(void *buffer, u32 buffer_size,
+			 struct list_head *chunks_list);
+
+int mausb_init_data_wrapper(struct mausb_kvec_data_wrapper *data,
+			    struct list_head *chunks_list,
+			    u32 num_of_data_chunks);
+
+void mausb_cleanup_chunks_list(struct list_head *chunks_list);
+
+static inline bool mausb_ctrl_transfer(struct ma_usb_hdr_common *hdr)
+{
+	return (hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK) ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL;
+}
+
+static inline bool mausb_isoch_transfer(struct ma_usb_hdr_common *hdr)
+{
+	return (hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK) ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH;
+}
+
+static inline bool mausb_ctrl_data_event(struct mausb_event *event)
+{
+	return event->data.transfer_type ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL;
+}
+
+static inline bool mausb_isoch_data_event(struct mausb_event *event)
+{
+	return event->data.transfer_type ==
+		MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH;
+}
+
+/* usb to mausb transfer type */
+static inline
+u8 mausb_transfer_type_from_usb(struct usb_endpoint_descriptor *epd)
+{
+	return (u8)usb_endpoint_type(epd) << 3;
+}
+
+static inline u8 mausb_transfer_type_from_hdr(struct ma_usb_hdr_common *hdr)
+{
+	return hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK;
+}
+
+static inline
+enum mausb_channel mausb_transfer_type_to_channel(u8 transfer_type)
+{
+	return transfer_type >> 3;
+}
+
+struct mausb_data_iter {
+	u32 length;
+
+	void *buffer;
+	u32  buffer_len;
+	u32  offset;
+
+	struct scatterlist	*sg;
+	struct sg_mapping_iter	sg_iter;
+	bool		sg_started;
+	unsigned int	num_sgs;
+	unsigned int	flags;
+};
+
+struct mausb_payload_chunk {
+	struct list_head list_entry;
+	struct kvec	 kvec;
+};
+
+int mausb_data_iterator_read(struct mausb_data_iter *iterator,
+			     u32 byte_num,
+			     struct list_head *data_chunks_list,
+			     u32 *data_chunks_num);
+
+u32 mausb_data_iterator_length(struct mausb_data_iter *iterator);
+u32 mausb_data_iterator_write(struct mausb_data_iter *iterator, void *buffer,
+			      u32 length);
+
+void mausb_init_data_iterator(struct mausb_data_iter *iterator,
+			      void *buffer, u32 buffer_len,
+			      struct scatterlist *sg, unsigned int num_sgs,
+			      bool direction);
+void mausb_reset_data_iterator(struct mausb_data_iter *iterator);
+void mausb_uninit_data_iterator(struct mausb_data_iter *iterator);
+void mausb_data_iterator_seek(struct mausb_data_iter *iterator, u32 seek_delta);
+
+static inline unsigned int mausb_get_page_order(unsigned int num_of_elems,
+						unsigned int elem_size)
+{
+	unsigned int num_of_pages = DIV_ROUND_UP(num_of_elems * elem_size,
+						 PAGE_SIZE);
+	unsigned int order = (unsigned int)ilog2(num_of_pages) +
+					(is_power_of_2(num_of_pages) ? 0 : 1);
+	return order;
+}
+
+#endif /* __MAUSB_HPAL_H__ */
diff --git a/drivers/usb/host/mausb/ma_usb.h b/drivers/usb/host/mausb/ma_usb.h
new file mode 100644
index 000000000000..65f6229c0dfe
--- /dev/null
+++ b/drivers/usb/host/mausb/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/host/mausb/mausb_address.h b/drivers/usb/host/mausb/mausb_address.h
new file mode 100644
index 000000000000..1a75482740ea
--- /dev/null
+++ b/drivers/usb/host/mausb/mausb_address.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
+ */
+#ifndef __MAUSB_MAUSB_ADDRESS_H__
+#define __MAUSB_MAUSB_ADDRESS_H__
+
+#include <linux/inet.h>
+#include <linux/types.h>
+
+struct mausb_device_address {
+	u8 link_type;
+	struct {
+		char address[INET6_ADDRSTRLEN];
+		u8 number_of_ports;
+		struct {
+			u16 management;
+			u16 control;
+			u16 bulk;
+			u16 interrupt;
+			u16 isochronous;
+		} port;
+	} ip;
+};
+
+#endif /* __MAUSB_MAUSB_ADDRESS_H__ */
diff --git a/drivers/usb/host/mausb/mausb_core.c b/drivers/usb/host/mausb/mausb_core.c
index 485f241d2b4c..e5ccf4e9173b 100644
--- a/drivers/usb/host/mausb/mausb_core.c
+++ b/drivers/usb/host/mausb/mausb_core.c
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 
 #include "hcd.h"
+#include "mausb_address.h"
 #include "utils.h"
 
 MODULE_LICENSE("GPL");
@@ -21,8 +22,16 @@ static int mausb_host_init(void)
 	if (status < 0)
 		goto cleanup_dev;
 
+	status = mausb_register_power_state_listener();
+	if (status < 0)
+		goto cleanup;
+
+	mausb_initialize_mss();
+
 	return 0;
 
+cleanup:
+	mausb_deinit_hcd();
 cleanup_dev:
 	mausb_host_dev_deregister();
 exit:
@@ -32,6 +41,8 @@ static int mausb_host_init(void)
 static void mausb_host_exit(void)
 {
 	dev_info(mausb_host_dev.this_device, "Module unloading started...");
+	mausb_unregister_power_state_listener();
+	mausb_deinitialize_mss();
 	mausb_deinit_hcd();
 	mausb_host_dev_deregister();
 }
diff --git a/drivers/usb/host/mausb/mausb_event.h b/drivers/usb/host/mausb/mausb_event.h
new file mode 100644
index 000000000000..a574f67d789d
--- /dev/null
+++ b/drivers/usb/host/mausb/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 {
+	uintptr_t urb;
+	uintptr_t recv_buf;
+	u32 iterator_seek_delta;
+	u32 transfer_size;
+	u32 rem_transfer_size;
+	u32 transfer_flags;
+	u32 isoch_seg_num;
+	u32 req_id;
+	u32 payload_size;
+	s32 status;
+
+	__aligned(4) char hdr[MAUSB_TRANSFER_HDR_SIZE];
+	__aligned(4) char hdr_ack[MAUSB_TRANSFER_HDR_SIZE];
+
+	u16 device_id;
+	u16 ep_handle;
+	u16 packet_size;
+	u8  setup_packet;
+	u8  direction;
+	u8  transfer_type;
+	u8  first_control_packet;
+	u8  transfer_eot;
+	u8  mausb_address;
+	u8  mausb_ssid;
+};
+
+struct mausb_port_changed_event {
+	u8 port;
+	u8 dev_type;
+	u8 dev_speed;
+	u8 lse;
+};
+
+struct mausb_event {
+	union {
+		struct mausb_mgmt_event		mgmt;
+		struct mausb_data_event		data;
+		struct mausb_port_changed_event port_changed;
+	};
+	s32 status;
+	u8 type;
+	u8 madev_addr;
+};
+
+struct mausb_events_notification {
+	u16 num_of_events;
+	u16 num_of_completed_events;
+	u8  madev_addr;
+};
+
+#endif /* __MAUSB_MAUSB_EVENT_H__ */
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ