lkml.org 
[lkml]   [2020]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v5 7/8] usb: mausb_host: MA-USB PAL events processing
    Date
    Implemented MA-USB management messages processing and communication
    with user-space driver via mapped memory.

    MA USB PAL events are being enqueued into ring buffer from which
    data is being send/received to/from user-space.

    Signed-off-by: Vladimir Stankovic <vladimir.stankovic@displaylink.com>
    ---
    drivers/usb/mausb_host/Makefile | 1 +
    drivers/usb/mausb_host/hcd.c | 245 +++++++-
    drivers/usb/mausb_host/hpal.c | 449 +++++++++++++-
    drivers/usb/mausb_host/hpal.h | 44 ++
    drivers/usb/mausb_host/hpal_events.c | 611 +++++++++++++++++++
    drivers/usb/mausb_host/hpal_events.h | 85 +++
    drivers/usb/mausb_host/mausb_driver_status.h | 17 +
    drivers/usb/mausb_host/utils.c | 273 +++++++++
    drivers/usb/mausb_host/utils.h | 5 +
    9 files changed, 1720 insertions(+), 10 deletions(-)
    create mode 100644 drivers/usb/mausb_host/hpal_events.c
    create mode 100644 drivers/usb/mausb_host/hpal_events.h
    create mode 100644 drivers/usb/mausb_host/mausb_driver_status.h

    diff --git a/drivers/usb/mausb_host/Makefile b/drivers/usb/mausb_host/Makefile
    index 829314b15cbb..fd2a36a04ad6 100644
    --- a/drivers/usb/mausb_host/Makefile
    +++ b/drivers/usb/mausb_host/Makefile
    @@ -11,5 +11,6 @@ mausb_host-y += utils.o
    mausb_host-y += ip_link.o
    mausb_host-y += hcd.o
    mausb_host-y += hpal.o
    +mausb_host-y += hpal_events.o

    ccflags-y += -I$(srctree)/$(src)
    diff --git a/drivers/usb/mausb_host/hcd.c b/drivers/usb/mausb_host/hcd.c
    index 5967c30d49a3..3e14add3e309 100644
    --- a/drivers/usb/mausb_host/hcd.c
    +++ b/drivers/usb/mausb_host/hcd.c
    @@ -10,6 +10,7 @@
    #include <linux/module.h>

    #include "hpal.h"
    +#include "hpal_events.h"
    #include "utils.h"

    static int mausb_open(struct inode *inode, struct file *file);
    @@ -1073,6 +1074,18 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
    }

    if (ep_ctx) {
    + status = mausb_epinactivate_event_to_user(ma_dev, dev_handle,
    + ep_ctx->ep_handle);
    +
    + mausb_pr_info("epinactivate request ep_handle=%#x, dev_handle=%#x, status=%d",
    + ep_ctx->ep_handle, dev_handle, status);
    +
    + status = mausb_epdelete_event_to_user(ma_dev, dev_handle,
    + ep_ctx->ep_handle);
    +
    + if (status < 0)
    + mausb_pr_warn("ep_handle_del request failed for ep0: ep_handle=%#x, dev_handle=%#x",
    + ep_ctx->ep_handle, dev_handle);
    dev->ep0.hcpriv = NULL;
    kfree(ep_ctx);

    @@ -1080,6 +1093,14 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
    mausb_pr_warn("ep_ctx is NULL: dev_handle=%#x", dev_handle);
    }

    + if (dev_handle != DEV_HANDLE_NOT_ASSIGNED) {
    + status = mausb_usbdevdisconnect_event_to_user(ma_dev,
    + dev_handle);
    + if (status < 0)
    + mausb_pr_warn("usb_dev_disconnect req failed for dev_handle=%#x",
    + dev_handle);
    + }
    +
    free_dev:
    if (atomic_sub_and_test(1, &ma_dev->num_of_usb_devices)) {
    mausb_pr_info("All usb devices destroyed - proceed with disconnecting");
    @@ -1094,6 +1115,21 @@ static void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
    mausb_clear_hcd_madev(port_number);
    }

    +static int mausb_device_assign_address(struct mausb_device *dev,
    + struct mausb_usb_device_ctx *usb_dev_ctx)
    +{
    + int status =
    + mausb_setusbdevaddress_event_to_user(dev,
    + usb_dev_ctx->dev_handle,
    + RESPONSE_TIMEOUT);
    +
    + mausb_pr_info("dev_handle=%#x, status=%d", usb_dev_ctx->dev_handle,
    + status);
    + usb_dev_ctx->addressed = (status == 0);
    +
    + return status;
    +}
    +
    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,
    @@ -1176,6 +1212,12 @@ static int mausb_address_device(struct usb_hcd *hcd, struct usb_device *dev)
    return status;
    }

    + if (!usb_device_ctx->addressed) {
    + status = mausb_device_assign_address(ma_dev, usb_device_ctx);
    + if (status < 0)
    + return status;
    + }
    +
    endpoint_ctx = dev->ep0.hcpriv;
    if (!endpoint_ctx) {
    mausb_pr_err("endpoint_ctx is NULL: dev_handle=%#x",
    @@ -1183,7 +1225,19 @@ static int mausb_address_device(struct usb_hcd *hcd, struct usb_device *dev)
    return -EINVAL;
    }

    - return 0;
    + if (dev->speed < USB_SPEED_SUPER && endpoint_ctx->ep_handle != 0)
    + return 0;
    +
    + status = mausb_modifyep0_event_to_user(ma_dev,
    + usb_device_ctx->dev_handle,
    + &endpoint_ctx->ep_handle,
    + dev->ep0.desc.wMaxPacketSize);
    +
    + mausb_pr_info("modify ep0 response, ep_handle=%#x, dev_handle=%#x, status=%d",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle,
    + status);
    +
    + return status;
    }

    static int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
    @@ -1236,10 +1290,32 @@ static int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
    mausb_init_superspeed_ep_descriptor(&descriptor_ss,
    &endpoint->desc,
    &endpoint->ss_ep_comp);
    + status = mausb_ephandle_event_to_user(ma_dev,
    + usb_dev_ctx->dev_handle,
    + sizeof(descriptor_ss),
    + &descriptor_ss,
    + &endpoint_ctx->ep_handle);
    +
    } else {
    mausb_init_standard_ep_descriptor(&descriptor, &endpoint->desc);
    + status = mausb_ephandle_event_to_user(ma_dev,
    + usb_dev_ctx->dev_handle,
    + sizeof(descriptor),
    + &descriptor,
    + &endpoint_ctx->ep_handle);
    }

    + if (status < 0) {
    + mausb_pr_err("ep_handle_request failed dev_handle=%#x",
    + usb_dev_ctx->dev_handle);
    + endpoint->hcpriv = NULL;
    + kfree(endpoint_ctx);
    + return status;
    + }
    +
    + mausb_pr_info("Endpoint added ep_handle=%#x, dev_handle=%#x",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle);
    +
    return 0;
    }

    @@ -1248,6 +1324,7 @@ static int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
    {
    u8 port_number;
    int status;
    + int retries = 0;
    struct hub_ctx *hub = (struct hub_ctx *)hcd->hcd_priv;
    struct mausb_device *ma_dev;
    struct mausb_usb_device_ctx *usb_dev_ctx;
    @@ -1282,9 +1359,49 @@ static int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
    return -ENODEV;
    }

    + mausb_pr_info("Start dropping ep_handle=%#x, dev_handle=%#x",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle);
    +
    + if (atomic_read(&ma_dev->unresponsive_client)) {
    + mausb_pr_err("Client is not responsive anymore - drop endpoint immediately");
    + endpoint->hcpriv = NULL;
    + kfree(endpoint_ctx);
    + return -ESHUTDOWN;
    + }
    +
    + status = mausb_epinactivate_event_to_user(ma_dev,
    + usb_dev_ctx->dev_handle,
    + endpoint_ctx->ep_handle);
    +
    + mausb_pr_info("epinactivate request ep_handle=%#x, dev_handle=%#x, status=%d",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle,
    + status);
    +
    + while (true) {
    + status = mausb_epdelete_event_to_user(ma_dev,
    + usb_dev_ctx->dev_handle,
    + endpoint_ctx->ep_handle);
    +
    + mausb_pr_info("ep_handle_delete_request, ep_handle=%#x, dev_handle=%#x, status=%d",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle,
    + status);
    +
    + if (status == -EBUSY) {
    + if (++retries < MAUSB_BUSY_RETRIES_COUNT)
    + usleep_range(10000, 10001);
    + else
    + return -EBUSY;
    + } else {
    + break;
    + }
    + }
    +
    + mausb_pr_info("Endpoint dropped ep_handle=%#x, dev_handle=%#x",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle);
    +
    endpoint->hcpriv = NULL;
    kfree(endpoint_ctx);
    - return 0;
    + return status;
    }

    static int mausb_device_assign_dev_handle(struct usb_hcd *hcd,
    @@ -1337,6 +1454,20 @@ static int mausb_device_assign_dev_handle(struct usb_hcd *hcd,
    return -EINVAL;
    }

    + status = mausb_usbdevhandle_event_to_user(ma_dev, (u8)dev_speed,
    + dev->route, hub_dev_handle,
    + parent_hs_hub_dev_handle,
    + parent_hs_hub_port, 0,
    + ma_dev->lse,
    + &usb_device_ctx->dev_handle);
    +
    + mausb_pr_info("mausb_usbdevhandle_event status=%d", status);
    +
    + if (status < 0)
    + return status;
    +
    + mausb_pr_info("Get ref dev_handle=%#x", usb_device_ctx->dev_handle);
    +
    endpoint_ctx = kzalloc(sizeof(*endpoint_ctx), GFP_ATOMIC);
    if (!endpoint_ctx)
    return -ENOMEM;
    @@ -1348,6 +1479,22 @@ static int mausb_device_assign_dev_handle(struct usb_hcd *hcd,

    mausb_init_standard_ep_descriptor(&descriptor, &dev->ep0.desc);

    + status = mausb_ephandle_event_to_user(ma_dev,
    + usb_device_ctx->dev_handle,
    + sizeof(descriptor),
    + &descriptor,
    + &endpoint_ctx->ep_handle);
    +
    + mausb_pr_info("mausb_ephandle_event ep_handle=%#x, dev_handle=%#x, status=%d",
    + endpoint_ctx->ep_handle, endpoint_ctx->dev_handle,
    + status);
    +
    + if (status < 0) {
    + dev->ep0.hcpriv = NULL;
    + kfree(endpoint_ctx);
    + return status;
    + }
    +
    return 0;
    }

    @@ -1385,9 +1532,18 @@ static int mausb_enable_device(struct usb_hcd *hcd, struct usb_device *dev)
    return status;
    }

    + mausb_pr_info("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);
    +
    + if (!usb_device_ctx->addressed)
    + return mausb_device_assign_address(ma_dev, usb_device_ctx);
    +
    + mausb_pr_info("Device assigned and addressed dev_handle=%#x",
    + usb_device_ctx->dev_handle);
    return 0;
    }

    @@ -1433,7 +1589,15 @@ static int mausb_update_device(struct usb_hcd *hcd, struct usb_device *dev)
    return -ENODEV;
    }

    - return 0;
    + status = mausb_updatedev_event_to_user(ma_dev,
    + usb_device_ctx->dev_handle,
    + 0, 0, 0, 0, 0, 0,
    + &dev->descriptor);
    +
    + mausb_pr_info("Finished dev_handle=%#x, status=%d",
    + usb_device_ctx->dev_handle, status);
    +
    + return status;
    }

    static int mausb_hub_update_device(struct usb_hcd *hcd, struct usb_device *dev,
    @@ -1443,8 +1607,10 @@ static int mausb_hub_update_device(struct usb_hcd *hcd, struct usb_device *dev,
    u8 port_number;
    unsigned long flags;
    u16 max_exit_latency = 0;
    + u8 number_of_ports = (u8)dev->maxchild;
    u8 mtt = 0;
    u8 ttt = 0;
    + u8 integrated_hub_latency = 0;
    struct hub_ctx *hub = (struct hub_ctx *)hcd->hcd_priv;
    struct mausb_device *ma_dev;
    struct mausb_usb_device_ctx *usb_device_ctx;
    @@ -1484,7 +1650,17 @@ static int mausb_hub_update_device(struct usb_hcd *hcd, struct usb_device *dev,
    else if (dev->usb3_lpm_u2_enabled)
    max_exit_latency = (u16)dev->u2_params.mel;

    - return 0;
    + status = mausb_updatedev_event_to_user(ma_dev,
    + usb_device_ctx->dev_handle,
    + max_exit_latency, 1,
    + number_of_ports, mtt, ttt,
    + integrated_hub_latency,
    + &dev->descriptor);
    +
    + mausb_pr_info("Finished dev_handle=%#x, status=%d",
    + usb_device_ctx->dev_handle, status);
    +
    + return status;
    }

    static int mausb_check_bandwidth(struct usb_hcd *hcd, struct usb_device *dev)
    @@ -1520,6 +1696,8 @@ static void mausb_endpoint_reset(struct usb_hcd *hcd,
    struct mausb_usb_device_ctx *usb_device_ctx;
    struct usb_device *dev;
    struct mausb_endpoint_ctx *ep_ctx;
    + struct ma_usb_ephandlereq_desc_ss descriptor_ss;
    + struct ma_usb_ephandlereq_desc_std descriptor;

    ep_ctx = endpoint->hcpriv;
    if (!ep_ctx) {
    @@ -1554,6 +1732,15 @@ static void mausb_endpoint_reset(struct usb_hcd *hcd,
    is_out = usb_endpoint_dir_out(&endpoint->desc);
    tsp = (u8)(is_out ? dev->toggle[1] : dev->toggle[0]);

    + status = mausb_epreset_event_to_user(ma_dev, dev_handle,
    + ep_ctx->ep_handle, tsp);
    +
    + mausb_pr_info("ep_reset status=%d, ep_handle=%#x, dev_handle=%#x",
    + status, ep_ctx->ep_handle, dev_handle);
    +
    + if (status < 0)
    + return;
    +
    if (status != EUCLEAN) {
    if (!tsp) {
    usb_settoggle(dev, epnum, is_out, 0U);
    @@ -1561,12 +1748,52 @@ static void mausb_endpoint_reset(struct usb_hcd *hcd,
    usb_settoggle(dev, epnum, !is_out, 0U);
    }

    + status = mausb_epactivate_event_to_user(ma_dev, dev_handle,
    + ep_ctx->ep_handle);
    +
    + mausb_pr_err("ep_activate failed, status=%d, ep_handle=%#x, dev_handle=%#x",
    + status, ep_ctx->ep_handle, dev_handle);
    +
    return;
    }

    if (tsp)
    return;

    + status = mausb_epinactivate_event_to_user(ma_dev, dev_handle,
    + ep_ctx->ep_handle);
    +
    + mausb_pr_info("ep_inactivate status=%d, ep_handle=%#x, dev_handle=%#x",
    + status, ep_ctx->ep_handle, dev_handle);
    +
    + if (status < 0)
    + return;
    +
    + status = mausb_epdelete_event_to_user(ma_dev, dev_handle,
    + ep_ctx->ep_handle);
    +
    + mausb_pr_info("ep_handle_delete status=%d, ep_handle=%#x, dev_handle=%#x",
    + status, ep_ctx->ep_handle, dev_handle);
    +
    + if (status < 0)
    + return;
    +
    + if (dev->speed >= USB_SPEED_SUPER) {
    + mausb_init_superspeed_ep_descriptor(&descriptor_ss,
    + &endpoint->desc,
    + &endpoint->ss_ep_comp);
    + status = mausb_ephandle_event_to_user(ma_dev, dev_handle,
    + sizeof(descriptor_ss),
    + &descriptor_ss,
    + &ep_ctx->ep_handle);
    + } else {
    + mausb_init_standard_ep_descriptor(&descriptor, &endpoint->desc);
    + status = mausb_ephandle_event_to_user(ma_dev, dev_handle,
    + sizeof(descriptor),
    + &descriptor,
    + &ep_ctx->ep_handle);
    + }
    +
    mausb_pr_info("ep_handle request status=%d, ep_handle=%#x, dev_handle=%#x",
    status, ep_ctx->ep_handle, dev_handle);
    }
    @@ -1608,7 +1835,15 @@ static int mausb_reset_device(struct usb_hcd *hcd, struct usb_device *dev)

    dev_handle = usb_device_ctx->dev_handle;

    - return 0;
    + status = mausb_usbdevreset_event_to_user(ma_dev, dev_handle);
    +
    + mausb_pr_info("usb_dev_reset dev_handle=%#x, status=%d",
    + dev_handle, status);
    +
    + if (status == 0)
    + usb_device_ctx->addressed = false;
    +
    + return status;
    }

    void mausb_clear_hcd_madev(u16 port_number)
    diff --git a/drivers/usb/mausb_host/hpal.c b/drivers/usb/mausb_host/hpal.c
    index 74bebc03d7e6..bf678f2707b9 100644
    --- a/drivers/usb/mausb_host/hpal.c
    +++ b/drivers/usb/mausb_host/hpal.c
    @@ -11,6 +11,7 @@
    #include <linux/uio.h>

    #include "hcd.h"
    +#include "hpal_events.h"
    #include "utils.h"

    #define MAUSB_DELETE_MADEV_TIMEOUT_MS 3000
    @@ -278,6 +279,31 @@ void mausb_release_event_resources(struct mausb_event *event)
    kfree(receive_buffer);
    }

    +static void mausb_iterator_reset(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + struct urb *urb = (struct urb *)event->data.urb;
    + struct mausb_urb_ctx *urb_ctx;
    +
    + urb_ctx = mausb_find_urb_in_tree(urb);
    +
    + if (urb_ctx)
    + mausb_reset_data_iterator(&urb_ctx->iterator);
    +}
    +
    +static void mausb_iterator_seek(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + struct urb *urb = (struct urb *)event->data.urb;
    + struct mausb_urb_ctx *urb_ctx;
    +
    + urb_ctx = mausb_find_urb_in_tree(urb);
    +
    + if (urb_ctx)
    + mausb_data_iterator_seek(&urb_ctx->iterator,
    + event->data.iterator_seek_delta);
    +}
    +
    void mausb_complete_urb(struct mausb_event *event)
    {
    struct urb *urb = (struct urb *)event->data.urb;
    @@ -291,6 +317,46 @@ void mausb_complete_urb(struct mausb_event *event)
    event->status);
    }

    +static void mausb_delete_ma_dev(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + mausb_signal_event(dev, event, event->mgmt.delete_ma_dev.event_id);
    +}
    +
    +static void mausb_process_user_finished(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + complete(&dev->user_finished_event);
    +}
    +
    +static int mausb_send_mgmt_msg(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + struct mausb_kvec_data_wrapper wrapper;
    + struct kvec kvec;
    + struct ma_usb_hdr_common *hdr;
    + int status;
    +
    + hdr = (struct ma_usb_hdr_common *)event->mgmt.mgmt_hdr.hdr;
    +
    + mausb_pr_info("event=%d, type=%d", event->type, hdr->type);
    +
    + kvec.iov_base = hdr;
    + kvec.iov_len = hdr->length;
    + wrapper.kvec = &kvec;
    + wrapper.kvec_num = 1;
    + wrapper.length = hdr->length;
    +
    + status = mausb_ip_send(dev->mgmt_channel, &wrapper);
    + if (status < 0) {
    + mausb_pr_err("Send failed. Disconnecting... status=%d", status);
    + queue_work(dev->workq, &dev->socket_disconnect_work);
    + queue_work(dev->workq, &dev->hcd_disconnect_work);
    + }
    +
    + return status;
    +}
    +
    static int mausb_get_first_free_port_number(u16 *port_number)
    {
    (*port_number) = 0;
    @@ -338,11 +404,142 @@ static inline void mausb_port_has_changed_event(struct mausb_device *dev,
    mausb_port_has_changed(USB20HUB, HIGH_SPEED, dev);
    }

    +static void mausb_complete_timeout_event(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + mausb_pr_debug("Event type=%d, event_id=%llu", event->type,
    + event->mgmt.mgmt_req_timedout.event_id);
    + mausb_signal_event(dev, event, event->mgmt.mgmt_req_timedout.event_id);
    +}
    +
    +static void mausb_process_event(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + mausb_pr_debug("Event type=%d", event->type);
    +
    + switch (event->type) {
    + case MAUSB_EVENT_TYPE_USB_DEV_HANDLE:
    + mausb_usbdevhandle_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_EP_HANDLE:
    + mausb_ephandle_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_EP_HANDLE_ACTIVATE:
    + mausb_epactivate_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_EP_HANDLE_INACTIVATE:
    + mausb_epinactivate_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_EP_HANDLE_RESET:
    + mausb_epreset_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_EP_HANDLE_DELETE:
    + mausb_epdelete_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_MODIFY_EP0:
    + mausb_modifyep0_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_SET_USB_DEV_ADDRESS:
    + mausb_setusbdevaddress_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_UPDATE_DEV:
    + mausb_updatedev_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_USB_DEV_RESET:
    + mausb_usbdevreset_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_CANCEL_TRANSFER:
    + mausb_canceltransfer_event_from_user(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_PORT_CHANGED:
    + mausb_port_has_changed_event(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_PING:
    + mausb_send_mgmt_msg(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_SEND_MGMT_MSG:
    + mausb_send_mgmt_msg(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_SEND_DATA_MSG:
    + mausb_send_data_msg(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_RECEIVED_DATA_MSG:
    + mausb_receive_data_msg(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_URB_COMPLETE:
    + mausb_complete_urb(event);
    + break;
    + case MAUSB_EVENT_TYPE_SEND_ACK:
    + mausb_send_transfer_ack(dev, event);
    + mausb_release_event_resources(event);
    + break;
    + case MAUSB_EVENT_TYPE_ITERATOR_RESET:
    + mausb_iterator_reset(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_ITERATOR_SEEK:
    + mausb_iterator_seek(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_DELETE_MA_DEV:
    + mausb_delete_ma_dev(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_USER_FINISHED:
    + mausb_process_user_finished(dev, event);
    + break;
    + case MAUSB_EVENT_TYPE_RELEASE_EVENT_RESOURCES:
    + mausb_release_event_resources(event);
    + break;
    + case MAUSB_EVENT_TYPE_NONE:
    + mausb_release_event_resources(event);
    + break;
    + case MAUSB_EVENT_TYPE_MGMT_REQUEST_TIMED_OUT:
    + mausb_complete_timeout_event(dev, event);
    + break;
    + default:
    + break;
    + }
    +
    + mausb_notify_completed_user_events(dev->ring_buffer);
    +}
    +
    +static void mausb_hpal_kernel_work(struct work_struct *work)
    +{
    + struct mausb_device *dev = container_of(work, struct mausb_device,
    + work);
    + struct mausb_event *event;
    + int status;
    + u16 i;
    + u16 events;
    + u16 completed_events;
    + unsigned long flags;
    + struct mausb_ring_buffer *dev_mausb_ring = dev->ring_buffer;
    +
    + spin_lock_irqsave(&dev->num_of_user_events_lock, flags);
    + events = dev->num_of_user_events;
    + completed_events = dev->num_of_completed_events;
    + dev->num_of_user_events = 0;
    + dev->num_of_completed_events = 0;
    + spin_unlock_irqrestore(&dev->num_of_user_events_lock, flags);
    +
    + status = mausb_ring_buffer_move_tail(dev_mausb_ring, completed_events);
    + if (status < 0) {
    + mausb_pr_err("Dequeue failed, status=%d", status);
    + kref_put(&dev->refcount, mausb_release_ma_dev_async);
    + return;
    + }
    +
    + for (i = 0; i < events; ++i) {
    + event = mausb_ring_current_from_user(dev_mausb_ring);
    + mausb_ring_next_from_user(dev_mausb_ring);
    + mausb_process_event(dev, event);
    + }
    +}
    +
    static void mausb_socket_disconnect_event(struct work_struct *work)
    {
    struct mausb_device *dev = container_of(work, struct mausb_device,
    socket_disconnect_work);
    struct mausb_event event;
    + int status;

    mausb_pr_info("madev_addr=%d", dev->madev_addr);

    @@ -363,6 +560,11 @@ static void mausb_socket_disconnect_event(struct work_struct *work)
    event.type = MAUSB_EVENT_TYPE_NETWORK_DISCONNECTED;
    event.data.device_id = dev->id;

    + status = mausb_enqueue_event_to_user(dev, &event);
    +
    + mausb_pr_info("Sending notification to user that network is disconnected status=%d",
    + status);
    +
    mausb_pr_info("Releasing MAUSB device ref");
    kref_put(&dev->refcount, mausb_release_ma_dev_async);
    }
    @@ -427,6 +629,13 @@ static void mausb_delete_madev(struct work_struct *work)

    mausb_insert_event(dev, &mausb_completion);

    + status = mausb_enqueue_event_to_user(dev, &event);
    + if (status < 0) {
    + mausb_remove_event(dev, &mausb_completion);
    + mausb_pr_err("Ring buffer full, enqueue failed");
    + return;
    + }
    +
    mausb_pr_debug("Deleting MAUSB device...");

    status = wait_for_completion_interruptible_timeout(&completion,
    @@ -449,10 +658,14 @@ static void mausb_delete_madev(struct work_struct *work)

    mausb_clear_hcd_madev(dev->port_number);

    + mausb_ring_buffer_cleanup(dev->ring_buffer);
    + mausb_ring_buffer_destroy(dev->ring_buffer);
    +
    mausb_remove_madev_from_list(dev->madev_addr);

    put_net(dev->net_ns);

    + kfree(dev->ring_buffer);
    kfree(dev);
    mausb_signal_empty_mss();

    @@ -463,6 +676,7 @@ static void mausb_ping_work(struct work_struct *work)
    {
    struct mausb_device *dev = container_of(work, struct mausb_device,
    ping_work);
    + int status = 0;

    if (mausb_start_connection_timer(dev) < 0) {
    mausb_pr_err("Device disconnecting due to session timeout madev_addr=%d",
    @@ -471,6 +685,13 @@ static void mausb_ping_work(struct work_struct *work)
    queue_work(dev->workq, &dev->hcd_disconnect_work);
    return;
    }
    +
    + status = mausb_ping_event_to_user(dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Ring buffer full");
    + return;
    + }
    }

    static void mausb_heartbeat_work(struct work_struct *work)
    @@ -576,6 +797,7 @@ mausb_create_madev(struct mausb_device_address dev_addr, u8 madev_address,

    dev->workq = workq;

    + INIT_WORK(&dev->work, mausb_hpal_kernel_work);
    INIT_WORK(&dev->socket_disconnect_work, mausb_socket_disconnect_event);
    INIT_WORK(&dev->hcd_disconnect_work, mausb_hcd_disconnect_event);
    INIT_WORK(&dev->madev_delete_work, mausb_delete_madev);
    @@ -601,6 +823,15 @@ mausb_create_madev(struct mausb_device_address dev_addr, u8 madev_address,
    dev->madev_addr = madev_address;
    dev->net_ns = get_net(current->nsproxy->net_ns);

    + if (!list_empty(&mss.available_ring_buffers)) {
    + dev->ring_buffer = container_of(mss.available_ring_buffers.next,
    + struct mausb_ring_buffer,
    + list_entry);
    + list_del(mss.available_ring_buffers.next);
    + } else {
    + mausb_pr_alert("Ring buffer for mausb device is not availbale!");
    + }
    +
    list_add_tail(&dev->list_entry, &mss.madev_list);

    reinit_completion(&mss.empty);
    @@ -659,6 +890,14 @@ int mausb_initiate_dev_connection(struct mausb_device_address dev_addr,
    return 0;
    }

    +void mausb_on_madev_connected(struct mausb_device *dev)
    +{
    + struct mausb_event mausb_event;
    +
    + mausb_dev_reset_req_event(&mausb_event);
    + mausb_enqueue_event_to_user(dev, &mausb_event);
    +}
    +
    int mausb_enqueue_event_from_user(u8 madev_addr, u16 num_of_events,
    u16 num_of_completed)
    {
    @@ -683,9 +922,29 @@ int mausb_enqueue_event_from_user(u8 madev_addr, u16 num_of_events,
    return 0;
    }

    +int mausb_enqueue_event_to_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + int status;
    +
    + event->madev_addr = dev->madev_addr;
    + status = mausb_ring_buffer_put(dev->ring_buffer, event);
    + if (status < 0) {
    + mausb_pr_err("Ring buffer operation failed");
    + mausb_cleanup_ring_buffer_event(event);
    + return status;
    + }
    +
    + mausb_notify_ring_events(dev->ring_buffer);
    + mausb_pr_debug("User-space notification sent.");
    +
    + return 0;
    +}
    +
    int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
    struct urb *request)
    {
    + int status;
    struct mausb_event mausb_event;

    mausb_event.type = MAUSB_EVENT_TYPE_SEND_DATA_MSG;
    @@ -728,7 +987,12 @@ int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
    &request->dev->route, sizeof(request->dev->route));
    }

    - return 0;
    + status = mausb_enqueue_event_to_user(dev, &mausb_event);
    + if (status < 0)
    + mausb_pr_err("Failed to enqueue event to user-space ep_handle=%#x, status=%d",
    + mausb_event.data.ep_handle, status);
    +
    + return status;
    }

    void mausb_complete_request(struct urb *urb, u32 actual_length, int status)
    @@ -841,6 +1105,17 @@ static void mausb_execute_urb_dequeue(struct work_struct *dequeue_work)
    mausb_pr_debug("urb=%p, ep_handle=%#x, dev_handle=%#x",
    urb, ep_ctx->ep_handle, ep_ctx->dev_handle);

    + if (!usb_endpoint_xfer_isoc(&urb->ep->desc)) {
    + status = mausb_canceltransfer_event_to_user(ep_ctx->ma_dev,
    + ep_ctx->dev_handle,
    + ep_ctx->ep_handle,
    + (uintptr_t)urb);
    + if (status < 0) {
    + mausb_pr_err("Failed to enqueue cancel transfer to user");
    + goto complete_urb;
    + }
    + }
    +
    memset(&mausb_event, 0, sizeof(mausb_event));

    mausb_event.type = MAUSB_EVENT_TYPE_DELETE_DATA_TRANSFER;
    @@ -855,6 +1130,13 @@ static void mausb_execute_urb_dequeue(struct work_struct *dequeue_work)
    MAUSB_DATA_MSG_DIRECTION_IN :
    MAUSB_DATA_MSG_DIRECTION_OUT);

    + status = mausb_enqueue_event_to_user(ep_ctx->ma_dev, &mausb_event);
    + if (status < 0) {
    + mausb_pr_alert("Failed to enqueue event to user-space ep_handle=%#x, status=%d",
    + mausb_event.data.ep_handle, status);
    + goto complete_urb;
    + }
    +
    if (!mausb_return_urb_ctx_to_tree(urb_ctx, false)) {
    mausb_pr_alert("Failed to insert in tree urb=%p ep_handle=%#x, status=%d",
    urb, mausb_event.data.ep_handle, status);
    @@ -916,6 +1198,7 @@ void mausb_deinitialize_mss(void)

    wait_for_completion(&mss.empty);
    mausb_pr_debug("Waiting for completion on disconnect_event ended");
    + mausb_stop_ring_events();

    timeout = wait_for_completion_timeout(&mss.client_stopped, timeout);
    mausb_pr_info("Remaining time after waiting for stopping client %ld",
    @@ -1104,7 +1387,6 @@ 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)
    {
    struct mausb_urb_ctx *urb_ctx;
    - int status = 0;

    if (event->status != 0) {
    mausb_pr_err("Event %d failed with status %d",
    @@ -1119,10 +1401,9 @@ int mausb_send_data_msg(struct mausb_device *dev, struct mausb_event *event)
    /* Transfer will be deleted from dequeue task */
    mausb_pr_warn("Urb is already cancelled for event=%d",
    event->type);
    - return status;
    }

    - return status;
    + return 0;
    }

    int mausb_receive_data_msg(struct mausb_device *dev, struct mausb_event *event)
    @@ -1142,8 +1423,10 @@ int mausb_receive_data_msg(struct mausb_device *dev, struct mausb_event *event)

    urb_ctx = mausb_find_urb_in_tree((struct urb *)event->data.urb);

    - if (!urb_ctx)
    + if (!urb_ctx) {
    + /* Transfer will be deleted from dequeue task */
    mausb_pr_warn("Urb is already cancelled");
    + }

    cleanup:
    mausb_release_event_resources(event);
    @@ -1279,6 +1562,7 @@ static void mausb_connect_callback(struct mausb_device *dev,
    if (channel == MAUSB_ISOCH_CHANNEL) {
    dev->channel_map[MAUSB_INTR_CHANNEL] =
    dev->channel_map[MAUSB_CTRL_CHANNEL];
    + mausb_on_madev_connected(dev);
    }
    }

    @@ -1305,6 +1589,16 @@ static void mausb_handle_receive_event(struct mausb_device *dev,
    }

    mausb_reset_connection_timer(dev);
    +
    + status = mausb_msg_received_event(&event,
    + (struct ma_usb_hdr_common *)data,
    + channel);
    +
    + if (status == 0)
    + status = mausb_enqueue_event_to_user(dev, &event);
    +
    + if (status < 0)
    + mausb_pr_err("Failed to enqueue, status=%d", status);
    }

    void mausb_ip_callback(void *ctx, enum mausb_channel channel,
    @@ -1614,3 +1908,148 @@ u32 mausb_data_iterator_length(struct mausb_data_iter *iterator)
    {
    return iterator->length;
    }
    +
    +static int mausb_ring_buffer_get(struct mausb_ring_buffer *ring,
    + struct mausb_event *event)
    +{
    + unsigned long flags = 0;
    +
    + spin_lock_irqsave(&ring->lock, flags);
    + if (CIRC_CNT(ring->head, ring->tail, MAUSB_RING_BUFFER_SIZE) < 1) {
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return -ENOSPC;
    + }
    + memcpy(event, ring->to_user_buffer + ring->tail, sizeof(*event));
    + mausb_pr_debug("HEAD=%d, TAIL=%d", ring->head, ring->tail);
    + ring->tail = (ring->tail + 1) & (MAUSB_RING_BUFFER_SIZE - 1);
    + mausb_pr_debug("HEAD=%d, TAIL=%d", ring->head, ring->tail);
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return 0;
    +}
    +
    +int mausb_ring_buffer_init(struct mausb_ring_buffer *ring)
    +{
    + unsigned int page_order =
    + mausb_get_page_order(2 * MAUSB_RING_BUFFER_SIZE,
    + sizeof(struct mausb_event));
    + ring->to_user_buffer =
    + (struct mausb_event *)__get_free_pages(GFP_KERNEL, page_order);
    + if (!ring->to_user_buffer)
    + return -ENOMEM;
    + ring->from_user_buffer = ring->to_user_buffer + MAUSB_RING_BUFFER_SIZE;
    + ring->head = 0;
    + ring->tail = 0;
    + ring->current_from_user = 0;
    + ring->buffer_full = false;
    + spin_lock_init(&ring->lock);
    +
    + return 0;
    +}
    +
    +int mausb_ring_buffer_put(struct mausb_ring_buffer *ring,
    + struct mausb_event *event)
    +{
    + unsigned long flags = 0;
    +
    + spin_lock_irqsave(&ring->lock, flags);
    +
    + if (ring->buffer_full) {
    + mausb_pr_err("Ring buffer is full");
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return -ENOSPC;
    + }
    +
    + if (CIRC_SPACE(ring->head, ring->tail, MAUSB_RING_BUFFER_SIZE) < 2) {
    + mausb_pr_err("Ring buffer capacity exceeded, disconnecting device");
    + ring->buffer_full = true;
    + mausb_disconect_event_unsafe(ring, event->madev_addr);
    + ring->head = (ring->head + 1) & (MAUSB_RING_BUFFER_SIZE - 1);
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return -ENOSPC;
    + }
    + memcpy(ring->to_user_buffer + ring->head, event, sizeof(*event));
    + mausb_pr_debug("HEAD=%d, TAIL=%d", ring->head, ring->tail);
    + ring->head = (ring->head + 1) & (MAUSB_RING_BUFFER_SIZE - 1);
    + mausb_pr_debug("HEAD=%d, TAIL=%d", ring->head, ring->tail);
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return 0;
    +}
    +
    +int mausb_ring_buffer_move_tail(struct mausb_ring_buffer *ring, u32 count)
    +{
    + unsigned long flags = 0;
    +
    + spin_lock_irqsave(&ring->lock, flags);
    + if (CIRC_CNT(ring->head, ring->tail, MAUSB_RING_BUFFER_SIZE) < count) {
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return -ENOSPC;
    + }
    + mausb_pr_debug("old HEAD=%d, TAIL=%d", ring->head, ring->tail);
    + ring->tail = (ring->tail + (int)count) & (MAUSB_RING_BUFFER_SIZE - 1);
    + mausb_pr_debug("new HEAD=%d, TAIL=%d", ring->head, ring->tail);
    + spin_unlock_irqrestore(&ring->lock, flags);
    + return 0;
    +}
    +
    +void mausb_ring_buffer_cleanup(struct mausb_ring_buffer *ring)
    +{
    + struct mausb_event event;
    +
    + while (mausb_ring_buffer_get(ring, &event) == 0)
    + mausb_cleanup_ring_buffer_event(&event);
    +}
    +
    +void mausb_ring_buffer_destroy(struct mausb_ring_buffer *ring)
    +{
    + unsigned int page_order =
    + mausb_get_page_order(2 * MAUSB_RING_BUFFER_SIZE,
    + sizeof(struct mausb_event));
    + if (ring && ring->to_user_buffer)
    + free_pages((unsigned long)ring->to_user_buffer, page_order);
    +}
    +
    +void mausb_cleanup_ring_buffer_event(struct mausb_event *event)
    +{
    + mausb_pr_debug("event=%d", event->type);
    + switch (event->type) {
    + case MAUSB_EVENT_TYPE_SEND_DATA_MSG:
    + mausb_cleanup_send_data_msg_event(event);
    + break;
    + case MAUSB_EVENT_TYPE_RECEIVED_DATA_MSG:
    + mausb_cleanup_received_data_msg_event(event);
    + break;
    + case MAUSB_EVENT_TYPE_DELETE_DATA_TRANSFER:
    + mausb_cleanup_delete_data_transfer_event(event);
    + break;
    + case MAUSB_EVENT_TYPE_NONE:
    + break;
    + default:
    + mausb_pr_warn("Unknown event type");
    + break;
    + }
    +}
    +
    +void mausb_disconect_event_unsafe(struct mausb_ring_buffer *ring,
    + uint8_t madev_addr)
    +{
    + struct mausb_event disconnect_event;
    + struct mausb_device *dev = mausb_get_dev_from_addr_unsafe(madev_addr);
    +
    + if (!dev) {
    + mausb_pr_err("Device not found, madev_addr=%#x", madev_addr);
    + return;
    + }
    +
    + disconnect_event.type = MAUSB_EVENT_TYPE_DEV_DISCONNECT;
    + disconnect_event.status = -EINVAL;
    + disconnect_event.madev_addr = madev_addr;
    +
    + memcpy(ring->to_user_buffer + ring->head, &disconnect_event,
    + sizeof(disconnect_event));
    +
    + mausb_pr_info("Disconnect event added to ring buffer for madev_addr=%#x",
    + madev_addr);
    + mausb_pr_info("Adding hcd_disconnect_work to dev workq, madev_addr=%#x",
    + madev_addr);
    + queue_work(dev->workq, &dev->hcd_disconnect_work);
    +}
    diff --git a/drivers/usb/mausb_host/hpal.h b/drivers/usb/mausb_host/hpal.h
    index a04ed120ba5e..24846d4bc4a3 100644
    --- a/drivers/usb/mausb_host/hpal.h
    +++ b/drivers/usb/mausb_host/hpal.h
    @@ -67,6 +67,7 @@ struct mss {
    struct mausb_device {
    struct mausb_device_address dev_addr;
    struct net *net_ns;
    + struct mausb_ring_buffer *ring_buffer;
    struct list_head list_entry;

    struct mausb_ip_ctx *mgmt_channel;
    @@ -133,6 +134,10 @@ static inline u64 mausb_event_id(struct mausb_device *dev)

    int mausb_initiate_dev_connection(struct mausb_device_address device_address,
    u8 madev_address);
    +int mausb_enqueue_event_from_user(u8 madev_addr, u16 num_of_events,
    + u16 num_of_completed);
    +int mausb_enqueue_event_to_user(struct mausb_device *dev,
    + struct mausb_event *event);
    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,
    @@ -282,6 +287,33 @@ 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);

    +struct mausb_ring_buffer {
    + atomic_t mausb_ring_events;
    + atomic_t mausb_completed_user_events;
    +
    + struct mausb_event *to_user_buffer;
    + int head;
    + int tail;
    + spinlock_t lock; /* Protect ring buffer */
    + u64 id;
    +
    + struct mausb_event *from_user_buffer;
    + int current_from_user;
    +
    + struct list_head list_entry;
    + bool buffer_full;
    +};
    +
    +int mausb_ring_buffer_init(struct mausb_ring_buffer *ring);
    +int mausb_ring_buffer_put(struct mausb_ring_buffer *ring,
    + struct mausb_event *event);
    +int mausb_ring_buffer_move_tail(struct mausb_ring_buffer *ring, u32 count);
    +void mausb_ring_buffer_cleanup(struct mausb_ring_buffer *ring);
    +void mausb_ring_buffer_destroy(struct mausb_ring_buffer *ring);
    +void mausb_cleanup_ring_buffer_event(struct mausb_event *event);
    +void mausb_disconect_event_unsafe(struct mausb_ring_buffer *ring,
    + uint8_t madev_addr);
    +
    static inline unsigned int mausb_get_page_order(unsigned int num_of_elems,
    unsigned int elem_size)
    {
    @@ -292,4 +324,16 @@ static inline unsigned int mausb_get_page_order(unsigned int num_of_elems,
    return order;
    }

    +static inline
    +struct mausb_event *mausb_ring_current_from_user(struct mausb_ring_buffer *ring)
    +{
    + return ring->from_user_buffer + ring->current_from_user;
    +}
    +
    +static inline void mausb_ring_next_from_user(struct mausb_ring_buffer *ring)
    +{
    + ring->current_from_user = (ring->current_from_user + 1) &
    + (MAUSB_RING_BUFFER_SIZE - 1);
    +}
    +
    #endif /* __MAUSB_HPAL_H__ */
    diff --git a/drivers/usb/mausb_host/hpal_events.c b/drivers/usb/mausb_host/hpal_events.c
    new file mode 100644
    index 000000000000..ee2cfa253e83
    --- /dev/null
    +++ b/drivers/usb/mausb_host/hpal_events.c
    @@ -0,0 +1,611 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
    + */
    +#include "hpal_events.h"
    +
    +#include <linux/slab.h>
    +
    +#include "hcd.h"
    +#include "utils.h"
    +
    +void mausb_dev_reset_req_event(struct mausb_event *event)
    +{
    + event->type = MAUSB_EVENT_TYPE_DEV_RESET;
    +}
    +
    +static int mausb_mgmt_msg_received_event(struct mausb_event *event,
    + struct ma_usb_hdr_common *hdr,
    + enum mausb_channel channel)
    +{
    + int status = 0;
    +
    + mausb_pr_info("channel=%d, type=%d", channel, hdr->type);
    + if (hdr->length <= MAUSB_MAX_MGMT_SIZE) {
    + event->type = MAUSB_EVENT_TYPE_RECEIVED_MGMT_MSG;
    + memcpy(event->mgmt.mgmt_hdr.hdr, hdr, hdr->length);
    + } else {
    + mausb_pr_err("MGMT message to long, failed to copy");
    + status = -EINVAL;
    + }
    +
    + kfree(hdr);
    + return status;
    +}
    +
    +static int mausb_data_msg_received_event(struct mausb_event *event,
    + struct ma_usb_hdr_common *hdr,
    + enum mausb_channel channel)
    +{
    + event->type = MAUSB_EVENT_TYPE_RECEIVED_DATA_MSG;
    + event->data.transfer_type = mausb_transfer_type_from_hdr(hdr);
    + event->data.device_id = (u16)((hdr->ssid << 8) | hdr->dev_addr);
    + event->data.ep_handle = hdr->handle.epv;
    + event->data.recv_buf = (uintptr_t)hdr;
    +
    + memcpy(event->data.hdr, hdr, MAUSB_TRANSFER_HDR_SIZE);
    +
    + if (mausb_ctrl_transfer(hdr) &&
    + hdr->length <= 2 * MAUSB_TRANSFER_HDR_SIZE) {
    + memcpy(event->data.hdr_ack,
    + shift_ptr(hdr, MAUSB_TRANSFER_HDR_SIZE),
    + (size_t)(hdr->length - MAUSB_TRANSFER_HDR_SIZE));
    + }
    +
    + return 0;
    +}
    +
    +static int mausb_isoch_msg_received_event(struct mausb_event *event,
    + struct ma_usb_hdr_common *hdr,
    + enum mausb_channel channel)
    +{
    + event->type = MAUSB_EVENT_TYPE_RECEIVED_DATA_MSG;
    + event->data.transfer_type = mausb_transfer_type_from_hdr(hdr);
    + event->data.device_id = (u16)((hdr->ssid << 8) | hdr->dev_addr);
    + event->data.ep_handle = hdr->handle.epv;
    + event->data.recv_buf = (uintptr_t)hdr;
    +
    + memcpy(event->data.hdr, hdr, MAUSB_TRANSFER_HDR_SIZE);
    +
    + return 0;
    +}
    +
    +int mausb_msg_received_event(struct mausb_event *event,
    + struct ma_usb_hdr_common *hdr,
    + enum mausb_channel channel)
    +{
    + mausb_pr_debug("channel=%d, type=%d", channel, hdr->type);
    + if (mausb_is_management_hdr_type(hdr->type))
    + return mausb_mgmt_msg_received_event(event, hdr, channel);
    + else if (hdr->type == MA_USB_HDR_TYPE_DATA_RESP(TRANSFER))
    + return mausb_data_msg_received_event(event, hdr, channel);
    + else if (hdr->type == MA_USB_HDR_TYPE_DATA_RESP(ISOCHTRANSFER))
    + return mausb_isoch_msg_received_event(event, hdr, channel);
    +
    + mausb_pr_warn("Unknown event type event=%d", hdr->type);
    + kfree(hdr);
    + return -EBADR;
    +}
    +
    +static void mausb_prepare_completion(struct mausb_completion *mausb_completion,
    + struct completion *completion,
    + struct mausb_event *event, u64 event_id)
    +{
    + init_completion(completion);
    +
    + mausb_completion->completion_event = completion;
    + mausb_completion->event_id = event_id;
    + mausb_completion->mausb_event = event;
    +}
    +
    +static int mausb_wait_for_completion(struct mausb_event *event, u64 event_id,
    + struct mausb_device *dev)
    +{
    + struct completion completion;
    + struct mausb_completion mausb_completion;
    + long status;
    + unsigned long timeout;
    +
    + mausb_prepare_completion(&mausb_completion, &completion, event,
    + event_id);
    + mausb_insert_event(dev, &mausb_completion);
    +
    + status = mausb_enqueue_event_to_user(dev, event);
    + if (status < 0) {
    + mausb_remove_event(dev, &mausb_completion);
    + mausb_pr_err("Ring buffer full, event_id=%lld", event_id);
    + return (int)status;
    + }
    +
    + timeout = msecs_to_jiffies(MANAGEMENT_EVENT_TIMEOUT);
    + status = wait_for_completion_interruptible_timeout(&completion,
    + timeout);
    +
    + mausb_remove_event(dev, &mausb_completion);
    +
    + if (status == 0) {
    + queue_work(dev->workq, &dev->socket_disconnect_work);
    + queue_work(dev->workq, &dev->hcd_disconnect_work);
    + return -ETIMEDOUT;
    + }
    +
    + return 0;
    +}
    +
    +int mausb_usbdevhandle_event_to_user(struct mausb_device *dev,
    + u8 device_speed,
    + u32 route_string,
    + u16 hub_dev_handle,
    + u16 parent_hs_hub_dev_handle,
    + u16 parent_hs_hub_port, u16 mtt,
    + u8 lse, s32 *usb_dev_handle)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_USB_DEV_HANDLE;
    + event.mgmt.dev_handle.device_speed = device_speed;
    + event.mgmt.dev_handle.route_string = route_string;
    + event.mgmt.dev_handle.hub_dev_handle = hub_dev_handle;
    + event.mgmt.dev_handle.parent_hs_hub_port = parent_hs_hub_port;
    + event.mgmt.dev_handle.mtt = mtt;
    + event.mgmt.dev_handle.lse = lse;
    + event.mgmt.dev_handle.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    + event.mgmt.dev_handle.parent_hs_hub_dev_handle =
    + parent_hs_hub_dev_handle;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Usbdevhandle failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + if (event.status < 0)
    + return event.status;
    +
    + *usb_dev_handle = event.mgmt.dev_handle.dev_handle;
    +
    + return 0;
    +}
    +
    +int mausb_usbdevhandle_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event, event->mgmt.dev_handle.event_id);
    +}
    +
    +int mausb_ephandle_event_to_user(struct mausb_device *dev,
    + u16 device_handle,
    + u16 descriptor_size, void *descriptor,
    + u16 *ep_handle)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_EP_HANDLE;
    + event.mgmt.ep_handle.device_handle = device_handle;
    + event.mgmt.ep_handle.descriptor_size = descriptor_size;
    + event.mgmt.ep_handle.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + memcpy(event.mgmt.ep_handle.descriptor, descriptor, descriptor_size);
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Ephandle failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + if (event.status < 0)
    + return event.status;
    +
    + *ep_handle = event.mgmt.ep_handle.ep_handle;
    +
    + return 0;
    +}
    +
    +int mausb_ephandle_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event, event->mgmt.ep_handle.event_id);
    +}
    +
    +int mausb_epactivate_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_EP_HANDLE_ACTIVATE;
    + event.mgmt.ep_activate.device_handle = device_handle;
    + event.mgmt.ep_activate.ep_handle = ep_handle;
    + event.mgmt.ep_activate.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Epactivate failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_epactivate_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event,
    + event->mgmt.ep_activate.event_id);
    +}
    +
    +int mausb_epinactivate_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_EP_HANDLE_INACTIVATE;
    + event.mgmt.ep_inactivate.device_handle = device_handle;
    + event.mgmt.ep_inactivate.ep_handle = ep_handle;
    + event.mgmt.ep_inactivate.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Epinactivate failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_epinactivate_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event,
    + event->mgmt.ep_inactivate.event_id);
    +}
    +
    +int mausb_epreset_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle,
    + u8 tsp_flag)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_EP_HANDLE_RESET;
    + event.mgmt.ep_reset.device_handle = device_handle;
    + event.mgmt.ep_reset.ep_handle = ep_handle;
    + event.mgmt.ep_reset.tsp = tsp_flag;
    + event.mgmt.ep_reset.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Epreset failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_epreset_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event, event->mgmt.ep_reset.event_id);
    +}
    +
    +int mausb_epdelete_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_EP_HANDLE_DELETE;
    + event.mgmt.ep_delete.device_handle = device_handle;
    + event.mgmt.ep_delete.ep_handle = ep_handle;
    + event.mgmt.ep_delete.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Epdelete failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_epdelete_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event, event->mgmt.ep_delete.event_id);
    +}
    +
    +int mausb_modifyep0_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 *ep_handle,
    + __le16 max_packet_size)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_MODIFY_EP0;
    + event.mgmt.modify_ep0.device_handle = device_handle;
    + event.mgmt.modify_ep0.ep_handle = *ep_handle;
    + event.mgmt.modify_ep0.max_packet_size = max_packet_size;
    + event.mgmt.modify_ep0.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Modifyep0 failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + if (event.status < 0)
    + return event.status;
    +
    + *ep_handle = event.mgmt.modify_ep0.ep_handle;
    +
    + return 0;
    +}
    +
    +int mausb_modifyep0_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event, event->mgmt.modify_ep0.event_id);
    +}
    +
    +int mausb_setusbdevaddress_event_to_user(struct mausb_device *dev,
    + u16 device_handle,
    + u16 response_timeout)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_SET_USB_DEV_ADDRESS;
    + event.mgmt.set_usb_dev_address.device_handle = device_handle;
    + event.mgmt.set_usb_dev_address.response_timeout = response_timeout;
    + event.mgmt.set_usb_dev_address.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Setusbdevaddress failed, event_id=%lld",
    + event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_setusbdevaddress_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event,
    + event->mgmt.set_usb_dev_address.event_id);
    +}
    +
    +static void
    +mausb_init_device_descriptor(struct ma_usb_updatedevreq_desc *update_descriptor,
    + struct usb_device_descriptor *device_descriptor)
    +{
    + update_descriptor->usb20.bLength = device_descriptor->bLength;
    + update_descriptor->usb20.bDescriptorType =
    + device_descriptor->bDescriptorType;
    + update_descriptor->usb20.bcdUSB = device_descriptor->bcdUSB;
    + update_descriptor->usb20.bDeviceClass =
    + device_descriptor->bDeviceClass;
    + update_descriptor->usb20.bDeviceSubClass =
    + device_descriptor->bDeviceSubClass;
    + update_descriptor->usb20.bDeviceProtocol =
    + device_descriptor->bDeviceProtocol;
    + update_descriptor->usb20.bMaxPacketSize0 =
    + device_descriptor->bMaxPacketSize0;
    + update_descriptor->usb20.idVendor = device_descriptor->idVendor;
    + update_descriptor->usb20.idProduct = device_descriptor->idProduct;
    + update_descriptor->usb20.bcdDevice = device_descriptor->bcdDevice;
    + update_descriptor->usb20.iManufacturer =
    + device_descriptor->iManufacturer;
    + update_descriptor->usb20.iProduct = device_descriptor->iProduct;
    + update_descriptor->usb20.iSerialNumber =
    + device_descriptor->iSerialNumber;
    + update_descriptor->usb20.bNumConfigurations =
    + device_descriptor->bNumConfigurations;
    +}
    +
    +int mausb_updatedev_event_to_user(struct mausb_device *dev,
    + u16 device_handle,
    + u16 max_exit_latency, u8 hub,
    + u8 number_of_ports, u8 mtt,
    + u8 ttt, u8 integrated_hub_latency,
    + struct usb_device_descriptor *dev_descriptor)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_UPDATE_DEV;
    + event.mgmt.update_dev.device_handle = device_handle;
    + event.mgmt.update_dev.max_exit_latency = max_exit_latency;
    + event.mgmt.update_dev.hub = hub;
    + event.mgmt.update_dev.number_of_ports = number_of_ports;
    + event.mgmt.update_dev.mtt = mtt;
    + event.mgmt.update_dev.ttt = ttt;
    + event.mgmt.update_dev.integrated_hub_latency = integrated_hub_latency;
    + event.mgmt.update_dev.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + mausb_init_device_descriptor(&event.mgmt.update_dev.update_descriptor,
    + dev_descriptor);
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Updatedev failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_updatedev_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event, event->mgmt.update_dev.event_id);
    +}
    +
    +int mausb_usbdevdisconnect_event_to_user(struct mausb_device *dev,
    + u16 dev_handle)
    +{
    + struct mausb_event event;
    + int status;
    +
    + event.type = MAUSB_EVENT_TYPE_USB_DEV_DISCONNECT;
    + event.mgmt.usb_dev_disconnect.device_handle = dev_handle;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_enqueue_event_to_user(dev, &event);
    + if (status < 0)
    + mausb_pr_err("Ring buffer full, usbdevdisconnect failed");
    +
    + return status;
    +}
    +
    +int mausb_ping_event_to_user(struct mausb_device *dev)
    +{
    + struct mausb_event event;
    + int status;
    +
    + event.type = MAUSB_EVENT_TYPE_PING;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_enqueue_event_to_user(dev, &event);
    + if (status < 0)
    + mausb_pr_err("Ring buffer full, devdisconnect failed");
    +
    + return status;
    +}
    +
    +__attribute__((unused))
    +static int mausb_devdisconnect_event_to_user(struct mausb_device *dev)
    +{
    + struct mausb_event event;
    + int status;
    +
    + event.type = MAUSB_EVENT_TYPE_DEV_DISCONNECT;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_enqueue_event_to_user(dev, &event);
    + if (status < 0)
    + mausb_pr_err("Ring buffer full, devdisconnect failed");
    +
    + return status;
    +}
    +
    +int mausb_usbdevreset_event_to_user(struct mausb_device *dev,
    + u16 device_handle)
    +{
    + struct mausb_event event;
    + int status;
    + u64 event_id = mausb_event_id(dev);
    +
    + event.type = MAUSB_EVENT_TYPE_USB_DEV_RESET;
    + event.mgmt.usb_dev_reset.device_handle = device_handle;
    + event.mgmt.usb_dev_reset.event_id = event_id;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_wait_for_completion(&event, event_id, dev);
    +
    + if (status < 0) {
    + mausb_pr_err("Usbdevreset failed, event_id=%lld", event_id);
    + return status;
    + }
    +
    + return event.status;
    +}
    +
    +int mausb_usbdevreset_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + return mausb_signal_event(dev, event,
    + event->mgmt.usb_dev_reset.event_id);
    +}
    +
    +int mausb_canceltransfer_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle,
    + uintptr_t urb)
    +{
    + struct mausb_event event;
    + int status;
    +
    + event.type = MAUSB_EVENT_TYPE_CANCEL_TRANSFER;
    + event.mgmt.cancel_transfer.device_handle = device_handle;
    + event.mgmt.cancel_transfer.ep_handle = ep_handle;
    + event.mgmt.cancel_transfer.urb = urb;
    + event.madev_addr = dev->madev_addr;
    +
    + status = mausb_enqueue_event_to_user(dev, &event);
    + if (status < 0) {
    + mausb_pr_err("Ring buffer full, canceltransfer failed");
    + return status;
    + }
    +
    + return status;
    +}
    +
    +int mausb_canceltransfer_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event)
    +{
    + mausb_pr_debug("");
    + return 0;
    +}
    +
    +void mausb_cleanup_send_data_msg_event(struct mausb_event *event)
    +{
    + mausb_complete_urb(event);
    +}
    +
    +void mausb_cleanup_received_data_msg_event(struct mausb_event *event)
    +{
    + mausb_release_event_resources(event);
    +}
    +
    +void mausb_cleanup_delete_data_transfer_event(struct mausb_event *event)
    +{
    + struct urb *urb = (struct urb *)event->data.urb;
    + struct mausb_urb_ctx *urb_ctx;
    + int status = 0;
    +
    + urb_ctx = mausb_unlink_and_delete_urb_from_tree(urb, status);
    + if (!urb_ctx) {
    + mausb_pr_warn("Urb=%p is not in tree", urb);
    + return;
    + }
    +
    + /* 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);
    +}
    diff --git a/drivers/usb/mausb_host/hpal_events.h b/drivers/usb/mausb_host/hpal_events.h
    new file mode 100644
    index 000000000000..8775f9c3438c
    --- /dev/null
    +++ b/drivers/usb/mausb_host/hpal_events.h
    @@ -0,0 +1,85 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
    + */
    +#ifndef __MAUSB_HPAL_EVENTS_H__
    +#define __MAUSB_HPAL_EVENTS_H__
    +
    +#include "hpal.h"
    +#include "ip_link.h"
    +#include "mausb_event.h"
    +
    +#define MANAGEMENT_EVENT_TIMEOUT 3000
    +
    +int mausb_msg_received_event(struct mausb_event *event,
    + struct ma_usb_hdr_common *hdr,
    + enum mausb_channel channel);
    +int mausb_usbdevhandle_event_to_user(struct mausb_device *dev,
    + u8 device_speed,
    + u32 route_string,
    + u16 hub_dev_handle,
    + u16 parent_hs_hub_dev_handle,
    + u16 parent_hs_hub_port, u16 mtt,
    + u8 lse, s32 *usb_dev_handle);
    +int mausb_usbdevhandle_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_ephandle_event_to_user(struct mausb_device *dev, u16 device_handle,
    + u16 descriptor_size, void *descriptor,
    + u16 *ep_handle);
    +int mausb_ephandle_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_epactivate_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle);
    +int mausb_epactivate_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_epinactivate_event_to_user(struct mausb_device *dev,
    + u16 device_handle,
    + u16 ep_handle);
    +int mausb_epinactivate_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_epreset_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle,
    + u8 tsp_flag);
    +int mausb_epreset_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_epdelete_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle);
    +int mausb_epdelete_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_modifyep0_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 *ep_handle,
    + __le16 max_packet_size);
    +int mausb_modifyep0_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_setusbdevaddress_event_to_user(struct mausb_device *dev,
    + u16 device_handle,
    + u16 response_timeout);
    +int mausb_setusbdevaddress_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_updatedev_event_to_user(struct mausb_device *dev,
    + u16 device_handle,
    + u16 max_exit_latency, u8 hub,
    + u8 number_of_ports, u8 mtt,
    + u8 ttt, u8 integrated_hub_latency,
    + struct usb_device_descriptor *dev_descriptor);
    +int mausb_updatedev_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_usbdevdisconnect_event_to_user(struct mausb_device *dev,
    + u16 dev_handle);
    +int mausb_ping_event_to_user(struct mausb_device *dev);
    +int mausb_usbdevreset_event_to_user(struct mausb_device *dev,
    + u16 device_handle);
    +int mausb_usbdevreset_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +int mausb_canceltransfer_event_to_user(struct mausb_device *dev,
    + u16 device_handle, u16 ep_handle,
    + uintptr_t urb);
    +int mausb_canceltransfer_event_from_user(struct mausb_device *dev,
    + struct mausb_event *event);
    +
    +void mausb_dev_reset_req_event(struct mausb_event *event);
    +void mausb_cleanup_send_data_msg_event(struct mausb_event *event);
    +void mausb_cleanup_received_data_msg_event(struct mausb_event *event);
    +void mausb_cleanup_delete_data_transfer_event(struct mausb_event *event);
    +
    +#endif /* __MAUSB_HPAL_EVENTS_H__ */
    diff --git a/drivers/usb/mausb_host/mausb_driver_status.h b/drivers/usb/mausb_host/mausb_driver_status.h
    new file mode 100644
    index 000000000000..9b55befe9cae
    --- /dev/null
    +++ b/drivers/usb/mausb_host/mausb_driver_status.h
    @@ -0,0 +1,17 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
    + */
    +#ifndef __MAUSB_MAUSB_DRIVER_STATUS_H__
    +#define __MAUSB_MAUSB_DRIVER_STATUS_H__
    +
    +#define MAUSB_DRIVER_BAD_READ_BUFFER_SIZE -1
    +#define MAUSB_DRIVER_RING_EVENTS_STOPPED -2
    +#define MAUSB_DRIVER_SYSTEM_SUSPENDED -3
    +#define MAUSB_DRIVER_COPY_TO_BUFFER_FAILED -4
    +
    +#define MAUSB_DRIVER_READ_TIMEOUT 0
    +#define MAUSB_DRIVER_READ_ERROR -1
    +#define MAUSB_DRIVER_WRITE_ERROR -2
    +
    +#endif /* __MAUSB_MAUSB_DRIVER_STATUS_H__ */
    diff --git a/drivers/usb/mausb_host/utils.c b/drivers/usb/mausb_host/utils.c
    index c055b578e402..3e0ee4a5d158 100644
    --- a/drivers/usb/mausb_host/utils.c
    +++ b/drivers/usb/mausb_host/utils.c
    @@ -13,6 +13,8 @@
    #include <linux/slab.h>
    #include <linux/uaccess.h>

    +#include "mausb_driver_status.h"
    +
    #define MAUSB_KERNEL_DEV_NAME "mausb_host"
    #define MAUSB_READ_DEVICE_TIMEOUT_MS 500

    @@ -20,6 +22,47 @@ static dev_t mausb_major_kernel;
    static struct cdev mausb_kernel_dev;
    static struct class *mausb_kernel_class;

    +static void mausb_vm_open(struct vm_area_struct *vma)
    +{
    + mausb_pr_debug("");
    +}
    +
    +static void mausb_vm_close(struct vm_area_struct *vma)
    +{
    + struct mausb_ring_buffer *buffer = NULL, *next = NULL;
    + unsigned long flags = 0;
    + u64 ring_buffer_id = *(u64 *)(vma->vm_private_data);
    +
    + mausb_pr_info("Releasing ring buffer with id: %llu", ring_buffer_id);
    + spin_lock_irqsave(&mss.lock, flags);
    + list_for_each_entry_safe(buffer, next, &mss.available_ring_buffers,
    + list_entry) {
    + if (buffer->id == ring_buffer_id) {
    + list_del(&buffer->list_entry);
    + mausb_ring_buffer_destroy(buffer);
    + kfree(buffer);
    + break;
    + }
    + }
    + spin_unlock_irqrestore(&mss.lock, flags);
    +}
    +
    +/*
    + * mausb_vm_fault is called the first time a memory area is accessed which is
    + * not in memory
    + */
    +static vm_fault_t mausb_vm_fault(struct vm_fault *vmf)
    +{
    + mausb_pr_debug("");
    + return 0;
    +}
    +
    +static const struct vm_operations_struct mausb_vm_ops = {
    + .open = mausb_vm_open,
    + .close = mausb_vm_close,
    + .fault = mausb_vm_fault,
    +};
    +
    static int mausb_file_open(struct inode *inode, struct file *filp)
    {
    filp->private_data = NULL;
    @@ -35,9 +78,213 @@ static int mausb_file_close(struct inode *inode, struct file *filp)
    return 0;
    }

    +static ssize_t mausb_file_read(struct file *filp, char __user *user_buffer,
    + size_t size, loff_t *offset)
    +{
    + ssize_t num_of_bytes_to_read = MAUSB_MAX_NUM_OF_MA_DEVS *
    + sizeof(struct mausb_events_notification);
    + unsigned long num_of_bytes_not_copied;
    + int completed_events;
    + int ring_events;
    + struct mausb_ring_buffer *ring_buffer;
    + struct mausb_device *dev;
    + struct completion *ring_has_events;
    + u8 current_device = 0;
    + s8 fail_ret_val;
    + unsigned long flags;
    + unsigned long timeout;
    + long status;
    +
    + /* Reset heartbeat timer events */
    + mausb_reset_heartbeat_cnt();
    +
    + if ((ssize_t)size != num_of_bytes_to_read) {
    + mausb_pr_alert("The actual size differs from the expected number of bytes");
    + fail_ret_val = MAUSB_DRIVER_BAD_READ_BUFFER_SIZE;
    + if (copy_to_user(user_buffer, &fail_ret_val,
    + sizeof(fail_ret_val)) != 0) {
    + mausb_pr_warn("Failed to set error code.");
    + }
    + return MAUSB_DRIVER_READ_ERROR;
    + }
    +
    + /* If suspend/hibernate happened delete all devices */
    + if (atomic_xchg(&mss.num_of_transitions_to_sleep, 0)) {
    + mausb_pr_alert("Suspend system event detected");
    + fail_ret_val = MAUSB_DRIVER_SYSTEM_SUSPENDED;
    + if (copy_to_user(user_buffer, &fail_ret_val,
    + sizeof(fail_ret_val)) != 0) {
    + mausb_pr_warn("Failed to set error code.");
    + }
    + return MAUSB_DRIVER_READ_ERROR;
    + }
    +
    + ring_has_events = &mss.rings_events.mausb_ring_has_events;
    + timeout = msecs_to_jiffies(MAUSB_READ_DEVICE_TIMEOUT_MS);
    + status = wait_for_completion_interruptible_timeout(ring_has_events,
    + timeout);
    + reinit_completion(ring_has_events);
    +
    + if (atomic_read(&mss.rings_events.mausb_stop_reading_ring_events)) {
    + mausb_pr_alert("Ring events stopped");
    + fail_ret_val = MAUSB_DRIVER_RING_EVENTS_STOPPED;
    + if (copy_to_user(user_buffer, &fail_ret_val,
    + sizeof(fail_ret_val)) != 0) {
    + mausb_pr_warn("Failed to set error code.");
    + }
    + return MAUSB_DRIVER_READ_ERROR;
    + }
    +
    + /* There are no new events - waiting for events hit timeout */
    + if (status == 0)
    + return MAUSB_DRIVER_READ_TIMEOUT;
    +
    + spin_lock_irqsave(&mss.lock, flags);
    +
    + list_for_each_entry(dev, &mss.madev_list, list_entry) {
    + mss.events[current_device].madev_addr = dev->madev_addr;
    + ring_buffer = dev->ring_buffer;
    + ring_events = atomic_xchg(&ring_buffer->mausb_ring_events, 0);
    + completed_events =
    + atomic_xchg(&ring_buffer->mausb_completed_user_events,
    + 0);
    + mss.events[current_device].num_of_events = (u16)ring_events;
    + mss.events[current_device].num_of_completed_events =
    + (u16)completed_events;
    + if (++current_device == MAUSB_MAX_NUM_OF_MA_DEVS)
    + break;
    + }
    +
    + spin_unlock_irqrestore(&mss.lock, flags);
    +
    + num_of_bytes_to_read =
    + (ssize_t)(current_device *
    + sizeof(struct mausb_events_notification));
    + num_of_bytes_not_copied =
    + copy_to_user(user_buffer, &mss.events,
    + (unsigned long)num_of_bytes_to_read);
    +
    + mausb_pr_debug("num_of_bytes_not_copied %lu, num_of_bytes_to_read %zd",
    + num_of_bytes_not_copied, num_of_bytes_to_read);
    +
    + if (num_of_bytes_not_copied) {
    + fail_ret_val = MAUSB_DRIVER_COPY_TO_BUFFER_FAILED;
    + if (copy_to_user(user_buffer, &fail_ret_val,
    + sizeof(fail_ret_val)) != 0) {
    + mausb_pr_warn("Failed to set error code.");
    + }
    + return MAUSB_DRIVER_READ_ERROR;
    + }
    +
    + return num_of_bytes_to_read;
    +}
    +
    +static ssize_t mausb_file_write(struct file *filp, const char __user *buffer,
    + size_t size, loff_t *offset)
    +{
    + ssize_t num_of_bytes_to_write =
    + sizeof(struct mausb_events_notification);
    + struct mausb_events_notification notification;
    + unsigned long flags;
    + struct mausb_device *dev;
    +
    + if (size != (size_t)num_of_bytes_to_write) {
    + mausb_pr_alert("The actual size differs from the expected number of bytes");
    + return MAUSB_DRIVER_WRITE_ERROR;
    + }
    +
    + if (copy_from_user(&notification, buffer, size))
    + return MAUSB_DRIVER_WRITE_ERROR;
    +
    + spin_lock_irqsave(&mss.lock, flags);
    + dev = mausb_get_dev_from_addr_unsafe(notification.madev_addr);
    +
    + if (!dev) {
    + spin_unlock_irqrestore(&mss.lock, flags);
    + return 0;
    + }
    +
    + spin_lock(&dev->num_of_user_events_lock);
    + dev->num_of_user_events += notification.num_of_events;
    + dev->num_of_completed_events += notification.num_of_completed_events;
    + spin_unlock(&dev->num_of_user_events_lock);
    +
    + queue_work(dev->workq, &dev->work);
    + spin_unlock_irqrestore(&mss.lock, flags);
    +
    + return num_of_bytes_to_write;
    +}
    +
    +static inline unsigned long mausb_ring_buffer_length(void)
    +{
    + int page_order = mausb_get_page_order(2 * MAUSB_RING_BUFFER_SIZE,
    + sizeof(struct mausb_event));
    + return PAGE_SIZE << page_order;
    +}
    +
    +static int mausb_mmap(struct file *filp, struct vm_area_struct *vma)
    +{
    + unsigned long size = vma->vm_end - vma->vm_start;
    + int ret;
    + struct page *page = NULL;
    + unsigned long flags = 0;
    + struct mausb_ring_buffer *ring_buffer = kzalloc(sizeof(*ring_buffer),
    + GFP_KERNEL);
    + if (!ring_buffer)
    + return -ENOMEM;
    +
    + ret = mausb_ring_buffer_init(ring_buffer);
    + if (ret < 0) {
    + mausb_pr_err("Ring buffer init failed");
    + goto release_ring_buffer;
    + }
    +
    + vma->vm_private_data = kzalloc(sizeof(ring_buffer->id), GFP_KERNEL);
    + if (!vma->vm_private_data) {
    + ret = -ENOMEM;
    + goto release_ring_buffer;
    + }
    +
    + filp->private_data = vma->vm_private_data;
    +
    + if (size > mausb_ring_buffer_length()) {
    + mausb_pr_err("Invalid memory size to map");
    + ret = -EINVAL;
    + goto release_ring_buffer;
    + }
    +
    + vma->vm_ops = &mausb_vm_ops;
    + mausb_vm_open(vma);
    +
    + page = virt_to_page(ring_buffer->to_user_buffer);
    + ret = remap_pfn_range(vma, vma->vm_start, page_to_pfn(page), size,
    + vma->vm_page_prot);
    + if (ret < 0) {
    + mausb_pr_err("Could not map the address area");
    + goto release_ring_buffer;
    + }
    +
    + spin_lock_irqsave(&mss.lock, flags);
    + ring_buffer->id = mss.ring_buffer_id++;
    + *(u64 *)(vma->vm_private_data) = ring_buffer->id;
    + list_add_tail(&ring_buffer->list_entry, &mss.available_ring_buffers);
    + mausb_pr_info("Allocated ring buffer with id: %llu", ring_buffer->id);
    + spin_unlock_irqrestore(&mss.lock, flags);
    +
    + return 0;
    +
    +release_ring_buffer:
    + mausb_ring_buffer_destroy(ring_buffer);
    + kfree(ring_buffer);
    + return ret;
    +}
    +
    static const struct file_operations mausb_file_ops = {
    .open = mausb_file_open,
    .release = mausb_file_close,
    + .read = mausb_file_read,
    + .write = mausb_file_write,
    + .mmap = mausb_mmap,
    };

    int mausb_create_dev(void)
    @@ -83,3 +330,29 @@ void mausb_cleanup_dev(int device_created)

    unregister_chrdev_region(mausb_major_kernel, 1);
    }
    +
    +void mausb_notify_completed_user_events(struct mausb_ring_buffer *ring_buffer)
    +{
    + int completed;
    +
    + completed =
    + atomic_inc_return(&ring_buffer->mausb_completed_user_events);
    + mausb_pr_debug("mausb_completed_user_events INCREMENTED %d", completed);
    + if (completed > MAUSB_RING_BUFFER_SIZE / 16)
    + complete(&mss.rings_events.mausb_ring_has_events);
    +}
    +
    +void mausb_notify_ring_events(struct mausb_ring_buffer *ring_buffer)
    +{
    + int events;
    +
    + events = atomic_inc_return(&ring_buffer->mausb_ring_events);
    + if (events == 1)
    + complete(&mss.rings_events.mausb_ring_has_events);
    +}
    +
    +void mausb_stop_ring_events(void)
    +{
    + atomic_set(&mss.rings_events.mausb_stop_reading_ring_events, 1);
    + complete(&mss.rings_events.mausb_ring_has_events);
    +}
    diff --git a/drivers/usb/mausb_host/utils.h b/drivers/usb/mausb_host/utils.h
    index 9adf4122e64d..54acd8585ad3 100644
    --- a/drivers/usb/mausb_host/utils.h
    +++ b/drivers/usb/mausb_host/utils.h
    @@ -5,6 +5,8 @@
    #ifndef __MAUSB_UTILS_H__
    #define __MAUSB_UTILS_H__

    +#include "hpal.h"
    +
    #if defined(MAUSB_NO_LOGS)
    #define mausb_pr_logs(...)
    #else
    @@ -36,5 +38,8 @@

    int mausb_create_dev(void);
    void mausb_cleanup_dev(int device_created);
    +void mausb_notify_completed_user_events(struct mausb_ring_buffer *ring_buffer);
    +void mausb_notify_ring_events(struct mausb_ring_buffer *ring_buffer);
    +void mausb_stop_ring_events(void);

    #endif /* __MAUSB_UTILS_H__ */
    --
    2.17.1
    \
     
     \ /
      Last update: 2020-04-25 11:21    [W:4.516 / U:0.120 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site