[U-Boot] [Bug Report] USB: descriptor handling
Stefan Althoefer
stefan.althoefer at web.de
Sun Dec 7 19:39:11 CET 2008
Hi,
I found a bug when working with the u-boot USB subsystem on IXP425 processor
(big endian Xscale aka ARMv5).
I recognized that the second usb_endpoint_descriptor of the attached memory
stick was corrupted.
The reason for this are the packed structures below (either u-boot and
u-boot-usb):
--------------
/* Endpoint descriptor */
struct usb_endpoint_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bEndpointAddress;
unsigned char bmAttributes;
unsigned short wMaxPacketSize;
unsigned char bInterval;
unsigned char bRefresh;
unsigned char bSynchAddress;
} __attribute__ ((packed));
/* Interface descriptor */
struct usb_interface_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bInterfaceNumber;
unsigned char bAlternateSetting;
unsigned char bNumEndpoints;
unsigned char bInterfaceClass;
unsigned char bInterfaceSubClass;
unsigned char bInterfaceProtocol;
unsigned char iInterface;
unsigned char no_of_ep;
unsigned char num_altsetting;
unsigned char act_altsetting;
struct usb_endpoint_descriptor ep_desc[USB_MAXENDPOINTS];
} __attribute__ ((packed));
------------
As usb_endpoint_descriptor is only 7byte in length, the start of all
odd ep_desc[] structures is not word aligned. This makes wMaxPacketSize
of these structures also not word aligned.
ARMv5 Architecture however does not support non-aligned multibyte
data type (see A2.8 of ARM Architecture Reference Manual).
--- this piece of code in usb.c -------
case USB_DT_ENDPOINT:
epno = dev->config.if_desc[ifno].no_of_ep;
/* found an endpoint */
{ int ii;
USB_PRINTF("EPD(%d): ", buffer[index]);
for(ii=0; ii<buffer[index]; ii++){
USB_PRINTF("%.2x ", buffer[index+ii]);
}
USB_PRINTF("\n");
}
dev->config.if_desc[ifno].no_of_ep++;
memcpy(&dev->config.if_desc[ifno].ep_desc[epno],
&buffer[index], buffer[index]);
le16_to_cpus(&(dev->config.if_desc[ifno].ep_desc[epno].\
wMaxPacketSize));
{ int ii;
USB_PRINTF("EPD(%d): ", buffer[index]);
for(ii=0; ii<buffer[index]; ii++){
USB_PRINTF("%.2x ",*((unsigned char *)(&dev->config.if_desc[ifno].ep_desc[epno])+ii));
}
USB_PRINTF("\n");
}
USB_PRINTF("if %d, ep %d\n", ifno, epno);
break;
----and following output (shortened) ---
<first descriptor>
EPD(7): 07 05 81 02 40 00 00 <- before endian swapping
EPD(7): 07 05 81 02 00 40 00 <- after endian swapping
<second descriptor>
EPD(7): 07 05 02 02 40 00 00
EPD(7): 07 05 02 02 00 40 00
-------
It seems that the actual ARM implementation does support reading of non-aligned
words (else USB would never have run on ARM) but writing is
definitely not. You see the data of the second descriptor garbled.
As writing is only needed on big endian ARM (for data swapping)
this issue has been undetected up to now.
Either wMaxPacket size must be accessed with special code, or it
must be aligned to modulo-2 address.
I suggest:
------------
diff --git a/include/usb.h b/include/usb.h
index 9a2e72c..b36272b 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -93,8 +93,7 @@ struct usb_endpoint_descriptor {
unsigned char bInterval;
unsigned char bRefresh;
unsigned char bSynchAddress;
-
-} __attribute__ ((packed));
+} __attribute__ ((packed)) __attribute__ ((aligned(2)));
/* Interface descriptor */
struct usb_interface_descriptor {
unsigned char bLength;
------------
With this change memory stick is identied correctly. I can do "fatls",
but I cannot read data correctly from the disk. But might be something
completely different issue ....
--- Stefan
More information about the U-Boot
mailing list