Implemented HCD initialization/deinitialization functionality. Signed-off-by: Vladimir Stankovic <vladimir.stankovic@xxxxxxxxxxxxxxx> --- drivers/usb/mausb_host/Makefile | 1 + drivers/usb/mausb_host/hcd.c | 188 ++++++++++++++++++++++++++++ drivers/usb/mausb_host/hcd.h | 71 +++++++++++ drivers/usb/mausb_host/mausb_core.c | 20 ++- 4 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 drivers/usb/mausb_host/hcd.c create mode 100644 drivers/usb/mausb_host/hcd.h diff --git a/drivers/usb/mausb_host/Makefile b/drivers/usb/mausb_host/Makefile index 19445b73b50b..cce4696682b2 100644 --- a/drivers/usb/mausb_host/Makefile +++ b/drivers/usb/mausb_host/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_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 ccflags-y += -I$(srctree)/$(src) diff --git a/drivers/usb/mausb_host/hcd.c b/drivers/usb/mausb_host/hcd.c new file mode 100644 index 000000000000..3aa548a6cb30 --- /dev/null +++ b/drivers/usb/mausb_host/hcd.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd. + */ +#include "hcd.h" + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/limits.h> +#include <linux/module.h> + +#include "utils.h" + +static int mausb_open(struct inode *inode, struct file *file); +static int mausb_release(struct inode *inode, struct file *file); +static ssize_t mausb_read(struct file *file, char __user *buffer, size_t length, + loff_t *offset); +static ssize_t mausb_write(struct file *file, const char __user *buffer, + size_t length, loff_t *offset); +static long mausb_ioctl(struct file *file, unsigned int ioctl_func, + unsigned long ioctl_buffer); +static int mausb_bus_probe(struct device *dev); +static int mausb_bus_remove(struct device *dev); +static int mausb_bus_match(struct device *dev, struct device_driver *drv); + +static const struct file_operations mausb_fops = { + .open = mausb_open, + .release = mausb_release, + .read = mausb_read, + .write = mausb_write, + .unlocked_ioctl = mausb_ioctl +}; + +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, + .probe = mausb_bus_probe, + .remove = mausb_bus_remove, +}; + +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_probe(struct device *dev) +{ + return 0; +} + +static int mausb_bus_remove(struct device *dev) +{ + return 0; +} + +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; +} + +static int mausb_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int mausb_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t mausb_read(struct file *file, char __user *buffer, size_t length, + loff_t *offset) +{ + return 0; +} + +static ssize_t mausb_write(struct file *file, const char __user *buffer, + size_t length, loff_t *offset) +{ + return 0; +} + +static long mausb_ioctl(struct file *file, unsigned int ioctl_func, + unsigned long ioctl_buffer) +{ + return 0; +} + +int mausb_init_hcd(void) +{ + int retval; + + retval = register_chrdev(0, DEVICE_NAME, &mausb_fops); + if (retval < 0) { + mausb_pr_err("Register_chrdev failed"); + return retval; + } + + major = (unsigned int)retval; + retval = bus_register(&mausb_bus_type); + if (retval) { + mausb_pr_err("Bus_register failed %d", retval); + goto bus_register_error; + } + + mausb_class = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(mausb_class)) { + mausb_pr_err("Class_create failed %ld", PTR_ERR(mausb_class)); + goto class_error; + } + + retval = driver_register(&mausb_driver); + if (retval) { + mausb_pr_err("Driver_register failed"); + 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)) { + mausb_pr_err("Device_create failed %ld", PTR_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/mausb_host/hcd.h b/drivers/usb/mausb_host/hcd.h new file mode 100644 index 000000000000..cac62ba1f1e2 --- /dev/null +++ b/drivers/usb/mausb_host/hcd.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd. + */ +#ifndef __MAUSB_HCD_H__ +#define __MAUSB_HCD_H__ + +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/major.h> +#include <linux/proc_fs.h> +#include <linux/rbtree.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#define DEVICE_NAME "mausb_host_hcd_dev" +#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/mausb_host/mausb_core.c b/drivers/usb/mausb_host/mausb_core.c index 8638dd0a4856..3ce90c29f6de 100644 --- a/drivers/usb/mausb_host/mausb_core.c +++ b/drivers/usb/mausb_host/mausb_core.c @@ -11,6 +11,7 @@ #include <linux/moduleparam.h> #include <linux/net.h> +#include "hcd.h" #include "utils.h" MODULE_LICENSE("GPL"); @@ -67,21 +68,30 @@ static const struct kernel_param_ops mausb_client_disconnect_ops = { static int mausb_host_init(void) { - int status = mausb_create_dev(); + int status; mausb_pr_info("Module load. Version=%s", MAUSB_DRIVER_VERSION); + status = mausb_init_hcd(); + if (status < 0) + goto cleanup; - if (status < 0) { - mausb_pr_alert("Failed to load MAUSB module!"); - return status; - } + status = mausb_create_dev(); + if (status < 0) + goto cleanup_hcd; return 0; + +cleanup_hcd: + mausb_deinit_hcd(); +cleanup: + mausb_pr_alert("Failed to load MAUSB module!"); + return status; } static void mausb_host_exit(void) { mausb_pr_info("Module unloading started..."); + mausb_deinit_hcd(); mausb_cleanup_dev(1); mausb_pr_info("Module unloaded. Version=%s", MAUSB_DRIVER_VERSION); } -- 2.17.1