* This file holds USB constants and structures that are needed for USB device
* APIs, as defined in the USB 2.0 specification.
*
+ * \attention The API is work in progress and may change in future versions.
+ *
* $WIZ$ module_name = "usb"
* $WIZ$ module_configuration = "bertos/cfg/cfg_usb.h"
* $WIZ$ module_supports = "stm32"
#include <cpu/byteorder.h>
-/*
- * Handle CPU endianess
- *
- * TODO: consider to move this stuff in compiler.h
- */
-#define usb_bswap16(x) (((x & 0xff) << 8) | (x >> 8))
-#define usb_bswap32(x) ((usb_bswap16(x & 0xffff) << 16) | usb_bswap16(x >> 16))
-
-#if CPU_BYTE_ORDER == CPU_LITTLE_ENDIAN
-#define usb_cpu_to_le16(x) (x)
-#define usb_le16_to_cpu(x) (x)
-#define usb_cpu_to_le32(x) (x)
-#define usb_le32_to_cpu(x) (x)
-#elif CPU_BYTE_ORDER == CPU_BIG_ENDIAN
-#define usb_cpu_to_le16(x) usb_bswap16(x)
-#define usb_le16_to_cpu(x) usb_bswap16(x)
-#define usb_cpu_to_le32(x) usb_bswap32(x)
-#define usb_le32_to_cpu(x) usb_bswap32(x)
-#else
-#error "unrecognized CPU endianness"
-#endif
+#define usb_cpu_to_le16(x) cpu_to_le16(x)
+#define usb_le16_to_cpu(x) le16_to_cpu(x)
+#define usb_cpu_to_le32(x) cpu_to_le32(x)
+#define usb_le32_to_cpu(x) le32_to_cpu(x)
/* State of a USB device */
enum usb_device_state {
*/
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
+#define USB_DIR_MASK 0x80
/*
* USB types, the second of three bRequestType fields
#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
-/*
+/**
+ *
+ * USB Control Request descriptor
+ *
* This structure is used to send control requests to a USB device.
*
- * It matches the different fields of the USB 2.0 spec. section 9.3, table 9-2.
+ * It matches the different fields of the USB 2.0 specification (section 9.3,
+ * table 9-2).
*/
-typedef struct usb_ctrlrequest
+typedef struct UsbCtrlRequest
{
uint8_t mRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
-} PACKED usb_ctrlrequest_t;
+} PACKED UsbCtrlRequest;
-/* All standard descriptors have these 2 fields at the beginning */
-typedef struct usb_descriptor_header
+/**
+ * USB common descriptor header.
+ *
+ * \note All the USB standard descriptors have these 2 fields at the beginning.
+ */
+typedef struct UsbDescHeader
{
uint8_t bLength;
uint8_t bDescriptorType;
-} PACKED usb_descriptor_header_t;
+} PACKED UsbDescHeader;
-/* Device descriptor */
-typedef struct usb_device_descriptor
+/**
+ * USB Device descriptor
+ *
+ * \note See USB 2.0 specification.
+ */
+typedef struct UsbDeviceDesc
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
-} PACKED usb_device_descriptor_t;
+} PACKED UsbDeviceDesc;
-/* USB string descriptor */
-typedef struct usb_string_descriptor
+/**
+ * USB string descriptor.
+ *
+ * \note See USB 2.0 specification.
+ */
+typedef struct UsbStringDesc
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t data[0];
-} PACKED usb_string_descriptor_t;
+} PACKED UsbStringDesc;
-/*
- * Macros to define USB strings
- *
- * TODO: add comment.
- */
#define USB_STRING_1(__a, ...) __a "\x00"
#define USB_STRING_2(__a, ...) __a "\x00" USB_STRING_1(__VA_ARGS__)
#define USB_STRING_3(__a, ...) __a "\x00" USB_STRING_2(__VA_ARGS__)
#define USB_STRING_15(__a, ...) __a "\x00" USB_STRING_14(__VA_ARGS__)
#define USB_STRING_16(__a, ...) __a "\x00" USB_STRING_15(__VA_ARGS__)
+/**
+ * Pack a list with a variable number of elements into a UTF-16LE USB string.
+ *
+ * \note The macro is recursively defined according the number of elements
+ * passed as argument. At the moment we support strings with up to 16
+ * characters.
+ */
#define USB_STRING(...) PP_CAT(USB_STRING_, PP_COUNT(__VA_ARGS__))(__VA_ARGS__)
-#define DEFINE_USB_STRING(__name, __text) \
- struct { \
- usb_descriptor_header_t __header; \
- uint8_t __body[sizeof(__text)]; \
- } PACKED __name = { \
- .__header = { \
- .bLength = sizeof(__name), \
- .bDescriptorType = USB_DT_STRING, \
- }, \
- .__body = {__text}, \
+/**
+ * Define and initialize an USB string descriptor.
+ *
+ * This macro is reuquired to properly declare and initialize a constant USB
+ * string in UTF-16LE format.
+ *
+ * The structure must contain the standard common USB header (UsbDescHeader)
+ * and the UTF-16LE string all packed in a contiguous memory region.
+ */
+#define DEFINE_USB_STRING(__name, __text) \
+ struct { \
+ UsbDescHeader __header; \
+ uint8_t __body[sizeof(__text)]; \
+ } PACKED __name = { \
+ .__header = { \
+ .bLength = \
+ cpu_to_le16((uint16_t)sizeof(__name)), \
+ .bDescriptorType = USB_DT_STRING, \
+ }, \
+ .__body = {__text}, \
}
/*
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
-/* Device configuration descriptor */
-typedef struct usb_config_descriptor
+/* USB Device subclasses */
+#define USB_CDC_SUBCLASS_ACM 0x02
+#define USB_CDC_SUBCLASS_ETHERNET 0x06
+#define USB_CDC_SUBCLASS_WHCM 0x08
+#define USB_CDC_SUBCLASS_DMM 0x09
+#define USB_CDC_SUBCLASS_MDLM 0x0a
+#define USB_CDC_SUBCLASS_OBEX 0x0b
+#define USB_CDC_SUBCLASS_EEM 0x0c
+#define USB_CDC_SUBCLASS_NCM 0x0d
+
+/**
+ * Device configuration descriptor
+ *
+ * \note See USB 2.0 specification.
+ */
+typedef struct UsbConfigDesc
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
-} PACKED usb_config_descriptor_t;
+} PACKED UsbConfigDesc;
/* from config descriptor bmAttributes */
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
-/* Device interface descriptor */
-typedef struct usb_interface_descriptor
+/**
+ * Device interface descriptor
+ *
+ * \note See USB 2.0 specification.
+ */
+typedef struct UsbInterfaceDesc
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
-} PACKED usb_interface_descriptor_t;
+} PACKED UsbInterfaceDesc;
-/* Endpoint descriptor */
-typedef struct usb_endpoint_descriptor
+/**
+ * Endpoint descriptor
+ *
+ * \note See USB 2.0 specification.
+ */
+typedef struct UsbEndpointDesc
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
-} PACKED usb_endpoint_descriptor_t;
+} PACKED UsbEndpointDesc;
/*
* Endpoints
*/
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
-#define USB_ENDPOINT_DIR_MASK 0x80
+#define USB_ENDPOINT_DIR_MASK USB_DIR_MASK
#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
-/* USB: generic device descriptor */
-struct usb_device
+/**
+ * USB: generic device descriptor
+ */
+typedef struct UsbDevice
{
- usb_device_descriptor_t *device;
- usb_descriptor_header_t **config;
- usb_string_descriptor_t **strings;
+ UsbDeviceDesc *device; ///< USB 2.0 device descriptor
+ const UsbDescHeader **config; ///< USB 2.0 configuration descriptors
+ const UsbStringDesc **strings; ///< USB strings
+
+ /* Callbacks */
+ void (*event_cb)(UsbCtrlRequest *); ///< Called to handle control requests.
+
/* Private data */
- bool configured;
-};
+ bool configured; ///< True when the device has been correctly initialized.
+} UsbDevice;
-/*
- * usb_endpoint_num - get the endpoint's number
+/**
+ * Get the endpoint's address number of \a epd.
*/
-INLINE int usb_endpoint_num(const usb_endpoint_descriptor_t *epd)
+INLINE int usb_endpointNum(const UsbEndpointDesc *epd)
{
return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
-/*
- * usb_endpoint_type - get the endpoint's transfer type
+/**
+ * Get the transfer type of the endpoint \a epd.
*/
-INLINE int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointType(const struct UsbEndpointDesc *epd)
{
return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
}
-/*
- * usb_endpoint_dir_in - check if the endpoint has IN direction
+/**
+ * Check if the endpoint \a epd has IN direction.
*/
-INLINE int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointDirIn(const struct UsbEndpointDesc *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
}
-/*
- * usb_endpoint_dir_out - check if the endpoint has OUT direction
+/**
+ * Check if the endpoint \a epd has OUT direction.
*/
-INLINE int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointDirOut(const struct UsbEndpointDesc *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
}
-/*
- * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
+/**
+ * Check if the endpoint \a epd has bulk transfer type.
*/
-INLINE int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointXferBulk(const struct UsbEndpointDesc *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK);
}
-/*
- * usb_endpoint_xfer_control - check if the endpoint has control transfer type
+/**
+ * Check if the endpoint \a epd has control transfer type.
*/
-INLINE int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointXferControl(const struct UsbEndpointDesc *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL);
}
-/*
- * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
+/**
+ * Check if the endpoint \a epd has interrupt transfer type.
*/
-INLINE int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointXferInt(const struct UsbEndpointDesc *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT);
}
-/*
- * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
+/**
+ * Check if the endpoint \a epd has isochronous transfer type.
*/
-INLINE int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointXferIsoc(const struct UsbEndpointDesc *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_ISOC);
}
-/*
- * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
+/**
+ * Check if the endpoint \a epd is bulk IN.
*/
-INLINE int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointIsBulkIn(const struct UsbEndpointDesc *epd)
{
- return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd);
+ return usb_endpointXferBulk(epd) && usb_endpointDirIn(epd);
}
-/*
- * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
+/**
+ * Check if the endpoint \a epd is bulk OUT.
*/
-INLINE int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointIsBulkOut(const struct UsbEndpointDesc *epd)
{
- return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd);
+ return usb_endpointXferBulk(epd) && usb_endpointDirOut(epd);
}
-/*
- * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
+/**
+ * Check if the endpoint \a epd is interrupt IN.
*/
-INLINE int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointIsIntIn(const struct UsbEndpointDesc *epd)
{
- return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd);
+ return usb_endpointXferInt(epd) && usb_endpointDirIn(epd);
}
-/*
- * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
+/**
+ * Check if the endpoint \a epd is interrupt OUT.
*/
-INLINE int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointIsIntOut(const struct UsbEndpointDesc *epd)
{
- return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd);
+ return usb_endpointXferInt(epd) && usb_endpointDirOut(epd);
}
-/*
- * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
+/**
+ * Check if the endpoint \a epd is isochronous IN.
*/
-INLINE int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointIsIsocIn(const struct UsbEndpointDesc *epd)
{
- return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd);
+ return usb_endpointXferIsoc(epd) && usb_endpointDirIn(epd);
}
-/*
- * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
+/**
+ * Check if the endpoint \a epd is isochronous OUT.
*/
-INLINE int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
+INLINE int usb_endpointIsIsocOut(const struct UsbEndpointDesc *epd)
{
- return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd);
+ return usb_endpointXferIsoc(epd) && usb_endpointDirOut(epd);
}
-/*
- * usb_ep_read - configure endponint and perform the read operation
+/**
+ * Read up to \a size bytes from the USB endpoint identified by the address
+ * \a ep and store them in \a buffer.
+ *
+ * The \a timeout is an upper bound on the amount of time (in ticks) elapsed
+ * before returns. If \a timeout is zero, the the function returns immediatly
+ * and it basically works in non-blocking fashion. A negative value for \a
+ * timeout means that the function can block indefinitely.
+ *
+ * \return number of bytes actually read, or a negative value in case of
+ * errors.
*/
-ssize_t usb_ep_read(int ep, void *buffer, ssize_t size);
+ssize_t usb_endpointReadTimeout(int ep, void *buffer, ssize_t size,
+ ticks_t timeout);
-/*
- * usb_ep_write - configure endponint and perform the write operation
+INLINE ssize_t usb_endpointRead(int ep, void *buffer, ssize_t size)
+{
+ return usb_endpointReadTimeout(ep, buffer, size, -1);
+}
+
+/**
+ * Write up to \a size bytes from the buffer pointed \a buffer to the USB
+ * endpoint identified by the address \a ep.
+ *
+ * The \a timeout is an upper bound on the amount of time (in ticks) elapsed
+ * before returns. If \a timeout is zero, the the function returns immediatly
+ * and it basically works in non-blocking fashion. A negative value for \a
+ * timeout means that the function can block indefinitely.
+ *
+ * \return number of bytes actually wrote, or a negative value in case of
+ * errors.
*/
-ssize_t usb_ep_write(int ep, const void *buffer, ssize_t size);
+ssize_t usb_endpointWriteTimeout(int ep, const void *buffer, ssize_t size,
+ ticks_t timeout);
-/*
- * usb_device_register - register a generic USB device driver
+INLINE ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size)
+{
+ return usb_endpointWriteTimeout(ep, buffer, size, -1);
+}
+
+/**
+ * Register a generic USB device driver \a dev in the USB controller.
*/
-int usb_device_register(struct usb_device *dev);
+int usb_deviceRegister(UsbDevice *dev);
#endif /* USB_H */