• Alan Stern's avatar
    USB: core: Unite old scheme and new scheme descriptor reads · 85d07c55
    Alan Stern authored
    In preparation for reworking the usb_get_device_descriptor() routine,
    it is desirable to unite the two different code paths responsible for
    initially determining endpoint 0's maximum packet size in a newly
    discovered USB device.  Making this determination presents a
    chicken-and-egg sort of problem, in that the only way to learn the
    maxpacket value is to get it from the device descriptor retrieved from
    the device, but communicating with the device to retrieve a descriptor
    requires us to know beforehand the ep0 maxpacket size.
    
    In practice this problem is solved in two different ways, referred to
    in hub.c as the "old scheme" and the "new scheme".  The old scheme
    (which is the approach recommended by the USB-2 spec) involves asking
    the device to send just the first eight bytes of its device
    descriptor.  Such a transfer uses packets containing no more than
    eight bytes each, and every USB device must have an ep0 maxpacket size
    >= 8, so this should succeed.  Since the bMaxPacketSize0 field of the
    device descriptor lies within the first eight bytes, this is all we
    need.
    
    The new scheme is an imitation of the technique used in an early
    Windows USB implementation, giving it the happy advantage of working
    with a wide variety of devices (some of them at the time would not
    work with the old scheme, although that's probably less true now).  It
    involves making an initial guess of the ep0 maxpacket size, asking the
    device to send up to 64 bytes worth of its device descriptor (which is
    only 18 bytes long), and then resetting the device to clear any error
    condition that might have resulted from the guess being wrong.  The
    initial guess is determined by the connection speed; it should be
    correct in all cases other than full speed, for which the allowed
    values are 8, 16, 32, and 64 (in this case the initial guess is 64).
    
    The reason for this patch is that the old- and new-scheme parts of
    hub_port_init() use different code paths, one involving
    usb_get_device_descriptor() and one not, for their initial reads of
    the device descriptor.  Since these reads have essentially the same
    purpose and are made under essentially the same circumstances, this is
    illogical.  It makes more sense to have both of them use a common
    subroutine.
    
    This subroutine does basically what the new scheme's code did, because
    that approach is more general than the one used by the old scheme.  It
    only needs to know how many bytes to transfer and whether or not it is
    being called for the first iteration of a retry loop (in case of
    certain time-out errors).  There are two main differences from the
    former code:
    
    	We initialize the bDescriptorType field of the transfer buffer
    	to 0 before performing the transfer, to avoid possibly
    	accessing an uninitialized value afterward.
    
    	We read the device descriptor into a temporary buffer rather
    	than storing it directly into udev->descriptor, which the old
    	scheme implementation used to do.
    
    Since the whole point of this first read of the device descriptor is
    to determine the bMaxPacketSize0 value, that is what the new routine
    returns (or an error code).  The value is stored in a local variable
    rather than in udev->descriptor.  As a side effect, this necessitates
    moving a section of code that checks the bcdUSB field for SuperSpeed
    devices until after the full device descriptor has been retrieved.
    Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
    Cc: Oliver Neukum <oneukum@suse.com>
    Link: https://lore.kernel.org/r/495cb5d4-f956-4f4a-a875-1e67e9489510@rowland.harvard.eduSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    85d07c55
hub.c 183 KB