| .. | .. |
|---|
| 16 | 16 | #include <linux/usb/ch9.h> |
|---|
| 17 | 17 | |
|---|
| 18 | 18 | #ifdef CONFIG_USB_CONFIGFS_F_ACC |
|---|
| 19 | | -extern int acc_ctrlrequest(struct usb_composite_dev *cdev, |
|---|
| 19 | +extern int acc_ctrlrequest_composite(struct usb_composite_dev *cdev, |
|---|
| 20 | 20 | const struct usb_ctrlrequest *ctrl); |
|---|
| 21 | 21 | void acc_disconnect(void); |
|---|
| 22 | 22 | #endif |
|---|
| .. | .. |
|---|
| 39 | 39 | int check_user_usb_string(const char *name, |
|---|
| 40 | 40 | struct usb_gadget_strings *stringtab_dev) |
|---|
| 41 | 41 | { |
|---|
| 42 | | - unsigned primary_lang; |
|---|
| 43 | | - unsigned sub_lang; |
|---|
| 44 | 42 | u16 num; |
|---|
| 45 | 43 | int ret; |
|---|
| 46 | 44 | |
|---|
| .. | .. |
|---|
| 48 | 46 | if (ret) |
|---|
| 49 | 47 | return ret; |
|---|
| 50 | 48 | |
|---|
| 51 | | - primary_lang = num & 0x3ff; |
|---|
| 52 | | - sub_lang = num >> 10; |
|---|
| 53 | | - |
|---|
| 54 | | - /* simple sanity check for valid langid */ |
|---|
| 55 | | - switch (primary_lang) { |
|---|
| 56 | | - case 0: |
|---|
| 57 | | - case 0x62 ... 0xfe: |
|---|
| 58 | | - case 0x100 ... 0x3ff: |
|---|
| 59 | | - return -EINVAL; |
|---|
| 60 | | - } |
|---|
| 61 | | - if (!sub_lang) |
|---|
| 49 | + if (!usb_validate_langid(num)) |
|---|
| 62 | 50 | return -EINVAL; |
|---|
| 63 | 51 | |
|---|
| 64 | 52 | stringtab_dev->language = num; |
|---|
| .. | .. |
|---|
| 341 | 329 | return ret; |
|---|
| 342 | 330 | } |
|---|
| 343 | 331 | |
|---|
| 332 | +static ssize_t gadget_dev_desc_max_speed_show(struct config_item *item, |
|---|
| 333 | + char *page) |
|---|
| 334 | +{ |
|---|
| 335 | + enum usb_device_speed speed = to_gadget_info(item)->composite.max_speed; |
|---|
| 336 | + |
|---|
| 337 | + return sprintf(page, "%s\n", usb_speed_string(speed)); |
|---|
| 338 | +} |
|---|
| 339 | + |
|---|
| 340 | +static ssize_t gadget_dev_desc_max_speed_store(struct config_item *item, |
|---|
| 341 | + const char *page, size_t len) |
|---|
| 342 | +{ |
|---|
| 343 | + struct gadget_info *gi = to_gadget_info(item); |
|---|
| 344 | + |
|---|
| 345 | + mutex_lock(&gi->lock); |
|---|
| 346 | + |
|---|
| 347 | + /* Prevent changing of max_speed after the driver is binded */ |
|---|
| 348 | + if (gi->composite.gadget_driver.udc_name) |
|---|
| 349 | + goto err; |
|---|
| 350 | + |
|---|
| 351 | + if (strncmp(page, "super-speed-plus", 16) == 0) |
|---|
| 352 | + gi->composite.max_speed = USB_SPEED_SUPER_PLUS; |
|---|
| 353 | + else if (strncmp(page, "super-speed", 11) == 0) |
|---|
| 354 | + gi->composite.max_speed = USB_SPEED_SUPER; |
|---|
| 355 | + else if (strncmp(page, "high-speed", 10) == 0) |
|---|
| 356 | + gi->composite.max_speed = USB_SPEED_HIGH; |
|---|
| 357 | + else if (strncmp(page, "full-speed", 10) == 0) |
|---|
| 358 | + gi->composite.max_speed = USB_SPEED_FULL; |
|---|
| 359 | + else if (strncmp(page, "low-speed", 9) == 0) |
|---|
| 360 | + gi->composite.max_speed = USB_SPEED_LOW; |
|---|
| 361 | + else |
|---|
| 362 | + goto err; |
|---|
| 363 | + |
|---|
| 364 | + gi->composite.gadget_driver.max_speed = gi->composite.max_speed; |
|---|
| 365 | + |
|---|
| 366 | + mutex_unlock(&gi->lock); |
|---|
| 367 | + return len; |
|---|
| 368 | +err: |
|---|
| 369 | + mutex_unlock(&gi->lock); |
|---|
| 370 | + return -EINVAL; |
|---|
| 371 | +} |
|---|
| 372 | + |
|---|
| 344 | 373 | CONFIGFS_ATTR(gadget_dev_desc_, bDeviceClass); |
|---|
| 345 | 374 | CONFIGFS_ATTR(gadget_dev_desc_, bDeviceSubClass); |
|---|
| 346 | 375 | CONFIGFS_ATTR(gadget_dev_desc_, bDeviceProtocol); |
|---|
| .. | .. |
|---|
| 350 | 379 | CONFIGFS_ATTR(gadget_dev_desc_, bcdDevice); |
|---|
| 351 | 380 | CONFIGFS_ATTR(gadget_dev_desc_, bcdUSB); |
|---|
| 352 | 381 | CONFIGFS_ATTR(gadget_dev_desc_, UDC); |
|---|
| 382 | +CONFIGFS_ATTR(gadget_dev_desc_, max_speed); |
|---|
| 353 | 383 | |
|---|
| 354 | 384 | static struct configfs_attribute *gadget_root_attrs[] = { |
|---|
| 355 | 385 | &gadget_dev_desc_attr_bDeviceClass, |
|---|
| .. | .. |
|---|
| 361 | 391 | &gadget_dev_desc_attr_bcdDevice, |
|---|
| 362 | 392 | &gadget_dev_desc_attr_bcdUSB, |
|---|
| 363 | 393 | &gadget_dev_desc_attr_UDC, |
|---|
| 394 | + &gadget_dev_desc_attr_max_speed, |
|---|
| 364 | 395 | NULL, |
|---|
| 365 | 396 | }; |
|---|
| 366 | 397 | |
|---|
| .. | .. |
|---|
| 1408 | 1439 | goto err_purge_funcs; |
|---|
| 1409 | 1440 | } |
|---|
| 1410 | 1441 | } |
|---|
| 1442 | + ret = usb_gadget_check_config(cdev->gadget); |
|---|
| 1443 | + if (ret) |
|---|
| 1444 | + goto err_purge_funcs; |
|---|
| 1445 | + |
|---|
| 1411 | 1446 | usb_ep_autoconfig_reset(cdev->gadget); |
|---|
| 1412 | 1447 | } |
|---|
| 1413 | 1448 | if (cdev->use_os_string) { |
|---|
| .. | .. |
|---|
| 1498 | 1533 | usb_ep_autoconfig_reset(cdev->gadget); |
|---|
| 1499 | 1534 | spin_lock_irqsave(&gi->spinlock, flags); |
|---|
| 1500 | 1535 | cdev->gadget = NULL; |
|---|
| 1536 | + cdev->deactivations = 0; |
|---|
| 1537 | + gadget->deactivated = false; |
|---|
| 1501 | 1538 | set_gadget_data(gadget, NULL); |
|---|
| 1502 | 1539 | spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1503 | 1540 | } |
|---|
| 1504 | 1541 | |
|---|
| 1505 | | -#ifndef CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1542 | +#ifdef CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1543 | +static int android_setup(struct usb_gadget *gadget, |
|---|
| 1544 | + const struct usb_ctrlrequest *c) |
|---|
| 1545 | +{ |
|---|
| 1546 | + struct usb_composite_dev *cdev; |
|---|
| 1547 | + unsigned long flags; |
|---|
| 1548 | + struct gadget_info *gi; |
|---|
| 1549 | + int value = -EOPNOTSUPP; |
|---|
| 1550 | + struct usb_function_instance *fi; |
|---|
| 1551 | + |
|---|
| 1552 | + if (!android_device) |
|---|
| 1553 | + return 0; |
|---|
| 1554 | + |
|---|
| 1555 | + gi = dev_get_drvdata(android_device); |
|---|
| 1556 | + spin_lock_irqsave(&gi->spinlock, flags); |
|---|
| 1557 | + cdev = get_gadget_data(gadget); |
|---|
| 1558 | + if (!cdev || gi->unbind) { |
|---|
| 1559 | + spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1560 | + return 0; |
|---|
| 1561 | + } |
|---|
| 1562 | + |
|---|
| 1563 | + if (c->bRequest == USB_REQ_GET_DESCRIPTOR && |
|---|
| 1564 | + (c->wValue >> 8) == USB_DT_CONFIG && !gi->connected) { |
|---|
| 1565 | + gi->connected = 1; |
|---|
| 1566 | + schedule_work(&gi->work); |
|---|
| 1567 | + } |
|---|
| 1568 | + |
|---|
| 1569 | + list_for_each_entry(fi, &gi->available_func, cfs_list) { |
|---|
| 1570 | + if (fi != NULL && fi->f != NULL && fi->f->setup != NULL) { |
|---|
| 1571 | + value = fi->f->setup(fi->f, c); |
|---|
| 1572 | + if (value >= 0) |
|---|
| 1573 | + break; |
|---|
| 1574 | + } |
|---|
| 1575 | + } |
|---|
| 1576 | + |
|---|
| 1577 | +#ifdef CONFIG_USB_CONFIGFS_F_ACC |
|---|
| 1578 | + if (value < 0) |
|---|
| 1579 | + value = acc_ctrlrequest_composite(cdev, c); |
|---|
| 1580 | +#endif |
|---|
| 1581 | + |
|---|
| 1582 | + if (value < 0) |
|---|
| 1583 | + value = composite_setup(gadget, c); |
|---|
| 1584 | + |
|---|
| 1585 | + if (c->bRequest == USB_REQ_SET_CONFIGURATION && |
|---|
| 1586 | + cdev->config) { |
|---|
| 1587 | + schedule_work(&gi->work); |
|---|
| 1588 | + } |
|---|
| 1589 | + spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1590 | + |
|---|
| 1591 | + return value; |
|---|
| 1592 | +} |
|---|
| 1593 | + |
|---|
| 1594 | +#else // CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1595 | + |
|---|
| 1506 | 1596 | static int configfs_composite_setup(struct usb_gadget *gadget, |
|---|
| 1507 | 1597 | const struct usb_ctrlrequest *ctrl) |
|---|
| 1508 | 1598 | { |
|---|
| .. | .. |
|---|
| 1528 | 1618 | return ret; |
|---|
| 1529 | 1619 | } |
|---|
| 1530 | 1620 | |
|---|
| 1621 | +#endif // CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1622 | + |
|---|
| 1531 | 1623 | static void configfs_composite_disconnect(struct usb_gadget *gadget) |
|---|
| 1624 | +{ |
|---|
| 1625 | + struct usb_composite_dev *cdev; |
|---|
| 1626 | + struct gadget_info *gi; |
|---|
| 1627 | + unsigned long flags; |
|---|
| 1628 | + |
|---|
| 1629 | + cdev = get_gadget_data(gadget); |
|---|
| 1630 | + if (!cdev) |
|---|
| 1631 | + return; |
|---|
| 1632 | + |
|---|
| 1633 | +#ifdef CONFIG_USB_CONFIGFS_F_ACC |
|---|
| 1634 | + /* |
|---|
| 1635 | + * accessory HID support can be active while the |
|---|
| 1636 | + * accessory function is not actually enabled, |
|---|
| 1637 | + * so we need to inform it when we are disconnected. |
|---|
| 1638 | + */ |
|---|
| 1639 | + acc_disconnect(); |
|---|
| 1640 | +#endif |
|---|
| 1641 | + gi = container_of(cdev, struct gadget_info, cdev); |
|---|
| 1642 | + spin_lock_irqsave(&gi->spinlock, flags); |
|---|
| 1643 | + cdev = get_gadget_data(gadget); |
|---|
| 1644 | + if (!cdev || gi->unbind) { |
|---|
| 1645 | + spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1646 | + return; |
|---|
| 1647 | + } |
|---|
| 1648 | + |
|---|
| 1649 | +#ifdef CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1650 | + gi->connected = 0; |
|---|
| 1651 | + schedule_work(&gi->work); |
|---|
| 1652 | +#endif |
|---|
| 1653 | + composite_disconnect(gadget); |
|---|
| 1654 | + spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1655 | +} |
|---|
| 1656 | + |
|---|
| 1657 | +static void configfs_composite_reset(struct usb_gadget *gadget) |
|---|
| 1532 | 1658 | { |
|---|
| 1533 | 1659 | struct usb_composite_dev *cdev; |
|---|
| 1534 | 1660 | struct gadget_info *gi; |
|---|
| .. | .. |
|---|
| 1546 | 1672 | return; |
|---|
| 1547 | 1673 | } |
|---|
| 1548 | 1674 | |
|---|
| 1549 | | - composite_disconnect(gadget); |
|---|
| 1675 | + composite_reset(gadget); |
|---|
| 1550 | 1676 | spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1551 | 1677 | } |
|---|
| 1552 | | -#endif |
|---|
| 1553 | 1678 | |
|---|
| 1554 | 1679 | static void configfs_composite_suspend(struct usb_gadget *gadget) |
|---|
| 1555 | 1680 | { |
|---|
| .. | .. |
|---|
| 1595 | 1720 | spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1596 | 1721 | } |
|---|
| 1597 | 1722 | |
|---|
| 1598 | | -#ifdef CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1599 | | -static int android_setup(struct usb_gadget *gadget, |
|---|
| 1600 | | - const struct usb_ctrlrequest *c) |
|---|
| 1601 | | -{ |
|---|
| 1602 | | - struct usb_composite_dev *cdev; |
|---|
| 1603 | | - unsigned long flags; |
|---|
| 1604 | | - struct gadget_info *gi; |
|---|
| 1605 | | - int value = -EOPNOTSUPP; |
|---|
| 1606 | | - struct usb_function_instance *fi; |
|---|
| 1607 | | - |
|---|
| 1608 | | - if (!android_device) |
|---|
| 1609 | | - return 0; |
|---|
| 1610 | | - |
|---|
| 1611 | | - gi = dev_get_drvdata(android_device); |
|---|
| 1612 | | - spin_lock_irqsave(&gi->spinlock, flags); |
|---|
| 1613 | | - cdev = get_gadget_data(gadget); |
|---|
| 1614 | | - if (!cdev || gi->unbind) { |
|---|
| 1615 | | - spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1616 | | - return 0; |
|---|
| 1617 | | - }; |
|---|
| 1618 | | - |
|---|
| 1619 | | - if (c->bRequest == USB_REQ_GET_DESCRIPTOR && |
|---|
| 1620 | | - (c->wValue >> 8) == USB_DT_CONFIG && !gi->connected) { |
|---|
| 1621 | | - gi->connected = 1; |
|---|
| 1622 | | - schedule_work(&gi->work); |
|---|
| 1623 | | - } |
|---|
| 1624 | | - |
|---|
| 1625 | | - list_for_each_entry(fi, &gi->available_func, cfs_list) { |
|---|
| 1626 | | - if (fi != NULL && fi->f != NULL && fi->f->setup != NULL) { |
|---|
| 1627 | | - value = fi->f->setup(fi->f, c); |
|---|
| 1628 | | - if (value >= 0) |
|---|
| 1629 | | - break; |
|---|
| 1630 | | - } |
|---|
| 1631 | | - } |
|---|
| 1632 | | - |
|---|
| 1633 | | -#ifdef CONFIG_USB_CONFIGFS_F_ACC |
|---|
| 1634 | | - if (value < 0) |
|---|
| 1635 | | - value = acc_ctrlrequest(cdev, c); |
|---|
| 1636 | | -#endif |
|---|
| 1637 | | - |
|---|
| 1638 | | - if (value < 0) |
|---|
| 1639 | | - value = composite_setup(gadget, c); |
|---|
| 1640 | | - |
|---|
| 1641 | | - if (c->bRequest == USB_REQ_SET_CONFIGURATION && |
|---|
| 1642 | | - cdev->config) { |
|---|
| 1643 | | - schedule_work(&gi->work); |
|---|
| 1644 | | - } |
|---|
| 1645 | | - spin_unlock_irqrestore(&gi->spinlock, flags); |
|---|
| 1646 | | - |
|---|
| 1647 | | - return value; |
|---|
| 1648 | | -} |
|---|
| 1649 | | - |
|---|
| 1650 | | -static void android_disconnect(struct usb_gadget *gadget) |
|---|
| 1651 | | -{ |
|---|
| 1652 | | - struct usb_composite_dev *cdev = get_gadget_data(gadget); |
|---|
| 1653 | | - struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); |
|---|
| 1654 | | - |
|---|
| 1655 | | - /* FIXME: There's a race between usb_gadget_udc_stop() which is likely |
|---|
| 1656 | | - * to set the gadget driver to NULL in the udc driver and this drivers |
|---|
| 1657 | | - * gadget disconnect fn which likely checks for the gadget driver to |
|---|
| 1658 | | - * be a null ptr. It happens that unbind (doing set_gadget_data(NULL)) |
|---|
| 1659 | | - * is called before the gadget driver is set to NULL and the udc driver |
|---|
| 1660 | | - * calls disconnect fn which results in cdev being a null ptr. |
|---|
| 1661 | | - */ |
|---|
| 1662 | | - if (cdev == NULL) { |
|---|
| 1663 | | - WARN(1, "%s: gadget driver already disconnected\n", __func__); |
|---|
| 1664 | | - return; |
|---|
| 1665 | | - } |
|---|
| 1666 | | - |
|---|
| 1667 | | - /* accessory HID support can be active while the |
|---|
| 1668 | | - accessory function is not actually enabled, |
|---|
| 1669 | | - so we need to inform it when we are disconnected. |
|---|
| 1670 | | - */ |
|---|
| 1671 | | - |
|---|
| 1672 | | -#ifdef CONFIG_USB_CONFIGFS_F_ACC |
|---|
| 1673 | | - acc_disconnect(); |
|---|
| 1674 | | -#endif |
|---|
| 1675 | | - gi->connected = 0; |
|---|
| 1676 | | - schedule_work(&gi->work); |
|---|
| 1677 | | - composite_disconnect(gadget); |
|---|
| 1678 | | -} |
|---|
| 1679 | | -#endif |
|---|
| 1680 | | - |
|---|
| 1681 | 1723 | static const struct usb_gadget_driver configfs_driver_template = { |
|---|
| 1682 | 1724 | .bind = configfs_composite_bind, |
|---|
| 1683 | 1725 | .unbind = configfs_composite_unbind, |
|---|
| 1726 | + |
|---|
| 1684 | 1727 | #ifdef CONFIG_USB_CONFIGFS_UEVENT |
|---|
| 1685 | 1728 | .setup = android_setup, |
|---|
| 1686 | | - .reset = android_disconnect, |
|---|
| 1687 | | - .disconnect = android_disconnect, |
|---|
| 1688 | 1729 | #else |
|---|
| 1689 | 1730 | .setup = configfs_composite_setup, |
|---|
| 1690 | | - .reset = configfs_composite_disconnect, |
|---|
| 1691 | | - .disconnect = configfs_composite_disconnect, |
|---|
| 1692 | 1731 | #endif |
|---|
| 1732 | + .reset = configfs_composite_reset, |
|---|
| 1733 | + .disconnect = configfs_composite_disconnect, |
|---|
| 1693 | 1734 | .suspend = configfs_composite_suspend, |
|---|
| 1694 | 1735 | .resume = configfs_composite_resume, |
|---|
| 1695 | 1736 | |
|---|