USB gadget with drivers "on board"

From: MichaÅ Nazarewicz
Date: Mon Apr 26 2010 - 08:06:23 EST


Hello everyone,

I need to create an USB gadget with drivers for Windows included
"on board". In particular, when the gadget is connected to Windows
host it is detected as mass storage and mounted drive include the
drivers. However, when the drivers are installed, it is detected
as some other device.

Now, it seems that a simple composite device with two configurations
is enough -- the first containing mass storage and the second other
functions. My tests show that Windows manages to set the first
configuration and detect the mass storage interface.

Unfortunately, Linux does the same thing -- chooses the first
configuration and detects the mass storage interface. What I'd
like to see is Linux choosing the second configuration which is
more functional.

Is there any way to accomplish that?

I came up with an idea of swapping bConfigurationValues (so that mass
storage configuration has it set to 2 and the other configuration
has it set to 1) but still retaining the order those are given to
host (a bit like with g_ether).

This however did not work, as Linux pretty much ignores those values
when choosing configuration.

So can it be done differently?

I think the following change would achieve the result I am seeking:

diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index bdf87a8..38fd44e 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -121,21 +121,22 @@ int usb_choose_configuration(struct usb_device *udev)
else if (udev->descriptor.bDeviceClass !=
USB_CLASS_VENDOR_SPEC &&
(!desc || desc->bInterfaceClass !=
USB_CLASS_VENDOR_SPEC)) {
best = c;
break;
}

/* If all the remaining configs are vendor-specific,
* choose the first one. */
- else if (!best)
+ else if (!best || best->desc.bConfigurationValue > c->desc.bConfigurationValue)
best = c;
}

if (insufficient_power > 0)
dev_info(&udev->dev, "rejected %d configuration%s "
"due to insufficient available bus power\n",
insufficient_power, plural(insufficient_power));

if (best) {
i = best->desc.bConfigurationValue;

Or maybe it'd be a good idea to prefer configurations with bigger
number of interfaces?

So what do you think? Does anyone know a (better) solution?

--
Best regards, _ _
--.--| Liege of Serenely Enlightened Majesty of o' \,=./ `o
---.-| Computer Science, MichaÅ "mina86" Nazarewicz (o o)
-...-+---[mina86@xxxxxxxxxx]---[mina86@jabber.org]---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/