From 9e1a28620ebe765656decd1ca98a5bfad2891941 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Mon, 11 Feb 2019 11:07:13 +0100 Subject: [PATCH] fixup! usbus: Initial work to a unified USB stack --- sys/include/usb/usbus.h | 168 ++++++++++-------- sys/usb/usbus/ep0.c | 330 ++++++++++++++++++++++++++++++++++ sys/usb/usbus/hdrs.c | 14 +- sys/usb/usbus/usbus.c | 381 ++++------------------------------------ 4 files changed, 471 insertions(+), 422 deletions(-) create mode 100644 sys/usb/usbus/ep0.c diff --git a/sys/include/usb/usbus.h b/sys/include/usb/usbus.h index 28df27d9ca820..4ae7bd065997e 100644 --- a/sys/include/usb/usbus.h +++ b/sys/include/usb/usbus.h @@ -31,25 +31,52 @@ #include "kernel_types.h" #include "msg.h" -#include "mutex.h" #ifdef __cplusplus extern "C" { #endif -#define USBUS_MSG_TYPE_EVENT (0x1234) -#define USBUS_MSG_TYPE_EP_EVENT (0x1235) -#define USBUS_MSG_TYPE_SETUP_RQ (0x1236) -#define USBUS_MSG_TYPE_TR_COMPLETE (0x1237) +#ifndef USBUS_STACKSIZE +#define USBUS_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#endif + +#ifndef USBUS_PRIO +#define USBUS_PRIO (THREAD_PRIORITY_MAIN - 6) +#endif + +#define USBUS_TNAME "usbus" + +#ifndef USBUS_AUTO_ATTACH +#define USBUS_AUTO_ATTACH (1) +#endif + +#ifndef USBUS_EP0_SIZE +#define USBUS_EP0_SIZE 64 +#endif +/** + * @name USBUS message types + */ +#define USBUS_MSG_TYPE_EVENT (0x0100) +#define USBUS_MSG_TYPE_EP_EVENT (0x0200) +#define USBUS_MSG_TYPE_SETUP_RQ (0x0300) +#define USBUS_MSG_TYPE_TR_COMPLETE (0x0400) +#define USBUS_MSG_TYPE_HANDLER (0x0500) + +/** + * @name USBUS global state machine states + */ typedef enum { - USBUS_STATE_DISCONNECT, - USBUS_STATE_RESET, - USBUS_STATE_ADDR, - USBUS_STATE_CONFIGURED, - USBUS_STATE_SUSPEND, + USBUS_STATE_DISCONNECT, /**< Device is disconnected from the host */ + USBUS_STATE_RESET, /**< Reset condition received */ + USBUS_STATE_ADDR, /**< Address configured */ + USBUS_STATE_CONFIGURED, /**< Peripheral is configured */ + USBUS_STATE_SUSPEND, /**< Peripheral is suspended by the host */ } usbus_state_t; +/** + * @name USBUS setup request state machine + */ typedef enum { USBUS_SETUPRQ_READY, /**< Ready for new request */ USBUS_SETUPRQ_INDATA, /**< Request received with expected DATA IN stage */ @@ -58,30 +85,48 @@ typedef enum { USBUS_SETUPRQ_INACK, /**< ACK in request */ } usbus_setuprq_state_t; -typedef struct usbus_string usbus_string_t; -typedef struct usbus_hdr_gen usbus_hdr_gen_t; -typedef struct usbus_interface usbus_interface_t; -typedef struct usbus_endpoint usbus_endpoint_t; +typedef struct usbus_string { + struct usbus_string *next; + const char *str; + uint16_t idx; +} usbus_string_t; + +typedef struct usbus usbus_t; typedef struct usbus_handler usbus_handler_t; +typedef size_t (*gen_hdr)(usbus_t *usbus, void *arg); +typedef size_t (*hdr_len)(usbus_t *usbus, void *arg); -struct usbus_string { - struct usbus_string *next; - uint16_t idx; - const char *str; - size_t len; -}; +typedef struct { + gen_hdr get_header; /**< function ptr to retrieve the header */ + hdr_len get_header_len; /**< function ptr to retrieve the header len */ +} usbus_hdr_gen_funcs_t; -struct usbus_endpoint { +/** + * @brief USBUS header generator function pointers + */ +typedef struct usbus_hdr_gen { + struct usbus_hdr_gen *next; /**< ptr to the next header generator */ + const usbus_hdr_gen_funcs_t *funcs; /**< Function pointers */ + void *arg; /**< Extra argument fot the headers */ +} usbus_hdr_gen_t; + +typedef struct usbus_endpoint { struct usbus_endpoint *next; usbus_hdr_gen_t *hdr_gen; usbdev_ep_t *ep; uint16_t maxpacketsize; /**< Max packet size of this endpoint */ uint8_t interval; /**< Poll interval for interrupt endpoints */ bool active; /**< If the endpoint should be activated after reset */ -}; +} usbus_endpoint_t; + +typedef struct usbus_interface_alt { + struct usbus_interface_alt *next; + usbus_hdr_gen_t *hdr_gen; + usbus_endpoint_t *ep; +} usbus_interface_alt_t; -struct usbus_interface { +typedef struct usbus_interface { struct usbus_interface *next; struct usbus_interface_alt *alts; usbus_handler_t* handler; @@ -92,51 +137,9 @@ struct usbus_interface { uint8_t class; uint8_t subclass; uint8_t protocol; -}; - -typedef struct usbus_interface_alt { - struct usbus_interface_alt *next; - usbus_hdr_gen_t *hdr_gen; - usbus_endpoint_t *ep; -} usbus_interface_alt_t; - -typedef struct { - size_t start; - size_t cur; - size_t len; - size_t transfered; - size_t reqlen; /**< Maximum length of request */ -} usbus_controlbuilder_t; - -typedef struct { - usbus_string_t manuf; /**< Manufacturer string */ - usbus_string_t product; /**< Product string */ - usbus_string_t config; /**< Configuration string */ - usbus_controlbuilder_t builder; - usbdev_ep_t *out; /**< EP0 out endpoint */ - usbdev_ep_t *in; /**< EP0 in endpoint */ - usbdev_t *dev; /**< usb phy device of the usb manager */ - usb_setup_t setup; /**< Last received setup packet */ - usbus_hdr_gen_t *hdr_gen; - usbus_string_t *strings; /**< List of descriptor strings */ - usbus_interface_t *iface; /**< List of USB interfaces */ - usbus_handler_t *handler; - kernel_pid_t pid; /**< PID of the usb manager's thread */ - uint16_t addr; /**< Address of the USB port */ - usbus_state_t state; /**< Current state */ - usbus_setuprq_state_t setup_state; /**< Setup request state machine */ - uint16_t str_idx; - mutex_t lock; /**< Mutex for modifying the object */ -} usbus_t; - -struct usbus_hdr_gen { - struct usbus_hdr_gen *next; - size_t (*gen_hdr)(usbus_t *usbus, void *arg); - size_t (*hdr_len)(usbus_t *usbus, void *arg); - void *arg; -}; +} usbus_interface_t; -typedef struct { +typedef struct usbus_handler_driver{ int (*init)(usbus_t *usbus, struct usbus_handler *handler); int (*event_handler)(usbus_t *usbus, struct usbus_handler *handler, uint16_t event, void *arg); } usbus_handler_driver_t; @@ -147,15 +150,42 @@ struct usbus_handler { usbus_interface_t *iface; }; +typedef struct { + size_t start; + size_t cur; + size_t len; + size_t transfered; /**< Number of bytes transfered */ + size_t reqlen; /**< Maximum length of the request */ +} usbus_controlslicer_t; + +struct usbus { + usbus_string_t manuf; /**< Manufacturer string */ + usbus_string_t product; /**< Product string */ + usbus_string_t config; /**< Configuration string */ + usbus_controlslicer_t slicer; /**< Slicer for multipart control messages */ + usbdev_ep_t *out; /**< EP0 out endpoint */ + usbdev_ep_t *in; /**< EP0 in endpoint */ + usbdev_t *dev; /**< usb phy device of the usb manager */ + usb_setup_t setup; /**< Last received setup packet */ + usbus_hdr_gen_t *hdr_gen; + usbus_string_t *strings; /**< List of descriptor strings */ + usbus_interface_t *iface; /**< List of USB interfaces */ + usbus_handler_t *handler; /**< */ + kernel_pid_t pid; /**< PID of the usb manager's thread */ + uint16_t addr; /**< Address of the USB port */ + usbus_state_t state; /**< Current state */ + usbus_setuprq_state_t setup_state; /**< Setup request state machine */ + uint16_t str_idx; +}; uint16_t usbus_add_interface(usbus_t *usbus, usbus_interface_t *iface); int usbus_add_endpoint(usbus_t *usbus, usbus_interface_t *iface, usbus_endpoint_t* ep, usb_ep_type_t type, usb_ep_dir_t dir, size_t len); void usbus_add_conf_descriptor(usbus_t *usbus, usbus_hdr_gen_t* hdr_gen); usbus_t *usbus_get_ctx(void); void usbus_register_event_handler(usbus_t *usbus, usbus_handler_t *handler); -void usbus_init(void); +void usbus_init(usbus_t *usbus, usbdev_t *usbdev); void usbus_create(char *stack, int stacksize, char priority, - const char *name, usbdev_t *usbdev); + const char *name, usbus_t *usbus); size_t usbus_put_bytes(usbus_t *usbus, const uint8_t *buf, size_t len); size_t usbus_put_char(usbus_t *usbus, char c); diff --git a/sys/usb/usbus/ep0.c b/sys/usb/usbus/ep0.c new file mode 100644 index 0000000000000..8c63293078f08 --- /dev/null +++ b/sys/usb/usbus/ep0.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2018 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 usb_usbus + * @{ + * @file + * @brief USBUS EP0 handling + * + * @author Koen Zandberg + * @} + */ +#include "usb/usbdev.h" +#include "usb/message.h" +#include "usb/usbus.h" +#include "usb/usbus/hdrs.h" + +#include +#include +#include +#define ENABLE_DEBUG (0) +#include "debug.h" + +int usbus_update_builder(usbus_t *usbus) +{ + usbus_controlslicer_t *bldr = &usbus->slicer; + size_t end = bldr->start + usbus->in->len; + if (bldr->cur > end && bldr->start < bldr->reqlen && bldr->transfered < bldr->reqlen) { + bldr->start += usbus->in->len; + bldr->cur = 0; + bldr->len = 0; + return 1; + } + return 0; +} + +static void _activate_endpoints(usbus_t *usbus) +{ + for (usbus_interface_t *iface = usbus->iface; iface; iface = iface->next) { + for (usbus_endpoint_t *ep = iface->ep; ep; ep = ep->next) { + if (ep->active) { + static const usbopt_enable_t enable = USBOPT_ENABLE; + ep->ep->driver->set(ep->ep, USBOPT_EP_ENABLE, &enable, + sizeof(usbopt_enable_t)); + DEBUG("activated endpoint %d, dir %s\n", ep->ep->num, + ep->ep->dir == USB_EP_DIR_OUT? "out" : "in"); + } + } + for (usbus_interface_alt_t *alt = iface->alts; alt; alt = alt->next) { + for (usbus_endpoint_t *ep = alt->ep; ep; ep = ep->next) { + if (ep->active) { + static const usbopt_enable_t enable = USBOPT_ENABLE; + ep->ep->driver->set(ep->ep, USBOPT_EP_ENABLE, &enable, + sizeof(usbopt_enable_t)); + DEBUG("activated endpoint %d, dir %s\n", ep->ep->num, + ep->ep->dir == USB_EP_DIR_OUT? "out" : "in"); + } + } + } + } +} + +static size_t usbus_cpy_str(usbus_t *usbus, const char *str) +{ + size_t len = 0; + while(*str) { + usbus_put_char(usbus, *str); + usbus_put_char(usbus, 0); + len += 2; + str++; + } + return len; +} + +usbus_string_t *_get_descriptor(usbus_t *usbus, uint16_t idx) +{ + for (usbus_string_t * str = usbus->strings; str; str = str->next) { + if (str->idx == idx) { + return str; + } + } + return NULL; +} + +void _req_status(usbus_t *usbus) +{ + uint8_t status[2]; + memset(status, 0, 2); + usbus_put_bytes(usbus, status, sizeof(status)); + usbus->in->driver->ready(usbus->in, 2); +} + +void _req_str(usbus_t *usbus, uint16_t idx) +{ + if (idx == 0) { + usb_descriptor_string_t desc; + desc.type = USB_TYPE_DESCRIPTOR_STRING; + desc.length = sizeof(uint16_t)+sizeof(usb_descriptor_string_t); + usbus_put_bytes(usbus, (uint8_t*)&desc, sizeof(desc)); + /* Only one language ID supported */ + uint16_t us = USB_CONFIG_DEFAULT_LANGID; + usbus_put_bytes(usbus, (uint8_t*)&us, sizeof(uint16_t)); + usbus_ep0_ready(usbus); + } + else { + usb_descriptor_string_t desc; + desc.type = USB_TYPE_DESCRIPTOR_STRING; + usbus_string_t *str = _get_descriptor(usbus, idx); + if (str) { + desc.length = sizeof(usb_descriptor_string_t); + desc.length += 2*strlen(str->str); + usbus_put_bytes(usbus, (uint8_t*)&desc, sizeof(desc)); + usbus_cpy_str(usbus, str->str); + usbus_ep0_ready(usbus); + } + else { + usbus_ep0_ready(usbus); + } + } +} + +static void _req_dev(usbus_t *usbus) +{ + usb_descriptor_device_t desc; + memset(&desc, 0, sizeof(usb_descriptor_device_t)); + desc.length = sizeof(usb_descriptor_device_t); + desc.type = USB_TYPE_DESCRIPTOR_DEVICE; + desc.bcd_usb = 0x0110; + desc.max_packet_size = USBUS_EP0_SIZE; + desc.vendor_id = USB_CONFIG_VID; + desc.product_id = USB_CONFIG_PID; + desc.manufacturer_idx = usbus->manuf.idx; + desc.product_idx = usbus->product.idx; + desc.num_configurations = 1; + usbus_put_bytes(usbus, (uint8_t*)&desc, sizeof(usb_descriptor_device_t)); + usbus_ep0_ready(usbus); +} + +static void _req_config(usbus_t *usbus) +{ + usbus_hdrs_fmt_conf(usbus); + usbus_ep0_ready(usbus); +} + +static void _req_dev_qualifier(usbus_t *usbus) +{ + usb_speed_t speed = USB_SPEED_LOW; + usbus->dev->driver->get(usbus->dev, USBOPT_MAX_SPEED, &speed, sizeof(usb_speed_t)); + if (speed == USB_SPEED_HIGH) { + /* TODO: implement device qualifier support */ + } + /* Signal stall to indicate unsupported (USB 2.0 spec 9.6.2 */ + static const usbopt_enable_t enable = USBOPT_ENABLE; + + usbus->in->driver->set(usbus->in, USBOPT_EP_STALL, &enable, sizeof(usbopt_enable_t)); +} + +static void _req_descriptor(usbus_t *usbus, usb_setup_t *pkt) +{ + uint8_t type = pkt->value >> 8; + uint8_t idx = (uint8_t)pkt->value; + switch (type) { + case 0x1: + _req_dev(usbus); + break; + case 0x2: + _req_config(usbus); + break; + case 0x03: + _req_str(usbus, idx); + break; + case 0x06: + _req_dev_qualifier(usbus); + break; + default: + break; + } +} + +void recv_dev_setup(usbus_t *usbus, usbdev_ep_t *ep, usb_setup_t *pkt) +{ + (void)ep; + if (pkt->type & 0x80) { + switch (pkt->request) { + case 0x00: + _req_status(usbus); + break; + case 0x06: + _req_descriptor(usbus, pkt); + break; + default: + break; + } + } + else{ + switch (pkt->request) { + case 0x05: + usbus->addr = (uint8_t)pkt->value; + break; + case 0x09: + _activate_endpoints(usbus); + break; + default: + break; + } + /* Signal zlp */ + usbus->in->driver->ready(usbus->in, 0); + } +} + +void recv_interface_setup(usbus_t *usbus, usbdev_ep_t *ep, usb_setup_t *pkt) +{ + uint16_t destination = pkt->index & 0x0f; + (void)ep; + /* Find interface handler */ + for (usbus_interface_t *iface = usbus->iface; iface; iface = iface->next) { + if (destination == iface->idx) { + iface->handler->driver->event_handler(usbus, iface->handler, USBUS_MSG_TYPE_SETUP_RQ, pkt); + } + } +} + +void recv_setup(usbus_t *usbus, usbdev_ep_t *ep) +{ + (void)ep; + usb_setup_t *pkt = &usbus->setup; + if (pkt->type & 0x80) { + usbus->setup_state = USBUS_SETUPRQ_INDATA; + } + else { + if (pkt->length) { + usbus->setup_state = USBUS_SETUPRQ_OUTDATA; + } + else { + usbus->setup_state = USBUS_SETUPRQ_INACK; + usbus->in->driver->ready(usbus->in, 0); + } + } + uint8_t destination = pkt->type & USB_SETUP_REQUEST_RECIPIENT_MASK; + switch(destination) { + case USB_SETUP_REQUEST_RECIPIENT_DEVICE: + recv_dev_setup(usbus, ep, pkt); + break; + case USB_SETUP_REQUEST_RECIPIENT_INTERFACE: + recv_interface_setup(usbus, ep, pkt); + break; + default: + DEBUG("usbus: Unhandled setup request\n"); + } +} + + +/* USB endpoint 0 callback */ +void _event_ep0_cb(usbdev_ep_t *ep, usbdev_event_t event) +{ + usbus_t *usbus = (usbus_t *)ep->context; + if (event == USBDEV_EVENT_ESR) { + msg_t msg = { .type = USBUS_MSG_TYPE_EP_EVENT, + .content = { .ptr = ep} }; + + DEBUG("usbus_ep: pid: %u\n", usbus->pid); + if (msg_send(&msg, usbus->pid) <= 0) { + puts("usbus_ep0: possibly lost interrupt."); + } + } + else { + switch (event) { + case USBDEV_EVENT_TR_COMPLETE: + /* Configure address if we have received one and handled the zlp */ + if (usbus->setup_state == USBUS_SETUPRQ_INACK && ep->dir == USB_EP_DIR_IN) { + if (usbus->addr && usbus->state == USBUS_STATE_RESET) { + usbus->dev->driver->set(usbus->dev, USBOPT_ADDRESS, &usbus->addr, sizeof(uint8_t)); + /* Address configured */ + usbus->state = USBUS_STATE_ADDR; + DEBUG("Setting addres %u\n", usbus->addr); + } + usbus->setup_state = USBUS_SETUPRQ_READY; + } + else if (usbus->setup_state == USBUS_SETUPRQ_OUTACK && ep->dir == USB_EP_DIR_OUT) { + memset(&usbus->slicer, 0, sizeof(usbus_controlslicer_t)); + static const usbopt_enable_t disable = USBOPT_DISABLE; + usbus->in->driver->set(usbus->in, USBOPT_EP_READY, &disable, sizeof(usbopt_enable_t)); + usbus->setup_state = USBUS_SETUPRQ_READY; + } + else if (usbus->setup_state == USBUS_SETUPRQ_INDATA && ep->dir == USB_EP_DIR_IN) { + if (usbus_update_builder(usbus)) { + recv_setup(usbus, ep); + usbus->setup_state = USBUS_SETUPRQ_INDATA; + } + else { + /* Ready out ZLP */ + usbus->setup_state = USBUS_SETUPRQ_OUTACK; + } + } + else if (usbus->setup_state == USBUS_SETUPRQ_OUTDATA && ep->dir == USB_EP_DIR_OUT) { + /* Ready in ZLP */ + usbus->setup_state = USBUS_SETUPRQ_INACK; + usbus->in->driver->ready(usbus->in, 0); + } + else if (ep->dir == USB_EP_DIR_OUT) { + memset(&usbus->slicer, 0, sizeof(usbus_controlslicer_t)); + memcpy(&usbus->setup, usbus->out->buf, sizeof(usb_setup_t)); + usbus->slicer.reqlen = usbus->setup.length; + usbus->out->driver->ready(usbus->out, 0); + recv_setup(usbus, ep); + } + break; + case USBDEV_EVENT_TR_FAIL: + if (ep->dir == USB_EP_DIR_OUT) { + } + else { + } + break; + case USBDEV_EVENT_TR_STALL: + { + static const usbopt_enable_t disable = USBOPT_DISABLE; + ep->driver->set(ep, USBOPT_EP_STALL, &disable, sizeof(usbopt_enable_t)); + } + break; + default: + break; + } + } +} + diff --git a/sys/usb/usbus/hdrs.c b/sys/usb/usbus/hdrs.c index f9844b6862274..e1156adc7e17e 100644 --- a/sys/usb/usbus/hdrs.c +++ b/sys/usb/usbus/hdrs.c @@ -68,11 +68,16 @@ static size_t _num_endpoints_alt(usbus_interface_alt_t *alt) return num; } +static inline size_t call_get_header_len(usbus_t *usbus, usbus_hdr_gen_t *hdr) +{ + return hdr->funcs->get_header_len(usbus, hdr->arg); +} + size_t _hdr_gen_size(usbus_t *usbus, usbus_hdr_gen_t *hdr) { size_t len = 0; for (; hdr; hdr = hdr->next) { - len += hdr->hdr_len(usbus, hdr->arg); + len += call_get_header_len(usbus, hdr); } return len; } @@ -118,11 +123,16 @@ size_t usbus_hdrs_fmt_hdrs(usbus_t *usbus) return usbus_hdrs_fmt_additional(usbus, usbus->hdr_gen); } +static inline size_t call_get_header(usbus_t *usbus, usbus_hdr_gen_t *hdr) +{ + return hdr->funcs->get_header(usbus, hdr->arg); +} + size_t usbus_hdrs_fmt_additional(usbus_t *usbus, usbus_hdr_gen_t *hdr) { size_t len = 0; for (; hdr; hdr = hdr->next) { - len += hdr->gen_hdr(usbus, hdr->arg); + len += call_get_header(usbus, hdr); } return len; } diff --git a/sys/usb/usbus/usbus.c b/sys/usb/usbus/usbus.c index ad6175167f150..08289af56e455 100644 --- a/sys/usb/usbus/usbus.c +++ b/sys/usb/usbus/usbus.c @@ -17,9 +17,7 @@ * @} */ -#include "sam_usb.h" #include "thread.h" -#include "xtimer.h" #include "byteorder.h" #include "usb/usbdev.h" #include "usb/message.h" @@ -29,17 +27,14 @@ #include "usb.h" #include "cpu.h" +#include #include #include + #define ENABLE_DEBUG (0) #include "debug.h" #define _USBUS_MSG_QUEUE_SIZE (8) -#define USBUS_STACKSIZE (THREAD_STACKSIZE_DEFAULT) -#define USBUS_PRIO (THREAD_PRIORITY_MAIN - 6) -#define USBUS_TNAME "usbus" - -#define USBUS_MAX_SIZE 64 static usbus_t _usbus; extern const usbdev_driver_t driver; @@ -51,35 +46,16 @@ void _event_ep0_cb(usbdev_ep_t *ep, usbdev_event_t event); void _event_ep_cb(usbdev_ep_t *ep, usbdev_event_t event); static void *_usbus_thread(void *args); -static size_t usbus_cpy_str(usbus_t *usbus, const char *str) -{ - size_t len = 0; - while(*str) { - usbus_put_char(usbus, *str); - usbus_put_char(usbus, 0); - len += 2; - str++; - } - return len; -} - -usbus_t *usbus_get_ctx(void) -{ - return &_usbus; -} - -void usbus_init(void) +void usbus_init(usbus_t *usbus, usbdev_t *usbdev) { - usbdev.usbdev.driver = &driver; - usbus_create(_stack, USBUS_STACKSIZE, USBUS_PRIO, - USBUS_TNAME, &usbdev.usbdev ); + /* TODO: Check if memset works/is necessary */ + memset(usbus, 0, sizeof(usbus)); + usbus->dev = usbdev; } void usbus_create(char *stack, int stacksize, char priority, - const char *name, usbdev_t *usbdev) + const char *name, usbus_t *usbus) { - usbus_t *usbus = &_usbus; - usbus->dev = usbdev; int res = thread_create(stack, stacksize, priority, THREAD_CREATE_STACKTEST, _usbus_thread, (void *)usbus, name); (void)res; @@ -88,7 +64,7 @@ void usbus_create(char *stack, int stacksize, char priority, size_t usbus_put_bytes(usbus_t *usbus, const uint8_t *buf, size_t len) { - usbus_controlbuilder_t *builder = &usbus->builder; + usbus_controlslicer_t *builder = &usbus->slicer; size_t end = builder->start + usbus->in->len; size_t byte_len = 0; /* Length of the string to copy */ @@ -110,14 +86,13 @@ size_t usbus_put_bytes(usbus_t *usbus, const uint8_t *buf, size_t len) size_t start_offset = builder->cur - builder->start + byte_offset; builder->cur += len; builder->len += byte_len; - //printf("%u+%u/%u@%u\n",byte_len, byte_offset, len, start_offset); memcpy(usbus->in->buf + start_offset , buf + byte_offset, byte_len); return byte_len; } size_t usbus_put_char(usbus_t *usbus, char c) { - usbus_controlbuilder_t *builder = &usbus->builder; + usbus_controlslicer_t *builder = &usbus->slicer; size_t end = builder->start + usbus->in->len; /* Only copy the char if it is within the window */ if ((builder->start <= builder->cur) && (builder->cur < end)) { @@ -133,31 +108,26 @@ size_t usbus_put_char(usbus_t *usbus, char c) uint16_t usbus_add_string_descriptor(usbus_t *usbus, usbus_string_t *desc, const char *str) { - mutex_lock(&usbus->lock); desc->next = usbus->strings; usbus->strings = desc; desc->idx = usbus->str_idx++; desc->str = str; - mutex_unlock(&usbus->lock); DEBUG("usbus: Adding string descriptor number %u for: \"%s\"\n", desc->idx, str); return desc->idx; } void usbus_add_conf_descriptor(usbus_t *usbus, usbus_hdr_gen_t* hdr_gen) { - mutex_lock(&usbus->lock); hdr_gen->next = usbus->hdr_gen; usbus->hdr_gen = hdr_gen; - mutex_unlock(&usbus->lock); } void usbus_ep0_ready(usbus_t *usbus) { - usbus_controlbuilder_t *bldr = &usbus->builder; + usbus_controlslicer_t *bldr = &usbus->slicer; size_t len = bldr->len; len = len < bldr->reqlen - bldr->start ? len : bldr->reqlen - bldr->start; bldr->transfered += len; - //printf("rdy %u, tx: %u\n", len, bldr->transfered); usbus->in->driver->ready(usbus->in, len); } @@ -180,52 +150,22 @@ usbus_interface_t *_ep_to_iface(usbus_t *usbus, usbdev_ep_t *ep) return NULL; } -int usbus_update_builder(usbus_t *usbus) -{ - usbus_controlbuilder_t *bldr = &usbus->builder; - size_t end = bldr->start + usbus->in->len; - if (bldr->cur > end && bldr->start < bldr->reqlen && bldr->transfered < bldr->reqlen) { - bldr->start += usbus->in->len; - bldr->cur = 0; - bldr->len = 0; - //printf("pkt cur %u, start: %u, end %u, max %u\n", bldr->cur, bldr->start, end, bldr->reqlen); - return 1; - } - return 0; -} - -usbus_string_t *_get_descriptor(usbus_t *usbus, uint16_t idx) -{ - for (usbus_string_t * str = usbus->strings; str; str = str->next) { - if (str->idx == idx) { - return str; - } - } - return NULL; -} - uint16_t usbus_add_interface(usbus_t *usbus, usbus_interface_t *iface) { - mutex_lock(&usbus->lock); iface->next = usbus->iface; usbus->iface = iface; - mutex_unlock(&usbus->lock); return iface->idx; } void usbus_register_event_handler(usbus_t *usbus, usbus_handler_t *handler) { - mutex_lock(&usbus->lock); handler->next = usbus->handler; usbus->handler = handler; - mutex_unlock(&usbus->lock); - handler->driver->init(usbus, handler); } int usbus_add_endpoint(usbus_t *usbus, usbus_interface_t *iface, usbus_endpoint_t* ep, usb_ep_type_t type, usb_ep_dir_t dir, size_t len) { int res = -ENOMEM; - mutex_lock(&usbus->lock); usbdev_ep_t* usbdev_ep = usbus->dev->driver->new_ep(usbus->dev, type, dir, len); if (usbdev_ep) { ep->maxpacketsize = usbdev_ep->len; @@ -236,32 +176,9 @@ int usbus_add_endpoint(usbus_t *usbus, usbus_interface_t *iface, usbus_endpoint_ iface->ep = ep; res = 0; } - mutex_unlock(&usbus->lock); return res; } -static void _activate_endpoints(usbus_t *usbus) -{ - for (usbus_interface_t *iface = usbus->iface; iface; iface = iface->next) { - for (usbus_endpoint_t *ep = iface->ep; ep; ep = ep->next) { - if (ep->active) { - static const usbopt_enable_t enable = USBOPT_ENABLE; - ep->ep->driver->set(ep->ep, USBOPT_EP_ENABLE, &enable, sizeof(usbopt_enable_t)); - printf("activated endpoint %d, dir %s\n", ep->ep->num, ep->ep->dir == USB_EP_DIR_OUT? "out" : "in"); - } - } - for (usbus_interface_alt_t *alt = iface->alts; alt; alt = alt->next) { - for (usbus_endpoint_t *ep = alt->ep; ep; ep = ep->next) { - if (ep->active) { - static const usbopt_enable_t enable = USBOPT_ENABLE; - ep->ep->driver->set(ep->ep, USBOPT_EP_ENABLE, &enable, sizeof(usbopt_enable_t)); - printf("activated endpoint %d, dir %s\n", ep->ep->num, ep->ep->dir == USB_EP_DIR_OUT? "out" : "in"); - } - } - } - } -} - static void _usbus_config_ep0(usbus_t *usbus) { static const usbopt_enable_t enable = USBOPT_ENABLE; @@ -270,187 +187,16 @@ static void _usbus_config_ep0(usbus_t *usbus) usbus->out->driver->ready(usbus->out, 0); } -void _req_status(usbus_t *usbus) -{ - uint8_t status[2]; - memset(status, 0, 2); - usbus_put_bytes(usbus, status, sizeof(status)); - usbus->in->driver->ready(usbus->in, 2); -} - -void _req_str(usbus_t *usbus, uint16_t idx) -{ - if (idx == 0) { - usb_descriptor_string_t desc; - desc.type = USB_TYPE_DESCRIPTOR_STRING; - desc.length = sizeof(uint16_t)+sizeof(usb_descriptor_string_t); - usbus_put_bytes(usbus, (uint8_t*)&desc, sizeof(desc)); - /* Only one language ID supported */ - uint16_t us = USB_CONFIG_DEFAULT_LANGID; - usbus_put_bytes(usbus, (uint8_t*)&us, sizeof(uint16_t)); - usbus_ep0_ready(usbus); - } - else { - usb_descriptor_string_t desc; - desc.type = USB_TYPE_DESCRIPTOR_STRING; - mutex_lock(&usbus->lock); - usbus_string_t *str = _get_descriptor(usbus, idx); - if (str) { - desc.length = sizeof(usb_descriptor_string_t); - desc.length += 2*strlen(str->str); - usbus_put_bytes(usbus, (uint8_t*)&desc, sizeof(desc)); - usbus_cpy_str(usbus, str->str); - usbus_ep0_ready(usbus); - } - else { - usbus_ep0_ready(usbus); - } - mutex_unlock(&usbus->lock); - } -} - -void _print_setup(usb_setup_t *pkt) -{ - printf("usbus: setup t:0x%.2x r:0x%x, v:0x%x l:%u\n", pkt->type, pkt->request, pkt->value, pkt->length); -} - -static void _req_dev(usbus_t *usbus) -{ - usb_descriptor_device_t desc; - memset(&desc, 0, sizeof(usb_descriptor_device_t)); - desc.length = sizeof(usb_descriptor_device_t); - desc.type = USB_TYPE_DESCRIPTOR_DEVICE; - desc.bcd_usb = 0x0110; - desc.max_packet_size = USBUS_MAX_SIZE; - desc.vendor_id = USB_CONFIG_VID; - desc.product_id = USB_CONFIG_PID; - desc.manufacturer_idx = usbus->manuf.idx; - desc.product_idx = usbus->product.idx; - desc.num_configurations = 1; - usbus_put_bytes(usbus, (uint8_t*)&desc, sizeof(usb_descriptor_device_t)); - usbus_ep0_ready(usbus); -} - -static void _req_config(usbus_t *usbus) -{ - mutex_lock(&usbus->lock); - usbus_hdrs_fmt_conf(usbus); - mutex_unlock(&usbus->lock); - usbus_ep0_ready(usbus); -} - -static void _req_dev_qualifier(usbus_t *usbus) -{ - usb_speed_t speed = USB_SPEED_LOW; - usbus->dev->driver->get(usbus->dev, USBOPT_MAX_SPEED, &speed, sizeof(usb_speed_t)); - if (speed == USB_SPEED_HIGH) { - /* TODO: implement device qualifier support */ - } - /* Signal stall to indicate unsupported (USB 2.0 spec 9.6.2 */ - static const usbopt_enable_t enable = USBOPT_ENABLE; - - usbus->in->driver->set(usbus->in, USBOPT_EP_STALL, &enable, sizeof(usbopt_enable_t)); -} - -static void _req_descriptor(usbus_t *usbus, usb_setup_t *pkt) -{ - uint8_t type = pkt->value >> 8; - uint8_t idx = (uint8_t)pkt->value; - switch (type) { - case 0x1: - _req_dev(usbus); - break; - case 0x2: - _req_config(usbus); - break; - case 0x03: - _req_str(usbus, idx); - break; - case 0x06: - _req_dev_qualifier(usbus); - break; - default: - break; - } -} - -void recv_dev_setup(usbus_t *usbus, usbdev_ep_t *ep, usb_setup_t *pkt) -{ - (void)ep; - if (pkt->type & 0x80) { - switch (pkt->request) { - case 0x00: - _req_status(usbus); - break; - case 0x06: - _req_descriptor(usbus, pkt); - break; - default: - break; - } - } - else{ - switch (pkt->request) { - case 0x05: - usbus->addr = (uint8_t)pkt->value; - break; - case 0x09: - _activate_endpoints(usbus); - break; - default: - break; - } - /* Signal zlp */ - usbus->in->driver->ready(usbus->in, 0); - } -} - -void recv_interface_setup(usbus_t *usbus, usbdev_ep_t *ep, usb_setup_t *pkt) -{ - uint16_t destination = pkt->index & 0x0f; - (void)ep; - /* Find interface handler */ - mutex_lock(&usbus->lock); - for (usbus_interface_t *iface = usbus->iface; iface; iface = iface->next) { - if (destination == iface->idx) { - iface->handler->driver->event_handler(usbus, iface->handler, USBUS_MSG_TYPE_SETUP_RQ, pkt); - } - } - mutex_unlock(&usbus->lock); -} - - static inline size_t usbus_pkt_maxlen(usbus_t *usbus, usb_setup_t *pkt) { return pkt->length > usbus->in->len ? usbus->in->len : pkt->length; } -void recv_setup(usbus_t *usbus, usbdev_ep_t *ep) +static void _usbus_init_handlers(usbus_t *usbus) { - (void)ep; - usb_setup_t *pkt = &usbus->setup; - if (pkt->type & 0x80) { - usbus->setup_state = USBUS_SETUPRQ_INDATA; - } - else { - if (pkt->length) { - usbus->setup_state = USBUS_SETUPRQ_OUTDATA; - } - else { - usbus->setup_state = USBUS_SETUPRQ_INACK; - usbus->in->driver->ready(usbus->in, 0); - } - } - uint8_t destination = pkt->type & USB_SETUP_REQUEST_RECIPIENT_MASK; - switch(destination) { - case USB_SETUP_REQUEST_RECIPIENT_DEVICE: - recv_dev_setup(usbus, ep, pkt); - break; - case USB_SETUP_REQUEST_RECIPIENT_INTERFACE: - recv_interface_setup(usbus, ep, pkt); - break; - default: - DEBUG("usbus: Unhandled setup request\n"); + for(usbus_handler_t *handler = usbus->handler; handler; + handler = handler->next) { + handler->driver->init(usbus, handler); } } @@ -458,7 +204,6 @@ static void *_usbus_thread(void *args) { usbus_t *usbus = (usbus_t*)args; - mutex_lock(&usbus->lock); usbdev_t *dev = usbus->dev; usbus->pid = sched_active_pid; usbus->addr = 0; @@ -466,7 +211,6 @@ static void *_usbus_thread(void *args) usbus->iface = NULL; usbus->str_idx = 1; usbus->setup_state = USBUS_SETUPRQ_READY; - mutex_init(&usbus->lock); msg_t msg, msg_queue[_USBUS_MSG_QUEUE_SIZE]; DEBUG("usbus: starting thread %i\n", sched_active_pid); /* setup the link-layer's message queue */ @@ -477,8 +221,8 @@ static void *_usbus_thread(void *args) dev->driver->init(dev); dev->context = usbus; - usbus->in = usbus->dev->driver->new_ep(usbus->dev, USB_EP_TYPE_CONTROL, USB_EP_DIR_IN, USBUS_MAX_SIZE); - usbus->out = usbus->dev->driver->new_ep(usbus->dev, USB_EP_TYPE_CONTROL, USB_EP_DIR_OUT, USBUS_MAX_SIZE); + usbus->in = usbus->dev->driver->new_ep(usbus->dev, USB_EP_TYPE_CONTROL, USB_EP_DIR_IN, USBUS_EP0_SIZE); + usbus->out = usbus->dev->driver->new_ep(usbus->dev, USB_EP_TYPE_CONTROL, USB_EP_DIR_OUT, USBUS_EP0_SIZE); usbus->in->cb = _event_ep0_cb; usbus->out->cb = _event_ep0_cb; usbus->in->context = usbus; @@ -492,17 +236,19 @@ static void *_usbus_thread(void *args) usbus_add_string_descriptor(usbus, &usbus->manuf, USB_CONFIG_MANUF_STR); usbus->state = USBUS_STATE_DISCONNECT; - mutex_unlock(&usbus->lock); - /* TODO: signal ready from application */ - xtimer_sleep(1); + /* Initialize handlers */ + _usbus_init_handlers(usbus); + +//#if(USBUS_AUTO_ATTACH) usbopt_enable_t enable = USBOPT_ENABLE; dev->driver->set(dev, USBOPT_ATTACH, &enable, sizeof(usbopt_enable_t)); +//#endif while (1) { msg_receive(&msg); - /* dispatch netdev, MAC and gnrc_netapi messages */ - switch (msg.type) { + /* dispatch USBUS messages */ + switch (msg.type & 0xFF00) { case USBUS_MSG_TYPE_EVENT: dev->driver->esr(dev); break; @@ -512,6 +258,12 @@ static void *_usbus_thread(void *args) ep->driver->esr(ep); } break; + case USBUS_MSG_TYPE_HANDLER: + { + usbus_handler_t *handler = (usbus_handler_t*)msg.content.ptr; + handler->driver->event_handler(usbus, handler, msg.type, handler); + } + break; default: DEBUG("usbus: unhandled event\n"); break; @@ -540,7 +292,7 @@ void _event_cb(usbdev_t *usbdev, usbdev_event_t event) usbus->addr = 0; usbus->setup_state = USBUS_SETUPRQ_READY; usbus->dev->driver->set(usbus->dev, USBOPT_ADDRESS, &usbus->addr, sizeof(uint8_t)); - puts("Reset"); + DEBUG("USB reset condition detected\n"); } break; default: @@ -550,79 +302,6 @@ void _event_cb(usbdev_t *usbdev, usbdev_event_t event) } } -/* USB endpoint 0 callback */ -void _event_ep0_cb(usbdev_ep_t *ep, usbdev_event_t event) -{ - usbus_t *usbus = (usbus_t *)ep->context; - if (event == USBDEV_EVENT_ESR) { - msg_t msg = { .type = USBUS_MSG_TYPE_EP_EVENT, - .content = { .ptr = ep} }; - - DEBUG("usbus_ep: pid: %u\n", usbus->pid); - if (msg_send(&msg, usbus->pid) <= 0) { - puts("usbus_ep0: possibly lost interrupt."); - } - } - else { - switch (event) { - case USBDEV_EVENT_TR_COMPLETE: - /* Configure address if we have received one and handled the zlp */ - if (usbus->setup_state == USBUS_SETUPRQ_INACK && ep->dir == USB_EP_DIR_IN) { - if (usbus->addr && usbus->state == USBUS_STATE_RESET) { - usbus->dev->driver->set(usbus->dev, USBOPT_ADDRESS, &usbus->addr, sizeof(uint8_t)); - /* Address configured */ - usbus->state = USBUS_STATE_ADDR; - DEBUG("Setting addres %u\n", usbus->addr); - } - usbus->setup_state = USBUS_SETUPRQ_READY; - } - else if (usbus->setup_state == USBUS_SETUPRQ_OUTACK && ep->dir == USB_EP_DIR_OUT) { - memset(&usbus->builder, 0, sizeof(usbus_controlbuilder_t)); - static const usbopt_enable_t disable = USBOPT_DISABLE; - usbus->in->driver->set(usbus->in, USBOPT_EP_READY, &disable, sizeof(usbopt_enable_t)); - usbus->setup_state = USBUS_SETUPRQ_READY; - } - else if (usbus->setup_state == USBUS_SETUPRQ_INDATA && ep->dir == USB_EP_DIR_IN) { - if (usbus_update_builder(usbus)) { - recv_setup(usbus, ep); - usbus->setup_state = USBUS_SETUPRQ_INDATA; - } - else { - /* Ready out ZLP */ - usbus->setup_state = USBUS_SETUPRQ_OUTACK; - } - } - else if (usbus->setup_state == USBUS_SETUPRQ_OUTDATA && ep->dir == USB_EP_DIR_OUT) { - /* Ready in ZLP */ - usbus->setup_state = USBUS_SETUPRQ_INACK; - usbus->in->driver->ready(usbus->in, 0); - } - else if (ep->dir == USB_EP_DIR_OUT) { - memset(&usbus->builder, 0, sizeof(usbus_controlbuilder_t)); - memcpy(&usbus->setup, usbus->out->buf, sizeof(usb_setup_t)); - usbus->builder.reqlen = usbus->setup.length; - usbus->out->driver->ready(usbus->out, 0); - recv_setup(usbus, ep); - } - break; - case USBDEV_EVENT_TR_FAIL: - if (ep->dir == USB_EP_DIR_OUT) { - } - else { - } - break; - case USBDEV_EVENT_TR_STALL: - { - static const usbopt_enable_t disable = USBOPT_DISABLE; - ep->driver->set(ep, USBOPT_EP_STALL, &disable, sizeof(usbopt_enable_t)); - } - break; - default: - break; - } - } -} - /* USB generic endpoint callback */ void _event_ep_cb(usbdev_ep_t *ep, usbdev_event_t event) {