On Tue, May 06 2014, Andrzej Pietrasiewicz wrote: > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> Acked-by: Michal Nazarewicz <mina86@xxxxxxxxxx> > diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c > index 4e8aaa6..47a6f4e 100644 > --- a/drivers/usb/gadget/composite.c > +++ b/drivers/usb/gadget/composite.c > @@ -454,8 +456,46 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) > > } > > - /* This is a lookup by config *INDEX* */ > w_value &= 0xff; > + /* > + * This is a lookup to make non-compliant USB hosts happy. > + * > + * By non-compliant USB hosts I mean those which only ask for > + * configuration @index 0. > + * If one configuration is marked "special" by storing > + * its address in cdev->os_desc_config, we try returning > + * exactly this configuration. > + * > + * Otherwise, regular list lookup is performed. > + * > + * If we are connected to a compliant USB host _and_ > + * one configuration is "special" we report it @ index 0, > + * but report remaining configurations as well - with adjusted > + * indices. > + */ > + c = cdev->os_desc_config; > + if (c) { > + if (!w_value) { > + switch (speed) { > + case USB_SPEED_SUPER: > + if (!c->superspeed) > + goto list_lookup; > + break; > + case USB_SPEED_HIGH: > + if (!c->highspeed) > + goto list_lookup; > + break; > + default: > + if (!c->fullspeed) > + goto list_lookup; > + } > + > + return config_buf(c, speed, cdev->req->buf, type); > + } > + --w_value; /* account for conf returned @ index 0 */ > + } This is non-ideal since the body of the if is repeated twice. Perhaps it could be folded into the loop, something like: /* This is a lookup by config *INDEX* */ w_value &= 0xff; struct list_head *pos = &cdev->configs; c = cdev->os_desc_config; if (c) goto check_config; while ((pos = pos->next) != &cdev->configs) { c = list_entry(pos, typeof(*c), list); /* skip OS config which is handled separately */ if (c == cdev->os_desc_config) continue; check_config: /* ignore configs that won't work at this speed */ switch (speed) { case USB_SPEED_SUPER: if (!c->superspeed) continue; break; case USB_SPEED_HIGH: if (!c->highspeed) continue; break; default: if (!c->fullspeed) continue; } if (w_value == 0) return config_buf(c, speed, cdev->req->buf, type); w_value--; } Not tested. > +list_lookup: > + /* This is a lookup by config *INDEX* */ > list_for_each_entry(c, &cdev->configs, list) { > /* ignore configs that won't work at this speed */ > switch (speed) { -- Best regards, _ _ .o. | Liege of Serenely Enlightened Majesty of o' \,=./ `o ..o | Computer Science, Michał “mina86” Nazarewicz (o o) ooo +--<mpn@xxxxxxxxxx>--<xmpp:mina86@xxxxxxxxxx>--ooO--(_)--Ooo--
Attachment:
signature.asc
Description: PGP signature