Re: autodetect USB MTP device characteristics without libusb_open()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 20, 2012 at 7:26 PM, Peter Stuge <peter@xxxxxxxx> wrote:

> Windows requests the 0xee string descriptor from *every* device,
> unless the same vid and pid has been seen before on the system.

I had no clue about that... have you seen this from USB traces?

I have seen devices crash when 0xee is requested, but it might
be that we're clearing the stall in the wrong way when it's not
there.

I was certainly under the impression that Windows does not
do this for devices it has seen before...

>> it turns out that users want MTP devices to "just work"
>> just like they "just work" on Windows.
>
> IMHO there's no other way to accomplish that other than to implement
> Microsoft's "extension" to USB; always request the 0xee string
> descriptor if the vidpid has not been seen before.

So currently we're doing this (using udev and the small program
mtp-probe, with the additional restriction that
it will only be done on devices that exhibit an interface that can
be MTP (1 BULK IN, 1 BULK OUT, 1 INTERRUPT IN).

We could do it for all devices but it might be that we're doing
something wrong with libusb so that several devices crash
when doing this.

Currently we do it like this:

    /* Read the special descriptor */
    ret = libusb_get_descriptor(devh, 0x03, 0xee, buf, sizeof(buf));

    /*
     * If something failed we're probably stalled to we need
     * to clear the stall off the endpoint and say this is not
     * MTP.
     */
    if (ret < 0) {
      /* EP0 is the default control endpoint */
      libusb_clear_halt (devh, 0);
      libusb_close(devh);
      return 0;
    }

    // Dump it, if requested
    if (dumpfile != NULL && ret > 0) {
      fprintf(dumpfile, "Microsoft device descriptor 0xee:\n");
      data_dump_ascii(dumpfile, buf, ret, 16);
    }

    /* Check if descriptor length is at least 10 bytes */
    if (ret < 10) {
      libusb_close(devh);
      return 0;
    }

    /* Check if this device has a Microsoft Descriptor */
    if (!((buf[2] == 'M') && (buf[4] == 'S') &&
	  (buf[6] == 'F') && (buf[8] == 'T'))) {
      libusb_close(devh);
      return 0;
    }

    /* Check if device responds to control message 1 or if there is an error */
    cmd = buf[16];
    ret = libusb_control_transfer (devh,
			   LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR,
			   cmd,
			   0,
			   4,
			   buf,
			   sizeof(buf),
			   USB_TIMEOUT_DEFAULT);

    // Dump it, if requested
    if (dumpfile != NULL && ret > 0) {
      fprintf(dumpfile, "Microsoft device response to control message
1, CMD 0x%02x:\n", cmd);
      data_dump_ascii(dumpfile, buf, ret, 16);
    }

    /* If this is true, the device either isn't MTP or there was an error */
    if (ret <= 0x15) {
      /* TODO: If there was an error, flag it and let the user know somehow */
      /* if(ret == -1) {} */
      libusb_close(devh);
      return 0;
    }

    /* Check if device is MTP or if it is something like a USB Mass Storage
       device with Janus DRM support */
    if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P')) {
      libusb_close(devh);
      return 0;
    }

    /* After this point we are probably dealing with an MTP device */

> It would mean that Linux systems must start keeping track of every
> device that a system has seen. It's atrocious.
>
> But I don't think there's another way. Of course, it could be part of
> a non-core package, so that only when the MTP software is installed
> will there be some database.

This is how it works today. The probing comes with libmtp,
which also provide the udev rules and thus notify userspace
that listen to the udev events.

> For most (I'm not sure I dare say all) other devices, it would add no
> value on Linux.

I fully agree ... well, Microsoft actually intended the device
descriptor to be used also for things like WiFi and Bluetooth
but it seems they never did that.

I have some vague indications that their DRM system for
USB mass storage is also using the special 0xee descriptor
to identify devices with such capabilities, but I have no
clue as to how this actually works. (You can see this from
the above code: we need to check that the returned descriptor
actually start with "MTP", it *could* say something else...)

> When a vidpid is attached which has never been seen on the system,
> Windows adds lots of values to the registry saying it has now seen
> this device, and then asks for the 0xee string descriptor.
>
> When a vidpid is attached which *has* been seen on this system
> (Windows looks for those values) the string descriptor is not
> requested.
>
> End result: A given device only ever crashes exactly once on a given
> Windows system.

Yep this is as far as I've understood as well.

But now you're contradicting the first paragraph of your
mail, so which one is it?

>> But they have this concept of an .inf file, so the first time
>> you insert an alien device, you are asked for an .inf file
>> with some driver information. Then you can bind that
>> VID+PID to a specific driver, and then  they will not look
>> further the next time the same device is plugged in again.
>> They will just load the driver given from the .inf file.
>
> Note that everything in the .inf gets stored in the registry.
> Noone looks at the .inf again, once the driver has been installed.

OK got it.

>> So I could mimic this by starting to cache away any
>> successfully initiated MTP devices in some /var/libmtp
>> file and just OK them the next time they are plugged in.
>
> You'll have to cache *every* device, so that you do not make a given
> device crash more than once, like Windows.

Hm, need to figure out how to do this then...

Thanks,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux