Re: autodetect USB MTP device characteristics without libusb_open()

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

 



On Wed, Nov 7, 2012 at 12:28 AM, Bjørn Mork <bjorn@xxxxxxx> wrote:
> Linus Walleij <linus.walleij@xxxxxxxxxx> writes:

>> So all MTP devices manufactured before that spec, and numerous produced
>> after that spec came out, and several still being produced don't use the
>> class code, i.e. they violate the spec. But we still have to detect them
>> somehow.
>
> Yes, I feared so.  But it still seemed likely that the non conforming
> ones could be managed as a whitelist, if only most of the new ones were
> using the standard class codes.

I don't know if most of them do actually. Here is another device I
bought just the other day, Philips GoGear Vibe:

Bus 002 Device 008: ID 0471:20e5 Philips (or NXP)
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x0471 Philips (or NXP)
  idProduct          0x20e5
  bcdDevice            0.01
  iManufacturer           1 Philips
  iProduct                2 GoGear ViBE
  iSerial                 5 400400009D0CDC190002DCE4AF289C19
  bNumConfigurations      2
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           39
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          3 USB/MSC LCD Player
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk (Zip)
      iInterface              4 USB/MSC LCD Player
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval              16
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           39
    bNumInterfaces          1
    bConfigurationValue     2
    iConfiguration          3 USB/MSC LCD Player
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk (Zip)
      iInterface              4 USB/MSC LCD Player
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval              16
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  bNumConfigurations      2
Device Status:     0x0000
  (Bus Powered)

So two configurations, each with a USB mass storage
interface right?

Wrong!

One of them is an MTP interface, and will respond to MTP traffic.
I think the magic OS handshake make that come into play...
So Linux erroneously tries to use MSC on it, and we have to
use libusb_detach_kernel_driver() and then use the interface.

And then it works.

This type of misbehaviour is not uncommon, I just took some
device at random, there are literally millions of these.

>> Here are some device logs I've been collecting:
>> http://libmtp.git.sourceforge.net/git/gitweb.cgi?p=libmtp/libmtp;a=tree;f=logs;hb=HEAD
>
> Thanks.  That looks somewhat useful, except that you only seem to
> collect the device codes and not the interface codes.

Yeah :-/ I admit to being young and foolish ...

>  I am wondering if
> that is much of the problem here?  You seem to only look at the device
> when in fact most of the new MTP devices are composite devices (phones)?

Yes, I'm perhaps not clever enough with my udev rules.

It currently looks like this, first the avoidance of unnecessary
or dangerous probes, the sensitive devices react to something in
our libusb_open() or subsequent stuff to enumerate configs,
interfaces, altsettings etc...

ACTION!="add", GOTO="libmtp_rules_end"
ENV{MAJOR}!="?*", GOTO="libmtp_rules_end"
SUBSYSTEM=="usb", GOTO="libmtp_usb_rules"
GOTO="libmtp_rules_end"

LABEL="libmtp_usb_rules"

# Some sensitive devices we surely don't wanna probe
# Color instruments
ATTR{idVendor}=="0670", GOTO="libmtp_rules_end"
ATTR{idVendor}=="0765", GOTO="libmtp_rules_end"
ATTR{idVendor}=="085c", GOTO="libmtp_rules_end"
ATTR{idVendor}=="0971", GOTO="libmtp_rules_end"
# Canon scanners that look like MTP devices (PID 0x22nn)
ATTR{idVendor}=="04a9", ATTR{idProduct}=="22*", GOTO="libmtp_rules_end"
# Canon digital camera (EOS 3D) that looks like MTP device (PID 0x3113)
ATTR{idVendor}=="04a9", ATTR{idProduct}=="3113", GOTO="libmtp_rules_end"
# Sensitive Atheros devices that look like MTP devices
ATTR{idVendor}=="0cf3", GOTO="libmtp_rules_end"
# Sensitive Atmel JTAG programmers
ATTR{idVendor}=="03eb", GOTO="libmtp_rules_end"

# Creative ZEN Vision
ATTR{idVendor}=="041e", ATTR{idProduct}=="411f", SYMLINK+="libmtp-%k",
ENV{ID_MTP_DEVICE}="1", ENV{ID_MEDIA_PLAYER}="1"
(...)

Then follows a long chunk of whitelisted, known MTP players.

(...)
# Autoprobe vendor-specific, communication and PTP devices
ENV{ID_MTP_DEVICE}!="1", ENV{MTP_NO_PROBE}!="1",
ENV{COLOR_MEASUREMENT_DEVICE}!="1", ENV{libsane_matched}!="yes",
ATTR{bDeviceClass}=="00|02|06|ef|ff", PROGRAM="mtp-probe
/sys$env{DEVPATH} $attr{busnum} $attr{devnum}", RESULT=="1",
SYMLINK+="libmtp-%k", ENV{ID_MTP_DEVICE}="1", ENV{ID_MEDIA_PLAYER}="1"

LABEL="libmtp_rules_end"


So that rather horrible rule avoids probing:

- Devices we just detected in the whitelist
- Color measurement or scanner devices (these have been
  prone to errors...)
- Then check only the classes we mentioned

So I guess you're suggesting another step, checking the interfaces?

>>       bInterfaceClass         0 (Defined at Interface level)
>>       bInterfaceSubClass      0
>>       bInterfaceProtocol      0
>>       iInterface             33 MTP Interface
>
>
> Ouch.  Yes, not much else to do there than using vid:pid or probing.

That's just one way of misbehaving. The other example is actually
more scary I think.

> Do you know if these early devices support the typical Microsoft
> descriptors? I.e. the 0xee string descriptor with "MSFT100<code>"
> and its friends?

Almost all devices support this. (There are exceptions even to this.)
So this is what we do as a last resort, if we can't figure it out
some other way.

The problem appear when you ask a device which is not MTP
for that descriptor, some of them just die, so I cannot do
that.

But the blacklisted devices at the top of the udev script does
not even survive having libusb open the device to check its
descriptors, configs, interfaces etc.

> I assume even the most buggy devices will survive asking for a string
> descriptor...

I don't know actually. We have experiences of devices
crashing for everything but maybe I'm over-cautious and
a bit superstitious...

> Sure you can and should check the interface class.   Do a
>
>    grep bInterfaceClass /lib/udev/rules.d/*
>
> and you will hopefully see a couple of examples.

OK this is nice. The first example above will totally violate
all such rules though (but it will be cought by the whitelist).

> And I still wonder about the libusb_open screwing up devices.  It does
> not touch the device at all. And you can get the configuration
> descriptor without communicating with the device.  The OS has already
> cached that for you.  So how come you think libusb_open screws up
> anything?  If it did, then the device would already be dead when the
> Linux USB core enumerated it.

Yeah so I'm not sure that is the case, when you push me on
this detail...

What we do is found here:
http://sourceforge.net/p/libmtp/code/ci/5b9bd248fefe6d6243be9649109718760179d9bd/tree/src/libusb1-glue.c

Check functions:

probe_device_descriptor()
LIBMTP_Check_Specific_Device()

The latter is called by the udev script to check if a specific
device is MTP or not.

>> 02 = comms device class, a lot of phones use this
>> 06 = yay! PTP yes among others...
>> ef = no idea why this is used, but it is
>
> I assume that is in combination with subclass 02 and protocol 01, which
> specifies "Interface Association Descriptor" and will be common for
> phones and modems.  See
> http://www.usb.org/developers/whitepapers/iadclasscode_r10.pdf
>
> It's just another "unspecified, check interfaces" really.

OK I get it ... that's sort of what I thought.

> Those are always going to be a problem.  But I was hoping they were only
> older devices.  The rest of your list of device classes should have
> meaningful interface class/subclass/protocol codes.  Don't they?

See example at top (not an old device) :-P

>> To check if a device with class 6 is PTP or MTP the only
>> trusted way is to open a PTP session and check for a specific
>> descriptor actually.
>
> Yes, that's what I gathered from the MTP spec.
>
>> Problem: you cannot open a session to
>> an MTP device in say a udev script, then close it and open
>> another session later, because many devices crash when
>> a session is closed. This is of course yet another spec
>> violation, but comes from the fact that Windows never
>> close sessions, it keeps the device hogged until it's
>> plugged out or the host is shut down.
>
> Nice.  But how are you then going to deal with PTP devices crashing?
> Blacklist them by vid:pid? Or is this only a problem with MTP devices?

I *think* this is a MTP-only problem.

The reason is that pure PTP devices are usually cameras,
and as such used by Mac OS geeks, i.e. anyone doing
a camera will of course test it with a Mac and scream if
it doesn't work. And Mac is more strict with it's PTP.

But MTP is only supported by Windows and libmtp
implementations... and non-Windows doesn't seem to
get much exercise. (I have got some mail from Phone
manufacturers recently, SONY are notably helpful.)

Yours,
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