USB Endpoints in Linux
26 July 2011 Leave a comment
USB endpoints are the logical entities that make up one-way communication channels in a USB system. Endpoints are unidirectional and the direction is always with respect to the host. IN endpoints are for transfers to the host from the device (host<-device), and OUT endpoints are for transfers from the host to the device (host->device). Refer to the USB specification for more information about endpoints, or try this reference from BeyondLogic on endpoint types.
In the Linux kernel the struct usb_host_endpoint, defined in <linux/usb.h>, is used to describe a USB endpoint.
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
Among other things, it contains the head of a linked list of URBs (to be discussed later) and a struct usb_endpoint_descriptorwhich is used to describe the endpoint in terms of the USB spec. In <linux/usb/ch9.h>, the definition of the endpoint descriptor can be seen:
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16 wMaxPacketSize;
__u8 bInterval;
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
In order to determine the direction of the endpoint, a few helper functions are available:
#define USB_ENDPOINT_DIR_MASK 0x80
...
static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
}
...
static inline int usb_endpoint_dir_out(
const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
}
This could all be done manually with the USB_ENDPOINT_DIR_MASK mask itself, but in order to guard against futures changes, it is best to use the abstractions and helper functions defined in the kernel. The endpoint transfer type can also be retrieved with helper functions.
#define USB_ENDPOINT_XFERTYPE_MASK 0x03
...
static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
{
return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
}
...
static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK);
}
...
static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL);
}
...
static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT);
}
...
static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_ISOC);
}
Next the Linux kernel representations of USB Interfaces and USB Configurations will be examined.