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

Signed-off-by: Vladimir Stankovic <[email protected]>
---
 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

Reply via email to