Cleanup
This commit is contained in:
parent
9f53d2b9f4
commit
65b14f399a
222
usb.c
222
usb.c
|
@ -8,37 +8,10 @@
|
|||
|
||||
#include "usb.h"
|
||||
|
||||
// Number of serial devices we want to provide.
|
||||
/* Number of serial devices we want to provide. */
|
||||
#define NUM_SERIAL 2
|
||||
|
||||
static const struct usb_device_descriptor dev = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
|
||||
// Devices with class 0xEF, subclass 2, and protocol 1 are interface associations
|
||||
.bDeviceClass = 0xEF,
|
||||
.bDeviceSubClass = 2,
|
||||
.bDeviceProtocol = 1,
|
||||
|
||||
.bMaxPacketSize0 = 64,
|
||||
|
||||
.idVendor = 0x0483,
|
||||
.idProduct = 0x5740,
|
||||
|
||||
// Revision of the device: 2.00
|
||||
.bcdDevice = 0x0200,
|
||||
|
||||
// Indices into the string table (starts at 1 - 0 is none)
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
|
||||
// We only have one configuration
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
// CDC-ACM devices need a functional descriptor that looks like this
|
||||
/* CDC-ACM devices need a functional descriptor that looks like this */
|
||||
struct usb_cdcacm_functional_descriptor {
|
||||
struct usb_cdc_header_descriptor header;
|
||||
struct usb_cdc_call_management_descriptor call_mgmt;
|
||||
|
@ -46,40 +19,14 @@ struct usb_cdcacm_functional_descriptor {
|
|||
struct usb_cdc_union_descriptor cdc_union;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Each CDC-ACM device has...
|
||||
// two data endpoints and one control endpoint
|
||||
static struct usb_endpoint_descriptor endpoints[3 * NUM_SERIAL];
|
||||
// one functional descriptor
|
||||
static struct usb_cdcacm_functional_descriptor
|
||||
cdcacm_functional_descriptors[NUM_SERIAL];
|
||||
// a data interface combining the two data endpoints, and a control interface
|
||||
static struct usb_interface_descriptor interface_descriptors[2 * NUM_SERIAL];
|
||||
|
||||
// instantiate the usb_interface struct needed by libopencm3
|
||||
static struct usb_interface interfaces[2 * NUM_SERIAL];
|
||||
|
||||
// Create the one configuration we have
|
||||
static const struct usb_config_descriptor config = {
|
||||
.bLength = USB_DT_CONFIGURATION_SIZE,
|
||||
.bDescriptorType = USB_DT_CONFIGURATION,
|
||||
.bNumInterfaces =
|
||||
sizeof(interface_descriptors) / sizeof(interface_descriptors[0]),
|
||||
// this is filled in later by libopencm3
|
||||
.wTotalLength = 0,
|
||||
// first and only config
|
||||
.bConfigurationValue = 1,
|
||||
// name of the config (none here)
|
||||
.iConfiguration = 0,
|
||||
// 0x80 is required to be set
|
||||
.bmAttributes = 0x80,
|
||||
// multiply by 2 mA to get maximum power we request
|
||||
.bMaxPower = 100,
|
||||
// pointer to the interfaces declared above
|
||||
.interface = interfaces,
|
||||
};
|
||||
|
||||
/* Allocate some space for our serial */
|
||||
static char serial[24];
|
||||
static char * usb_strings[] = {
|
||||
|
||||
/*
|
||||
These strings will be used as identifiers in some descriptors.
|
||||
* In descriptors, indices are 1-based, and 0 is an empty string.
|
||||
*/
|
||||
static char const *usb_strings[] = {
|
||||
"Imaginaerraum.de",
|
||||
"DoorControl",
|
||||
serial,
|
||||
|
@ -87,13 +34,75 @@ static char * usb_strings[] = {
|
|||
"Other"
|
||||
};
|
||||
|
||||
usbd_device *g_usbd_dev;
|
||||
|
||||
/* The descriptor for our device. We need only one of these. */
|
||||
static const struct usb_device_descriptor dev = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
/*
|
||||
* Devices with class 0xEF, subclass 2, and protocol 1 are interface
|
||||
* associations that can contain multiple unrelated interfaces, like a
|
||||
* keyboard and a video device, or multiple serial devices
|
||||
*/
|
||||
.bDeviceClass = 0xEF,
|
||||
.bDeviceSubClass = 2,
|
||||
.bDeviceProtocol = 1,
|
||||
/* Maximum packet size for endpoint zero */
|
||||
.bMaxPacketSize0 = 64,
|
||||
/* Vendor and product ID are for ST's virtual modem */
|
||||
.idVendor = 0x0483,
|
||||
.idProduct = 0x5740,
|
||||
/* Revision of the device: 2.00 */
|
||||
.bcdDevice = 0x0200,
|
||||
/* Indices into the string table (starts at 1 - 0 is none) */
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
/* We only have one configuration */
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
/* Each CDC-ACM device has... */
|
||||
/* two data endpoints and one control endpoint */
|
||||
static struct usb_endpoint_descriptor endpoints[3 * NUM_SERIAL];
|
||||
/* one functional descriptor */
|
||||
static struct usb_cdcacm_functional_descriptor
|
||||
cdcacm_functional_descriptors[NUM_SERIAL];
|
||||
/* a data interface combining the two data endpoints, and a control interface */
|
||||
static struct usb_interface_descriptor interface_descriptors[2 * NUM_SERIAL];
|
||||
|
||||
/* instantiate the usb_interface struct needed by libopencm3 */
|
||||
static struct usb_interface interfaces[sizeof(interface_descriptors) / sizeof(interface_descriptors[0])];
|
||||
|
||||
/* Create the one configuration we have */
|
||||
static const struct usb_config_descriptor config = {
|
||||
.bLength = USB_DT_CONFIGURATION_SIZE,
|
||||
.bDescriptorType = USB_DT_CONFIGURATION,
|
||||
.bNumInterfaces =
|
||||
sizeof(interface_descriptors) / sizeof(interface_descriptors[0]),
|
||||
/* this is filled in later by libopencm3, and also why we can't just create all of this in ROM */
|
||||
.wTotalLength = 0,
|
||||
/* first and only config */
|
||||
.bConfigurationValue = 1,
|
||||
/* name of the config (none here) */
|
||||
.iConfiguration = 0,
|
||||
/* 0x80 is required to be set */
|
||||
.bmAttributes = 0x80,
|
||||
/* multiply by 2 mA to get maximum power we request */
|
||||
.bMaxPower = 100,
|
||||
/* pointer to the interfaces declared above */
|
||||
.interface = interfaces,
|
||||
};
|
||||
|
||||
/* Buffer to be used for control requests. */
|
||||
uint8_t usbd_control_buffer[512];
|
||||
|
||||
static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev,
|
||||
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
|
||||
void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
|
||||
{
|
||||
static enum usbd_request_return_codes cdcacm_control_request(
|
||||
usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
|
||||
uint16_t *len,
|
||||
void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) {
|
||||
(void)complete;
|
||||
(void)buf;
|
||||
(void)usbd_dev;
|
||||
|
@ -123,11 +132,11 @@ static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
|
|||
|
||||
char buf[64];
|
||||
|
||||
// Read some data from the endpoint
|
||||
/* Read some data from the endpoint */
|
||||
int len = usbd_ep_read_packet(usbd_dev, ep, buf, 64);
|
||||
|
||||
if (len) {
|
||||
// Write it to the endpoint of the other interface
|
||||
/* Write it back */
|
||||
while (usbd_ep_write_packet(usbd_dev, ep | 0x80, buf, len) == 0);
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +146,7 @@ static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
|||
(void)wValue;
|
||||
|
||||
for (int i = 0; i < NUM_SERIAL; i++) {
|
||||
// set up all the endpoints
|
||||
/* set up all the endpoints for each serial device */
|
||||
usbd_ep_setup(usbd_dev, 0x01 + 2*i, USB_ENDPOINT_ATTR_BULK, 64,
|
||||
cdcacm_data_rx_cb);
|
||||
usbd_ep_setup(usbd_dev, 0x81 + 2*i, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
||||
|
@ -151,8 +160,6 @@ static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
|||
cdcacm_control_request);
|
||||
}
|
||||
|
||||
usbd_device *usbd_dev;
|
||||
|
||||
void usb_setup() {
|
||||
rcc_periph_clock_enable(RCC_GPIOA);
|
||||
rcc_periph_clock_enable(RCC_OTGFS);
|
||||
|
@ -162,21 +169,26 @@ void usb_setup() {
|
|||
gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
|
||||
|
||||
for (uint8_t i = 0; i < NUM_SERIAL; i++) {
|
||||
// set up the endpoints
|
||||
// data endpoints are at addresses 1, 3, 5 (or 0x81, 0x83, 0x85) and so on
|
||||
// control endpoints are at addresses 0x82, 0x84, 0x86...
|
||||
|
||||
// index of the first endpoint in our array
|
||||
/*
|
||||
* set up the endpoints Data endpoints are at addresses 1, 3, 5 (or 0x81,
|
||||
* 0x83, 0x85) and so on.
|
||||
*
|
||||
* Control endpoints are at addresses 0x82, 0x84, 0x86...
|
||||
*/
|
||||
/* index of the first data endpoint in our array struct */
|
||||
struct usb_endpoint_descriptor *data_ep = &endpoints[3 * i];
|
||||
/* Index of the control endpoint */
|
||||
struct usb_endpoint_descriptor *ctrl_ep = data_ep + 2;
|
||||
|
||||
// address of the first endpoint -
|
||||
/* Numbers of the data and control endpoints */
|
||||
const uint8_t data_ep_num = 0x01 + 2*i;
|
||||
const uint8_t ctrl_ep_num = data_ep_num + 1;
|
||||
/* Interface numbers */
|
||||
const uint8_t data_iface = 2*i;
|
||||
const uint8_t control_iface = data_iface + 1;
|
||||
|
||||
// OUT endpoint for data (host to device)
|
||||
/* OUT endpoint for data (host to device) */
|
||||
data_ep[0] = (struct usb_endpoint_descriptor) {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
@ -184,13 +196,15 @@ void usb_setup() {
|
|||
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||
.wMaxPacketSize = 64
|
||||
};
|
||||
// IN endpoint (device to host) is the same except for the direction
|
||||
/* IN endpoint (device to host) is the same except for the direction */
|
||||
data_ep[1] = data_ep[0];
|
||||
data_ep[1].bEndpointAddress |= 0x80;
|
||||
|
||||
// The control endpoint is for interrupt transfers. Its address is one
|
||||
// higher than the data endpoints, has smaller packets, and we don't really
|
||||
// care about its interval (because we're not using it)
|
||||
/*
|
||||
* The control endpoint is for interrupt transfers. Its address is one
|
||||
* higher than the data endpoints, has smaller packets, and we don't really
|
||||
* care about its interval (because we're not using it)
|
||||
*/
|
||||
*ctrl_ep = (struct usb_endpoint_descriptor) {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
@ -205,66 +219,80 @@ void usb_setup() {
|
|||
.bFunctionLength = sizeof (struct usb_cdc_header_descriptor),
|
||||
.bDescriptorType = CS_INTERFACE,
|
||||
.bDescriptorSubtype = USB_CDC_TYPE_HEADER,
|
||||
// Version of the standard
|
||||
/* Version of the standard */
|
||||
.bcdCDC = 0x0110
|
||||
},
|
||||
.call_mgmt = (struct usb_cdc_call_management_descriptor) {
|
||||
.bFunctionLength = sizeof (struct usb_cdc_call_management_descriptor),
|
||||
.bDescriptorType = CS_INTERFACE,
|
||||
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
|
||||
// We do no call management
|
||||
/* We do no call management */
|
||||
.bmCapabilities = 0,
|
||||
// Index of our data interface
|
||||
/* Index of our data interface */
|
||||
.bDataInterface = data_iface,
|
||||
},
|
||||
.acm = (struct usb_cdc_acm_descriptor){
|
||||
.bFunctionLength = sizeof (struct usb_cdc_acm_descriptor),
|
||||
.bDescriptorType = CS_INTERFACE,
|
||||
.bDescriptorSubtype = USB_CDC_TYPE_ACM,
|
||||
// Nothing here either
|
||||
/* Nothing here either */
|
||||
.bmCapabilities = 0,
|
||||
},
|
||||
.cdc_union = (struct usb_cdc_union_descriptor) {
|
||||
.bFunctionLength = sizeof (struct usb_cdc_union_descriptor),
|
||||
.bDescriptorType = CS_INTERFACE,
|
||||
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
|
||||
// Our interfaces
|
||||
/* Our interfaces */
|
||||
.bControlInterface = control_iface,
|
||||
.bSubordinateInterface0 = data_iface,
|
||||
}
|
||||
};
|
||||
|
||||
// A plain data interface
|
||||
/* A plain data interface */
|
||||
interface_descriptors[data_iface] = (struct usb_interface_descriptor) {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = data_iface,
|
||||
/* This is the first alternate setting. There are no others. */
|
||||
.bAlternateSetting = 0,
|
||||
// OUT and IN
|
||||
/* OUT and IN */
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_DATA,
|
||||
/* No subclass or protocol */
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0,
|
||||
/*
|
||||
* A pointer to the first of its endpoints - the others must be
|
||||
* contiguous.
|
||||
*/
|
||||
.endpoint = data_ep
|
||||
};
|
||||
|
||||
/* Required by libopencm3 for some reason. */
|
||||
interfaces[data_iface] = (struct usb_interface) {
|
||||
.num_altsetting = 1, .altsetting = &interface_descriptors[data_iface]
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The control interface gets the actual CDC ACM classes, and the string
|
||||
* description. It also needs the CDC ACM functional descriptors.
|
||||
*/
|
||||
interface_descriptors[control_iface] = (struct usb_interface_descriptor) {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = control_iface,
|
||||
.bAlternateSetting = 0,
|
||||
// Just one direction here
|
||||
/* Just one direction here */
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_CDC,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
|
||||
/* The first three names are for manufacturer, product, and serial. */
|
||||
.iInterface = (uint8_t)(4 + i),
|
||||
/* Pointer to the single endpoint */
|
||||
.endpoint = ctrl_ep,
|
||||
/* Pointer and length for the CDC ACM functional descriptors */
|
||||
.extra = &cdcacm_functional_descriptors[i],
|
||||
.extralen = sizeof cdcacm_functional_descriptors[0]
|
||||
};
|
||||
|
@ -272,12 +300,16 @@ void usb_setup() {
|
|||
.num_altsetting = 1, .altsetting = &interface_descriptors[control_iface]};
|
||||
}
|
||||
|
||||
usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config,
|
||||
(char const * const *)usb_strings, (sizeof usb_strings) / sizeof(usb_strings[0]),
|
||||
usbd_control_buffer, sizeof(usbd_control_buffer));
|
||||
/* Initialize the device... */
|
||||
g_usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config,
|
||||
(char const * const *)usb_strings,
|
||||
(sizeof usb_strings) / sizeof(usb_strings[0]),
|
||||
usbd_control_buffer, sizeof(usbd_control_buffer));
|
||||
|
||||
usbd_register_set_config_callback(usbd_dev, cdcacm_set_config);
|
||||
usbd_register_set_config_callback(g_usbd_dev, cdcacm_set_config);
|
||||
|
||||
/* And use interrupts instead of polling. */
|
||||
nvic_enable_irq(NVIC_OTG_FS_IRQ);
|
||||
}
|
||||
|
||||
void otg_fs_isr() { usbd_poll(usbd_dev); }
|
||||
void otg_fs_isr() { usbd_poll(g_usbd_dev); }
|
||||
|
|
Loading…
Reference in New Issue
Block a user