Implemented HCD initialization/deinitialization functionality. Signed-off-by: Vladimir Stankovic <vladimir.stankovic@xxxxxxxxxxxxxxx> --- drivers/usb/host/mausb/Makefile | 1 + drivers/usb/host/mausb/hcd.c | 120 ++++++++++++++++++++++++++++ drivers/usb/host/mausb/hcd.h | 65 +++++++++++++++ drivers/usb/host/mausb/mausb_core.c | 18 ++++- 4 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/mausb/hcd.c create mode 100644 drivers/usb/host/mausb/hcd.h diff --git a/drivers/usb/host/mausb/Makefile b/drivers/usb/host/mausb/Makefile index acc8ad3f0eff..4d655cb7fab4 100644 --- a/drivers/usb/host/mausb/Makefile +++ b/drivers/usb/host/mausb/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_USB_HOST_MAUSB) += mausb_host.o mausb_host-y := mausb_core.o mausb_host-y += utils.o mausb_host-y += ip_link.o +mausb_host-y += hcd.o diff --git a/drivers/usb/host/mausb/hcd.c b/drivers/usb/host/mausb/hcd.c new file mode 100644 index 000000000000..3a6ef9313dcb --- /dev/null +++ b/drivers/usb/host/mausb/hcd.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd. + */ +#include "hcd.h" + +#include "utils.h" + +static int mausb_bus_match(struct device *dev, struct device_driver *drv); + +static const struct file_operations mausb_fops; + +static unsigned int major; +static unsigned int minor = 1; +static dev_t devt; +static struct device *device; + +struct mausb_hcd *mhcd; +static struct class *mausb_class; +static struct bus_type mausb_bus_type = { + .name = DEVICE_NAME, + .match = mausb_bus_match, +}; + +static struct device_driver mausb_driver = { + .name = DEVICE_NAME, + .bus = &mausb_bus_type, + .owner = THIS_MODULE, +}; + +static void mausb_remove(void) +{ + struct usb_hcd *hcd, *shared_hcd; + + hcd = mhcd->hcd_hs_ctx->hcd; + shared_hcd = mhcd->hcd_ss_ctx->hcd; + + if (shared_hcd) { + usb_remove_hcd(shared_hcd); + usb_put_hcd(shared_hcd); + mhcd->hcd_ss_ctx = NULL; + } + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + mhcd->hcd_hs_ctx = NULL; +} + +static int mausb_bus_match(struct device *dev, struct device_driver *drv) +{ + if (strncmp(dev->bus->name, drv->name, strlen(drv->name))) + return 0; + else + return 1; +} + +int mausb_init_hcd(void) +{ + int retval = register_chrdev(0, DEVICE_NAME, &mausb_fops); + + if (retval < 0) + return retval; + + major = (unsigned int)retval; + retval = bus_register(&mausb_bus_type); + if (retval) + goto bus_register_error; + + mausb_class = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(mausb_class)) { + retval = (int)PTR_ERR(mausb_class); + goto class_error; + } + + retval = driver_register(&mausb_driver); + if (retval) + goto driver_register_error; + + mhcd = kzalloc(sizeof(*mhcd), GFP_ATOMIC); + if (!mhcd) { + retval = -ENOMEM; + goto mausb_hcd_alloc_failed; + } + + devt = MKDEV(major, minor); + device = device_create(mausb_class, NULL, devt, mhcd, DEVICE_NAME); + if (IS_ERR(device)) { + retval = (int)IS_ERR(device); + goto device_create_error; + } + + device->driver = &mausb_driver; + + return retval; +device_create_error: + kfree(mhcd); + mhcd = NULL; +mausb_hcd_alloc_failed: + driver_unregister(&mausb_driver); +driver_register_error: + class_destroy(mausb_class); +class_error: + bus_unregister(&mausb_bus_type); +bus_register_error: + unregister_chrdev(major, DEVICE_NAME); + + return retval; +} + +void mausb_deinit_hcd(void) +{ + if (mhcd) { + mausb_remove(); + device_destroy(mausb_class, devt); + driver_unregister(&mausb_driver); + class_destroy(mausb_class); + bus_unregister(&mausb_bus_type); + unregister_chrdev(major, DEVICE_NAME); + } +} diff --git a/drivers/usb/host/mausb/hcd.h b/drivers/usb/host/mausb/hcd.h new file mode 100644 index 000000000000..e2374af67663 --- /dev/null +++ b/drivers/usb/host/mausb/hcd.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd. + */ +#ifndef __MAUSB_HCD_H__ +#define __MAUSB_HCD_H__ + +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/hcd.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 + +#define MAUSB_PORT_20_STATUS_LOW_SPEED 0x0200 +#define MAUSB_PORT_20_STATUS_HIGH_SPEED 0x0400 + +enum mausb_device_type { + USBDEVICE = 0, + USB20HUB = 1, + USB30HUB = 2 +}; + +enum mausb_device_speed { + LOW_SPEED = 0, + FULL_SPEED = 1, + HIGH_SPEED = 2, + SUPER_SPEED = 3, + SUPER_SPEED_PLUS = 4 +}; + +struct mausb_hcd { + spinlock_t lock; /* Protect HCD during URB processing */ + struct device *pdev; + u16 connected_ports; + + struct rb_root mausb_urbs; + struct hub_ctx *hcd_ss_ctx; + struct hub_ctx *hcd_hs_ctx; + struct notifier_block power_state_listener; +}; + +struct mausb_dev { + u32 port_status; + struct rb_root usb_devices; + u8 dev_speed; + void *ma_dev; +}; + +struct hub_ctx { + struct mausb_hcd *mhcd; + struct usb_hcd *hcd; + struct mausb_dev ma_devs[NUMBER_OF_PORTS]; +}; + +int mausb_init_hcd(void); +void mausb_deinit_hcd(void); + +#endif /* __MAUSB_HCD_H__ */ diff --git a/drivers/usb/host/mausb/mausb_core.c b/drivers/usb/host/mausb/mausb_core.c index 44f76a1b74de..485f241d2b4c 100644 --- a/drivers/usb/host/mausb/mausb_core.c +++ b/drivers/usb/host/mausb/mausb_core.c @@ -4,6 +4,7 @@ */ #include <linux/module.h> +#include "hcd.h" #include "utils.h" MODULE_LICENSE("GPL"); @@ -11,12 +12,27 @@ MODULE_AUTHOR("DisplayLink (UK) Ltd."); static int mausb_host_init(void) { - return mausb_host_dev_register(); + int status = mausb_host_dev_register(); + + if (status < 0) + goto exit; + + status = mausb_init_hcd(); + if (status < 0) + goto cleanup_dev; + + return 0; + +cleanup_dev: + mausb_host_dev_deregister(); +exit: + return status; } static void mausb_host_exit(void) { dev_info(mausb_host_dev.this_device, "Module unloading started..."); + mausb_deinit_hcd(); mausb_host_dev_deregister(); } -- 2.17.1