From 04dd17822334871b23ea2862f7798fb0e0007777 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 11 May 2024 08:53:19 +0000 Subject: [PATCH] change otg to host mode --- kernel/drivers/usb/gadget/configfs.c | 256 ++++++++++++++++++++++++++++++-------------------- 1 files changed, 152 insertions(+), 104 deletions(-) diff --git a/kernel/drivers/usb/gadget/configfs.c b/kernel/drivers/usb/gadget/configfs.c index f0d8dc1..35c6442 100644 --- a/kernel/drivers/usb/gadget/configfs.c +++ b/kernel/drivers/usb/gadget/configfs.c @@ -16,7 +16,7 @@ #include <linux/usb/ch9.h> #ifdef CONFIG_USB_CONFIGFS_F_ACC -extern int acc_ctrlrequest(struct usb_composite_dev *cdev, +extern int acc_ctrlrequest_composite(struct usb_composite_dev *cdev, const struct usb_ctrlrequest *ctrl); void acc_disconnect(void); #endif @@ -39,8 +39,6 @@ int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev) { - unsigned primary_lang; - unsigned sub_lang; u16 num; int ret; @@ -48,17 +46,7 @@ if (ret) return ret; - primary_lang = num & 0x3ff; - sub_lang = num >> 10; - - /* simple sanity check for valid langid */ - switch (primary_lang) { - case 0: - case 0x62 ... 0xfe: - case 0x100 ... 0x3ff: - return -EINVAL; - } - if (!sub_lang) + if (!usb_validate_langid(num)) return -EINVAL; stringtab_dev->language = num; @@ -341,6 +329,47 @@ return ret; } +static ssize_t gadget_dev_desc_max_speed_show(struct config_item *item, + char *page) +{ + enum usb_device_speed speed = to_gadget_info(item)->composite.max_speed; + + return sprintf(page, "%s\n", usb_speed_string(speed)); +} + +static ssize_t gadget_dev_desc_max_speed_store(struct config_item *item, + const char *page, size_t len) +{ + struct gadget_info *gi = to_gadget_info(item); + + mutex_lock(&gi->lock); + + /* Prevent changing of max_speed after the driver is binded */ + if (gi->composite.gadget_driver.udc_name) + goto err; + + if (strncmp(page, "super-speed-plus", 16) == 0) + gi->composite.max_speed = USB_SPEED_SUPER_PLUS; + else if (strncmp(page, "super-speed", 11) == 0) + gi->composite.max_speed = USB_SPEED_SUPER; + else if (strncmp(page, "high-speed", 10) == 0) + gi->composite.max_speed = USB_SPEED_HIGH; + else if (strncmp(page, "full-speed", 10) == 0) + gi->composite.max_speed = USB_SPEED_FULL; + else if (strncmp(page, "low-speed", 9) == 0) + gi->composite.max_speed = USB_SPEED_LOW; + else + goto err; + + gi->composite.gadget_driver.max_speed = gi->composite.max_speed; + + mutex_unlock(&gi->lock); + return len; +err: + mutex_unlock(&gi->lock); + return -EINVAL; +} + CONFIGFS_ATTR(gadget_dev_desc_, bDeviceClass); CONFIGFS_ATTR(gadget_dev_desc_, bDeviceSubClass); CONFIGFS_ATTR(gadget_dev_desc_, bDeviceProtocol); @@ -350,6 +379,7 @@ CONFIGFS_ATTR(gadget_dev_desc_, bcdDevice); CONFIGFS_ATTR(gadget_dev_desc_, bcdUSB); CONFIGFS_ATTR(gadget_dev_desc_, UDC); +CONFIGFS_ATTR(gadget_dev_desc_, max_speed); static struct configfs_attribute *gadget_root_attrs[] = { &gadget_dev_desc_attr_bDeviceClass, @@ -361,6 +391,7 @@ &gadget_dev_desc_attr_bcdDevice, &gadget_dev_desc_attr_bcdUSB, &gadget_dev_desc_attr_UDC, + &gadget_dev_desc_attr_max_speed, NULL, }; @@ -430,6 +461,12 @@ * from another gadget or a random directory. * Also a function instance can only be linked once. */ + + if (gi->composite.gadget_driver.udc_name) { + ret = -EINVAL; + goto out; + } + list_for_each_entry(a_fi, &gi->available_func, cfs_list) { if (a_fi == fi) break; @@ -1408,6 +1445,10 @@ goto err_purge_funcs; } } + ret = usb_gadget_check_config(cdev->gadget); + if (ret) + goto err_purge_funcs; + usb_ep_autoconfig_reset(cdev->gadget); } if (cdev->use_os_string) { @@ -1498,11 +1539,67 @@ usb_ep_autoconfig_reset(cdev->gadget); spin_lock_irqsave(&gi->spinlock, flags); cdev->gadget = NULL; + cdev->deactivations = 0; + gadget->deactivated = false; set_gadget_data(gadget, NULL); spin_unlock_irqrestore(&gi->spinlock, flags); } -#ifndef CONFIG_USB_CONFIGFS_UEVENT +#ifdef CONFIG_USB_CONFIGFS_UEVENT +static int android_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *c) +{ + struct usb_composite_dev *cdev; + unsigned long flags; + struct gadget_info *gi; + int value = -EOPNOTSUPP; + struct usb_function_instance *fi; + + cdev = get_gadget_data(gadget); + if (!cdev) + return 0; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return 0; + } + + if (c->bRequest == USB_REQ_GET_DESCRIPTOR && + (c->wValue >> 8) == USB_DT_CONFIG && !gi->connected) { + gi->connected = 1; + schedule_work(&gi->work); + } + + list_for_each_entry(fi, &gi->available_func, cfs_list) { + if (fi != NULL && fi->f != NULL && fi->f->setup != NULL) { + value = fi->f->setup(fi->f, c); + if (value >= 0) + break; + } + } + +#ifdef CONFIG_USB_CONFIGFS_F_ACC + if (value < 0) + value = acc_ctrlrequest_composite(cdev, c); +#endif + + if (value < 0) + value = composite_setup(gadget, c); + + if (c->bRequest == USB_REQ_SET_CONFIGURATION && + cdev->config) { + schedule_work(&gi->work); + } + spin_unlock_irqrestore(&gi->spinlock, flags); + + return value; +} + +#else // CONFIG_USB_CONFIGFS_UEVENT + static int configfs_composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { @@ -1528,7 +1625,43 @@ return ret; } +#endif // CONFIG_USB_CONFIGFS_UEVENT + static void configfs_composite_disconnect(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + +#ifdef CONFIG_USB_CONFIGFS_F_ACC + /* + * accessory HID support can be active while the + * accessory function is not actually enabled, + * so we need to inform it when we are disconnected. + */ + acc_disconnect(); +#endif + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + +#ifdef CONFIG_USB_CONFIGFS_UEVENT + gi->connected = 0; + schedule_work(&gi->work); +#endif + composite_disconnect(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + +static void configfs_composite_reset(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; struct gadget_info *gi; @@ -1546,10 +1679,9 @@ return; } - composite_disconnect(gadget); + composite_reset(gadget); spin_unlock_irqrestore(&gi->spinlock, flags); } -#endif static void configfs_composite_suspend(struct usb_gadget *gadget) { @@ -1595,101 +1727,17 @@ spin_unlock_irqrestore(&gi->spinlock, flags); } -#ifdef CONFIG_USB_CONFIGFS_UEVENT -static int android_setup(struct usb_gadget *gadget, - const struct usb_ctrlrequest *c) -{ - struct usb_composite_dev *cdev; - unsigned long flags; - struct gadget_info *gi; - int value = -EOPNOTSUPP; - struct usb_function_instance *fi; - - if (!android_device) - return 0; - - gi = dev_get_drvdata(android_device); - spin_lock_irqsave(&gi->spinlock, flags); - cdev = get_gadget_data(gadget); - if (!cdev || gi->unbind) { - spin_unlock_irqrestore(&gi->spinlock, flags); - return 0; - }; - - if (c->bRequest == USB_REQ_GET_DESCRIPTOR && - (c->wValue >> 8) == USB_DT_CONFIG && !gi->connected) { - gi->connected = 1; - schedule_work(&gi->work); - } - - list_for_each_entry(fi, &gi->available_func, cfs_list) { - if (fi != NULL && fi->f != NULL && fi->f->setup != NULL) { - value = fi->f->setup(fi->f, c); - if (value >= 0) - break; - } - } - -#ifdef CONFIG_USB_CONFIGFS_F_ACC - if (value < 0) - value = acc_ctrlrequest(cdev, c); -#endif - - if (value < 0) - value = composite_setup(gadget, c); - - if (c->bRequest == USB_REQ_SET_CONFIGURATION && - cdev->config) { - schedule_work(&gi->work); - } - spin_unlock_irqrestore(&gi->spinlock, flags); - - return value; -} - -static void android_disconnect(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); - - /* FIXME: There's a race between usb_gadget_udc_stop() which is likely - * to set the gadget driver to NULL in the udc driver and this drivers - * gadget disconnect fn which likely checks for the gadget driver to - * be a null ptr. It happens that unbind (doing set_gadget_data(NULL)) - * is called before the gadget driver is set to NULL and the udc driver - * calls disconnect fn which results in cdev being a null ptr. - */ - if (cdev == NULL) { - WARN(1, "%s: gadget driver already disconnected\n", __func__); - return; - } - - /* accessory HID support can be active while the - accessory function is not actually enabled, - so we need to inform it when we are disconnected. - */ - -#ifdef CONFIG_USB_CONFIGFS_F_ACC - acc_disconnect(); -#endif - gi->connected = 0; - schedule_work(&gi->work); - composite_disconnect(gadget); -} -#endif - static const struct usb_gadget_driver configfs_driver_template = { .bind = configfs_composite_bind, .unbind = configfs_composite_unbind, + #ifdef CONFIG_USB_CONFIGFS_UEVENT .setup = android_setup, - .reset = android_disconnect, - .disconnect = android_disconnect, #else .setup = configfs_composite_setup, - .reset = configfs_composite_disconnect, - .disconnect = configfs_composite_disconnect, #endif + .reset = configfs_composite_reset, + .disconnect = configfs_composite_disconnect, .suspend = configfs_composite_suspend, .resume = configfs_composite_resume, -- Gitblit v1.6.2