diff options
Diffstat (limited to 'drivers/usb/gadget/composite.c')
| -rw-r--r-- | drivers/usb/gadget/composite.c | 90 |
1 files changed, 44 insertions, 46 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f25dd2cb5d03..5b3866909b75 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1011,7 +1011,7 @@ static int set_config(struct usb_composite_dev *cdev, ep = (struct usb_endpoint_descriptor *)*descriptors; addr = ((ep->bEndpointAddress & 0x80) >> 3) - | (ep->bEndpointAddress & 0x0f); + | usb_endpoint_num(ep); set_bit(addr, f->endpoints); } @@ -1050,10 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev, else usb_gadget_set_remote_wakeup(gadget, 0); done: - if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) - usb_gadget_set_selfpowered(gadget); - else + if (power > USB_SELF_POWER_VBUS_MAX_DRAW || + (c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER))) usb_gadget_clear_selfpowered(gadget); + else + usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, power); if (result >= 0 && cdev->delayed_status) @@ -1193,30 +1194,6 @@ static void remove_config(struct usb_composite_dev *cdev, } } -/** - * usb_remove_config() - remove a configuration from a device. - * @cdev: wraps the USB gadget - * @config: the configuration - * - * Drivers must call usb_gadget_disconnect before calling this function - * to disconnect the device from the host and make sure the host will not - * try to enumerate the device while we are changing the config list. - */ -void usb_remove_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) -{ - unsigned long flags; - - spin_lock_irqsave(&cdev->lock, flags); - - if (cdev->config == config) - reset_config(cdev); - - spin_unlock_irqrestore(&cdev->lock, flags); - - remove_config(cdev, config); -} - /*-------------------------------------------------------------------------*/ /* We support strings in multiple languages ... string descriptor zero @@ -1844,7 +1821,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) cdev->desc.bcdUSB = cpu_to_le16(0x0200); } - value = min(w_length, (u16) sizeof cdev->desc); + value = min_t(u16, w_length, sizeof(cdev->desc)); memcpy(req->buf, &cdev->desc, value); break; case USB_DT_DEVICE_QUALIFIER: @@ -1863,19 +1840,19 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_CONFIG: value = config_desc(cdev, w_value); if (value >= 0) - value = min(w_length, (u16) value); + value = min_t(u16, w_length, value); break; case USB_DT_STRING: value = get_string(cdev, req->buf, w_index, w_value & 0xff); if (value >= 0) - value = min(w_length, (u16) value); + value = min_t(u16, w_length, value); break; case USB_DT_BOS: if (gadget_is_superspeed(gadget) || gadget->lpm_capable || cdev->use_webusb) { value = bos_desc(cdev); - value = min(w_length, (u16) value); + value = min_t(u16, w_length, value); } break; case USB_DT_OTG: @@ -1930,7 +1907,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) *(u8 *)req->buf = cdev->config->bConfigurationValue; else *(u8 *)req->buf = 0; - value = min(w_length, (u16) 1); + value = min_t(u16, w_length, 1); break; /* function drivers must handle get/set altsetting */ @@ -1976,7 +1953,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (value < 0) break; *((u8 *)req->buf) = value; - value = min(w_length, (u16) 1); + value = min_t(u16, w_length, 1); break; case USB_REQ_GET_STATUS: if (gadget_is_otg(gadget) && gadget->hnp_polling_support && @@ -2010,15 +1987,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (f->get_status) { status = f->get_status(f); + if (status < 0) break; - } else { - /* Set D0 and D1 bits based on func wakeup capability */ - if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { - status |= USB_INTRF_STAT_FUNC_RW_CAP; - if (f->func_wakeup_armed) - status |= USB_INTRF_STAT_FUNC_RW; - } + + /* if D5 is not set, then device is not wakeup capable */ + if (!(f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP)) + status &= ~(USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW); } put_unaligned_le16(status & 0x0000ffff, req->buf); @@ -2111,8 +2086,20 @@ unknown: memset(buf, 0, w_length); buf[5] = 0x01; switch (ctrl->bRequestType & USB_RECIP_MASK) { + /* + * The Microsoft CompatID OS Descriptor Spec(w_index = 0x4) and + * Extended Prop OS Desc Spec(w_index = 0x5) state that the + * HighByte of wValue is the InterfaceNumber and the LowByte is + * the PageNumber. This high/low byte ordering is incorrectly + * documented in the Spec. USB analyzer output on the below + * request packets show the high/low byte inverted i.e LowByte + * is the InterfaceNumber and the HighByte is the PageNumber. + * Since we dont support >64KB CompatID/ExtendedProp descriptors, + * PageNumber is set to 0. Hence verify that the HighByte is 0 + * for below two cases. + */ case USB_RECIP_DEVICE: - if (w_index != 0x4 || (w_value & 0xff)) + if (w_index != 0x4 || (w_value >> 8)) break; buf[6] = w_index; /* Number of ext compat interfaces */ @@ -2128,9 +2115,9 @@ unknown: } break; case USB_RECIP_INTERFACE: - if (w_index != 0x5 || (w_value & 0xff)) + if (w_index != 0x5 || (w_value >> 8)) break; - interface = w_value >> 8; + interface = w_value & 0xFF; if (interface >= MAX_CONFIG_INTERFACES || !os_desc_cfg->interface[interface]) break; @@ -2478,6 +2465,11 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, if (!cdev->os_desc_req->buf) { ret = -ENOMEM; usb_ep_free_request(ep0, cdev->os_desc_req); + /* + * Set os_desc_req to NULL so that composite_dev_cleanup() + * will not try to free it again. + */ + cdev->os_desc_req = NULL; goto end; } cdev->os_desc_req->context = cdev; @@ -2603,7 +2595,10 @@ void composite_suspend(struct usb_gadget *gadget) cdev->suspended = 1; - usb_gadget_set_selfpowered(gadget); + if (cdev->config && + cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER) + usb_gadget_set_selfpowered(gadget); + usb_gadget_vbus_draw(gadget, 2); } @@ -2637,8 +2632,11 @@ void composite_resume(struct usb_gadget *gadget) else maxpower = min(maxpower, 900U); - if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW) + if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW || + !(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) usb_gadget_clear_selfpowered(gadget); + else + usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, maxpower); } else { |
