/* Copyright (c) 2011,2012 Simon Schubert <2@0x2c.org>. * Modifications by Jacob Alexander 2014-2015 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // ----- Compiler Includes ----- #include // ----- Local Includes ----- #include "mchck.h" #include "usb-common.h" // ----- Defines ----- #define USB_CTRL_REQ_DIR_SHIFT 0 #define USB_CTRL_REQ_TYPE_SHIFT 1 #define USB_CTRL_REQ_RECP_SHIFT 3 #define USB_CTRL_REQ_CODE_SHIFT 8 #define USB_CTRL_REQ(req_inout, req_type, req_code) \ (uint16_t) \ ((USB_CTRL_REQ_##req_inout << USB_CTRL_REQ_DIR_SHIFT) \ |(USB_CTRL_REQ_##req_type << USB_CTRL_REQ_TYPE_SHIFT) \ |(USB_CTRL_REQ_##req_code << USB_CTRL_REQ_CODE_SHIFT)) // ----- Macros ----- #define USB_DESC_STRING(s) \ (const void *)&(const struct { \ struct usb_desc_string_t dsc; \ char16_t str[sizeof(s) / 2 - 1]; \ }) {{ \ .bLength = sizeof(struct usb_desc_string_t) + \ sizeof(s) - 2, \ .bDescriptorType = USB_DESC_STRING, \ }, \ s \ } #define USB_DESC_STRING_LANG_ENUS USB_DESC_STRING(u"\x0409") #define USB_DESC_STRING_SERIALNO ((const void *)1) #define USB_FUNCTION_IFACE(iface, iface_off, tx_ep_off, rx_ep_off) \ ((iface_off) + (iface)) #define USB_FUNCTION_TX_EP(ep, iface_off, tx_ep_off, rx_ep_off) \ ((tx_ep_off) + (ep)) #define USB_FUNCTION_RX_EP(ep, iface_off, tx_ep_off, rx_ep_off) \ ((rx_ep_off) + (ep)) #define USB__INCREMENT(i, _0) (i + 1) #define USB__COUNT_IFACE_EP(i, e) \ __DEFER(USB__COUNT_IFACE_EP_)(__EXPAND i, e) #define USB__COUNT_IFACE_EP_(iface, tx_ep, rx_ep, func) \ (iface + USB_FUNCTION_ ## func ## _IFACE_COUNT, \ tx_ep + USB_FUNCTION_ ## func ## _TX_EP_COUNT, \ rx_ep + USB_FUNCTION_ ## func ## _RX_EP_COUNT) #define USB__GET_FUNCTION_IFACE_COUNT(iter, func) \ USB_FUNCTION_ ## func ## _IFACE_COUNT + #define USB__DEFINE_FUNCTION_DESC(iter, func) \ USB_FUNCTION_DESC_ ## func ## _DECL __CAT(__usb_func_desc, __COUNTER__); #define USB__INIT_FUNCTION_DESC(iter, func) \ USB_FUNCTION_DESC_ ## func iter, #define USB__DEFINE_CONFIG_DESC(confignum, name, ...) \ &((const struct name { \ struct usb_desc_config_t config; \ __REPEAT_INNER(, __EAT, USB__DEFINE_FUNCTION_DESC, __VA_ARGS__) \ }){ \ .config = { \ .bLength = sizeof(struct usb_desc_config_t), \ .bDescriptorType = USB_DESC_CONFIG, \ .wTotalLength = sizeof(struct name), \ .bNumInterfaces = __REPEAT_INNER(, __EAT, USB__GET_FUNCTION_IFACE_COUNT, __VA_ARGS__) 0, \ .bConfigurationValue = confignum, \ .iConfiguration = 0, \ .one = 1, \ .bMaxPower = 50 \ }, \ __REPEAT_INNER((0, 0, 0), USB__COUNT_IFACE_EP, USB__INIT_FUNCTION_DESC, __VA_ARGS__) \ }).config #define USB__DEFINE_CONFIG(iter, args) \ __DEFER(USB__DEFINE_CONFIG_)(iter, __EXPAND args) #define USB__DEFINE_CONFIG_(confignum, initfun, ...) \ &(const struct usbd_config){ \ .init = initfun, \ .desc = USB__DEFINE_CONFIG_DESC( \ confignum, \ __CAT(__usb_desc, __COUNTER__), \ __VA_ARGS__) \ }, #define USB_INIT_DEVICE(vid, pid, manuf, product, ...) \ { \ .dev_desc = &(const struct usb_desc_dev_t){ \ .bLength = sizeof(struct usb_desc_dev_t), \ .bDescriptorType = USB_DESC_DEV, \ .bcdUSB = { .maj = 2 }, \ .bDeviceClass = USB_DEV_CLASS_SEE_IFACE, \ .bDeviceSubClass = USB_DEV_SUBCLASS_SEE_IFACE, \ .bDeviceProtocol = USB_DEV_PROTO_SEE_IFACE, \ .bMaxPacketSize0 = EP0_BUFSIZE, \ .idVendor = vid, \ .idProduct = pid, \ .bcdDevice = { .raw = 0 }, \ .iManufacturer = 1, \ .iProduct = 2, \ .iSerialNumber = 3, \ .bNumConfigurations = __PP_NARG(__VA_ARGS__), \ }, \ .string_descs = (const struct usb_desc_string_t * const []){ \ USB_DESC_STRING_LANG_ENUS, \ USB_DESC_STRING(manuf), \ USB_DESC_STRING(product), \ USB_DESC_STRING_SERIALNO, \ NULL \ }, \ .configs = { \ __REPEAT(1, USB__INCREMENT, USB__DEFINE_CONFIG, __VA_ARGS__) \ NULL \ } \ } // ----- Structs & Enumerations ----- /** * Note: bitfields ahead. * GCC fills the fields lsb-to-msb on little endian. */ /** * USB descriptors */ enum usb_desc_type { USB_DESC_DEV = 1, USB_DESC_CONFIG = 2, USB_DESC_STRING = 3, USB_DESC_IFACE = 4, USB_DESC_EP = 5, USB_DESC_DEVQUAL = 6, USB_DESC_OTHERSPEED = 7, USB_DESC_POWER = 8 }; struct usb_desc_type_t { UNION_STRUCT_START(8); enum usb_desc_type id : 5; enum usb_desc_type_type { USB_DESC_TYPE_STD = 0, USB_DESC_TYPE_CLASS = 1, USB_DESC_TYPE_VENDOR = 2 } type_type : 2; uint8_t _rsvd0 : 1; UNION_STRUCT_END; }; CTASSERT_SIZE_BYTE(struct usb_desc_type_t, 1); enum usb_dev_class { USB_DEV_CLASS_SEE_IFACE = 0, USB_DEV_CLASS_APP = 0xfe, USB_DEV_CLASS_VENDOR = 0xff }; enum usb_dev_subclass { USB_DEV_SUBCLASS_SEE_IFACE = 0, USB_DEV_SUBCLASS_VENDOR = 0xff }; enum usb_dev_proto { USB_DEV_PROTO_SEE_IFACE = 0, USB_DEV_PROTO_VENDOR = 0xff }; struct usb_bcd_t { UNION_STRUCT_START(16); struct { uint8_t sub : 4; uint8_t min : 4; uint16_t maj : 8; }; UNION_STRUCT_END; }; CTASSERT_SIZE_BYTE(struct usb_bcd_t, 2); struct usb_desc_generic_t { uint8_t bLength; struct usb_desc_type_t bDescriptorType; uint8_t data[]; }; CTASSERT_SIZE_BYTE(struct usb_desc_generic_t, 2); struct usb_desc_dev_t { uint8_t bLength; enum usb_desc_type bDescriptorType : 8; /* = USB_DESC_DEV */ struct usb_bcd_t bcdUSB; /* = 0x0200 */ enum usb_dev_class bDeviceClass : 8; enum usb_dev_subclass bDeviceSubClass : 8; enum usb_dev_proto bDeviceProtocol : 8; uint8_t bMaxPacketSize0; uint16_t idVendor; uint16_t idProduct; struct usb_bcd_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; }; CTASSERT_SIZE_BYTE(struct usb_desc_dev_t, 18); struct usb_desc_ep_t { uint8_t bLength; enum usb_desc_type bDescriptorType : 8; /* = USB_DESC_EP */ union { struct { uint8_t ep_num : 4; uint8_t _rsvd0 : 3; uint8_t in : 1; }; uint8_t bEndpointAddress; }; struct { enum usb_ep_type { USB_EP_CONTROL = 0, USB_EP_ISO = 1, USB_EP_BULK = 2, USB_EP_INTR = 3 } type : 2; enum usb_ep_iso_synctype { USB_EP_ISO_NOSYNC = 0, USB_EP_ISO_ASYNC = 1, USB_EP_ISO_ADAPTIVE = 2, USB_EP_ISO_SYNC = 3 } sync_type : 2; enum usb_ep_iso_usagetype { USB_EP_ISO_DATA = 0, USB_EP_ISO_FEEDBACK = 1, USB_EP_ISO_IMPLICIT = 2 } usage_type : 2; uint8_t _rsvd1 : 2; }; struct { uint16_t wMaxPacketSize : 11; uint16_t _rsvd2 : 5; }; uint8_t bInterval; } __packed; CTASSERT_SIZE_BYTE(struct usb_desc_ep_t, 7); struct usb_desc_iface_t { uint8_t bLength; enum usb_desc_type bDescriptorType : 8; /* = USB_DESC_IFACE */ uint8_t bInterfaceNumber; uint8_t bAlternateSetting; uint8_t bNumEndpoints; enum usb_dev_class bInterfaceClass : 8; enum usb_dev_subclass bInterfaceSubClass: 8; enum usb_dev_proto bInterfaceProtocol : 8; uint8_t iInterface; }; CTASSERT_SIZE_BYTE(struct usb_desc_iface_t, 9); struct usb_desc_config_t { uint8_t bLength; enum usb_desc_type bDescriptorType : 8; /* = USB_DESC_CONFIG */ uint16_t wTotalLength; /* size of config, iface, ep */ uint8_t bNumInterfaces; uint8_t bConfigurationValue; uint8_t iConfiguration; struct { uint8_t _rsvd0 : 5; uint8_t remote_wakeup : 1; uint8_t self_powered : 1; uint8_t one : 1; /* = 1 for historical reasons */ }; uint8_t bMaxPower; /* units of 2mA */ } __packed; CTASSERT_SIZE_BYTE(struct usb_desc_config_t, 9); struct usb_desc_string_t { uint8_t bLength; enum usb_desc_type bDescriptorType : 8; /* = USB_DESC_STRING */ const char16_t bString[]; }; CTASSERT_SIZE_BYTE(struct usb_desc_string_t, 2); struct usb_ctrl_req_t { union /* reqtype and request & u16 */ { struct /* reqtype and request */ { union /* reqtype in bitfield & u8 */ { struct /* reqtype */ { enum usb_ctrl_req_recp { USB_CTRL_REQ_DEV = 0, USB_CTRL_REQ_IFACE = 1, USB_CTRL_REQ_EP = 2, USB_CTRL_REQ_OTHER = 3 } recp : 5; enum usb_ctrl_req_type { USB_CTRL_REQ_STD = 0, USB_CTRL_REQ_CLASS = 1, USB_CTRL_REQ_VENDOR = 2 } type : 2; enum usb_ctrl_req_dir { USB_CTRL_REQ_OUT = 0, USB_CTRL_REQ_IN = 1 } in : 1; }; uint8_t bmRequestType; }; /* union */ enum usb_ctrl_req_code { USB_CTRL_REQ_GET_STATUS = 0, USB_CTRL_REQ_CLEAR_FEATURE = 1, USB_CTRL_REQ_SET_FEATURE = 3, USB_CTRL_REQ_SET_ADDRESS = 5, USB_CTRL_REQ_GET_DESCRIPTOR = 6, USB_CTRL_REQ_SET_DESCRIPTOR = 7, USB_CTRL_REQ_GET_CONFIGURATION = 8, USB_CTRL_REQ_SET_CONFIGURATION = 9, USB_CTRL_REQ_GET_INTERFACE = 10, USB_CTRL_REQ_SET_INTERFACE = 11, USB_CTRL_REQ_SYNC_FRAME = 12 } bRequest : 8; }; /* struct */ uint16_t type_and_req; }; /* union */ union { uint16_t wValue; struct { uint8_t wValueLow; uint8_t wValueHigh; }; }; uint16_t wIndex; uint16_t wLength; }; CTASSERT_SIZE_BYTE(struct usb_ctrl_req_t, 8); /** * status replies for GET_STATUS. */ struct usb_ctrl_req_status_dev_t { uint16_t self_powered : 1; uint16_t remote_wakeup : 1; uint16_t _rsvd : 14; }; CTASSERT_SIZE_BIT(struct usb_ctrl_req_status_dev_t, 16); struct usb_ctrl_req_status_iface_t { uint16_t _rsvd; }; CTASSERT_SIZE_BIT(struct usb_ctrl_req_status_iface_t, 16); struct usb_ctrl_req_status_ep_t { uint16_t halt : 1; uint16_t _rsvd : 15; }; CTASSERT_SIZE_BIT(struct usb_ctrl_req_status_ep_t, 16); /** * Descriptor type (in req->value) for GET_DESCRIPTOR. */ struct usb_ctrl_req_desc_t { uint8_t idx; enum usb_desc_type type : 8; }; CTASSERT_SIZE_BIT(struct usb_ctrl_req_desc_t, 16); /** * Feature selector (in req->value) for CLEAR_FEATURE. */ enum usb_ctrl_req_feature { USB_CTRL_REQ_FEAT_EP_HALT = 0, USB_CTRL_REQ_FEAT_DEV_REMOTE_WKUP = 1, USB_CTRL_REQ_FEAT_TEST_MODE = 2 }; struct usb_xfer_info; typedef void (*ep_callback_t)(void *buf, ssize_t len, void *data); /** * (Artificial) function. Aggregates one or more interfaces. */ struct usbd_function { int (*configure)(int orig_iface, int iface, int altsetting, void *data); int (*control)(struct usb_ctrl_req_t *, void *); int interface_count; int ep_rx_count; int ep_tx_count; }; struct usbd_function_ctx_header { struct usbd_function_ctx_header *next; const struct usbd_function *function; int interface_offset; int ep_rx_offset; int ep_tx_offset; }; typedef void (usbd_init_fun_t)(int); typedef void (usbd_suspend_resume_fun_t)(void); /** * Configuration. Contains one or more functions which all will be * active concurrently. */ struct usbd_config { usbd_init_fun_t *init; usbd_suspend_resume_fun_t *suspend; usbd_suspend_resume_fun_t *resume; /** * We will not set a config for now, because there is not much to * configure, except for power * * const struct usb_desc_config_t *config_desc; */ const struct usb_desc_config_t *desc; const struct usbd_function *function[]; }; /** * Device. Contains one or more configurations, out of which only one * is active at a time. */ struct usbd_device { const struct usb_desc_dev_t *dev_desc; const struct usb_desc_string_t * const *string_descs; const struct usbd_config *configs[]; }; /* Provided by MD code */ struct usbd_ep_pipe_state_t; // ----- Functions ----- void *usb_get_xfer_data(struct usb_xfer_info *); enum usb_tok_pid usb_get_xfer_pid(struct usb_xfer_info *); int usb_get_xfer_ep(struct usb_xfer_info *); enum usb_ep_dir usb_get_xfer_dir(struct usb_xfer_info *); void usb_enable_xfers(void); void usb_set_addr(int); void usb_ep_stall(int); size_t usb_ep_get_transfer_size(struct usbd_ep_pipe_state_t *); void usb_queue_next(struct usbd_ep_pipe_state_t *, void *, size_t); void usb_pipe_stall(struct usbd_ep_pipe_state_t *); void usb_pipe_unstall(struct usbd_ep_pipe_state_t *); void usb_pipe_enable(struct usbd_ep_pipe_state_t *s); void usb_pipe_disable(struct usbd_ep_pipe_state_t *s); #ifdef VUSB void vusb_main_loop(void); #else void usb_poll(void); #endif int usb_tx_serialno(size_t reqlen); /* Provided by MI code */ void usb_init(const struct usbd_device *); void usb_attach_function(const struct usbd_function *function, struct usbd_function_ctx_header *ctx); void usb_handle_transaction(struct usb_xfer_info *); void usb_setup_control(void); void usb_handle_control_status_cb(ep_callback_t cb); void usb_handle_control_status(int); struct usbd_ep_pipe_state_t *usb_init_ep(struct usbd_function_ctx_header *ctx, int ep, enum usb_ep_dir dir, size_t size); int usb_rx(struct usbd_ep_pipe_state_t *, void *, size_t, ep_callback_t, void *); int usb_tx(struct usbd_ep_pipe_state_t *, const void *, size_t, size_t, ep_callback_t, void *); int usb_ep0_rx(void *, size_t, ep_callback_t, void *); void *usb_ep0_tx_inplace_prepare(size_t len); int usb_ep0_tx(void *buf, size_t len, size_t reqlen, ep_callback_t cb, void *cb_data); int usb_ep0_tx_cp(const void *, size_t, size_t, ep_callback_t, void *); // ----- DFU USB Additional Includes ----- #include "dfu.h"