Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

USBUS: Initial work towards an USB stack #10916

Merged
merged 3 commits into from
Jun 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,12 @@ ifneq (,$(filter tlsf-malloc,$(USEMODULE)))
USEPKG += tlsf
endif

ifneq (,$(filter usbus,$(USEMODULE)))
FEATURES_REQUIRED += periph_usbdev
USEMODULE += core_thread_flags
USEMODULE += event
endif

ifneq (,$(filter uuid,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += random
Expand Down
31 changes: 31 additions & 0 deletions examples/usbus_minimal/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# name of your application
APPLICATION = usbus_minimal

# If no BOARD is found in the environment, use this default:
BOARD ?= samr21-xpro

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

USEMODULE += usbus

# USB device vendor and product ID
USB_VID ?= 1209
USB_PID ?= 0001

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

CFLAGS += -DUSB_CONFIG_VID=0x$(USB_VID) -DUSB_CONFIG_PID=0x$(USB_PID)

include $(RIOTBASE)/Makefile.include

ifeq ($(USB_VID):$(USB_PID), 1209:0001)
$(shell $(COLOR_ECHO) "$(COLOR_RED)Private testing pid.codes USB VID/PID used!, do not use it outside of test environments!$(COLOR_RESET)" 1>&2)
$(shell $(COLOR_ECHO) "$(COLOR_RED)MUST NOT be used on any device redistributed, sold or manufactured, VID/PID is not unique!$(COLOR_RESET)" 1>&2)
endif
16 changes: 16 additions & 0 deletions examples/usbus_minimal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# usbus_minimal example

This is a minimalistic example for RIOT's USB stack. The application will
initialize and start the USB stack. The stack is started without any USB
handlers, it should show up as an empty USB device on the host.

RIOT doesn't own any USB vendor and product ID. To compile this example, add
your own vendor and product ID to the makefile:

```
CFLAGS += -DUSB_CONFIG_VID=0xYOURVID -DUSB_CONFIG_PID=0xYOURPID
```

The example demonstrates basic USB communication between a host and a RIOT
based USB peripheral. Tools such as `lsusb` should display the device and
detailed information about the device such as descriptor strings.
44 changes: 44 additions & 0 deletions examples/usbus_minimal/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2019 Koen Zandberg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup examples
* @{
*
* @file
* @brief Example application for demonstrating the RIOT USB stack
*
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/

#include <stdio.h>
#include "usb/usbus.h"

static char _stack[USBUS_STACKSIZE];

static usbus_t usbus;
/* TODO: remove as soon as we have decent auto_init */
#include "periph_conf.h"
#include "sam_usb.h"

int main(void)
{
puts("RIOT USB stack example application");

/* TODO: remove as soon as we have decent auto_init */
usbdev_t *usbdev_ctx = usbdev_get_ctx(0);
/* start usb stack */
usbus_init(&usbus, usbdev_ctx);
usbus_create(_stack, sizeof(_stack), USBUS_PRIO, USBUS_TNAME, &usbus);

/* start shell */
puts("Started USB stack!");
return 0;
}
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ endif
ifneq (,$(filter bluetil_%,$(USEMODULE)))
DIRS += net/ble/bluetil
endif
ifneq (,$(filter usbus usbus_%,$(USEMODULE)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ifneq (,$(filter usbus,$(USEMODULE))) isn't enough ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit of future planning. I can remove it here but I would have to include it again in one of the follow ups.

DIRS += usb/usbus
endif

DIRS += $(dir $(wildcard $(addsuffix /Makefile, $(USEMODULE))))

Expand Down
9 changes: 8 additions & 1 deletion sys/include/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,14 @@ extern "C" {
* @note Not to be be confused with the USB version number
*/
#ifndef USB_CONFIG_PRODUCT_BCDVERSION
#define USB_CONFIG_PRODUCT_BCDVERSION "0x0100"
#define USB_CONFIG_PRODUCT_BCDVERSION 0x0100
#endif

/**
* @brief USB specification version
*/
#ifndef USB_CONFIG_SPEC_BCDVERSION
#define USB_CONFIG_SPEC_BCDVERSION 0x0200
#endif

/**
Expand Down
223 changes: 223 additions & 0 deletions sys/include/usb/descriptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
* Copyright (C) 2018 Koen Zandberg <koen@bergzand.net>
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for
* more details.
*/
/**
* @defgroup usb_descriptor USB descriptors
* @ingroup usb
* @brief Provides USB protocol descriptors and defines for USB frameworks.
* @{
*
* @file
* @brief Definitions for USB protocol messages
*
* @author Koen Zandberg <koen@bergzand.net>
*/
#ifndef USB_DESCRIPTOR_H
#define USB_DESCRIPTOR_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @name USB standard device request codes (USB 2.0 spec table 9-4)
* @{
*/
#define USB_SETUP_REQ_GET_STATUS 0x00 /**< Status request */
#define USB_SETUP_REQ_CLEAR_FEATURE 0x01 /**< Clear feature */
#define USB_SETUP_REQ_SET_FEATURE 0x03 /**< Set feature */
#define USB_SETUP_REQ_SET_ADDRESS 0x05 /**< Set address */
#define USB_SETUP_REQ_GET_DESCRIPTOR 0x06 /**< Get descriptor */
#define USB_SETUP_REQ_SET_DESCRIPTOR 0x07 /**< Set descriptor */
#define USB_SETUP_REQ_GET_CONFIGURATION 0x08 /**< Get configuration */
#define USB_SETUP_REQ_SET_CONFIGURATION 0x09 /**< Set configuration */
#define USB_SETUP_REQ_GET_INTERFACE 0x0a /**< Get interface */
#define USB_SETUP_REQ_SET_INTERFACE 0x0b /**< Set interface */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing SYNCH_FRAME.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also 0xb or 0xB, you must choose and unify this :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unified

/** @} */

/**
* @name USB descriptor types (USB 2.0 spec table 9-5)
* @{
*/
#define USB_TYPE_DESCRIPTOR_DEVICE 0x01 /**< Device descriptor */
#define USB_TYPE_DESCRIPTOR_CONFIGURATION 0x02 /**< Configuration Descriptor */
#define USB_TYPE_DESCRIPTOR_STRING 0x03 /**< String descriptor */
#define USB_TYPE_DESCRIPTOR_INTERFACE 0x04 /**< Interface descriptor */
#define USB_TYPE_DESCRIPTOR_ENDPOINT 0x05 /**< Endpoint descriptor */
#define USB_TYPE_DESCRIPTOR_DEV_QUALIFIER 0x06 /**< Device qualifier */
#define USB_TYPE_DESCRIPTOR_SPEED_CONFIG 0x07 /**< Other speed configuration */
#define USB_TYPE_DESCRIPTOR_IFACE_POWER 0x08 /**< Interface power */
#define USB_TYPE_DESCRIPTOR_INTERFACE_ASSOC 0x0b /**< Interface association */
/** @} */

/**
* @name USB configuration attributes
* @anchor USB_CONF_ATTR
* @{
*/
#define USB_CONF_ATTR_RESERVED 0x80 /**< Reserved bit (always 1) */
#define USB_CONF_ATTR_SELF_POWERED 0x40 /**< Self powered device flag */
#define USB_CONF_ATTR_REM_WAKEUP 0x20 /**< Remote wake-up flag */
/** @} */

/**
* @name USB setup packet requests types
* @{
*/
#define USB_SETUP_REQUEST_DEVICE2HOST 0x80 /**< Request direction
From device to host if
the bit is set */

#define USB_SETUP_REQUEST_RECIPIENT_MASK 0x1f /**< Recipient mask */
#define USB_SETUP_REQUEST_RECIPIENT_DEVICE 0x00 /**< Device request */
#define USB_SETUP_REQUEST_RECIPIENT_INTERFACE 0x01 /**< Interface request */
#define USB_SETUP_REQUEST_RECIPIENT_ENDPOINT 0x02 /**< Endpoint request */
#define USB_SETUP_REQUEST_RECIPIENT_OTHER 0x03 /**< Other type request */

#define USB_SETUP_REQUEST_TYPE_MASK 0x60 /**< Mask to select the type */
#define USB_SETUP_REQUEST_TYPE_STANDARD 0x00 /**< Standard request */
#define USB_SETUP_REQUEST_TYPE_CLASS 0x20 /**< Class request */
#define USB_SETUP_REQUEST_TYPE_VENDOR 0x40 /**< Vendor specific request */
/** @} */

/**
* @brief USB isochronous endpoint interval
*/
#define USB_ENDPOINT_DESCRIPTOR_INTERVAL_ISOCHRONOUS 1

/**
* @name USB device class numbers
* @{
*/
#define USB_CLASS_AUDIO 0x01 /**< Audio device */
#define USB_CLASS_CDC_CONTROL 0x02 /**< CDC control interface */
#define USB_CLASS_HID 0x03 /**< Human Interface device */
#define USB_CLASS_PHYSICAL 0x05 /**< Physical device class */
#define USB_CLASS_IMAGE 0x06 /**< Image device class */
#define USB_CLASS_PRINTER 0x07 /**< Printer device class */
#define USB_CLASS_MASS_STORAGE 0x08 /**< Mass storage device class */
#define USB_CLASS_CDC_DATA 0x0a /**< CDC data specification */
#define USB_CLASS_VENDOR 0xff /**< Vendor specific class */
/** @} */

/**
* @brief USB device descriptor (USB 2.0 spec table 9-8)
*/
typedef struct __attribute__((packed)) {
uint8_t length; /**< Size of this descriptor */
uint8_t type; /**< Descriptor type (@ref USB_TYPE_DESCRIPTOR_DEVICE) */
uint16_t bcd_usb; /**< Binary-coded decimal USB release specification */
uint8_t class; /**< Device class code */
uint8_t subclass; /**< Device subclass code */
uint8_t protocol; /**< Device protocol code */
uint8_t max_packet_size; /**< EP0 max packet size (8, 16, 32 or 64 bytes) */
uint16_t vendor_id; /**< Vendor ID (as assigned by the USB-IF) */
uint16_t product_id; /**< Product ID */
uint16_t bcd_device; /**< Binary-coded decimal device release */
uint8_t manufacturer_idx; /**< Manufacturer string index number */
uint8_t product_idx; /**< Product string index number */
uint8_t serial_idx; /**< Device serial number string index number */
uint8_t num_configurations; /**< Number of possible configurations */
} usb_descriptor_device_t;

/**
* @brief USB configuration descriptor (USB 2.0 spec table 9-10)
*/
typedef struct __attribute__((packed)) {
uint8_t length; /**< Size of this descriptor */
uint8_t type; /**< Descriptor type (@ref USB_TYPE_DESCRIPTOR_CONFIGURATION) */
uint16_t total_length; /**< Total length of the configuration */
uint8_t num_interfaces; /**< Number of interfaces supported by this configuration */
uint8_t val; /**< Value to select this configuration by */
uint8_t idx; /**< Configuration descriptor string index */
uint8_t attributes; /**< Configuration attributes (@ref USB_CONF_ATTR) */
uint8_t max_power; /**< Maximum power consumption in 2mA steps */
} usb_descriptor_configuration_t;

/**
* @brief USB interface descriptor (USB 2.0 spec table 9-12)
*/
typedef struct __attribute__((packed)) {
uint8_t length; /**< Size of this descriptor */
uint8_t type; /**< Descriptor type (@ref USB_TYPE_DESCRIPTOR_INTERFACE) */
uint8_t interface_num; /**< Interface number */
uint8_t alternate_setting; /**< Alternate setting index */
uint8_t num_endpoints; /**< Number of endpoints used by this interface */
uint8_t class; /**< Interface class code as assigned by the USB-IF */
uint8_t subclass; /**< Subclass code as assigned by the USB-IF */
uint8_t protocol; /**< Protocol code */
uint8_t idx; /**< Interface descriptor string index */
} usb_descriptor_interface_t;

/**
* @brief USB endpoint descriptor (USB 2.0 spec table 9-13)
*/
typedef struct __attribute__((packed)) {
uint8_t length; /**< Size of this descriptor */
uint8_t type; /**< Descriptor type (@ref USB_TYPE_DESCRIPTOR_ENDPOINT) */
uint8_t address; /**< Address of the endpoint */
uint8_t attributes; /**< Attributes of the endpoint */
uint16_t max_packet_size; /**< Maximum packet size of the endpoint */
uint8_t interval; /**< Polling interval for the endpoint */
} usb_descriptor_endpoint_t;

/**
* @brief USB string descriptor (USB 2.0 spec table 9-16)
*/
typedef struct __attribute__((packed)) {
uint8_t length; /**< Size of this descriptor */
uint8_t type; /**< String descriptor type */
} usb_descriptor_string_t;

/**
* @brief USB interface association descriptor (Interface Association
* Descriptors table 9-Z)
*/
typedef struct __attribute__((packed)) {
uint8_t length; /**< Size of this descriptor */
uint8_t type; /**< Descriptor type (@ref USB_TYPE_DESCRIPTOR_INTERFACE_ASSOC) */
uint8_t first_interface; /**< Index of the first associated interface */
uint8_t interface_count; /**< Number of associated interfaces */
uint8_t class; /**< Non-zero class code */
uint8_t subclass; /**< Subclass code */
uint8_t protocol; /**< Protocol code */
uint8_t idx; /**< Descriptor string index */
} usb_descriptor_interface_association_t;

/**
* @brief USB setup packet (USB 2.0 spec table 9-2)
*/
typedef struct __attribute__((packed)) {
uint8_t type; /**< Request type */
uint8_t request; /**< Specific request */
uint16_t value; /**< Value word */
uint16_t index; /**< Index/offset word */
uint16_t length; /**< Length of the data stage */
} usb_setup_t;

/**
* @brief getter for setup packet direction
*
* @param[in] pkt setup packet
*
* @return nonzero if it is a read request
* @return zero if it is a write request
*/
static inline bool usb_setup_is_read(usb_setup_t *pkt)
{
return pkt->type & USB_SETUP_REQUEST_DEVICE2HOST;
}

#ifdef __cplusplus
}
#endif

#endif /* USB_DESCRIPTOR_H */
/** @} */
Loading