Re: [PATCHv2] usb: gadget: get rid of USB_GADGET_DUALSPEED andUSB_GADGET_SUPERSPEED

From: Michal Nazarewicz
Date: Thu Aug 18 2011 - 16:13:24 EST


On Thu, 18 Aug 2011 19:27:21 +0200, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:

On Thu, 18 Aug 2011, Michal Nazarewicz wrote:

For the most part, usb_composite_probe() is called only once in module's
init function. As far as I know, only g_ffs calls it several times. So
in all cases expect for g_ffs, composite_driver.speed =
min(composite_driver.speed,
driver->max_speed) should have the same effect as composite_driver.speed
= driver->max_speed.

> For example, if you have a composite gadget where one of the function
> drivers can handle SuperSpeed and the other can't go beyond high speed,
> the overall gadget must never run faster than high speed.

Shouldn't that be dealt in usb_add_function()? I cannot see any code that would do that here atm though.

Maybe you're right. But isn't that too late? The UDC driver has to
know the gadget driver's limitations before it can connect to the host.

usb_add_function() is called before usb_composite_probe() which only then
calls usb_gadget_probe_driver().

What's more, if I understand it correctly, comment in usb_add_function()
says that we support all the speeds usb_composite_driver structure claims
we do but then return different sets of functions depending on speed. Ie.
if a function is only full speed and host requests high speed, configuration
will lack that function. The comment in question is:

/* We allow configurations that don't work at both speeds.
* If we run into a lowspeed Linux system, treat it the same
* as full speed ... it's the function drivers that will need
* to avoid bulk and ISO transfers. */

usb_add_function() then proceeds to set config->fullspeed, config->highspeed
and config->superspeed depending on what descriptors function provides.

Those are later used in config_desc() where it iterates over all
configurations checking which have functions supporting given speed:

list_for_each_entry(c, &cdev->configs, list) {
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--;
}

config_buf() at the same time, iterates over all functions and skips the ones
that do not provide descriptors for given speed:

list_for_each_entry(f, &config->functions, list) {
switch (speed) {
case USB_SPEED_SUPER: descriptors = f->ss_descriptors; break;
case USB_SPEED_HIGH: descriptors = f->hs_descriptors; break;
default: descriptors = f->descriptors;
}
if (!descriptors)
continue;
[...]
}

So I think that your suggestion to use composite_driver.speed =
driver->max_speed was by all means correct.

--
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michal "mina86" Nazarewicz (o o)
ooo +-----<email/xmpp: mnazarewicz@xxxxxxxxxx>-----ooO--(_)--Ooo--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/