diff options
Diffstat (limited to 'atmel-samd/asf4/samd21/usb')
24 files changed, 6879 insertions, 0 deletions
diff --git a/atmel-samd/asf4/samd21/usb/class/cdc/device/cdcdf_acm.c b/atmel-samd/asf4/samd21/usb/class/cdc/device/cdcdf_acm.c new file mode 100644 index 000000000..f0a8de446 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/cdc/device/cdcdf_acm.c @@ -0,0 +1,389 @@ +/** + * \file + * + * \brief USB Device Stack CDC ACM Function Implementation. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel micro controller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "cdcdf_acm.h" + +#define CDCDF_ACM_VERSION 0x00000001u +#define CDCDF_ACM_COMM_EP_INDEX 0 +#define CDCDF_ACM_DATA_EP_INDEX 1 + +/** USB Device CDC ACM Fucntion Specific Data */ +struct cdcdf_acm_func_data { + /** CDC Device ACM Interface information */ + uint8_t func_iface[2]; + /** CDC Device ACM IN Endpoint */ + uint8_t func_ep_in[2]; + /** CDC Device ACM OUT Endpoint */ + uint8_t func_ep_out; + /** CDC Device ACM Enable Flag */ + bool enabled; +}; + +static struct usbdf_driver _cdcdf_acm; +static struct cdcdf_acm_func_data _cdcdf_acm_funcd; +static struct usb_cdc_line_coding usbd_cdc_line_coding; + +static cdcdf_acm_notify_state_t cdcdf_acm_notify_state = NULL; +static cdcdf_acm_set_line_coding_t cdcdf_acm_set_line_coding = NULL; + +/** + * \brief Enable CDC ACM Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB interface descriptor + * \return Operation status. + */ +static int32_t cdcdf_acm_enable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + struct cdcdf_acm_func_data *func_data = (struct cdcdf_acm_func_data *)(drv->func_data); + + usb_ep_desc_t ep_desc; + usb_iface_desc_t ifc_desc; + uint8_t * ifc, *ep; + uint8_t i; + + ifc = desc->sod; + for (i = 0; i < 2; i++) { + if (NULL == ifc) { + return ERR_NOT_FOUND; + } + + ifc_desc.bInterfaceNumber = ifc[2]; + ifc_desc.bInterfaceClass = ifc[5]; + + if ((CDC_CLASS_COMM == ifc_desc.bInterfaceClass) || (CDC_CLASS_DATA == ifc_desc.bInterfaceClass)) { + if (func_data->func_iface[i] == ifc_desc.bInterfaceNumber) { // Initialized + return ERR_ALREADY_INITIALIZED; + } else if (func_data->func_iface[i] != 0xFF) { // Occupied + return ERR_NO_RESOURCE; + } else { + func_data->func_iface[i] = ifc_desc.bInterfaceNumber; + } + } else { // Not supported by this function driver + return ERR_NOT_FOUND; + } + + // Install endpoints + ep = usb_find_desc(ifc, desc->eod, USB_DT_ENDPOINT); + while (NULL != ep) { + ep_desc.bEndpointAddress = ep[2]; + ep_desc.bmAttributes = ep[3]; + ep_desc.wMaxPacketSize = usb_get_u16(ep + 4); + if (usb_d_ep_init(ep_desc.bEndpointAddress, ep_desc.bmAttributes, ep_desc.wMaxPacketSize)) { + return ERR_NOT_INITIALIZED; + } + if (ep_desc.bEndpointAddress & USB_EP_DIR_IN) { + func_data->func_ep_in[i] = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_in[i]); + } else { + func_data->func_ep_out = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_out); + } + desc->sod = ep; + ep = usb_find_ep_desc(usb_desc_next(desc->sod), desc->eod); + } + ifc = usb_find_desc(usb_desc_next(desc->sod), desc->eod, USB_DT_INTERFACE); + } + // Installed + _cdcdf_acm_funcd.enabled = true; + return ERR_NONE; +} + +/** + * \brief Disable CDC ACM Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB device descriptor + * \return Operation status. + */ +static int32_t cdcdf_acm_disable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + struct cdcdf_acm_func_data *func_data = (struct cdcdf_acm_func_data *)(drv->func_data); + + usb_iface_desc_t ifc_desc; + uint8_t i; + + if (desc) { + ifc_desc.bInterfaceClass = desc->sod[5]; + // Check interface + if ((ifc_desc.bInterfaceClass != CDC_CLASS_COMM) && (ifc_desc.bInterfaceClass != CDC_CLASS_DATA)) { + return ERR_NOT_FOUND; + } + } + + for (i = 0; i < 2; i++) { + if (func_data->func_iface[i] == 0xFF) { + continue; + } else { + func_data->func_iface[i] = 0xFF; + if (func_data->func_ep_in[i] != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_in[i]); + func_data->func_ep_in[i] = 0xFF; + } + } + } + + if (func_data->func_ep_out != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_out); + func_data->func_ep_out = 0xFF; + } + + _cdcdf_acm_funcd.enabled = false; + return ERR_NONE; +} + +/** + * \brief CDC ACM Control Function + * \param[in] drv Pointer to USB device function driver + * \param[in] ctrl USB device general function control type + * \param[in] param Parameter pointer + * \return Operation status. + */ +static int32_t cdcdf_acm_ctrl(struct usbdf_driver *drv, enum usbdf_control ctrl, void *param) +{ + switch (ctrl) { + case USBDF_ENABLE: + return cdcdf_acm_enable(drv, (struct usbd_descriptors *)param); + + case USBDF_DISABLE: + return cdcdf_acm_disable(drv, (struct usbd_descriptors *)param); + + case USBDF_GET_IFACE: + return ERR_UNSUPPORTED_OP; + + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the CDC class set request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t cdcdf_acm_set_req(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + struct usb_cdc_line_coding line_coding_tmp; + uint16_t len = req->wLength; + uint8_t * ctrl_buf = usbdc_get_ctrl_buffer(); + + switch (req->bRequest) { + case USB_REQ_CDC_SET_LINE_CODING: + if (sizeof(struct usb_cdc_line_coding) != len) { + return ERR_INVALID_DATA; + } + if (USB_SETUP_STAGE == stage) { + return usbdc_xfer(ep, ctrl_buf, len, false); + } else { + memcpy(&line_coding_tmp, ctrl_buf, sizeof(struct usb_cdc_line_coding)); + if ((NULL == cdcdf_acm_set_line_coding) || (true == cdcdf_acm_set_line_coding(&line_coding_tmp))) { + usbd_cdc_line_coding = line_coding_tmp; + } + return ERR_NONE; + } + case USB_REQ_CDC_SET_CONTROL_LINE_STATE: + usbdc_xfer(0, NULL, 0, 0); + if (NULL != cdcdf_acm_notify_state) { + cdcdf_acm_notify_state(req->wValue); + } + return ERR_NONE; + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the CDC class get request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t cdcdf_acm_get_req(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + uint16_t len = req->wLength; + + if (USB_DATA_STAGE == stage) { + return ERR_NONE; + } + + switch (req->bRequest) { + case USB_REQ_CDC_GET_LINE_CODING: + if (sizeof(struct usb_cdc_line_coding) != len) { + return ERR_INVALID_DATA; + } + return usbdc_xfer(ep, (uint8_t *)&usbd_cdc_line_coding, len, false); + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the CDC class request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t cdcdf_acm_req(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + if (0x01 != ((req->bmRequestType >> 5) & 0x03)) { // class request + return ERR_NOT_FOUND; + } + if ((req->wIndex == _cdcdf_acm_funcd.func_iface[0]) || (req->wIndex == _cdcdf_acm_funcd.func_iface[1])) { + if (req->bmRequestType & USB_EP_DIR_IN) { + return cdcdf_acm_get_req(ep, req, stage); + } else { + return cdcdf_acm_set_req(ep, req, stage); + } + } else { + return ERR_NOT_FOUND; + } +} + +/** USB Device CDC ACM Handler Struct */ +static struct usbdc_handler cdcdf_acm_req_h = {NULL, (FUNC_PTR)cdcdf_acm_req}; + +/** + * \brief Initialize the USB CDC ACM Function Driver + */ +int32_t cdcdf_acm_init(void) +{ + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _cdcdf_acm.ctrl = cdcdf_acm_ctrl; + _cdcdf_acm.func_data = &_cdcdf_acm_funcd; + + usbdc_register_function(&_cdcdf_acm); + usbdc_register_handler(USBDC_HDL_REQ, &cdcdf_acm_req_h); + return ERR_NONE; +} + +/** + * \brief Deinitialize the USB CDC ACM Function Driver + */ +void cdcdf_acm_deinit(void) +{ + usb_d_ep_deinit(_cdcdf_acm_funcd.func_ep_in[CDCDF_ACM_COMM_EP_INDEX]); + usb_d_ep_deinit(_cdcdf_acm_funcd.func_ep_in[CDCDF_ACM_DATA_EP_INDEX]); + usb_d_ep_deinit(_cdcdf_acm_funcd.func_ep_out); +} + +/** + * \brief USB CDC ACM Function Read Data + */ +int32_t cdcdf_acm_read(uint8_t *buf, uint32_t size) +{ + if (!cdcdf_acm_is_enabled()) { + return ERR_DENIED; + } + return usbdc_xfer(_cdcdf_acm_funcd.func_ep_out, buf, size, false); +} + +/** + * \brief USB CDC ACM Function Write Data + */ +int32_t cdcdf_acm_write(uint8_t *buf, uint32_t size) +{ + if (!cdcdf_acm_is_enabled()) { + return ERR_DENIED; + } + return usbdc_xfer(_cdcdf_acm_funcd.func_ep_in[CDCDF_ACM_DATA_EP_INDEX], buf, size, true); +} + +/** + * \brief USB CDC ACM Stop the data transfer + */ +void cdcdf_acm_stop_xfer(void) +{ + /* Stop transfer. */ + usb_d_ep_abort(_cdcdf_acm_funcd.func_ep_in[CDCDF_ACM_DATA_EP_INDEX]); + usb_d_ep_abort(_cdcdf_acm_funcd.func_ep_out); +} + +/** + * \brief USB CDC ACM Function Register Callback + */ +int32_t cdcdf_acm_register_callback(enum cdcdf_acm_cb_type cb_type, FUNC_PTR func) +{ + switch (cb_type) { + case CDCDF_ACM_CB_READ: + usb_d_ep_register_callback(_cdcdf_acm_funcd.func_ep_out, USB_D_EP_CB_XFER, func); + break; + case CDCDF_ACM_CB_WRITE: + usb_d_ep_register_callback(_cdcdf_acm_funcd.func_ep_in[CDCDF_ACM_DATA_EP_INDEX], USB_D_EP_CB_XFER, func); + break; + case CDCDF_ACM_CB_LINE_CODING_C: + cdcdf_acm_set_line_coding = (cdcdf_acm_set_line_coding_t)func; + break; + case CDCDF_ACM_CB_STATE_C: + cdcdf_acm_notify_state = (cdcdf_acm_notify_state_t)func; + break; + default: + return ERR_INVALID_ARG; + } + return ERR_NONE; +} + +/** + * \brief Check whether CDC ACM Function is enabled + */ +bool cdcdf_acm_is_enabled(void) +{ + return _cdcdf_acm_funcd.enabled; +} + +/** + * \brief Return the CDC ACM line coding structure start address + */ +const struct usb_cdc_line_coding *cdcdf_acm_get_line_coding(void) +{ + return (const struct usb_cdc_line_coding *)&usbd_cdc_line_coding; +} + +/** + * \brief Return version + */ +uint32_t cdcdf_acm_get_version(void) +{ + return CDCDF_ACM_VERSION; +} diff --git a/atmel-samd/asf4/samd21/usb/class/cdc/device/cdcdf_acm.h b/atmel-samd/asf4/samd21/usb/class/cdc/device/cdcdf_acm.h new file mode 100644 index 000000000..913e734be --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/cdc/device/cdcdf_acm.h @@ -0,0 +1,114 @@ +/** + * \file + * + * \brief USB Device Stack CDC ACM Function Definition. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef USBDF_CDC_ACM_SER_H_ +#define USBDF_CDC_ACM_SER_H_ + +#include "usbdc.h" +#include "usb_protocol_cdc.h" + +/** CDC ACM Class Callback Type */ +enum cdcdf_acm_cb_type { CDCDF_ACM_CB_READ, CDCDF_ACM_CB_WRITE, CDCDF_ACM_CB_LINE_CODING_C, CDCDF_ACM_CB_STATE_C }; + +/** CDC ACM Notify Line State Callback. */ +typedef void (*cdcdf_acm_notify_state_t)(uint16_t); + +/** CDC ACM Set Line Coding Callback. */ +typedef bool (*cdcdf_acm_set_line_coding_t)(struct usb_cdc_line_coding *); + +/** + * \brief Initialize the USB CDC ACM Function Driver + * \return Operation status. + */ +int32_t cdcdf_acm_init(void); + +/** + * \brief Deinitialize the USB CDC ACM Function Driver + * \return Operation status. + */ +void cdcdf_acm_deinit(void); + +/** + * \brief USB CDC ACM Function Read Data + * \param[in] buf Pointer to the buffer which receives data + * \param[in] size the size of data to be received + * \return Operation status. + */ +int32_t cdcdf_acm_read(uint8_t *buf, uint32_t size); + +/** + * \brief USB CDC ACM Function Write Data + * \param[in] buf Pointer to the buffer which stores data + * \param[in] size the size of data to be sent + * \return Operation status. + */ +int32_t cdcdf_acm_write(uint8_t *buf, uint32_t size); + +/** + * \brief USB CDC ACM Stop the currnet data transfer + */ +void cdcdf_acm_stop_xfer(void); + +/** + * \brief USB CDC ACM Function Register Callback + * \param[in] cb_type Callback type of CDC ACM Function + * \param[in] func Pointer to callback function + * \return Operation status. + */ +int32_t cdcdf_acm_register_callback(enum cdcdf_acm_cb_type cb_type, FUNC_PTR func); + +/** + * \brief Check whether CDC ACM Function is enabled + * \return Operation status. + * \return true CDC ACM Function is enabled + * \return false CDC ACM Function is disabled + */ +bool cdcdf_acm_is_enabled(void); + +/** + * \brief Return the CDC ACM line coding structure start address + * \return Pointer to USB CDC ACM line coding data. + */ +const struct usb_cdc_line_coding *cdcdf_acm_get_line_coding(void); + +/** + * \brief Return version + */ +uint32_t cdcdf_acm_get_version(void); + +#endif /* USBDF_CDC_ACM_SER_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/cdc/usb_protocol_cdc.h b/atmel-samd/asf4/samd21/usb/class/cdc/usb_protocol_cdc.h new file mode 100644 index 000000000..6017864cb --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/cdc/usb_protocol_cdc.h @@ -0,0 +1,407 @@ +/** + * \file + * + * \brief USB Communication Device Class (CDC) protocol definitions + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> + */ +#ifndef _USB_PROTOCOL_CDC_H_ +#define _USB_PROTOCOL_CDC_H_ + +#include "usb_includes.h" + +/** + * \ingroup usb_protocol_group + * \defgroup cdc_protocol_group Communication Device Class Definitions + * @{ + */ + +/** + * \name Possible values of class + */ +//@{ +#define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class +#define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface +#define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface +//@} + +//! \name USB CDC Subclass IDs +//@{ +#define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model +#define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model +#define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model +#define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model +#define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model +#define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model +#define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model +//@} + +//! \name USB CDC Communication Interface Protocol IDs +//@{ +#define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands +//@} + +//! \name USB CDC Data Interface Protocol IDs +//@{ +#define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI +#define CDC_PROTOCOL_HDLC 0x31 //!< HDLC +#define CDC_PROTOCOL_TRANS 0x32 //!< Transparent +#define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol +#define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol +#define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor +#define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures +#define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control +#define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN +#define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands +#define CDC_PROTOCOL_HOST 0xFD //!< Host based driver + /** + * \brief Describes the Protocol Unit Functional Descriptors [sic] + * on Communication Class Interface + */ +#define CDC_PROTOCOL_PUFD 0xFE +//@} + +//! \name USB CDC Functional Descriptor Types +//@{ +#define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor +#define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor +//@} + +//! \name USB CDC Functional Descriptor Subtypes +//@{ +#define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor +#define CDC_SCS_CALL_MGMT 0x01 //!< Call Management +#define CDC_SCS_ACM 0x02 //!< Abstract Control Management +#define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor +//@} + +//! \name USB CDC Request IDs +//@{ +#define USB_REQ_CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define USB_REQ_CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define USB_REQ_CDC_SET_COMM_FEATURE 0x02 +#define USB_REQ_CDC_GET_COMM_FEATURE 0x03 +#define USB_REQ_CDC_CLEAR_COMM_FEATURE 0x04 +#define USB_REQ_CDC_SET_AUX_LINE_STATE 0x10 +#define USB_REQ_CDC_SET_HOOK_STATE 0x11 +#define USB_REQ_CDC_PULSE_SETUP 0x12 +#define USB_REQ_CDC_SEND_PULSE 0x13 +#define USB_REQ_CDC_SET_PULSE_TIME 0x14 +#define USB_REQ_CDC_RING_AUX_JACK 0x15 +#define USB_REQ_CDC_SET_LINE_CODING 0x20 +#define USB_REQ_CDC_GET_LINE_CODING 0x21 +#define USB_REQ_CDC_SET_CONTROL_LINE_STATE 0x22 +#define USB_REQ_CDC_SEND_BREAK 0x23 +#define USB_REQ_CDC_SET_RINGER_PARMS 0x30 +#define USB_REQ_CDC_GET_RINGER_PARMS 0x31 +#define USB_REQ_CDC_SET_OPERATION_PARMS 0x32 +#define USB_REQ_CDC_GET_OPERATION_PARMS 0x33 +#define USB_REQ_CDC_SET_LINE_PARMS 0x34 +#define USB_REQ_CDC_GET_LINE_PARMS 0x35 +#define USB_REQ_CDC_DIAL_DIGITS 0x36 +#define USB_REQ_CDC_SET_UNIT_PARAMETER 0x37 +#define USB_REQ_CDC_GET_UNIT_PARAMETER 0x38 +#define USB_REQ_CDC_CLEAR_UNIT_PARAMETER 0x39 +#define USB_REQ_CDC_GET_PROFILE 0x3A +#define USB_REQ_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define USB_REQ_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERNFILTER 0x41 +#define USB_REQ_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERNFILTER 0x42 +#define USB_REQ_CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define USB_REQ_CDC_GET_ETHERNET_STATISTIC 0x44 +#define USB_REQ_CDC_SET_ATM_DATA_FORMAT 0x50 +#define USB_REQ_CDC_GET_ATM_DEVICE_STATISTICS 0x51 +#define USB_REQ_CDC_SET_ATM_DEFAULT_VC 0x52 +#define USB_REQ_CDC_GET_ATM_VC_STATISTICS 0x53 +// Added bNotification codes according cdc spec 1.1 chapter 6.3 +#define USB_REQ_CDC_NOTIFY_RING_DETECT 0x09 +#define USB_REQ_CDC_NOTIFY_SERIAL_STATE 0x20 +#define USB_REQ_CDC_NOTIFY_CALL_STATE_CHANGE 0x28 +#define USB_REQ_CDC_NOTIFY_LINE_STATE_CHANGE 0x29 +//@} + +/* + * Need to pack structures tightly, or the compiler might insert padding + * and violate the spec-mandated layout. + */ +COMPILER_PACK_SET(1) + +//! \name USB CDC Descriptors +//@{ + +//! CDC Header Functional Descriptor +typedef struct usb_cdc_hdr_desc { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + le16_t bcdCDC; +} usb_cdc_hdr_desc_t; + +#define USB_CDC_HDR_DESC_LEN 5 +#define USB_CDC_HDR_DESC_BYTES(bcdCDC) \ + USB_CDC_HDR_DESC_LEN, /* bFunctionLength */ \ + CDC_CS_INTERFACE, /* bDescriptorType */ \ + CDC_SCS_HEADER, /* bDescriptorSubtype */ \ + LE_BYTE0(bcdCDC), LE_BYTE1(bcdCDC) /* bcdCDC */ + +//! CDC Call Management Functional Descriptor +typedef struct usb_cdc_call_mgmt_desc { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; +} usb_cdc_call_mgmt_desc_t; + +#define USB_CDC_CALL_MGMT_DESC_LEN 5 +#define USB_CDC_CALL_MGMT_DESC_BYTES(bmCapabilities, bDataInterface) \ + USB_CDC_CALL_MGMT_DESC_LEN, /* bFunctionLength */ \ + CDC_CS_INTERFACE, /* bDescriptorType */ \ + CDC_SCS_CALL_MGMT, /* bDescriptorSubtype */ \ + bmCapabilities, bDataInterface + +//! CDC ACM Functional Descriptor +typedef struct usb_cdc_acm_desc { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; +} usb_cdc_acm_desc_t; + +#define USB_CDC_ACM_DESC_LEN 4 +#define USB_CDC_ACM_DESC_BYTES(bmCapabilities) \ + USB_CDC_ACM_DESC_LEN, /* bFunctionLength */ \ + CDC_CS_INTERFACE, /* bDescriptorType */ \ + CDC_SCS_ACM, /* bDescriptorSubType */ \ + bmCapabilities + +//! CDC Union Functional Descriptor +typedef struct usb_cdc_union_desc { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bMasterInterface; + uint8_t bSlaveInterface0; +} usb_cdc_union_desc_t; + +#define USB_CDC_UNION_DESC_LEN 5 +#define USB_CDC_UNION_DESC_BYTES(bMasterInterface, bSlaveInterface) \ + USB_CDC_UNION_DESC_LEN, CDC_CS_INTERFACE, CDC_SCS_UNION, bMasterInterface, bSlaveInterface + +//! \name USB CDC Call Management Capabilities +//@{ +//! Device handles call management itself +#define CDC_CALL_MGMT_SUPPORTED (1 << 0) +//! Device can send/receive call management info over a Data Class interface +#define CDC_CALL_MGMT_OVER_DCI (1 << 1) +//@} + +//! \name USB CDC ACM Capabilities +//@{ +//! Device supports the request combination of +//! Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. +#define CDC_ACM_SUPPORT_FEATURE_REQUESTS (1 << 0) +//! Device supports the request combination of +//! Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, +//! and the notification Serial_State. +#define CDC_ACM_SUPPORT_LINE_REQUESTS (1 << 1) +//! Device supports the request Send_Break +#define CDC_ACM_SUPPORT_SENDBREAK_REQUESTS (1 << 2) +//! Device supports the notification Network_Connection. +#define CDC_ACM_SUPPORT_NOTIFY_REQUESTS (1 << 3) +//@} +//@} + +//! \name USB CDC line control +//@{ + +//! \name USB CDC line coding +//@{ + +//! Line Coding structure +typedef struct usb_cdc_line_coding { + le32_t dwDTERate; //!< Data rate, bits per second + uint8_t bCharFormat; //!< 0-1 Stop bit,1-1.5 Stop bits,2-2 Stop bits + uint8_t bParityType; //!< 0-None,1-Odd,2-Even,3-Mark,4-Space + uint8_t bDataBits; //!< 5,6,7,8 or 16 +} usb_cdc_line_coding_t; + +//! Possible values of bCharFormat +enum cdc_char_format { + CDC_STOP_BITS_1 = 0, //!< 1 stop bit + CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits + CDC_STOP_BITS_2 = 2 //!< 2 stop bits +}; + +//! Possible values of bParityType +enum cdc_parity { + CDC_PAR_NONE = 0, //!< No parity + CDC_PAR_ODD = 1, //!< Odd parity + CDC_PAR_EVEN = 2, //!< Even parity + CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) + CDC_PAR_SPACE = 4 //!< Parity forced to 1 (mark) +}; +//@} + +//! \name USB CDC control signals +//! spec 1.1 chapter 6.2.14 +//@{ + +//! Control signal structure +typedef struct usb_cdc_control_signal { + union { + le16_t value; + struct { + uint8_t dte_present; + uint8_t carrier_ctrl; + } modem; + struct { + uint8_t DTR : 1; //!< Data Terminal Ready + uint8_t RTS : 1; //!< Request To Send + } rs232; + struct { + uint8_t s108_2 : 1; //!< V.24 signal 108/2 + uint8_t s105 : 1; //!< V.24 signal 105 + } v24; + }; +} usb_cdc_control_signal_t; + +//! \name Possible values in usb_cdc_control_signal_t +//@{ +//! Carrier control for half duplex modems. +//! This signal corresponds to V.24 signal 105 and RS-232 signal RTS. +//! The device ignores the value of this bit +//! when operating in full duplex mode. +#define CDC_CTRL_SIGNAL_ACTIVATE_CARRIER (1 << 1) +//! Indicates to DCE if DTE is present or not. +//! This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. +#define CDC_CTRL_SIGNAL_DTE_PRESENT (1 << 0) +//@} +//@} + +//! \name USB CDC notification message +//@{ + +typedef struct usb_cdc_notify_msg { + uint8_t bmRequestType; + uint8_t bNotification; + union { + le16_t wValue; + struct { + uint8_t low; + uint8_t high; + } wValueBytes; + }; + union { + le16_t wIndex; + struct { + uint8_t low; + uint8_t high; + } wIndexBytes; + }; + union { + le16_t wLength; + struct { + uint8_t low; + uint8_t high; + } wLengthBytes; + }; +} usb_cdc_notify_msg_t; + +//! \name USB CDC serial state +//@{* + +//! UART State Bitmap (cdc spec 1.1 chapter 6.3.5) +typedef union usb_cdc_uart_state { + le16_t value; + struct { + uint8_t bRxCarrier : 1; + uint8_t bTxCarrier : 1; + uint8_t bBreak : 1; + uint8_t bRingSignal : 1; + uint8_t bFraming : 1; + uint8_t bParity : 1; + uint8_t bOverRun; + } bitmap; + struct { + uint8_t bDCD : 1; + uint8_t bDSR : 1; + uint8_t bBreak : 1; + uint8_t bRingSignal : 1; + uint8_t bFraming : 1; + uint8_t bParity : 1; + uint8_t bOverRun; + } rs232; + struct { + uint8_t bS109 : 1; //!< V.24 signal 109 + uint8_t bS106 : 1; //!< V.24 signal 106 + uint8_t bBreak : 1; + uint8_t bRingSignal : 1; + uint8_t bFraming : 1; + uint8_t bParity : 1; + uint8_t bOverRun; + } v24; +} usb_cdc_uart_state_t; + +//! Hardware handshake support (cdc spec 1.1 chapter 6.3.5) +typedef struct usb_cdc_notify_serial_state { + usb_cdc_notify_msg_t header; + union usb_cdc_uart_state state; +} usb_cdc_notify_serial_state_t; + +//! \name Possible values in usb_cdc_notify_serial_state_t +//@{ +#define CDC_SERIAL_STATE_DCD CPU_TO_LE16((1 << 0)) +#define CDC_SERIAL_STATE_DSR CPU_TO_LE16((1 << 1)) +#define CDC_SERIAL_STATE_BREAK CPU_TO_LE16((1 << 2)) +#define CDC_SERIAL_STATE_RING CPU_TO_LE16((1 << 3)) +#define CDC_SERIAL_STATE_FRAMING CPU_TO_LE16((1 << 4)) +#define CDC_SERIAL_STATE_PARITY CPU_TO_LE16((1 << 5)) +#define CDC_SERIAL_STATE_OVERRUN CPU_TO_LE16((1 << 6)) +//@} +//! @} + +//! @} + +COMPILER_PACK_RESET() + +//! @} + +#endif // _USB_PROTOCOL_CDC_H_ diff --git a/atmel-samd/asf4/samd21/usb/class/composite/device/composite_desc.h b/atmel-samd/asf4/samd21/usb/class/composite/device/composite_desc.h new file mode 100644 index 000000000..68db57af9 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/composite/device/composite_desc.h @@ -0,0 +1,170 @@ +/** + * \file + * + * \brief USB Device Stack Composite Class Descriptor Setting. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef USBDF_COMPOSITE_DESC_H_ +#define USBDF_COMPOSITE_DESC_H_ + +#include "usb_protocol.h" +#include "usbd_composite_config.h" + +#if CONF_USB_COMPOSITE_CDC_ACM_EN == 1 +#define CONF_CDC_ACM_IFC_LEN 66 +#define CONF_CDC_ACM_IFC_NUM 2 +#define CONF_USB_COMPOSITE_CDC_ACM_COMM_BIFCNUM 0 +#define CONF_USB_COMPOSITE_CDC_ACM_DATA_BIFCNUM 1 +#define CONF_CDC_ACM_IFC_DESC \ + USB_IAD_DESC_BYTES( \ + CONF_USB_COMPOSITE_CDC_ACM_COMM_BIFCNUM, 0x02, CDC_CLASS_DEVICE, CDC_SUBCLASS_ACM, CDC_PROTOCOL_V25TER, 0x00) \ + , \ + USB_IFACE_DESC_BYTES(CONF_USB_COMPOSITE_CDC_ACM_COMM_BIFCNUM, \ + 0x00, \ + 0x01, \ + CDC_CLASS_DEVICE, \ + CDC_SUBCLASS_ACM, \ + CDC_PROTOCOL_V25TER, \ + 0x00), \ + USB_CDC_HDR_DESC_BYTES(0x1001), USB_CDC_CALL_MGMT_DESC_BYTES(0x01, 0x00), USB_CDC_ACM_DESC_BYTES(0x02), \ + USB_CDC_UNION_DESC_BYTES(CONF_USB_COMPOSITE_CDC_ACM_COMM_BIFCNUM, 0x01), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_CDC_ACM_COMM_INT_EPADDR, 3, CONF_USB_COMPOSITE_CDC_ACM_COMM_INT_MAXPKSZ, 10), \ + USB_IFACE_DESC_BYTES(CONF_USB_COMPOSITE_CDC_ACM_DATA_BIFCNUM, 0x00, 2, 0x0A, 0x00, 0x00, 0x00), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKOUT_EPADDR, 2, CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKOUT_MAXPKSZ, 0x00), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_EPADDR, 2, CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_MAXPKSZ, 0x00), +#else +#define CONF_CDC_ACM_IFC_LEN 0 +#define CONF_CDC_ACM_IFC_NUM 0 +#define CONF_USB_COMPOSITE_CDC_ACM_COMM_BIFCNUM -2 +#define CONF_USB_COMPOSITE_CDC_ACM_DATA_BIFCNUM -1 +#define CONF_CDC_ACM_IFC_DESC +#endif + +#if CONF_USB_COMPOSITE_HID_MOUSE_EN == 1 +#define CONF_HID_MOUSE_IFC_LEN 25 +#define CONF_HID_MOUSE_IFC_NUM 1 +#define CONF_USB_COMPOSITE_HID_MOUSE_BIFCNUM (CONF_USB_COMPOSITE_CDC_ACM_DATA_BIFCNUM + 1) +#define CONF_HID_MOUSE_IFC_DESC \ + USB_IFACE_DESC_BYTES(CONF_USB_COMPOSITE_HID_MOUSE_BIFCNUM, 0x00, 0x01, 0x03, 0x01, 0x02, 0x00) \ + , USB_HID_DESC_BYTES(0x09, 0x21, 0x01, 0x22, 0x34), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_HID_MOUSE_INTIN_EPADDR, 0x03, CONF_USB_COMPOSITE_HID_MOUSE_INTIN_MAXPKSZ, 10), +#else +#define CONF_HID_MOUSE_IFC_LEN 0 +#define CONF_HID_MOUSE_IFC_NUM 0 +#define CONF_USB_COMPOSITE_HID_MOUSE_BIFCNUM CONF_USB_COMPOSITE_CDC_ACM_DATA_BIFCNUM +#define CONF_HID_MOUSE_IFC_DESC +#endif + +#if CONF_USB_COMPOSITE_HID_KEYBOARD_EN == 1 +#define CONF_HID_KEYBOARD_IFC_LEN 32 +#define CONF_HID_KEYBOARD_IFC_NUM 1 +#define CONF_USB_COMPOSITE_HID_KEYBOARD_BIFCNUM (CONF_USB_COMPOSITE_HID_MOUSE_BIFCNUM + 1) +#define CONF_HID_KEYBOARD_IFC_DESC \ + USB_IFACE_DESC_BYTES(CONF_USB_COMPOSITE_HID_KEYBOARD_BIFCNUM, 0x00, 0x02, 0x03, 0x01, 0x01, 0x00) \ + , USB_HID_DESC_BYTES(0x09, 0x21, 0x01, 0x22, 59), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_HID_KEYBOARD_INTIN_EPADDR, 0x03, CONF_USB_COMPOSITE_HID_KEYBOARD_INTIN_MAXPKSZ, 10), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_HID_KEYBOARD_INTOUT_EPADDR, 0x03, CONF_USB_COMPOSITE_HID_KEYBOARD_INTOUT_MAXPKSZ, 10), +#else +#define CONF_HID_KEYBOARD_IFC_LEN 0 +#define CONF_HID_KEYBOARD_IFC_NUM 0 +#define CONF_USB_COMPOSITE_HID_KEYBOARD_BIFCNUM CONF_USB_COMPOSITE_HID_MOUSE_BIFCNUM +#define CONF_HID_KEYBOARD_IFC_DESC +#endif + +#if CONF_USB_COMPOSITE_HID_GENERIC_EN == 1 +#define CONF_HID_GENERIC_IFC_LEN 32 +#define CONF_HID_GENERIC_IFC_NUM 1 +#define CONF_USB_COMPOSITE_HID_GENERIC_BIFCNUM (CONF_USB_COMPOSITE_HID_KEYBOARD_BIFCNUM + 1) +#define CONF_HID_GENERIC_IFC_DESC \ + USB_IFACE_DESC_BYTES(CONF_USB_COMPOSITE_HID_GENERIC_BIFCNUM, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00) \ + , USB_HID_DESC_BYTES(0x09, 0x21, 0x01, 0x22, CONF_USB_COMPOSITE_HID_GENERIC_REPORT_LEN), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_HID_GENERIC_INTIN_EPADDR, 0x03, CONF_USB_COMPOSITE_HID_GENERIC_INTIN_MAXPKSZ, 10), \ + USB_ENDP_DESC_BYTES( \ + CONF_USB_COMPOSITE_HID_GENERIC_INTOUT_EPADDR, 0x03, CONF_USB_COMPOSITE_HID_GENERIC_INTOUT_MAXPKSZ, 10), +#else +#define CONF_HID_GENERIC_IFC_LEN 0 +#define CONF_HID_GENERIC_IFC_NUM 0 +#define CONF_USB_COMPOSITE_HID_GENERIC_BIFCNUM CONF_USB_COMPOSITE_HID_KEYBOARD_BIFCNUM +#define CONF_HID_GENERIC_IFC_DESC +#endif + +#define CONF_USB_COMPOSITE_TOTAL_LEN \ + (USB_CONFIG_DESC_LEN + CONF_CDC_ACM_IFC_LEN + CONF_HID_MOUSE_IFC_LEN + CONF_HID_KEYBOARD_IFC_LEN \ + + CONF_HID_GENERIC_IFC_LEN) + +#define CONF_USB_COMPOSITE_IFC_NUM \ + (CONF_CDC_ACM_IFC_NUM + CONF_HID_MOUSE_IFC_NUM + CONF_HID_KEYBOARD_IFC_NUM + CONF_HID_GENERIC_IFC_NUM) + +#define COMPOSITE_DEV_DESC \ + USB_DEV_DESC_BYTES(CONF_USB_COMPOSITE_BCDUSB, \ + 0xEF, \ + 0x02, \ + 0x01, \ + CONF_USB_COMPOSITE_BMAXPKSZ0, \ + CONF_USB_COMPOSITE_IDVENDER, \ + CONF_USB_COMPOSITE_IDPRODUCT, \ + CONF_USB_COMPOSITE_BCDDEVICE, \ + CONF_USB_COMPOSITE_IMANUFACT, \ + CONF_USB_COMPOSITE_IPRODUCT, \ + CONF_USB_COMPOSITE_ISERIALNUM, \ + CONF_USB_COMPOSITE_BNUMCONFIG) + +#define COMPOSITE_CFG_DESC \ + USB_CONFIG_DESC_BYTES(CONF_USB_COMPOSITE_TOTAL_LEN, \ + CONF_USB_COMPOSITE_IFC_NUM, \ + CONF_USB_COMPOSITE_BCONFIGVAL, \ + CONF_USB_COMPOSITE_ICONFIG, \ + CONF_USB_COMPOSITE_BMATTRI, \ + CONF_USB_COMPOSITE_BMAXPOWER) + +#define COMPOSITE_IFACE_DESCES \ + CONF_CDC_ACM_IFC_DESC \ + CONF_HID_MOUSE_IFC_DESC \ + CONF_HID_KEYBOARD_IFC_DESC \ + CONF_HID_GENERIC_IFC_DESC + +/** USB Device descriptors and configuration descriptors */ +#define COMPOSITE_DESCES_LS_FS \ + COMPOSITE_DEV_DESC, COMPOSITE_CFG_DESC, COMPOSITE_IFACE_DESCES CONF_USB_COMPOSITE_LANGUAGE_ID_STR_DESC, \ + CONF_USB_COMPOSITE_MANUFACTOR_STR_DESC, CONF_USB_COMPOSITE_PRODUCT_STR_DESC + +#endif /* USBDF_COMPOSITE_DESC_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/composite/device/usbd_composite_config.h b/atmel-samd/asf4/samd21/usb/class/composite/device/usbd_composite_config.h new file mode 100644 index 000000000..1b29802b0 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/composite/device/usbd_composite_config.h @@ -0,0 +1,355 @@ +/* Auto-generated config file usbd_composite_config.h */ +#ifndef USBD_COMPOSITE_CONFIG_H +#define USBD_COMPOSITE_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// <h> Composite Device Descriptor + +// <o> bcdUSB +// <0x0200=> USB 2.0 version +// <0x0210=> USB 2.1 version +// <id> usb_composite_bcdusb +#ifndef CONF_USB_COMPOSITE_BCDUSB +#define CONF_USB_COMPOSITE_BCDUSB 0x200 +#endif + +// <o> bMaxPackeSize0 +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_bmaxpksz0 +#ifndef CONF_USB_COMPOSITE_BMAXPKSZ0 +#define CONF_USB_COMPOSITE_BMAXPKSZ0 0x40 +#endif + +// <o> idVender <0x0000-0xFFFF> +// <id> usb_composite_idvender +#ifndef CONF_USB_COMPOSITE_IDVENDER +#define CONF_USB_COMPOSITE_IDVENDER 0x3eb +#endif + +// <o> idProduct <0x0000-0xFFFF> +// <id> usb_composite_idproduct +#ifndef CONF_USB_COMPOSITE_IDPRODUCT +#define CONF_USB_COMPOSITE_IDPRODUCT 0x2421 +#endif + +// <o> bcdDevice <0x0000-0xFFFF> +// <id> usb_composite_bcddevice +#ifndef CONF_USB_COMPOSITE_BCDDEVICE +#define CONF_USB_COMPOSITE_BCDDEVICE 0x100 +#endif + +// <o> iManufacturer <0x00-0xFF> +// <id> usb_composite_imanufact +#ifndef CONF_USB_COMPOSITE_IMANUFACT +#define CONF_USB_COMPOSITE_IMANUFACT 0x0 +#endif + +#ifndef CONF_USB_COMPOSITE_LANGUAGE_ID_STR_DESC +#define CONF_USB_COMPOSITE_LANGUAGE_ID_STR_DESC 0x04, 0x03, 0x09, 0x04 +#endif + +#ifndef CONF_USB_COMPOSITE_MANUFACTOR_STR_DESC +#define CONF_USB_COMPOSITE_MANUFACTOR_STR_DESC \ + 0x14, 0x03, 0x41, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x4C, 0x00, 0x20, 0x00, 0x41, 0x00, 0x53, 0x00, 0x46, \ + 0x00 +#endif + +// <o> iProduct <0x00-0xFF> +// <id> usb_composite_iproduct +#ifndef CONF_USB_COMPOSITE_IPRODUCT +#define CONF_USB_COMPOSITE_IPRODUCT 0x0 +#endif + +#ifndef CONF_USB_COMPOSITE_PRODUCT_STR_DESC +#define CONF_USB_COMPOSITE_PRODUCT_STR_DESC \ + 0x22, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, \ + 0x00, 0x20, 0x00, 0x44, 0x00, 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00 +#endif + +// <o> iSerialNumber <0x00-0xFF> +// <id> usb_composite_iserialnum +#ifndef CONF_USB_COMPOSITE_ISERIALNUM +#define CONF_USB_COMPOSITE_ISERIALNUM 0x0 +#endif + +// <o> bNumConfigurations <0x01-0xFF> +// <id> usb_composite_bnumconfig +#ifndef CONF_USB_COMPOSITE_BNUMCONFIG +#define CONF_USB_COMPOSITE_BNUMCONFIG 0x1 +#endif +// </h> + +// <h> Composite Configuration Descriptor + +// <o> bConfigurationValue <0x01-0xFF> +// <id> usb_composite_bconfigval +#ifndef CONF_USB_COMPOSITE_BCONFIGVAL +#define CONF_USB_COMPOSITE_BCONFIGVAL 0x1 +#endif + +// <o> iConfiguration <0x00-0xFF> +// <id> usb_composite_iconfig +#ifndef CONF_USB_COMPOSITE_ICONFIG +#define CONF_USB_COMPOSITE_ICONFIG 0x0 +#endif + +// <o> bmAttributes +// <0x80=> Bus power supply, not support for remote wakeup +// <0xA0=> Bus power supply, support for remote wakeup +// <0xC0=> Self powered, not support for remote wakeup +// <0xE0=> Self powered, support for remote wakeup +// <id> usb_composite_bmattri +#ifndef CONF_USB_COMPOSITE_BMATTRI +#define CONF_USB_COMPOSITE_BMATTRI 0x80 +#endif + +// <o> bMaxPower <0x00-0xFF> +// <id> usb_composite_bmaxpower +#ifndef CONF_USB_COMPOSITE_BMAXPOWER +#define CONF_USB_COMPOSITE_BMAXPOWER 0x32 +#endif +// </h> + +// <e> CDC ACM Support +// <id> usb_composite_cdc_acm_support +#ifndef CONF_USB_COMPOSITE_CDC_ACM_EN +#define CONF_USB_COMPOSITE_CDC_ACM_EN 1 +#endif + +// <o> CDC ACM Comm Interrupt IN Endpoint Address +// <0x81=> EndpointAddress = 0x81 +// <0x82=> EndpointAddress = 0x82 +// <0x83=> EndpointAddress = 0x83 +// <0x84=> EndpointAddress = 0x84 +// <0x85=> EndpointAddress = 0x85 +// <0x86=> EndpointAddress = 0x86 +// <0x87=> EndpointAddress = 0x87 +// <id> usb_composite_cdc_acm_epaddr +#ifndef CONF_USB_COMPOSITE_CDC_ACM_COMM_INT_EPADDR +#define CONF_USB_COMPOSITE_CDC_ACM_COMM_INT_EPADDR 0x82 +#endif + +// <o> CDC ACM Comm Interrupt IN Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_cdc_acm_comm_int_maxpksz +#ifndef CONF_USB_COMPOSITE_CDC_ACM_COMM_INT_MAXPKSZ +#define CONF_USB_COMPOSITE_CDC_ACM_COMM_INT_MAXPKSZ 0x40 +#endif + +// <o> CDC ACM Data BULK IN Endpoint Address +// <0x81=> EndpointAddress = 0x81 +// <0x82=> EndpointAddress = 0x82 +// <0x83=> EndpointAddress = 0x83 +// <0x84=> EndpointAddress = 0x84 +// <0x85=> EndpointAddress = 0x85 +// <0x86=> EndpointAddress = 0x86 +// <0x87=> EndpointAddress = 0x87 +// <id> usb_composite_cdc_acm_data_bulkin_epaddr +#ifndef CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_EPADDR +#define CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_EPADDR 0x81 +#endif + +// <o> CDC ACM Data BULK IN Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_cdc_acm_data_builin_maxpksz +#ifndef CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_MAXPKSZ +#define CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_MAXPKSZ 0x40 +#endif + +// <o> CDC ACM Data BULK OUT Endpoint Address +// <0x01=> EndpointAddress = 0x01 +// <0x02=> EndpointAddress = 0x02 +// <0x03=> EndpointAddress = 0x03 +// <0x04=> EndpointAddress = 0x04 +// <0x05=> EndpointAddress = 0x05 +// <0x06=> EndpointAddress = 0x06 +// <0x07=> EndpointAddress = 0x07 +// <id> usb_composite_cdc_acm_data_bulkout_epaddr +#ifndef CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKOUT_EPADDR +#define CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKOUT_EPADDR 0x1 +#endif + +// <o> CDC ACM Data BULK OUT Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_cdc_acm_data_buckout_maxpksz +#ifndef CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKOUT_MAXPKSZ +#define CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKOUT_MAXPKSZ 0x40 +#endif +// </e> + +// <e> HID Mouse Support +// <id> usb_composite_hid_mouse_support +#ifndef CONF_USB_COMPOSITE_HID_MOUSE_EN +#define CONF_USB_COMPOSITE_HID_MOUSE_EN 0 +#endif + +// <o> HID Mouse INTERRUPT IN Endpoint Address +// <0x81=> EndpointAddress = 0x81 +// <0x82=> EndpointAddress = 0x82 +// <0x83=> EndpointAddress = 0x83 +// <0x84=> EndpointAddress = 0x84 +// <0x85=> EndpointAddress = 0x85 +// <0x86=> EndpointAddress = 0x86 +// <0x87=> EndpointAddress = 0x87 +// <id> usb_composite_hid_mouse_intin_epaddr +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_MOUSE_INTIN_EPADDR +#define CONF_USB_COMPOSITE_HID_MOUSE_INTIN_EPADDR 0x83 +#endif + +// <o> HID Mouse INTERRUPT IN Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_hid_mouse_intin_maxpksz +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_MOUSE_INTIN_MAXPKSZ +#define CONF_USB_COMPOSITE_HID_MOUSE_INTIN_MAXPKSZ 0x8 +#endif + +// </e> + +// <e> HID Keyboard Support +// <id> usb_composite_hid_keyboard_support +#ifndef CONF_USB_COMPOSITE_HID_KEYBOARD_EN +#define CONF_USB_COMPOSITE_HID_KEYBOARD_EN 0 +#endif + +// <o> HID Keyboard INTERRUPT IN Endpoint Address +// <0x81=> EndpointAddress = 0x81 +// <0x82=> EndpointAddress = 0x82 +// <0x83=> EndpointAddress = 0x83 +// <0x84=> EndpointAddress = 0x84 +// <0x85=> EndpointAddress = 0x85 +// <0x86=> EndpointAddress = 0x86 +// <0x87=> EndpointAddress = 0x87 +// <id> usb_composite_hid_keyboard_intin_epaddr +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_KEYBOARD_INTIN_EPADDR +#define CONF_USB_COMPOSITE_HID_KEYBOARD_INTIN_EPADDR 0x84 +#endif + +// <o> HID Keyboard INTERRUPT IN Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_hid_keyboard_intin_maxpksz +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_KEYBOARD_INTIN_MAXPKSZ +#define CONF_USB_COMPOSITE_HID_KEYBOARD_INTIN_MAXPKSZ 0x8 +#endif + +// <o> HID Keyboard INTERRUPT OUT Endpoint Address +// <0x01=> EndpointAddress = 0x01 +// <0x02=> EndpointAddress = 0x02 +// <0x03=> EndpointAddress = 0x03 +// <0x04=> EndpointAddress = 0x04 +// <0x05=> EndpointAddress = 0x05 +// <0x06=> EndpointAddress = 0x06 +// <0x07=> EndpointAddress = 0x07 +// <id> usb_composite_hid_keyboard_intout_epaddr +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_KEYBOARD_INTOUT_EPADDR +#define CONF_USB_COMPOSITE_HID_KEYBOARD_INTOUT_EPADDR 0x2 +#endif + +// <o> HID Keyboard INTERRUPT OUT Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_hid_keyboard_intout_maxpksz +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_KEYBOARD_INTOUT_MAXPKSZ +#define CONF_USB_COMPOSITE_HID_KEYBOARD_INTOUT_MAXPKSZ 0x8 +#endif + +// </e> + +// <e> HID Generic Support +// <id> usb_composite_hid_generic_support +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_EN +#define CONF_USB_COMPOSITE_HID_GENERIC_EN 0 +#endif + +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_REPORT_LEN +#define CONF_USB_COMPOSITE_HID_GENERIC_REPORT_LEN 53 +#endif + +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_REPORT +#define CONF_USB_COMPOSITE_HID_GENERIC_REPORT \ + 0x06, 0xFF, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x02, 0x09, 0x03, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, \ + 0x40, 0x81, 0x02, 0x09, 0x04, 0x09, 0x05, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91, 0x02, \ + 0x09, 0x06, 0x09, 0x07, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x04, 0xB1, 0x02, 0xC0 +#endif + +// <o> HID Generic INTERRUPT IN Endpoint Address +// <0x81=> EndpointAddress = 0x81 +// <0x82=> EndpointAddress = 0x82 +// <0x83=> EndpointAddress = 0x83 +// <0x84=> EndpointAddress = 0x84 +// <0x85=> EndpointAddress = 0x85 +// <0x86=> EndpointAddress = 0x86 +// <0x87=> EndpointAddress = 0x87 +// <id> usb_composite_hid_generic_intin_epaddr +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_INTIN_EPADDR +#define CONF_USB_COMPOSITE_HID_GENERIC_INTIN_EPADDR 0x85 +#endif + +// <o> HID Generic INTERRUPT IN Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_hid_generic_intin_maxpksz +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_INTIN_MAXPKSZ +#define CONF_USB_COMPOSITE_HID_GENERIC_INTIN_MAXPKSZ 0x40 +#endif + +// <o> HID Generic INTERRUPT OUT Endpoint Address +// <0x01=> EndpointAddress = 0x01 +// <0x02=> EndpointAddress = 0x02 +// <0x03=> EndpointAddress = 0x03 +// <0x04=> EndpointAddress = 0x04 +// <0x05=> EndpointAddress = 0x05 +// <0x06=> EndpointAddress = 0x06 +// <0x07=> EndpointAddress = 0x07 +// <id> usb_composite_hid_generic_intout_epaddr +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_INTOUT_EPADDR +#define CONF_USB_COMPOSITE_HID_GENERIC_INTOUT_EPADDR 0x3 +#endif + +// <o> HID Generic INTERRUPT OUT Endpoint wMaxPacketSize +// <0x0008=> 8 bytes +// <0x0010=> 16 bytes +// <0x0020=> 32 bytes +// <0x0040=> 64 bytes +// <id> usb_composite_hid_generic_intout_maxpksz +// <i> Please make sure that the setting here is coincide with the endpoint setting in USB device driver. +#ifndef CONF_USB_COMPOSITE_HID_GENERIC_INTOUT_MAXPKSZ +#define CONF_USB_COMPOSITE_HID_GENERIC_INTOUT_MAXPKSZ 0x40 +#endif + +// </e> + +// <<< end of configuration section >>> + +#endif // USBD_COMPOSITE_CONFIG_H diff --git a/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_generic.c b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_generic.c new file mode 100644 index 000000000..2c7cd3584 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_generic.c @@ -0,0 +1,358 @@ +/** + * \file + * + * \brief USB Device Stack HID Generic Function Implementation. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel micro controller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "hiddf_generic.h" +#include <string.h> + +#define HIDDF_GENERIC_VERSION 0x00000001u + +/** USB Device HID Generic Function Specific Data */ +struct hiddf_generic_func_data { + /** HID Device Generic Interface information */ + uint8_t func_iface; + /** HID Device Generic IN Endpoint */ + uint8_t func_ep_in; + /** HID Device Generic OUT Endpoint */ + uint8_t func_ep_out; + /** HID Device Generic Report Descriptor */ + const uint8_t *report_desc; + /** HID Device Generic Report Descriptor Length */ + uint32_t report_desc_len; + /** HID Device Generic Enable Flag */ + bool enabled; +}; + +/* USB Device HID Generic Function Instance */ +static struct usbdf_driver _hiddf_generic; + +/* USB Device HID Generic Function Data Instance */ +static struct hiddf_generic_func_data _hiddf_generic_funcd; + +/* USB Device HID Generic Set Report Function Callback */ +static hiddf_generic_set_report_t hiddf_generic_set_report = NULL; + +/** + * \brief Enable HID Generic Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB interface descriptor + * \return Operation status. + */ +static int32_t hid_generic_enable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + uint8_t * ifc, *ep, i; + usb_iface_desc_t ifc_desc; + usb_ep_desc_t ep_desc; + + struct hiddf_generic_func_data *func_data = (struct hiddf_generic_func_data *)(drv->func_data); + + ifc = desc->sod; + if (NULL == ifc) { + return ERR_NOT_FOUND; + } + + ifc_desc.bInterfaceNumber = ifc[2]; + ifc_desc.bInterfaceClass = ifc[5]; + + if (HID_CLASS == ifc_desc.bInterfaceClass) { + if (func_data->func_iface == ifc_desc.bInterfaceNumber) { // Initialized + return ERR_ALREADY_INITIALIZED; + } else if (func_data->func_iface != 0xFF) { // Occupied + return ERR_NO_RESOURCE; + } else { + func_data->func_iface = ifc_desc.bInterfaceNumber; + } + } else { // Not supported by this function driver + return ERR_NOT_FOUND; + } + + // Install endpoints + for (i = 0; i < 2; i++) { + ep = usb_find_ep_desc(usb_desc_next(desc->sod), desc->eod); + desc->sod = ep; + if (NULL != ep) { + ep_desc.bEndpointAddress = ep[2]; + ep_desc.bmAttributes = ep[3]; + ep_desc.wMaxPacketSize = usb_get_u16(ep + 4); + if (usb_d_ep_init(ep_desc.bEndpointAddress, ep_desc.bmAttributes, ep_desc.wMaxPacketSize)) { + return ERR_NOT_INITIALIZED; + } + if (ep_desc.bEndpointAddress & USB_EP_DIR_IN) { + func_data->func_ep_in = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_in); + } else { + func_data->func_ep_out = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_out); + } + } else { + return ERR_NOT_FOUND; + } + } + + // Installed + _hiddf_generic_funcd.enabled = true; + return ERR_NONE; +} + +/** + * \brief Disable HID Generic Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB device descriptor + * \return Operation status. + */ +static int32_t hid_generic_disable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + struct hiddf_generic_func_data *func_data = (struct hiddf_generic_func_data *)(drv->func_data); + + usb_iface_desc_t ifc_desc; + + if (desc) { + ifc_desc.bInterfaceClass = desc->sod[5]; + if (ifc_desc.bInterfaceClass != HID_CLASS) { + return ERR_NOT_FOUND; + } + } + + if (func_data->func_iface != 0xFF) { + func_data->func_iface = 0xFF; + } + + if (func_data->func_ep_in != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_in); + func_data->func_ep_in = 0xFF; + } + + if (func_data->func_ep_out != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_out); + func_data->func_ep_out = 0xFF; + } + + _hiddf_generic_funcd.enabled = false; + return ERR_NONE; +} + +/** + * \brief HID Generic Control Function + * \param[in] drv Pointer to USB device function driver + * \param[in] ctrl USB device general function control type + * \param[in] param Parameter pointer + * \return Operation status. + */ +static int32_t hid_generic_ctrl(struct usbdf_driver *drv, enum usbdf_control ctrl, void *param) +{ + switch (ctrl) { + case USBDF_ENABLE: + return hid_generic_enable(drv, (struct usbd_descriptors *)param); + + case USBDF_DISABLE: + return hid_generic_disable(drv, (struct usbd_descriptors *)param); + + case USBDF_GET_IFACE: + return ERR_UNSUPPORTED_OP; + + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the HID class get descriptor + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t hid_generic_get_desc(uint8_t ep, struct usb_req *req) +{ + switch (req->wValue >> 8) { + case USB_DT_HID_REPORT: + return usbdc_xfer(ep, (uint8_t *)_hiddf_generic_funcd.report_desc, _hiddf_generic_funcd.report_desc_len, false); + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the HID class request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t hid_generic_req(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + uint8_t *ctrl_buf = usbdc_get_ctrl_buffer(); + uint16_t len = req->wLength; + + if ((0x81 == req->bmRequestType) && (0x06 == req->bRequest) && (req->wIndex == _hiddf_generic_funcd.func_iface)) { + return hid_generic_get_desc(ep, req); + } else { + if (0x01 != ((req->bmRequestType >> 5) & 0x03)) { // class request + return ERR_NOT_FOUND; + } + if (req->wIndex == _hiddf_generic_funcd.func_iface) { + if (req->bmRequestType & USB_EP_DIR_IN) { + return ERR_INVALID_ARG; + } else { + if (USB_REQ_HID_SET_REPORT == req->bRequest) { + if (USB_SETUP_STAGE == stage) { + return usbdc_xfer(ep, ctrl_buf, len, false); + } else { + if (NULL != hiddf_generic_set_report) { + hiddf_generic_set_report(ctrl_buf, len); + } + return ERR_NONE; + } + } else { + return usbdc_xfer(0, NULL, 0, 0); + } + } + } else { + return ERR_NOT_FOUND; + } + } +} + +/** USB Device HID Generic Handler Struct */ +static struct usbdc_handler hid_generic_req_h = {NULL, (FUNC_PTR)hid_generic_req}; + +/** + * \brief Initialize the USB HID Generic Function Driver + */ +int32_t hiddf_generic_init(const uint8_t *report_desc, uint32_t len) +{ + if (NULL == report_desc || 0 == len) { + return ERR_INVALID_ARG; + } + + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _hiddf_generic_funcd.report_desc = report_desc; + _hiddf_generic_funcd.report_desc_len = len; + _hiddf_generic.ctrl = hid_generic_ctrl; + _hiddf_generic.func_data = &_hiddf_generic_funcd; + + usbdc_register_function(&_hiddf_generic); + usbdc_register_handler(USBDC_HDL_REQ, &hid_generic_req_h); + + return ERR_NONE; +} + +/** + * \brief Deinitialize the USB HID Generic Function Driver + */ +int32_t hiddf_generic_deinit(void) +{ + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _hiddf_generic.ctrl = NULL; + _hiddf_generic.func_data = NULL; + + usbdc_unregister_function(&_hiddf_generic); + usbdc_unregister_handler(USBDC_HDL_REQ, &hid_generic_req_h); + return ERR_NONE; +} + +/** + * \brief Check whether HID Generic Function is enabled + */ +bool hiddf_generic_is_enabled(void) +{ + return _hiddf_generic_funcd.enabled; +} + +/** + * \brief USB HID Generic Function Read Data + */ +int32_t hiddf_generic_read(uint8_t *buf, uint32_t size) +{ + if (!hiddf_generic_is_enabled()) { + return ERR_DENIED; + } + return usbdc_xfer(_hiddf_generic_funcd.func_ep_out, buf, size, false); +} + +/** + * \brief USB HID Generic Function Write Data + */ +int32_t hiddf_generic_write(uint8_t *buf, uint32_t size) +{ + if (!hiddf_generic_is_enabled()) { + return ERR_DENIED; + } + return usbdc_xfer(_hiddf_generic_funcd.func_ep_in, buf, size, false); +} + +/** + * \brief USB HID Generic Function Register Callback + */ +int32_t hiddf_generic_register_callback(enum hiddf_generic_cb_type cb_type, FUNC_PTR func) +{ + if (!hiddf_generic_is_enabled()) { + return ERR_DENIED; + } + switch (cb_type) { + case HIDDF_GENERIC_CB_READ: + usb_d_ep_register_callback(_hiddf_generic_funcd.func_ep_out, USB_D_EP_CB_XFER, func); + break; + case HIDDF_GENERIC_CB_WRITE: + usb_d_ep_register_callback(_hiddf_generic_funcd.func_ep_in, USB_D_EP_CB_XFER, func); + break; + case HIDDF_GENERIC_CB_SET_REPORT: + hiddf_generic_set_report = (hiddf_generic_set_report_t)func; + break; + default: + return ERR_INVALID_ARG; + } + + return ERR_NONE; +} + +/** + * \brief Return version + */ +uint32_t hiddf_generic_get_version(void) +{ + return HIDDF_GENERIC_VERSION; +} diff --git a/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_generic.h b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_generic.h new file mode 100644 index 000000000..c12f1575a --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_generic.h @@ -0,0 +1,102 @@ +/** + * \file + * + * \brief USB Device Stack HID Generic Function Definition. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef USBDF_HID_GENERIC_H_ +#define USBDF_HID_GENERIC_H_ + +#include "usbdc.h" +#include "usb_protocol_hid.h" + +/** HID Generic Callback Type */ +enum hiddf_generic_cb_type { HIDDF_GENERIC_CB_READ, HIDDF_GENERIC_CB_WRITE, HIDDF_GENERIC_CB_SET_REPORT }; + +/** HID Generic Set Report Callback. */ +typedef bool (*hiddf_generic_set_report_t)(uint8_t *, uint16_t); + +/** + * \brief Initialize the USB HID Generic Function Driver + * \param[in] report_desc Point to usr HID Report Descriptor + * \param[in] len length of usr HID Report Descriptor + * \return Operation status. + */ +int32_t hiddf_generic_init(const uint8_t *report_desc, uint32_t len); + +/** + * \brief Deinitialize the USB HID Generic Function Driver + * \return Operation status. + */ +int32_t hiddf_generic_deinit(void); + +/** + * \brief Check whether HID Generic Function is enabled + * \return Operation status. + * \return true HID Generic Function is enabled + * \return false HID Generic Function is disabled + */ +bool hiddf_generic_is_enabled(void); + +/** + * \brief USB HID Generic Function Read Data + * \param[in] buf Pointer to the buffer which receives data + * \param[in] size the size of data to be received + * \return Operation status. + */ +int32_t hiddf_generic_read(uint8_t *buf, uint32_t size); + +/** + * \brief USB HID Generic Function Write Data + * \param[in] buf Pointer to the buffer which stores data + * \param[in] size the size of data to be sent + * \return Operation status. + */ +int32_t hiddf_generic_write(uint8_t *buf, uint32_t size); + +/** + * \brief USB HID Generic Function Register Callback + * \param[in] cb_type Callback type of HID Generic Function + * \param[in] func Pointer to callback function + * \return Operation status. + */ +int32_t hiddf_generic_register_callback(enum hiddf_generic_cb_type cb_type, FUNC_PTR func); + +/** + * \brief Return version + */ +uint32_t hiddf_generic_get_version(void); + +#endif /* USBDF_HID_GENERIC_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_keyboard.c b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_keyboard.c new file mode 100644 index 000000000..835481e41 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_keyboard.c @@ -0,0 +1,365 @@ +/** + * \file + * + * \brief USB Device Stack HID Keyboard Function Implementation. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel micro controller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "hiddf_keyboard.h" +#include <string.h> + +#define HIDDF_KEYBOARD_VERSION 0x00000001u + +#define KEYBOARD_REPORT_DESC_LEN 59 + +/** USB Device HID Keyboard Function Specific Data */ +struct hiddf_keyboard_func_data { + /* HID Device Keyboard Report */ + uint8_t kb_report[8]; + /** HID Device Keyboard Interface information */ + uint8_t func_iface; + /** HID Device Keyboard IN Endpoint */ + uint8_t func_ep_in; + /** HID Device Keyboard OUT Endpoint */ + uint8_t func_ep_out; + /** HID Device Keyboard Enable Flag */ + bool enabled; +}; + +/* HID report descriptor for standard HID keyboard */ +const uint8_t keyboard_report_desc[KEYBOARD_REPORT_DESC_LEN] = { + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x05, 0x07, /* Usage Page (Keyboard) */ + 0x19, 0xE0, /* Usage Minimum (224) */ + 0x29, 0xE7, /* Usage Maximum (231) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x81, 0x01, /* Input (Constant) */ + 0x19, 0x00, /* Usage Minimum (0) */ + 0x29, 0x65, /* Usage Maximum (101) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x65, /* Logical Maximum (101) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x06, /* Report Count (6) */ + 0x81, 0x00, /* Input (Data, Array) */ + 0x05, 0x08, /* Usage Page (LED) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x05, /* Usage Maximum (5) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x05, /* Report Count (5) */ + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ + 0x95, 0x03, /* Report Count (3) */ + 0x91, 0x01, /* Output (Constant) */ + 0xC0 /* End Collection */ +}; + +/* USB Device HID Keyboard Function Instance */ +static struct usbdf_driver _hiddf_keyboard; + +/* USB Device HID Keyboard Function Data Instance */ +static struct hiddf_keyboard_func_data _hiddf_keyboard_funcd; + +/** + * \brief Enable HID Keyboard Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB interface descriptor + * \return Operation status. + */ +static int32_t hid_keyboard_enable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + uint8_t * ifc, *ep, i; + usb_iface_desc_t ifc_desc; + usb_ep_desc_t ep_desc; + + struct hiddf_keyboard_func_data *func_data = (struct hiddf_keyboard_func_data *)(drv->func_data); + + ifc = desc->sod; + if (NULL == ifc) { + return ERR_NOT_FOUND; + } + + ifc_desc.bInterfaceNumber = ifc[2]; + ifc_desc.bInterfaceClass = ifc[5]; + + if (HID_CLASS == ifc_desc.bInterfaceClass) { + if (func_data->func_iface == ifc_desc.bInterfaceNumber) { // Initialized + return ERR_ALREADY_INITIALIZED; + } else if (func_data->func_iface != 0xFF) { // Occupied + return ERR_NO_RESOURCE; + } else { + func_data->func_iface = ifc_desc.bInterfaceNumber; + } + } else { // Not supported by this function driver + return ERR_NOT_FOUND; + } + + // Install endpoints + for (i = 0; i < 2; i++) { + ep = usb_find_ep_desc(usb_desc_next(desc->sod), desc->eod); + desc->sod = ep; + if (NULL != ep) { + ep_desc.bEndpointAddress = ep[2]; + ep_desc.bmAttributes = ep[3]; + ep_desc.wMaxPacketSize = usb_get_u16(ep + 4); + if (usb_d_ep_init(ep_desc.bEndpointAddress, ep_desc.bmAttributes, ep_desc.wMaxPacketSize)) { + return ERR_NOT_INITIALIZED; + } + if (ep_desc.bEndpointAddress & USB_EP_DIR_IN) { + func_data->func_ep_in = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_in); + } else { + func_data->func_ep_out = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_out); + } + } else { + return ERR_NOT_FOUND; + } + } + + // Installed + _hiddf_keyboard_funcd.enabled = true; + return ERR_NONE; +} + +/** + * \brief Disable HID Keyboard Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB device descriptor + * \return Operation status. + */ +static int32_t hid_keyboard_disable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + struct hiddf_keyboard_func_data *func_data = (struct hiddf_keyboard_func_data *)(drv->func_data); + + usb_iface_desc_t ifc_desc; + + if (desc) { + ifc_desc.bInterfaceClass = desc->sod[5]; + if (ifc_desc.bInterfaceClass != HID_CLASS) { + return ERR_NOT_FOUND; + } + } + + if (func_data->func_iface != 0xFF) { + func_data->func_iface = 0xFF; + } + + if (func_data->func_ep_in != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_in); + func_data->func_ep_in = 0xFF; + } + + if (func_data->func_ep_out != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_out); + func_data->func_ep_out = 0xFF; + } + + _hiddf_keyboard_funcd.enabled = false; + return ERR_NONE; +} + +/** + * \brief HID Keyboard Control Function + * \param[in] drv Pointer to USB device function driver + * \param[in] ctrl USB device general function control type + * \param[in] param Parameter pointer + * \return Operation status. + */ +static int32_t hid_keyboard_ctrl(struct usbdf_driver *drv, enum usbdf_control ctrl, void *param) +{ + switch (ctrl) { + case USBDF_ENABLE: + return hid_keyboard_enable(drv, (struct usbd_descriptors *)param); + + case USBDF_DISABLE: + return hid_keyboard_disable(drv, (struct usbd_descriptors *)param); + + case USBDF_GET_IFACE: + return ERR_UNSUPPORTED_OP; + + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the HID class get descriptor + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t hid_keyboard_get_desc(uint8_t ep, struct usb_req *req) +{ + switch (req->wValue >> 8) { + case USB_DT_HID_REPORT: + return usbdc_xfer(ep, (uint8_t *)keyboard_report_desc, KEYBOARD_REPORT_DESC_LEN, false); + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the HID class request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t hid_keyboard_req(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + if ((0x81 == req->bmRequestType) && (0x06 == req->bRequest) && (req->wIndex == _hiddf_keyboard_funcd.func_iface)) { + return hid_keyboard_get_desc(ep, req); + } else { + if (0x01 != ((req->bmRequestType >> 5) & 0x03)) { // class request + return ERR_NOT_FOUND; + } + if (req->wIndex == _hiddf_keyboard_funcd.func_iface) { + if (req->bmRequestType & USB_EP_DIR_IN) { + return ERR_INVALID_ARG; + } else { + return usbdc_xfer(0, NULL, 0, 0); + } + } else { + return ERR_NOT_FOUND; + } + } + (void)stage; +} + +/** USB Device HID Keyboard Handler Struct */ +static struct usbdc_handler hid_keyboard_req_h = {NULL, (FUNC_PTR)hid_keyboard_req}; + +/** + * \brief Initialize the USB HID Keyboard Function Driver + */ +int32_t hiddf_keyboard_init(void) +{ + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _hiddf_keyboard.ctrl = hid_keyboard_ctrl; + _hiddf_keyboard.func_data = &_hiddf_keyboard_funcd; + + usbdc_register_function(&_hiddf_keyboard); + usbdc_register_handler(USBDC_HDL_REQ, &hid_keyboard_req_h); + return ERR_NONE; +} + +/** + * \brief Deinitialize the USB HID Keyboard Function Driver + */ +int32_t hiddf_keyboard_deinit(void) +{ + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _hiddf_keyboard.ctrl = NULL; + _hiddf_keyboard.func_data = NULL; + + usbdc_unregister_function(&_hiddf_keyboard); + usbdc_unregister_handler(USBDC_HDL_REQ, &hid_keyboard_req_h); + return ERR_NONE; +} + +/** + * \brief Check whether HID Keyboard Function is enabled + */ +bool hiddf_keyboard_is_enabled(void) +{ + return _hiddf_keyboard_funcd.enabled; +} + +/** + * \brief Process the HID Keyboard key state change request + * \param keys_desc[] keys_descriptor array for state changing + * \param keys_count total keys amount for state changing + * \return Operation status. + */ +int32_t hiddf_keyboard_keys_state_change(struct hiddf_kb_key_descriptors keys_desc[], uint8_t keys_count) +{ + uint8_t i, j; + uint8_t modifier_keys, regular_keys; + + if (!hiddf_keyboard_is_enabled()) { + return ERR_DENIED; + } + + memset(_hiddf_keyboard_funcd.kb_report, 0x00, 8); + modifier_keys = 0; + + for (i = 0; i < keys_count; i++) { + if (true == keys_desc[i].b_modifier) { + modifier_keys++; + } + } + + regular_keys = keys_count - modifier_keys; + + if (regular_keys > 6) { + memset(&_hiddf_keyboard_funcd.kb_report[2], 0xFF, 6); + } else { + i = 2; + for (j = 0; j < keys_count; j++) { + if (HID_KB_KEY_DOWN == keys_desc[j].state) { + if (true == keys_desc[j].b_modifier) { + _hiddf_keyboard_funcd.kb_report[0] |= keys_desc[j].key_id; + } else { + _hiddf_keyboard_funcd.kb_report[i++] = keys_desc[j].key_id; + } + } + } + } + return usbdc_xfer(_hiddf_keyboard_funcd.func_ep_in, &_hiddf_keyboard_funcd.kb_report[0], 8, false); +} + +/** + * \brief Return version + */ +uint32_t hiddf_keyboard_get_version(void) +{ + return HIDDF_KEYBOARD_VERSION; +} diff --git a/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_keyboard.h b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_keyboard.h new file mode 100644 index 000000000..3295d1b78 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_keyboard.h @@ -0,0 +1,91 @@ +/** + * \file + * + * \brief USB Device Stack HID Keyboard Function Definition. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef USBDF_HID_KEYBOARD_H_ +#define USBDF_HID_KEYBOARD_H_ + +#include "usbdc.h" +#include "usb_protocol_hid.h" + +/** HID Keyboard Class Key State Type */ +enum hiddf_kb_key_state { HID_KB_KEY_UP, HID_KB_KEY_DOWN }; + +/** Describes the USB HID Keyboard Key descriptors. */ +struct hiddf_kb_key_descriptors { + /* HID Key Value, defined in usb_protocol_hid.h */ + uint8_t key_id; + /* Flag whether it is a modifier key */ + bool b_modifier; + /* Key State */ + enum hiddf_kb_key_state state; +}; + +/** + * \brief Initialize the USB HID Keyboard Function Driver + * \return Operation status. + */ +int32_t hiddf_keyboard_init(void); + +/** + * \brief Deinitialize the USB HID Keyboard Function Driver + * \return Operation status. + */ +int32_t hiddf_keyboard_deinit(void); + +/** + * \brief Check whether HID Keyboard Function is enabled + * \return Operation status. + * \return true HID Keyboard Function is enabled + * \return false HID Keyboard Function is disabled + */ +bool hiddf_keyboard_is_enabled(void); + +/** + * \brief Process the HID Keyboard key state change request + * \param keys_desc[] keys_descriptor array for state changing + * \param keys_count total keys amount for state changing + * \return Operation status. + */ +int32_t hiddf_keyboard_keys_state_change(struct hiddf_kb_key_descriptors keys_desc[], uint8_t keys_count); + +/** + * \brief Return version + */ +uint32_t hiddf_keyboard_get_version(void); + +#endif /* USBDF_HID_KEYBOARD_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_mouse.c b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_mouse.c new file mode 100644 index 000000000..7a58ce66e --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_mouse.c @@ -0,0 +1,363 @@ +/** + * \file + * + * \brief USB Device Stack HID Mouse Function Implementation. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel micro controller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "hiddf_mouse.h" + +#define HIDDF_MOUSE_VERSION 0x00000001u + +#define MOUSE_REPORT_DESC_LEN 52 + +/** USB Device HID Mouse Function Specific Data */ +struct hiddf_mouse_func_data { + /* HID Device Mouse Report */ + union { + /** Interpreted by bytes. */ + struct { + /** Button Status. */ + uint8_t button_state; + /** X Axis Variant.*/ + uint8_t x_axis_var; + /** Y Axis Variant.*/ + uint8_t y_axis_var; + /** Scroll Variant.*/ + uint8_t scroll_var; + } bytes; + uint32_t u32; + } mouse_report; + /** HID Device Mouse Interface information */ + uint8_t func_iface; + /** HID Device Mouse IN Endpoint */ + uint8_t func_ep_in; + /** HID Device Mouse Enable Flag */ + bool enabled; +}; + +/* HID report descriptor for standard HID mouse */ +const uint8_t mouse_report_desc[MOUSE_REPORT_DESC_LEN] = { + 0x05, 0x01, /* Usage Page (Generic Desktop), */ + 0x09, 0x02, /* Usage (Mouse), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x05, 0x09, /* Usage Page (Buttons), */ + 0x19, 0x01, /* Usage Minimum (01), */ + 0x29, 0x03, /* Usage Maximum (03), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x75, 0x05, /* Report Size (5), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x01, /* Usage Page (Generic Desktop), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x09, 0x38, /* Usage (Scroll), */ + 0x15, 0x81, /* Logical Minimum (-127), */ + 0x25, 0x7F, /* Logical Maximum (127), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xC0, /* End Collection, */ + 0xC0, /* End Collection */ +}; + +/* USB Device HID Mouse Function Instance */ +static struct usbdf_driver _hiddf_mouse; + +/* USB Device HID Mouse Function Data Instance */ +static struct hiddf_mouse_func_data _hiddf_mouse_funcd; + +/** + * \brief Enable HID Mouse Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB interface descriptor + * \return Operation status. + */ +static int32_t hid_mouse_enable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + uint8_t * ifc, *ep; + usb_iface_desc_t ifc_desc; + usb_ep_desc_t ep_desc; + + struct hiddf_mouse_func_data *func_data = (struct hiddf_mouse_func_data *)(drv->func_data); + + ifc = desc->sod; + if (NULL == ifc) { + return ERR_NOT_FOUND; + } + + ifc_desc.bInterfaceNumber = ifc[2]; + ifc_desc.bInterfaceClass = ifc[5]; + + if (HID_CLASS == ifc_desc.bInterfaceClass) { + if (func_data->func_iface == ifc_desc.bInterfaceNumber) { // Initialized + return ERR_ALREADY_INITIALIZED; + } else if (func_data->func_iface != 0xFF) { // Occupied + return ERR_NO_RESOURCE; + } else { + func_data->func_iface = ifc_desc.bInterfaceNumber; + } + } else { // Not supported by this function driver + return ERR_NOT_FOUND; + } + + // Install endpoints + ep = usb_find_ep_desc(usb_desc_next(desc->sod), desc->eod); + desc->sod = ep; + if (NULL != ep) { + ep_desc.bEndpointAddress = ep[2]; + ep_desc.bmAttributes = ep[3]; + ep_desc.wMaxPacketSize = usb_get_u16(ep + 4); + if (usb_d_ep_init(ep_desc.bEndpointAddress, ep_desc.bmAttributes, ep_desc.wMaxPacketSize)) { + return ERR_NOT_INITIALIZED; + } + if (ep_desc.bEndpointAddress & USB_EP_DIR_IN) { + func_data->func_ep_in = ep_desc.bEndpointAddress; + usb_d_ep_enable(func_data->func_ep_in); + } else { + return ERR_INVALID_DATA; + } + } else { + return ERR_NOT_FOUND; + } + // Installed + _hiddf_mouse_funcd.enabled = true; + return ERR_NONE; +} + +/** + * \brief Disable HID Mouse Function + * \param[in] drv Pointer to USB device function driver + * \param[in] desc Pointer to USB device descriptor + * \return Operation status. + */ +static int32_t hid_mouse_disable(struct usbdf_driver *drv, struct usbd_descriptors *desc) +{ + struct hiddf_mouse_func_data *func_data = (struct hiddf_mouse_func_data *)(drv->func_data); + + usb_iface_desc_t ifc_desc; + + if (desc) { + ifc_desc.bInterfaceClass = desc->sod[5]; + if (ifc_desc.bInterfaceClass != HID_CLASS) { + return ERR_NOT_FOUND; + } + } + + if (func_data->func_iface != 0xFF) { + func_data->func_iface = 0xFF; + } + + if (func_data->func_ep_in != 0xFF) { + usb_d_ep_deinit(func_data->func_ep_in); + func_data->func_ep_in = 0xFF; + } + + _hiddf_mouse_funcd.enabled = false; + return ERR_NONE; +} + +/** + * \brief HID Mouse Control Function + * \param[in] drv Pointer to USB device function driver + * \param[in] ctrl USB device general function control type + * \param[in] param Parameter pointer + * \return Operation status. + */ +static int32_t hid_mouse_ctrl(struct usbdf_driver *drv, enum usbdf_control ctrl, void *param) +{ + switch (ctrl) { + case USBDF_ENABLE: + return hid_mouse_enable(drv, (struct usbd_descriptors *)param); + + case USBDF_DISABLE: + return hid_mouse_disable(drv, (struct usbd_descriptors *)param); + + case USBDF_GET_IFACE: + return ERR_UNSUPPORTED_OP; + + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the HID class get descriptor + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t hid_mouse_get_desc(uint8_t ep, struct usb_req *req) +{ + switch (req->wValue >> 8) { + case USB_DT_HID_REPORT: + return usbdc_xfer(ep, (uint8_t *)mouse_report_desc, MOUSE_REPORT_DESC_LEN, false); + default: + return ERR_INVALID_ARG; + } +} + +/** + * \brief Process the HID class request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + */ +static int32_t hid_mouse_req(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + if ((0x81 == req->bmRequestType) && (0x06 == req->bRequest) && (req->wIndex == _hiddf_mouse_funcd.func_iface)) { + return hid_mouse_get_desc(ep, req); + } else { + if (0x01 != ((req->bmRequestType >> 5) & 0x03)) { // class request + return ERR_NOT_FOUND; + } + if (req->wIndex == _hiddf_mouse_funcd.func_iface) { + if (req->bmRequestType & USB_EP_DIR_IN) { + return ERR_INVALID_ARG; + } else { + return usbdc_xfer(0, NULL, 0, 0); + } + } else { + return ERR_NOT_FOUND; + } + } + (void)stage; +} + +/** USB Device HID Mouse Handler Struct */ +static struct usbdc_handler hid_mouse_req_h = {NULL, (FUNC_PTR)hid_mouse_req}; + +/** + * \brief Initialize the USB HID Mouse Function Driver + */ +int32_t hiddf_mouse_init(void) +{ + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _hiddf_mouse.ctrl = hid_mouse_ctrl; + _hiddf_mouse.func_data = &_hiddf_mouse_funcd; + + usbdc_register_function(&_hiddf_mouse); + usbdc_register_handler(USBDC_HDL_REQ, &hid_mouse_req_h); + return ERR_NONE; +} + +/** + * \brief Deinitialize the USB HID Mouse Function Driver + */ +int32_t hiddf_mouse_deinit(void) +{ + if (usbdc_get_state() > USBD_S_POWER) { + return ERR_DENIED; + } + + _hiddf_mouse.ctrl = NULL; + _hiddf_mouse.func_data = NULL; + + usbdc_unregister_function(&_hiddf_mouse); + usbdc_unregister_handler(USBDC_HDL_REQ, &hid_mouse_req_h); + return ERR_NONE; +} + +/** + * \brief Check whether HID Mouse Function is enabled + */ +bool hiddf_mouse_is_enabled(void) +{ + return _hiddf_mouse_funcd.enabled; +} + +/** + * \brief Move the mouse pointer + * \param pos Signed value to move + * \param type HID mouse class pointer move type + * \return Operation status. + */ +int32_t hiddf_mouse_move(int8_t pos, enum hiddf_mouse_move_type type) +{ + + _hiddf_mouse_funcd.mouse_report.u32 = 0; + + if (type == HID_MOUSE_X_AXIS_MV) { + _hiddf_mouse_funcd.mouse_report.bytes.x_axis_var = pos; + } else if (type == HID_MOUSE_Y_AXIS_MV) { + _hiddf_mouse_funcd.mouse_report.bytes.y_axis_var = pos; + } else if (type == HID_MOUSE_SCROLL_MV) { + _hiddf_mouse_funcd.mouse_report.bytes.scroll_var = pos; + } else { + return ERR_INVALID_ARG; + } + + return usbdc_xfer(_hiddf_mouse_funcd.func_ep_in, &_hiddf_mouse_funcd.mouse_report.bytes.button_state, 4, false); +} + +/** + * \brief Changes button state + * \param b_state New button state + * \param type Button type + * \return Operation status. + */ +int32_t hiddf_mouse_button_change(enum hiddf_mouse_button_state b_state, enum hiddf_mouse_button_type type) +{ + _hiddf_mouse_funcd.mouse_report.u32 = 0; + + if (b_state == HID_MOUSE_BTN_DOWN) { + _hiddf_mouse_funcd.mouse_report.bytes.button_state = type; + } else { + _hiddf_mouse_funcd.mouse_report.bytes.button_state = 0x00; + } + + return usbdc_xfer(_hiddf_mouse_funcd.func_ep_in, &_hiddf_mouse_funcd.mouse_report.bytes.button_state, 4, false); +} + +/** + * \brief Return version + */ +uint32_t hiddf_mouse_get_version(void) +{ + return HIDDF_MOUSE_VERSION; +} diff --git a/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_mouse.h b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_mouse.h new file mode 100644 index 000000000..464b1e92d --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/device/hiddf_mouse.h @@ -0,0 +1,95 @@ +/** + * \file + * + * \brief USB Device Stack HID Mouse Function Definition. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef USBDF_HID_MOUSE_H_ +#define USBDF_HID_MOUSE_H_ + +#include "usbdc.h" +#include "usb_protocol_hid.h" + +/** HID Mouse Class Button State Type */ +enum hiddf_mouse_button_state { HID_MOUSE_BTN_UP, HID_MOUSE_BTN_DOWN }; + +/* HID Mosue Class Button Type */ +enum hiddf_mouse_button_type { HID_MOUSE_LEFT_BTN = 0x01, HID_MOUSE_RIGHT_BTN = 0x02, HID_MOUSE_MIDDLE_BTN = 0x04 }; + +/* HID Mouse Class Pointer Move Type */ +enum hiddf_mouse_move_type { HID_MOUSE_X_AXIS_MV = 0x01, HID_MOUSE_Y_AXIS_MV = 0x02, HID_MOUSE_SCROLL_MV = 0x03 }; + +/** + * \brief Initialize the USB HID Mouse Function Driver + * \return Operation status. + */ +int32_t hiddf_mouse_init(void); + +/** + * \brief Deinitialize the USB HID Mouse Function Driver + * \return Operation status. + */ +int32_t hiddf_mouse_deinit(void); + +/** + * \brief Check whether HID Mouse Function is enabled + * \return Operation status. + * \return true HID Mouse Function is enabled + * \return false HID Mouse Function is disabled + */ +bool hiddf_mouse_is_enabled(void); + +/** + * \brief Move the mouse pointer + * \param pos Signed value to move + * \param type HID mouse class pointer move type + * \return Operation status. + */ +int32_t hiddf_mouse_move(int8_t pos, enum hiddf_mouse_move_type type); + +/** + * \brief Changes button state + * \param b_state New button state + * \param type Button type + * \return Operation status. + */ +int32_t hiddf_mouse_button_change(enum hiddf_mouse_button_state b_state, enum hiddf_mouse_button_type type); + +/** + * \brief Return version + */ +uint32_t hiddf_mouse_get_version(void); + +#endif /* USBDF_CDC_ACM_SER_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/hid/usb_protocol_hid.h b/atmel-samd/asf4/samd21/usb/class/hid/usb_protocol_hid.h new file mode 100644 index 000000000..71d74e632 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hid/usb_protocol_hid.h @@ -0,0 +1,597 @@ +/** + * \file + * + * \brief USB Human Interface Device (HID) protocol definitions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef _USB_PROTOCOL_HID_H_ +#define _USB_PROTOCOL_HID_H_ + +#include "usb_includes.h" + +/** + * \ingroup usb_protocol_group + * \defgroup usb_hid_protocol USB Human Interface Device (HID) + * protocol definitions + * \brief USB Human Interface Device (HID) protocol definitions + * + * @{ + */ + +//! \name Possible Class value +//@{ +#define HID_CLASS 0x03 +//@} + +//! \name Possible SubClass value +//@{ +//! Interface subclass NO support BOOT protocol +#define HID_SUB_CLASS_NOBOOT 0x00 +//! Interface subclass support BOOT protocol +#define HID_SUB_CLASS_BOOT 0x01 +//@} + +//! \name Possible protocol value +//@{ +//! Protocol generic standard +#define HID_PROTOCOL_GENERIC 0x00 +//! Protocol keyboard standard +#define HID_PROTOCOL_KEYBOARD 0x01 +//! Protocol mouse standard +#define HID_PROTOCOL_MOUSE 0x02 +//@} + +//! \brief Hid USB requests (bRequest) + +#define USB_REQ_HID_GET_REPORT 0x01 +#define USB_REQ_HID_GET_IDLE 0x02 +#define USB_REQ_HID_GET_PROTOCOL 0x03 +#define USB_REQ_HID_SET_REPORT 0x09 +#define USB_REQ_HID_SET_IDLE 0x0A +#define USB_REQ_HID_SET_PROTOCOL 0x0B + +//! \brief HID USB descriptor types +#define USB_DT_HID 0x21 +#define USB_DT_HID_REPORT 0x22 +#define USB_DT_HID_PHYSICAL 0x23 + +//! \brief HID Type for report descriptor +#define USB_HID_ITEM_REPORT_TYPE_MAIN 0 +#define USB_HID_ITEM_REPORT_TYPE_GLOBAL 1 +#define USB_HID_ITEM_REPORT_TYPE_LOCAL 2 +#define USB_HID_ITEM_REPORT_TYPE_LONG 3 + +//! \brief HID report type +#define USB_HID_REPORT_TYPE_INPUT 1 +#define USB_HID_REPORT_TYPE_OUTPUT 2 +#define USB_HID_REPORT_TYPE_FEATURE 3 + +//! \brief HID protocol +#define USB_HID_PROCOTOL_BOOT 0 +#define USB_HID_PROCOTOL_REPORT 1 + +#define USB_HID_DESC_BYTES(bLength, bCountryCode, bNumDescriptors, bDescriptorType, bDescriptorLength) \ + bLength, 0x21, 0x10, 0x01, bCountryCode, bNumDescriptors, bDescriptorType, LE_BYTE0(bDescriptorLength), \ + LE_BYTE1(bDescriptorLength) + +COMPILER_PACK_SET(1) + +//! \brief HID Descriptor +typedef struct usb_hid_descriptor { + uint8_t bLength; //!< Size of this descriptor in bytes + uint8_t bDescriptorType; //!< HID descriptor type + le16_t bcdHID; //!< Binary Coded Decimal Spec. release + uint8_t bCountryCode; //!< Hardware target country + uint8_t bNumDescriptors; //!< Number of HID class descriptors to follow + uint8_t bRDescriptorType; //!< Report descriptor type + le16_t wDescriptorLength; //!< Total length of Report descriptor +} usb_hid_descriptor_t; + +COMPILER_PACK_RESET() + +//! \name HID Report type +//! Used by SETUP_HID_GET_REPORT & SETUP_HID_SET_REPORT +//! @{ +#define REPORT_TYPE_INPUT 0x01 +#define REPORT_TYPE_OUTPUT 0x02 +#define REPORT_TYPE_FEATURE 0x03 +//! @} + +//! \name Constants of field DESCRIPTOR_HID +//! @{ +//! Numeric expression identifying the HID Class +//! Specification release (here V1.11) +#define USB_HID_BDC_V1_11 0x0111 +//! Numeric expression specifying the number of class descriptors +//! Note: Always at least one i.e. Report descriptor. +#define USB_HID_NUM_DESC 0x01 + +//! \name Country code +//! @{ +#define USB_HID_NO_COUNTRY_CODE 0 // Not Supported +#define USB_HID_COUNTRY_ARABIC 1 // Arabic +#define USB_HID_COUNTRY_BELGIAN 2 // Belgian +#define USB_HID_COUNTRY_CANADIAN_BILINGUAL 3 // Canadian-Bilingual +#define USB_HID_COUNTRY_CANADIAN_FRENCH 4 // Canadian-French +#define USB_HID_COUNTRY_CZECH_REPUBLIC 5 // Czech Republic +#define USB_HID_COUNTRY_DANISH 6 // Danish +#define USB_HID_COUNTRY_FINNISH 7 // Finnish +#define USB_HID_COUNTRY_FRENCH 8 // French +#define USB_HID_COUNTRY_GERMAN 9 // German +#define USB_HID_COUNTRY_GREEK 10 // Greek +#define USB_HID_COUNTRY_HEBREW 11 // Hebrew +#define USB_HID_COUNTRY_HUNGARY 12 // Hungary +#define USB_HID_COUNTRY_INTERNATIONAL_ISO 13 // International (ISO) +#define USB_HID_COUNTRY_ITALIAN 14 // Italian +#define USB_HID_COUNTRY_JAPAN_KATAKANA 15 // Japan (Katakana) +#define USB_HID_COUNTRY_KOREAN 16 // Korean +#define USB_HID_COUNTRY_LATIN_AMERICAN 17 // Latin American +#define USB_HID_COUNTRY_NETHERLANDS_DUTCH 18 // Netherlands/Dutch +#define USB_HID_COUNTRY_NORWEGIAN 19 // Norwegian +#define USB_HID_COUNTRY_PERSIAN_FARSI 20 // Persian (Farsi) +#define USB_HID_COUNTRY_POLAND 21 // Poland +#define USB_HID_COUNTRY_PORTUGUESE 22 // Portuguese +#define USB_HID_COUNTRY_RUSSIA 23 // Russia +#define USB_HID_COUNTRY_SLOVAKIA 24 // Slovakia +#define USB_HID_COUNTRY_SPANISH 25 // Spanish +#define USB_HID_COUNTRY_SWEDISH 26 // Swedish +#define USB_HID_COUNTRY_SWISS_FRENCH 27 // Swiss/French +#define USB_HID_COUNTRY_SWISS_GERMAN 28 // Swiss/German +#define USB_HID_COUNTRY_SWITZERLAND 29 // Switzerland +#define USB_HID_COUNTRY_TAIWAN 30 // Taiwan +#define USB_HID_COUNTRY_TURKISH_Q 31 // Turkish-Q +#define USB_HID_COUNTRY_UK 32 // UK +#define USB_HID_COUNTRY_US 33 // US +#define USB_HID_COUNTRY_YUGOSLAVIA 34 // Yugoslavia +#define USB_HID_COUNTRY_TURKISH_F 35 // Turkish-F + //! @} + //! @} +//! @} + +//! \name HID KEYS values +//! @{ +#define HID_A 0x04 +#define HID_B 0x05 +#define HID_C 0x06 +#define HID_D 0x07 +#define HID_E 0x08 +#define HID_F 0x09 +#define HID_G 0x0A +#define HID_H 0x0B +#define HID_I 0x0C +#define HID_J 0x0D +#define HID_K 0x0E +#define HID_L 0x0F +#define HID_M 0x10 +#define HID_N 0x11 +#define HID_O 0x12 +#define HID_P 0x13 +#define HID_Q 0x14 +#define HID_R 0x15 +#define HID_S 0x16 +#define HID_T 0x17 +#define HID_U 0x18 +#define HID_V 0x19 +#define HID_W 0x1A +#define HID_X 0x1B +#define HID_Y 0x1C +#define HID_Z 0x1D +#define HID_1 30 +#define HID_2 31 +#define HID_3 32 +#define HID_4 33 +#define HID_5 34 +#define HID_6 35 +#define HID_7 36 +#define HID_8 37 +#define HID_9 38 +#define HID_0 39 +#define HID_ENTER 40 +#define HID_ESCAPE 41 +#define HID_BACKSPACE 42 +#define HID_TAB 43 +#define HID_SPACEBAR 44 +#define HID_UNDERSCORE 45 +#define HID_PLUS 46 +#define HID_OPEN_BRACKET 47 // { +#define HID_CLOSE_BRACKET 48 // } +#define HID_BACKSLASH 49 +#define HID_ASH 50 // # ~ +#define HID_COLON 51 // ; : +#define HID_QUOTE 52 // ' " +#define HID_TILDE 53 +#define HID_COMMA 54 +#define HID_DOT 55 +#define HID_SLASH 56 +#define HID_CAPS_LOCK 57 +#define HID_F1 58 +#define HID_F2 59 +#define HID_F3 60 +#define HID_F4 61 +#define HID_F5 62 +#define HID_F6 63 +#define HID_F7 64 +#define HID_F8 65 +#define HID_F9 66 +#define HID_F10 67 +#define HID_F11 68 +#define HID_F12 69 +#define HID_PRINTSCREEN 70 +#define HID_SCROLL_LOCK 71 +#define HID_PAUSE 72 +#define HID_INSERT 73 +#define HID_HOME 74 +#define HID_PAGEUP 75 +#define HID_DELETE 76 +#define HID_END 77 +#define HID_PAGEDOWN 78 +#define HID_RIGHT 79 +#define HID_LEFT 80 +#define HID_DOWN 81 +#define HID_UP 82 +#define HID_KEYPAD_NUM_LOCK 83 +#define HID_KEYPAD_DIVIDE 84 +#define HID_KEYPAD_AT 85 +#define HID_KEYPAD_MULTIPLY 85 +#define HID_KEYPAD_MINUS 86 +#define HID_KEYPAD_PLUS 87 +#define HID_KEYPAD_ENTER 88 +#define HID_KEYPAD_1 89 +#define HID_KEYPAD_2 90 +#define HID_KEYPAD_3 91 +#define HID_KEYPAD_4 92 +#define HID_KEYPAD_5 93 +#define HID_KEYPAD_6 94 +#define HID_KEYPAD_7 95 +#define HID_KEYPAD_8 96 +#define HID_KEYPAD_9 97 +#define HID_KEYPAD_0 98 + +//! \name HID modifier values +//! @{ +#define HID_MODIFIER_NONE 0x00 +#define HID_MODIFIER_LEFT_CTRL 0x01 +#define HID_MODIFIER_LEFT_SHIFT 0x02 +#define HID_MODIFIER_LEFT_ALT 0x04 +#define HID_MODIFIER_LEFT_UI 0x08 +#define HID_MODIFIER_RIGHT_CTRL 0x10 +#define HID_MODIFIER_RIGHT_SHIFT 0x20 +#define HID_MODIFIER_RIGHT_ALT 0x40 +#define HID_MODIFIER_RIGHT_UI 0x80 +//! @} +//! @} + +//! \name HID KEYS LED values +//! @{ +#define HID_LED_NUM_LOCK (1 << 0) +#define HID_LED_CAPS_LOCK (1 << 1) +#define HID_LED_SCROLL_LOCK (1 << 2) +#define HID_LED_COMPOSE (1 << 3) +#define HID_LED_KANA (1 << 4) +//! @} + +/** \name Standard HID mouse definitions from HID spec. example */ +/*@{*/ + +/** \brief Structure for standard HID keyboard modified keys */ +typedef union hid_kbd_modifier { + uint8_t byte; + struct { + uint8_t lctrl : 1; /**< Left Ctrl */ + uint8_t lshift : 1; /**< Left Shift */ + uint8_t lalt : 1; /**< Left Alt */ + uint8_t lgui : 1; /**< Left Gui */ + uint8_t rctrl : 1; /**< Right Ctrl */ + uint8_t rshift : 1; /**< Right Shift */ + uint8_t ralt : 1; /**< Right Alt */ + uint8_t rgui : 1; /**< Right Gui */ + } bm; +} hid_kbd_modifier_t; +#define HID_KBD_L_CTRL (1 << 0) /**< Left Ctrl */ +#define HID_KBD_L_SHIFT (1 << 1) /**< Left Shift */ +#define HID_KBD_L_ALT (1 << 2) /**< Left Alt */ +#define HID_KBD_L_GUI (1 << 3) /**< Left Gui */ +#define HID_KBD_R_CTRL (1 << 4) /**< Right Ctrl */ +#define HID_KBD_R_SHIFT (1 << 5) /**< Right Shift */ +#define HID_KBD_R_ALT (1 << 6) /**< Right Alt */ +#define HID_KBD_R_GUI (1 << 7) /**< Right Gui */ + +/** \brief Structure for standard HID keyboard input report */ +typedef union hid_kbd_input_report { + uint8_t byte[8]; + struct { + union hid_kbd_modifier modifier; + uint8_t reserved_oem; + uint8_t key[6]; /** < Key array */ + } field; +} hid_kbd_input_report_t; +/** Access to the modifier keys in HID keyboard report + * \param rpt Pointer to report data of bytes + */ +#define hid_kbd_modifier_keys(rpt) (rpt[0]) +/** Access to the OEM reserved in HID keyboard report + * \param rpt Pointer to report data of bytes + */ +#define hid_kbd_oem(rpt) (rpt[1]) +/** Access to the Key code in HID keyboard report + * \param rpt Pointer to report data of bytes + * \param i Index in the report key array (0~n) + */ +#define hid_kbd_keycode(rpt, i) (rpt[2 + i]) + +/** \brief Structure for standard HID keyboard output report */ +typedef union hid_kbd_output_report { + uint8_t byte; + struct { + uint8_t num_lock : 1; /**< LED of Num Lock */ + uint8_t caps_lock : 1; /**< LED of Caps Lock */ + uint8_t scroll_lock : 1; /**< LED of Scroll Lock */ + uint8_t compose : 1; /**< LED of COMPOSE LOCK */ + uint8_t kana : 1; /**< LED of KANA */ + uint8_t constant : 3; + } field; +} hid_kbd_output_report_t; +#define HID_KBD_NUM_LOCK (1 << 0) /**< LED of Num Lock */ +#define HID_KBD_CAPS_LOCK (1 << 1) /**< LED of Caps Lock */ +#define HID_KBD_SCROLL_LOCK (1 << 2) /**< LED of Scroll Lock */ +#define HID_KBD_COMPOSE (1 << 3) /**< LED of COMPOSE LOCK */ +#define HID_KBD_KANA (1 << 4) /**< LED of KANA */ + +/*@}*/ + +/** \name Standard HID mouse definitions from HID spec. example */ +/*@{*/ +/** \brief Structure for standard HID mouse report */ +typedef union hid_mouse_report { + uint8_t byte[3]; + struct { + uint8_t btn1 : 1; /**< Button 1 */ + uint8_t btn2 : 2; /**< Button 2 */ + uint8_t btn3 : 3; /**< Button 3 */ + uint8_t device_spec : 5; + int8_t x; /**< X displacement */ + int8_t y; /**< Y displacement */ + } field; + /* More bytes are optional */ +} hid_mouse_report_t; +#define HID_MOUSE_BTN1 (1 << 0) /**< Button 1 */ +#define HID_MOUSE_BTN2 (1 << 1) /**< Button 2 */ +#define HID_MOUSE_BTN3 (1 << 2) /**< Button 3 */ + +/** Access to the button state in HID mouse report + * \param rpt Pointer to report data of bytes + */ +#define hid_mouse_btn_state(rpt) (rpt[0]) +/** Check if the button is done in HID mouse report + * \param rpt Pointer to report data of bytes + * \param btn Button bitmap to check + */ +#define hid_mouse_is_btn_down(rpt, btn) (rpt[0] & (btn)) +/** Access to the relative X displacement in HID mouse report + * \param rpt Pointer to report data of bytes + */ +#define hid_mouse_x(rpt) ((int8_t)rpt[1]) +/** Access to the relative Y displacement in HID mouse report + * \param rpt Pointer to report data of bytes + */ +#define hid_mouse_y(rpt) ((int8_t)rpt[2]) + +/*@}*/ + +/** \name Standard HID joystick definitions from HID spec. example */ +/*@{*/ + +/** \brief Structure for standard HID joystick report */ +typedef union hid_joystick_report { + uint8_t byte[4]; + struct { + int8_t x; + int8_t y; + uint8_t hat_sw : 4; /**< Hat switch */ + uint8_t btn1 : 1; /**< Button 1 */ + uint8_t btn2 : 1; /**< Button 2 */ + uint8_t btn3 : 1; /**< Button 3 */ + uint8_t btn4 : 1; /**< Button 4 */ + uint8_t throttle; + } field; +} hid_joystick_report_t; +#define HID_JOYSTICK_BTN1 (1 << 4) /**< Button 1 */ +#define HID_JOYSTICK_BTN2 (1 << 5) /**< Button 2 */ +#define HID_JOYSTICK_BTN3 (1 << 6) /**< Button 3 */ +#define HID_JOYSTICK_BTN4 (1 << 7) /**< Button 4 */ + +/** Access to the absolute X position in HID joystick report + * \param rpt Pointer to report data of bytes + */ +#define hid_joystick_x(rpt) ((int8_t)rpt[0]) +/** Access to the absolute Y position in HID joystick report + * \param rpt Pointer to report data of bytes + */ +#define hid_joystick_y(rpt) ((int8_t)rpt[1]) +/** Access to the button state in HID joystick report + * \param rpt Pointer to report data of bytes + */ +#define hid_joystick_btn_state(rpt) (rpt[2]) +/** Check if the button is done in HID joystick report + * \param rpt Pointer to report data of bytes + * \param btn Button bitmap to check + */ +#define hid_joystick_is_btn_down(rpt, btn) (rpt[2] & (btn)) +/** Get the Hat switch in HID joystick report + * \param rpt Pointer to report data of bytes + */ +#define hid_joystick_hat_sw(rpt) (rpt[2] & 0xF) +/** Access to the throttle in HID joystick report + * \param rpt Pointer to report data of bytes + */ +#define hid_joystick_throttle(rpt) (rpt[3]) + +/*@}*/ + +/** + * \brief Fill a GetHIDDescriptor request + * \param[out] req Pointer to the request to fill + * \param[in] type Descriptor type + * \param[in] index Descriptor index + * \param[in] iface Interface Number + * \param[in] len Descriptor Length + */ +static inline void usb_fill_GetHIDDesc_req(struct usb_req *req, uint8_t type, uint8_t index, uint8_t iface, + uint16_t len) +{ + req->bmRequestType = 0x81; + req->bRequest = USB_REQ_GET_DESC; + req->wValue = (type << 8) | index; + req->wIndex = iface; + req->wLength = len; +} + +/** + * \brief Fill a SetHIDDescriptor request + * \param[out] req Pointer to the request to fill + * \param[in] type Descriptor type + * \param[in] index Descriptor index + * \param[in] iface Interface Number + * \param[in] len Descriptor Length + */ +static inline void usb_fill_SetHIDDesc_req(struct usb_req *req, uint8_t type, uint8_t index, uint8_t iface, + uint16_t len) +{ + req->bmRequestType = 0x01; + req->bRequest = USB_REQ_SET_DESC; + req->wValue = (type << 8) | index; + req->wIndex = iface; + req->wLength = len; +} + +/** + * \brief Fill a GetReport request + * \param[out] req Pointer to the request to fill + * \param[in] type Report type + * \param[in] id Report ID + * \param[in] iface Interface Number + * \param[in] len Report Length + */ +static inline void usb_fill_GetReport_req(struct usb_req *req, uint8_t type, uint8_t id, uint8_t iface, uint16_t len) +{ + req->bmRequestType = 0xA1; + req->bRequest = USB_REQ_HID_GET_REPORT; + req->wValue = (type << 8) | id; + req->wIndex = iface; + req->wLength = len; +} + +/** + * \brief Fill a SetReport request + * \param[out] req Pointer to the request to fill + * \param[in] type Report type + * \param[in] id Report ID + * \param[in] iface Interface Number + * \param[in] len Report Length + */ +static inline void usb_fill_SetReport_req(struct usb_req *req, uint8_t type, uint8_t id, uint8_t iface, uint16_t len) +{ + req->bmRequestType = 0x21; + req->bRequest = USB_REQ_HID_GET_REPORT; + req->wValue = (type << 8) | id; + req->wIndex = iface; + req->wLength = len; +} + +/** + * \brief Fill a GetIdle request + * \param[out] req Pointer to the request to fill + * \param[in] id Report ID + * \param[in] iface Interface Number + */ +static inline void usb_fill_GetIdle_req(struct usb_req *req, uint8_t id, uint8_t iface) +{ + req->bmRequestType = 0xA1; + req->bRequest = USB_REQ_HID_GET_IDLE; + req->wValue = id; + req->wIndex = iface; + req->wLength = 1; +} + +/** + * \brief Fill a SetIdle request + * \param[out] req Pointer to the request to fill + * \param[in] duration Duration value + * \param[in] id Report ID + * \param[in] iface Interface Number + */ +static inline void usb_fill_SetIdle_req(struct usb_req *req, uint8_t duration, uint8_t id, uint8_t iface) +{ + req->bmRequestType = 0x21; + req->bRequest = USB_REQ_HID_SET_IDLE; + req->wValue = (duration << 8) | id; + req->wIndex = iface; + req->wLength = 0; +} + +/** + * \brief Fill a GetProtocol request + * \param[out] req Pointer to the request to fill + * \param[in] iface Interface Number + */ +static inline void usb_fill_GetProtocol_req(struct usb_req *req, uint8_t iface) +{ + req->bmRequestType = 0xA1; + req->bRequest = USB_REQ_HID_GET_PROTOCOL; + req->wValue = 0; + req->wIndex = iface; + req->wLength = 1; +} + +/** + * \brief Fill a SetProtocol request + * \param[out] req Pointer to the request to fill + * \param[in] iface Interface Number + */ +static inline void usb_fill_SetProtocol_req(struct usb_req *req, uint8_t protocol, uint8_t iface) +{ + req->bmRequestType = 0x21; + req->bRequest = USB_REQ_HID_SET_PROTOCOL; + req->wValue = protocol; + req->wIndex = iface; + req->wLength = 0; +} + +#endif // _USB_PROTOCOL_HID_H_ diff --git a/atmel-samd/asf4/samd21/usb/class/hub/usb_protocol_hub.h b/atmel-samd/asf4/samd21/usb/class/hub/usb_protocol_hub.h new file mode 100644 index 000000000..dbfc04a2c --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/hub/usb_protocol_hub.h @@ -0,0 +1,364 @@ +/** + * \file + * + * \brief USB hub protocol definitions. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef _USB_PROTOCOL_HUB_H_ +#define _USB_PROTOCOL_HUB_H_ + +#include <usb_protocol.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** \name Possible class value */ +/*@{*/ +#define HUB_CLASS 0x09 +/*@}*/ + +/** \brief Hub USB requests (bRequest) */ +enum usb_reqid_hub { + USB_REQ_HUB_GET_STATUS = 0, + /** CLEAR_FEATURE */ + USB_REQ_HUB_CLR_FTR = 1, + /** SET_FEATURE */ + USB_REQ_HUB_SET_FTR = 3, + /** GET_DESCRIPTOR */ + USB_REQ_HUB_GET_DESC = 6, + /** SET_DESCRIPTOR */ + USB_REQ_HUB_SET_DESC = 7, + /** CLEAR_TT_BUFFER */ + USB_REQ_HUB_CLR_TT_BUF = 8, + /** RESET_TT */ + USB_REQ_HUB_RESET_TT = 9, + /** GET_TT_STATE */ + USB_REQ_HUB_GET_TT_STATE = 10, + /** STOP_TT */ + USB_REQ_HUB_STOP_TT +}; + +/** \brief Hub USB descriptor type */ +enum usb_descriptor_type_hub { USB_DT_HUB = 0x29 }; + +/** \brief Hub feature selector */ +enum usb_hub_ftr_sel { + USB_HUB_FTR_C_HUB_LOCAL_POWER = 0, + USB_HUB_FTR_C_HUB_OVER_CURRENT = 1, + USB_HUB_FTR_PORT_CONNECTION = 0, + USB_HUB_FTR_PORT_ENABLE = 1, + USB_HUB_FTR_PORT_SUSPEND = 2, + USB_HUB_FTR_PORT_OVER_CURRENT = 3, + USB_HUB_FTR_PORT_RESET = 4, + USB_HUB_FTR_PORT_POWER = 8, + USB_HUB_FTR_PORT_LOW_SPEED = 9, + USB_HUB_FTR_PORT_LS = 9, + USB_HUB_FTR_PORT_HIGH_SPEED = 10, + USB_HUB_FTR_PORT_HS = 10, + USB_HUB_FTR_C_PORT_CONNECTION = 16, + USB_HUB_FTR_C_PORT_ENABLE = 17, + USB_HUB_FTR_C_PORT_SUSPEND = 18, + USB_HUB_FTR_C_PORT_OVER_CURRENT = 19, + USB_HUB_FTR_C_PORT_RESET = 20, + USB_HUB_FTR_PORT_TEST = 21, + USB_HUB_FTR_PORT_INDICATOR +}; + +COMPILER_PACK_SET(1) + +/** + * \brief General Hub Descriptor + */ +typedef struct usb_hub_descriptor { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint32_t variables[1]; +} usb_hub_descriptor_t; + +/** + * \brief Hub Descriptor with no more than 7 ports + */ +typedef struct usb_hub_descriptor_7p { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable[1]; + uint8_t PortPwrCtrlMask[1]; +} usb_hub_descriptor_7p_t; + +/** + * \brief Hub Descriptor with no more than 15 ports + */ +typedef struct usb_hub_descriptor_15p { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable[2]; + uint8_t PortPwrCtrlMask[2]; +} usb_hub_descriptor_15p_t; + +/** + * \brief Hub Descriptor with no more than 23 ports + */ +typedef struct usb_hub_descriptor_23p { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable[3]; + uint8_t PortPwrCtrlMask[3]; +} usb_hub_descriptor_23p_t; + +/** + * \brief Hub Descriptor with no more than 31 ports + */ +typedef struct usb_hub_descriptor_31p { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable[4]; + uint8_t PortPwrCtrlMask[4]; +} usb_hub_descriptor_31p_t; + +COMPILER_PACK_RESET() + +/** + * \brief Check if hub change is detected + * \param[in] bitmap Pointer to the bitmap location + * \return \c true if hub change is detected + */ +static inline bool usb_is_hub_change_detected(const uint8_t *bitmap) +{ + return (*bitmap & 0x1); +} + +/** + * \brief Check if port change is detected + * \param[in] bitmap Pointer to the bitmap location + * \param[in] port Port number ( 1 ~ n ) + * \return \c true if port change is detected + */ +static inline bool usb_is_port_change_detected(const uint8_t *bitmap, const uint8_t port) +{ + uint8_t idx = port >> 3; + uint8_t pos = port & 0x7; + return (bitmap[idx] & (1u << pos)); +} + +/** + * \brief Fill a ClearHubFeature request + * \param[out] req Pointer to the request to fill + * \param[in] ftr Feature selector + */ +static inline void usb_fill_ClrHubFtr_req(struct usb_req *req, uint8_t ftr) +{ + req->bmRequestType = 0x20; + req->bRequest = USB_REQ_CLEAR_FTR; + req->wValue = ftr; + req->wIndex = 0; + req->wLength = 0; +} + +/** + * \brief Fill a ClearPortFeature request + * \param[out] req Pointer to the request to fill + * \param[in] ftr Feature selector + * \param[in] port Port number ( 1 ~ n ) + */ +static inline void usb_fill_ClrPortFtr_req(struct usb_req *req, uint8_t ftr, uint8_t port) +{ + req->bmRequestType = 0x23; + req->bRequest = USB_REQ_CLEAR_FTR; + req->wValue = ftr; + req->wIndex = port; + req->wLength = 0; +} + +/** + * \brief Fill a ClearTTBuffer request + * \param[out] req Pointer to the request to fill + * \param[in] dev Dev_Addr + * \param[in] ep EP_Num + * \param[in] tt_port TT_port + */ +static inline void usb_fill_ClrTTBuf_req(struct usb_req *req, uint8_t dev, uint8_t ep, uint8_t tt_port) +{ + req->bmRequestType = 0x23; + req->bRequest = USB_REQ_HUB_CLR_TT_BUF; + req->wValue = (dev << 8) | ep; + req->wIndex = tt_port; + req->wLength = 0; +} + +/** + * \brief Fill a GetHubDescriptor request + * \param[out] req Pointer to the request to fill + * \param[in] len Length of available buffer for request data + */ +static inline void usb_fill_GetHubDesc_req(struct usb_req *req, uint16_t len) +{ + req->bmRequestType = 0xA0; + req->bRequest = USB_REQ_GET_DESC; + req->wValue = (USB_DT_HUB << 8) | 0; + req->wIndex = 0; + req->wLength = len; +} + +/** + * \brief Fill a GetHubStatus request + * \param[out] req Pointer to the request to fill + */ +static inline void usb_fill_GetHubStatus_req(struct usb_req *req) +{ + req->bmRequestType = 0xA0; + req->bRequest = USB_REQ_GET_STATUS; + req->wValue = 0; + req->wIndex = 0; + req->wLength = 4; +} + +/** + * \brief Fill a GetPortStatus request + * \param[out] req Pointer to the request to fill + * \param[in] port Port number ( 1 ~ n ) + */ +static inline void usb_fill_GetPortStatus_req(struct usb_req *req, uint8_t port) +{ + req->bmRequestType = 0xA3; + req->bRequest = USB_REQ_GET_STATUS; + req->wValue = 0; + req->wIndex = port; + req->wLength = 4; +} + +/** + * \brief Fill a ResetTT request + * \param[out] req Pointer to the request to fill + * \param[in] port Port number ( 1 ~ n ) + */ +static inline void usb_fill_ResetTT_req(struct usb_req *req, uint8_t port) +{ + req->bmRequestType = 0x23; + req->bRequest = USB_REQ_HUB_RESET_TT; + req->wValue = 0; + req->wIndex = port; + req->wLength = 0; +} + +/** + * \brief Fill a SetHubFeature request + * \param[out] req Pointer to the request to fill + * \param[in] ftr Feature selector + */ +static inline void usb_fill_SetHubFtr_req(struct usb_req *req, uint8_t ftr) +{ + req->bmRequestType = 0x20; + req->bRequest = USB_REQ_SET_FTR; + req->wValue = ftr; + req->wIndex = 0; + req->wLength = 0; +} + +/** + * \brief Fill a SetPortFeature request + * \param[out] req Pointer to the request to fill + * \param[in] ftr Feature selector + * \param[in] port Port number ( 1 ~ n ) + */ +static inline void usb_fill_SetPortFtr_req(struct usb_req *req, uint8_t ftr, uint8_t port) +{ + req->bmRequestType = 0x23; + req->bRequest = USB_REQ_SET_FTR; + req->wValue = ftr; + req->wIndex = port; + req->wLength = 0; +} + +/** + * \brief Fill a GetTTState request + * \param[out] req Pointer to the request to fill + * \param[in] tt_flags TT_Flags + * \param[in] port Port number ( 1 ~ n ) + * \param[in] len TT State Length + */ +static inline void usb_fill_GetTTState_req(struct usb_req *req, uint16_t tt_flags, uint8_t port, uint16_t len) +{ + req->bmRequestType = 0xA3; + req->bRequest = USB_REQ_HUB_GET_TT_STATE; + req->wValue = tt_flags; + req->wIndex = port; + req->wLength = len; +} + +/** + * \brief Fill a StopTT request + * \param[out] req Pointer to the request to fill + * \param[in] port Port number ( 1 ~ n ) + */ +static inline void usb_fill_StopTT_req(struct usb_req *req, uint8_t port) +{ + req->bmRequestType = 0x23; + req->bRequest = USB_REQ_HUB_STOP_TT; + req->wValue = 0; + req->wIndex = port; + req->wLength = 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _USB_PROTOCOL_HUB_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/msc/sbc_protocol.h b/atmel-samd/asf4/samd21/usb/class/msc/sbc_protocol.h new file mode 100644 index 000000000..925933522 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/msc/sbc_protocol.h @@ -0,0 +1,163 @@ +/** + * \file + * + * \brief SCSI Block Commands + * + * This file contains definitions of some of the commands found in the + * SCSI SBC-2 standard. + * + * Note that the SBC specification depends on several commands defined + * by the SCSI Primary Commands (SPC) standard. Each version of the SBC + * standard is meant to be used in conjunction with a specific version + * of the SPC standard, as follows: + * - SBC depends on SPC + * - SBC-2 depends on SPC-3 + * - SBC-3 depends on SPC-4 + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +#ifndef _SBC_PROTOCOL_H_ +#define _SBC_PROTOCOL_H_ + +/** + * \ingroup usb_msc_protocol + * \defgroup usb_sbc_protocol SCSI Block Commands protocol definitions + * + * @{ + */ + +/** \name SCSI commands defined by SBC-2 */ +#define SBC_FORMAT_UNIT 0x04 +#define SBC_READ6 0x08 +#define SBC_WRITE6 0x0A +#define SBC_START_STOP_UNIT 0x1B +#define SBC_READ_CAPACITY10 0x25 +#define SBC_READ10 0x28 +#define SBC_WRITE10 0x2A +#define SBC_VERIFY10 0x2F + +/** \name SBC-2 Mode page definitions */ +enum scsi_sbc_mode { + SCSI_MS_MODE_RW_ERR_RECOV = 0x01, /**< Read-Write Error Recovery mode page */ + SCSI_MS_MODE_FORMAT_DEVICE = 0x03, /**< Format Device mode page */ + SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, /**< Flexible Disk mode page */ + SCSI_MS_MODE_CACHING = 0x08 +}; + +/** \name SBC-2 Device-Specific Parameter */ +#define SCSI_MS_SBC_WP 0x80 /**< Write Protected */ +#define SCSI_MS_SBC_DPOFUA 0x10 /**< DPO and FUA supported */ + +/** + * \brief SBC-2 Short LBA mode parameter block descriptor + * \note Fields are MSB first (BE) + */ +struct sbc_slba_block_desc { + be32_t nr_blocks; /**< Number of Blocks (BE32) */ + be32_t block_len; /**< Block Length (BE32) */ +#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU /**< Mask reserved bits */ +}; + +/** + * \brief SBC-2 Caching mode page + * \note Fields are MSB first (BE) + */ +struct sbc_caching_mode_page { + uint8_t page_code; + uint8_t page_length; + uint8_t flags2; +#define SBC_MP_CACHE_IC (1 << 7) /**< Initiator Control */ +#define SBC_MP_CACHE_ABPF (1 << 6) /**< Abort Pre-Fetch */ +#define SBC_MP_CACHE_CAP (1 << 5) /**< Catching Analysis Permitted */ +#define SBC_MP_CACHE_DISC (1 << 4) /**< Discontinuity */ +#define SBC_MP_CACHE_SIZE (1 << 3) /**< Size enable */ +#define SBC_MP_CACHE_WCE (1 << 2) /**< Write back Cache Enable */ +#define SBC_MP_CACHE_MF (1 << 1) /**< Multiplication Factor */ +#define SBC_MP_CACHE_RCD (1 << 0) /**< Read Cache Disable */ + uint8_t retention; + be16_t dis_pf_transfer_len; + be16_t min_prefetch; + be16_t max_prefetch; + be16_t max_prefetch_ceil; + uint8_t flags12; +#define SBC_MP_CACHE_FSW (1 << 7) /**< Force Sequential Write */ +#define SBC_MP_CACHE_LBCSS (1 << 6) /**< Logical Blk Cache Seg Sz */ +#define SBC_MP_CACHE_DRA (1 << 5) /**< Disable Read-Ahead */ +#define SBC_MP_CACHE_NV_DIS (1 << 0) /**< Non-Volatile Cache Disable */ + uint8_t nr_cache_segments; + be16_t cache_segment_size; + uint8_t reserved[4]; +}; + +/** + * \brief SBC-2 Read-Write Error Recovery mode page + * \note Fields are MSB first (BE) + */ +struct sbc_rdwr_error_recovery_mode_page { + uint8_t page_code; + uint8_t page_length; +#define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A + uint8_t flags1; +#define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7) +#define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6) +#define SBC_MP_RW_ERR_RECOV_TB (1 << 5) +#define SBC_MP_RW_ERR_RECOV_RC (1 << 4) +#define SBC_MP_RW_ERR_RECOV_ERR (1 << 3) +#define SBC_MP_RW_ERR_RECOV_PER (1 << 2) +#define SBC_MP_RW_ERR_RECOV_DTE (1 << 1) +#define SBC_MP_RW_ERR_RECOV_DCR (1 << 0) + uint8_t read_retry_count; + uint8_t correction_span; + uint8_t head_offset_count; + uint8_t data_strobe_offset_count; + uint8_t flags2; + uint8_t write_retry_count; + uint8_t flags3; + be16_t recovery_time_limit; +}; + +/** + * \brief SBC-2 READ CAPACITY (10) parameter data (8 bytes) + * \note Fields are MSB first (BE) + */ +struct sbc_read_capacity10_data { + be32_t max_lba; /**< LBA of last logical block (BE32) */ + be32_t block_len; /**< Number of bytes in the last logical block (BE32) */ +}; + +#endif /*_SBC_PROTOCOL_H_*/ diff --git a/atmel-samd/asf4/samd21/usb/class/msc/spc_protocol.h b/atmel-samd/asf4/samd21/usb/class/msc/spc_protocol.h new file mode 100644 index 000000000..c44cbef32 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/msc/spc_protocol.h @@ -0,0 +1,340 @@ +/** + * \file + * + * \brief SCSI Primary Commands + * + * This file contains definitions of some of the commands found in the + * SPC-2 standard. + * + * Copyright (c) 2009-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +#ifndef _SPC_PROTOCOL_H_ +#define _SPC_PROTOCOL_H_ + +/** + * \ingroup usb_msc_protocol + * \defgroup usb_spc_protocol SCSI Primary Commands protocol definitions + * + * + */ + +/**< \name SCSI commands defined by SPC-2 */ +#define SPC_TEST_UNIT_READY 0x00 +#define SPC_REQUEST_SENSE 0x03 +#define SPC_INQUIRY 0x12 +#define SPC_MODE_SELECT6 0x15 +#define SPC_MODE_SENSE6 0x1A +#define SPC_SEND_DIAGNOSTIC 0x1D +#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SPC_MODE_SENSE10 0x5A +#define SPC_REPORT_LUNS 0xA0 + +/**< \brief May be set in byte 0 of the INQUIRY CDB */ +/**< Enable Vital Product Data */ +#define SCSI_INQ_REQ_EVPD 0x01 +/**< Command Support Data specified by the PAGE OR OPERATION CODE field */ +#define SCSI_INQ_REQ_CMDT 0x02 + +COMPILER_PACK_SET(1) + +/** + * \brief SCSI Standard Inquiry data structure + */ +struct scsi_inquiry_data { + uint8_t pq_pdt; /**< Peripheral Qual / Peripheral Dev Type */ +#define SCSI_INQ_PQ_CONNECTED 0x00 /**< Peripheral connected */ +#define SCSI_INQ_PQ_NOT_CONN 0x20 /**< Peripheral not connected */ +#define SCSI_INQ_PQ_NOT_SUPP 0x60 /**< Peripheral not supported */ +#define SCSI_INQ_DT_DIR_ACCESS 0x00 /**< Direct Access (SBC) */ +#define SCSI_INQ_DT_SEQ_ACCESS 0x01 /**< Sequential Access */ +#define SCSI_INQ_DT_PRINTER 0x02 /**< Printer */ +#define SCSI_INQ_DT_PROCESSOR 0x03 /**< Processor device */ +#define SCSI_INQ_DT_WRITE_ONCE 0x04 /**< Write-once device */ +#define SCSI_INQ_DT_CD_DVD 0x05 /**< CD/DVD device */ +#define SCSI_INQ_DT_OPTICAL 0x07 /**< Optical Memory */ +#define SCSI_INQ_DT_MC 0x08 /**< Medium Changer */ +#define SCSI_INQ_DT_ARRAY 0x0c /**< Storage Array Controller */ +#define SCSI_INQ_DT_ENCLOSURE 0x0d /**< Enclosure Services */ +#define SCSI_INQ_DT_RBC 0x0e /**< Simplified Direct Access */ +#define SCSI_INQ_DT_OCRW 0x0f /**< Optical card reader/writer */ +#define SCSI_INQ_DT_BCC 0x10 /**< Bridge Controller Commands */ +#define SCSI_INQ_DT_OSD 0x11 /**< Object-based Storage */ +#define SCSI_INQ_DT_NONE 0x1f /**< No Peripheral */ + uint8_t flags1; /**< Flags (byte 1) */ +#define SCSI_INQ_RMB 0x80 /**< Removable Medium */ + uint8_t version; /**< Version */ +#define SCSI_INQ_VER_NONE 0x00 /**< No standards conformance */ +#define SCSI_INQ_VER_SPC 0x03 /**< SCSI Primary Commands (link to SBC) */ +#define SCSI_INQ_VER_SPC2 0x04 /**< SCSI Primary Commands - 2 (link to SBC-2) */ +#define SCSI_INQ_VER_SPC3 0x05 /**< SCSI Primary Commands - 3 (link to SBC-2) */ +#define SCSI_INQ_VER_SPC4 0x06 /**< SCSI Primary Commands - 4 (link to SBC-3) */ + uint8_t flags3; /**< Flags (byte 3) */ +#define SCSI_INQ_NORMACA 0x20 /**< Normal ACA Supported */ +#define SCSI_INQ_HISUP 0x10 /**< Hierarchal LUN addressing */ +#define SCSI_INQ_RSP_SPC2 0x02 /**< SPC-2 / SPC-3 response format */ + uint8_t addl_len; /**< Additional Length (n-4) */ +#define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) /**< Total length is \a tot */ + uint8_t flags5; /**< Flags (byte 5) */ +#define SCSI_INQ_SCCS 0x80 + uint8_t flags6; /**< Flags (byte 6) */ +#define SCSI_INQ_BQUE 0x80 +#define SCSI_INQ_ENCSERV 0x40 +#define SCSI_INQ_MULTIP 0x10 +#define SCSI_INQ_MCHGR 0x08 +#define SCSI_INQ_ADDR16 0x01 + uint8_t flags7; /**< Flags (byte 7) */ +#define SCSI_INQ_WBUS16 0x20 +#define SCSI_INQ_SYNC 0x10 +#define SCSI_INQ_LINKED 0x08 +#define SCSI_INQ_CMDQUE 0x02 + uint8_t vendor_id[8]; /**< T10 Vendor Identification */ + uint8_t product_id[16]; /**< Product Identification */ + uint8_t product_rev[4]; /**< Product Revision Level */ +}; + +/** + * \brief SCSI Standard Request sense data structure + */ +#define SCSI_SENSE_VALID 0x80 /**< Indicates the INFORMATION field contains valid information */ +#define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F +#define SCSI_SENSE_CURRENT 0x70 /**< Response code 70h (current errors) */ +#define SCSI_SENSE_DEFERRED 0x71 + +#define SCSI_SENSE_FILEMARK 0x80 /**< Indicates that the current command has read a filemark or setmark. */ +#define SCSI_SENSE_EOM 0x40 /**< Indicates that an end-of-medium condition exists. */ +#define SCSI_SENSE_ILI \ + 0x20 /**< Indicates that the requested logical block length did not match the logical block length of the data on \ + the medium. */ +#define SCSI_SENSE_RESERVED 0x10 /**< Reserved */ +#define SCSI_SENSE_KEY(x) (x & 0x0F) /**< Sense Key */ + +#define SCSI_SENSE_ADDL_LEN(total_len) ((total_len)-8) + +#define SCSI_SENSE_SKSV 0x80 /**< Indicates the SENSE-KEY SPECIFIC field contains valid information */ + +struct scsi_request_sense_data { + /** 1st byte: REQUEST SENSE response flags*/ + uint8_t valid_reponse_code; + /** 2nd byte */ + uint8_t obsolete; + /** 3rd byte */ + uint8_t sense_flag_key; + /** 4th to 7th bytes - INFORMATION field */ + uint8_t information[4]; + /** 8th byte - ADDITIONAL SENSE LENGTH field */ + uint8_t AddSenseLen; + /** 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */ + uint8_t CmdSpecINFO[4]; + /** 13th to 14th byte - ADDITIONAL SENSE CODE and QUALIFIER field */ + union { + struct { + uint8_t code; /**< ADDITIONAL SENSE CODE (ASC) */ + uint8_t qualifier; /**< ADDITIONAL SENSE CODE QUALIFIER (ASCQ) */ + } add_sense; + be16_t AddSense; /**< ASC | ASCQ */ + }; + /** 15th byte - FIELD REPLACEABLE UNIT CODE field */ + uint8_t FldReplUnitCode; + /** 16th byte */ + uint8_t SenseKeySpec[3]; +}; + +COMPILER_PACK_RESET() + +/**< Vital Product Data page codes */ +enum scsi_vpd_page_code { + SCSI_VPD_SUPPORTED_PAGES = 0x00, + SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80, + SCSI_VPD_DEVICE_IDENTIFICATION = 0x83 +}; +#define SCSI_VPD_HEADER_SIZE 4 + +/**< Constants associated with the Device Identification VPD page */ +#define SCSI_VPD_ID_HEADER_SIZE 4 + +#define SCSI_VPD_CODE_SET_BINARY 1 +#define SCSI_VPD_CODE_SET_ASCII 2 +#define SCSI_VPD_CODE_SET_UTF8 3 + +#define SCSI_VPD_ID_TYPE_T10 1 + +/**< Sense keys */ +enum scsi_sense_key { + SCSI_SK_NO_SENSE = 0x0, + SCSI_SK_RECOVERED_ERROR = 0x1, + SCSI_SK_NOT_READY = 0x2, + SCSI_SK_MEDIUM_ERROR = 0x3, + SCSI_SK_HARDWARE_ERROR = 0x4, + SCSI_SK_ILLEGAL_REQUEST = 0x5, + SCSI_SK_UNIT_ATTENTION = 0x6, + SCSI_SK_DATA_PROTECT = 0x7, + SCSI_SK_BLANK_CHECK = 0x8, + SCSI_SK_VENDOR_SPECIFIC = 0x9, + SCSI_SK_COPY_ABORTED = 0xa, + SCSI_SK_ABORTED_COMMAND = 0xb, + SCSI_SK_VOLUME_OVERFLOW = 0xd, + SCSI_SK_MISCOMPARE = 0xe +}; + +/**< Additional Sense Code | Additional Sense Code Qualifier pairs (BE16) */ +enum scsi_asc_ascq { + SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000, + SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405, + SCSI_ASC_WRITE_ERROR = 0x0c00, + SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100, + SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000, + SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400, + SCSI_ASC_WRITE_PROTECTED = 0x2700, + SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800, + SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00, + SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400 +}; + +/** + * \brief SPC-2 Mode parameter + * This subclauses describes the block descriptors and the pages + * used with MODE SELECT and MODE SENSE commands + * that are applicable to all SCSI devices. + */ +enum scsi_spc_mode { + SCSI_MS_MODE_VENDOR_SPEC = 0x00, + SCSI_MS_MODE_INFEXP = 0x1C, /**< Informational exceptions control page */ + SCSI_MS_MODE_ALL = 0x3f +}; + +/** + * \brief SPC-2 Informational exceptions control page + * See chapter 8.3.8 + * \note Fields are MSB first (BE) + */ +struct spc_control_page_info_execpt { + uint8_t page_code; + uint8_t page_length; +#define SPC_MP_INFEXP_PAGE_LENGTH 0x0A + uint8_t flags1; +#define SPC_MP_INFEXP_PERF (1 << 7) /**< Initiator Control */ +#define SPC_MP_INFEXP_EBF (1 << 5) /**< Caching Analysis Permitted */ +#define SPC_MP_INFEXP_EWASC (1 << 4) /**< Discontinuity */ +#define SPC_MP_INFEXP_DEXCPT (1 << 3) /**< Size enable */ +#define SPC_MP_INFEXP_TEST (1 << 2) /**< Write-back Cache Enable */ +#define SPC_MP_INFEXP_LOGERR (1 << 0) /**< Log errors bit */ + uint8_t mrie; +#define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00 +#define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01 +#define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02 +#define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03 +#define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04 +#define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05 +#define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06 + be32_t interval_timer; + be32_t report_count; +}; + +enum scsi_spc_mode_sense_pc { + SCSI_MS_SENSE_PC_CURRENT = 0, + SCSI_MS_SENSE_PC_CHANGEABLE = 1, + SCSI_MS_SENSE_PC_DEFAULT = 2, + SCSI_MS_SENSE_PC_SAVED = 3 +}; + +/** + * \brief Check whether dbd field is set in sense code + * \param[in] cdb pointer to the sense code block + * \return Operation status. + */ +static inline bool scsi_mode_sense_dbd_is_set(const uint8_t *cdb) +{ + return (cdb[1] >> 3) & 1; +} + +/** + * \brief Get page code from mode sense code + * \param[in] cdb pointer to the sense code block + * \return Operation status. + */ +static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t *cdb) +{ + return cdb[2] & 0x3f; +} + +/** + * \brief Get pc from mode sense code + * \param[in] cdb pointer to the sense code block + * \return Operation status. + */ +static inline uint8_t scsi_mode_sense_get_pc(const uint8_t *cdb) +{ + return cdb[2] >> 6; +} + +/** + * \brief SCSI Mode Parameter Header used by MODE SELECT(6) and MODE SENSE(6) + * \note Fields are MSB first (BE) + */ +struct scsi_mode_param_header6 { + uint8_t mode_data_length; /**< Number of bytes after this */ + uint8_t medium_type; /**< Medium Type */ + uint8_t device_specific_parameter; /**< Defined by command set */ + uint8_t block_descriptor_length; /**< Length of block descriptors */ +}; + +/** + * \brief SCSI Mode Parameter Header used by MODE SELECT(10) and MODE SENSE(10) + * \note Fields are MSB first (BE) + */ +struct scsi_mode_param_header10 { + le16_t mode_data_length; /**< Number of bytes after this */ + uint8_t medium_type; /**< Medium Type */ + uint8_t device_specific_parameter; /**< Defined by command set */ + uint8_t flags4; /**< LONGLBA in bit 0 */ + uint8_t reserved; + le16_t block_descriptor_length; /**< Length of block descriptors */ +}; + +/** + * \brief SCSI Page_0 Mode Page header (SPF not set) + */ +struct scsi_mode_page_0_header { + uint8_t page_code; +#define SCSI_PAGE_CODE_PS (1 << 7) /**< Parameters Savable */ +#define SCSI_PAGE_CODE_SPF (1 << 6) /**< SubPage Format */ + uint8_t page_length; /**< Number of bytes after this */ +#define SCSI_MS_PAGE_LEN(total) ((total)-2) +}; + +#endif /**< SPC_PROTOCOL_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/class/msc/usb_protocol_msc.h b/atmel-samd/asf4/samd21/usb/class/msc/usb_protocol_msc.h new file mode 100644 index 000000000..f69eae232 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/msc/usb_protocol_msc.h @@ -0,0 +1,177 @@ +/** + * \file + * + * \brief USB Mass Storage Class (MSC) protocol definitions. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef _USB_PROTOCOL_MSC_H_ +#define _USB_PROTOCOL_MSC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup usb_protocol_group + * \defgroup usb_msc_protocol USB Mass Storage Class (MSC) protocol definitions + * + * @{ + */ + +/** + * \name Possible Class value + */ +//@{ +#define MSC_CLASS 0x08 +//@} + +/** + * \name Possible SubClass value + * \note In practice, most devices should use + * #MSC_SUBCLASS_TRANSPARENT and specify the actual command set in + * the standard INQUIRY data block, even if the MSC spec indicates + * otherwise. In particular, RBC is not supported by certain major + * operating systems like Windows XP. + */ +//@{ +#define MSC_SUBCLASS_RBC 0x01 /**< Reduced Block Commands */ +#define MSC_SUBCLASS_ATAPI 0x02 /**< CD/DVD devices */ +#define MSC_SUBCLASS_QIC_157 0x03 /**< Tape devices */ +#define MSC_SUBCLASS_UFI 0x04 /**< Floppy disk drives */ +#define MSC_SUBCLASS_SFF_8070I 0x05 /**< Floppy disk drives */ +#define MSC_SUBCLASS_TRANSPARENT 0x06 /**< Determined by INQUIRY */ + //@} + +/** + * \name Possible protocol value + * \note Only the BULK protocol should be used in new designs. + */ +//@{ +#define MSC_PROTOCOL_CBI 0x00 /**< Command/Bulk/Interrupt */ +#define MSC_PROTOCOL_CBI_ALT 0x01 /**< W/o command completion */ +#define MSC_PROTOCOL_BULK 0x50 /**< Bulk-only */ + //@} + +/** + * \brief MSC USB requests (bRequest) + */ + +#define USB_REQ_MSC_BULK_RESET 0xFF /**< Mass Storage Reset */ +#define USB_REQ_MSC_GET_MAX_LUN 0xFE /**< Get Max LUN */ + +COMPILER_PACK_SET(1) + +/** + * \name A Command Block Wrapper (CBW) + * \note Fields are LSB first (LE) + */ +//@{ +struct usb_msc_cbw { + le32_t dCBWSignature; /**< Must contain 'USBC' (0x43425355, LE32) */ + le32_t dCBWTag; /**< Unique command ID (LE32) */ + le32_t dCBWDataTransferLength; /**< Number of bytes to transfer (LE32) */ + uint8_t bmCBWFlags; /**< Direction in bit 7 */ + uint8_t bCBWLUN; /**< Logical Unit Number */ + uint8_t bCBWCBLength; /**< Number of valid CDB bytes */ + uint8_t CDB[16]; /**< SCSI Command Descriptor Block */ +}; + +#define USB_CBW_SIGNATURE 0x43425355 /**< dCBWSignature value */ +#define USB_CBW_DIRECTION_IN (1 << 7) /**< Data from device to host */ +#define USB_CBW_DIRECTION_OUT (0 << 7) /**< Data from host to device */ +#define USB_CBW_LUN_MASK 0x0F /**< Valid bits in bCBWLUN */ +#define USB_CBW_LEN_MASK 0x1F /**< Valid bits in bCBWCBLength */ + //@} + +/** + * \name A Command Status Wrapper (CSW) + * \note Fields are LSB first (LE) + */ +//@{ +struct usb_msc_csw { + le32_t dCSWSignature; /**< Must contain 'USBS' */ + le32_t dCSWTag; /**< Same as dCBWTag */ + le32_t dCSWDataResidue; /**< Number of bytes not transfered */ + uint8_t bCSWStatus; /**< Status code */ +}; + +#define USB_CSW_SIGNATURE 0x53425355 /**< dCSWSignature value */ +#define USB_CSW_STATUS_PASS 0x00 /**< Command Passed */ +#define USB_CSW_STATUS_FAIL 0x01 /**< Command Failed */ +#define USB_CSW_STATUS_PE 0x02 /**< Phase Error */ +//@} + +COMPILER_PACK_RESET() + +//@} + +/** + * \brief Fill a Bulk-Only Mass Storage Reset request + * \param[out] req Pointer to the request to fill + * \param[in] iface Interface Number + */ +static inline void usb_fill_BOMSReset_req(struct usb_req *req, uint8_t iface) +{ + req->bmRequestType = 0x21; + req->bRequest = USB_REQ_MSC_BULK_RESET; + req->wValue = 0; + req->wIndex = iface; + req->wLength = 0; +} + +/** + * \brief Fill a GetMaxLUN request + * \param[out] req Pointer to the request to fill + * \param[in] iface Interface Number + */ +static inline void usb_fill_GetMaxLUN_req(struct usb_req *req, uint8_t iface) +{ + req->bmRequestType = 0xA1; + req->bRequest = USB_REQ_MSC_GET_MAX_LUN; + req->wValue = 0; + req->wIndex = iface; + req->wLength = 1; +} + +#ifdef __cplusplus +} +#endif + +#endif // _USB_PROTOCOL_MSC_H_ diff --git a/atmel-samd/asf4/samd21/usb/class/vendor/usb_protocol_vendor.h b/atmel-samd/asf4/samd21/usb/class/vendor/usb_protocol_vendor.h new file mode 100644 index 000000000..e865fb808 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/class/vendor/usb_protocol_vendor.h @@ -0,0 +1,63 @@ +/** + * \file + * + * \brief USB Vendor class protocol definitions. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> + */ + +#ifndef _USB_PROTOCOL_VENDOR_H_ +#define _USB_PROTOCOL_VENDOR_H_ + +/** + * \ingroup usb_protocol_group + * \defgroup usb_vendor_protocol USB Vendor Class definitions + * + */ + +/** + * \name Vendor class values + */ +#define VENDOR_CLASS 0xFF +#define VENDOR_SUBCLASS 0xFF +#define VENDOR_PROTOCOL 0xFF + +#endif /* _USB_PROTOCOL_VENDOR_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/device/usbdc.c b/atmel-samd/asf4/samd21/usb/device/usbdc.c new file mode 100644 index 000000000..f5243cad0 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/device/usbdc.c @@ -0,0 +1,836 @@ +/** + * \file + * + * \brief USB Device Stack Core Layer Implementation. + * + * Copyright (C) 2015-2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel micro controller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "usbdc.h" + +#define USBDC_VERSION 0x00000001u + +/** + * \brief USB Device Core Sof Handler + */ +struct usbdc_sof_handler { + struct usbdc_sof_handler *next; + usbdc_sof_cb_t cb; +}; + +/** + * \brief USB Device Core Request Handler + */ +struct usbdc_req_handler { + struct usbdc_req_handler *next; + usbdc_req_cb_t cb; +}; + +/** + * \brief USB Device Core Change Handler + */ +struct usbdc_change_handler { + struct usbdc_change_handler *next; + usbdc_change_cb_t cb; +}; + +/** + * \brief USB Device Core Handler + */ +struct usbdc_handlers { + struct list_descriptor sof_list; + struct list_descriptor req_list; + struct list_descriptor change_list; +}; + +/** + * \brief USB Device Core Driver Structure + */ +struct usbdc_driver { + /** Pointer to descriptions of descriptors. */ + struct usbdc_descriptors desces; + /** Callback handlers. */ + struct usbdc_handlers handlers; + /** list of function drivers. */ + struct list_descriptor func_list; + /** Control buffer. */ + uint8_t *ctrl_buf; + /** Device status. */ + uint16_t status; + /** Device state. */ + uint8_t state; + /** Configuration value. */ + uint8_t cfg_value; + /** Control endpoint size. */ + uint8_t ctrl_size; +}; + +/** + * \brief USB Device Core Driver Instance + */ +static struct usbdc_driver usbdc; + +/** + * \brief Process the GetDescriptor request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_get_desc_req(const uint8_t ep, struct usb_req *req) +{ + uint8_t *cfg_desc, *str_desc; + uint16_t total_len; + uint16_t length = req->wLength; + uint8_t type = (uint8_t)(req->wValue >> 8); + uint8_t index = req->wValue & 0x00FF; + bool need_zlp = !(length & (usbdc.ctrl_size - 1)); + + switch (type) { + case USB_DT_DEVICE: + if (length > 0x12) { + length = 0x12; + } + usbdc_xfer(ep, usbdc.desces.ls_fs->sod, length, false); + return true; + case USB_DT_CONFIG: + cfg_desc = usb_find_cfg_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, index + 1); + if (NULL == cfg_desc) { + return false; + } + total_len = usb_cfg_desc_total_len(cfg_desc); + if (length <= total_len) { + need_zlp = false; + } else { + length = total_len; + } + usbdc_xfer(ep, cfg_desc, length, need_zlp); + return true; + case USB_DT_STRING: + str_desc = usb_find_str_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, index); + if (NULL == str_desc) { + return false; + } + total_len = str_desc[0]; + if (length <= total_len) { + need_zlp = false; + } else { + length = total_len; + } + usbdc_xfer(ep, str_desc, length, need_zlp); + return true; + + default: + break; + } + return false; +} + +/** + * \brief Process the GetStatus request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_get_status_req(const uint8_t ep, const struct usb_req *req) +{ + int32_t st; + (void)ep; + + switch (req->bmRequestType & USB_REQT_RECIP_MASK) { + case USB_REQT_RECIP_DEVICE: + case USB_REQT_RECIP_INTERFACE: + st = 0; + break; + case USB_REQT_RECIP_ENDPOINT: + st = usb_d_ep_halt(req->wIndex & 0xFF, USB_EP_HALT_GET); + if (st < 0) { + return false; + } + st = st & 0x1; + break; + default: + return false; + } + memcpy(usbdc.ctrl_buf, &st, 2); + usbdc_xfer(ep, usbdc.ctrl_buf, 2, false); + return true; +} + +/** + * \brief Process the standard Get Interface + * \param[in] req Point to usb request struct. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_get_interface(struct usb_req *req) +{ + struct usbdf_driver *func = (struct usbdf_driver *)usbdc.func_list.head; + int32_t rc; + + while (NULL != func) { + if (0 > (rc = func->ctrl(func, USBDF_GET_IFACE, req))) { + func = func->next; + } else { + usbdc.ctrl_buf[0] = (uint8_t)rc; + usbdc_xfer(0, usbdc.ctrl_buf, 1, false); + return true; + } + } + return false; +} + +/** + * \brief Process the standard Get request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_get_req(const uint8_t ep, struct usb_req *req) +{ + switch (req->bRequest) { + case USB_REQ_GET_DESC: + return usbdc_get_desc_req(ep, req); + case USB_REQ_GET_CONFIG: + *(uint8_t *)usbdc.ctrl_buf = usbdc.cfg_value; + usbdc_xfer(ep, usbdc.ctrl_buf, 1, false); + return true; + case USB_REQ_GET_STATUS: + return usbdc_get_status_req(ep, req); + case USB_REQ_GET_INTERFACE: + return usbdc_get_interface(req); + default: + return false; + } +} + +/** + * \brief Process the standard ClearFeature request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_clear_ftr_req(const uint8_t ep, const struct usb_req *req) +{ + (void)ep; + switch (req->bmRequestType & USB_REQT_RECIP_MASK) { + case USB_REQT_RECIP_ENDPOINT: + if (req->wLength != 0) { + return false; + } + usb_d_ep_halt(req->wIndex & 0xFF, USB_EP_HALT_CLR); + return true; + default: + return false; + } +} + +/** + * \brief Process the standard SetFeature request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_set_ftr_req(const uint8_t ep, const struct usb_req *req) +{ + (void)ep; + switch (req->bmRequestType & USB_REQT_RECIP_MASK) { + case USB_REQT_RECIP_ENDPOINT: + if (req->wLength != 0) { + return false; + } + usb_d_ep_halt(req->wIndex & 0xFF, USB_EP_HALT_SET); + return true; + default: + return false; + } +} + +/** + * \brief Unconfig, close all interfaces + */ +static void usbdc_unconfig(void) +{ + struct usbdf_driver *func = (struct usbdf_driver *)usbdc.func_list.head; + while (NULL != func) { + func->ctrl(func, USBDF_DISABLE, NULL); + func = func->next; + } +} + +/** + * \brief Apply Set Configuration Value + */ +static void usbdc_set_config(void) +{ + struct usbd_descriptors desc; + struct usbdf_driver * func; + uint8_t * cfg_desc; + uint16_t total_len; + uint8_t last_iface = 0xFF; + + if (usbdc.cfg_value == 0) { + usbdc_unconfig(); + return; + } + + cfg_desc = usb_find_cfg_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, usbdc.cfg_value); + + if (NULL == cfg_desc) { + return; + } + + total_len = usb_cfg_desc_total_len(cfg_desc); + desc.eod = cfg_desc + total_len; + desc.sod = usb_find_desc(cfg_desc, desc.eod, USB_DT_INTERFACE); + + while (NULL != desc.sod) { + /* Apply very first alternate setting (must be 0) of the interface */ + if (last_iface != desc.sod[2] /* bInterfaceNumber */) { + last_iface = desc.sod[2]; + func = (struct usbdf_driver *)usbdc.func_list.head; + while (NULL != func) { + if (func->ctrl(func, USBDF_ENABLE, &desc)) { + func = func->next; + } else { + break; + } + } + } + desc.sod = usb_desc_next(desc.sod); + desc.sod = usb_find_desc(desc.sod, desc.eod, USB_DT_INTERFACE); + } +} + +/** + * \brief Apply the USB device address + * \param[in] addr address to be set. + */ +static void usbdc_set_address(uint8_t addr) +{ + usb_d_set_address(addr); +} + +/** + * \brief Process the standard Set Interface + * \param[in] alt_set Alternate Setting. + * \param[in] ifc_id Interface Index. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_set_interface(uint16_t alt_set, uint16_t ifc_id) +{ + struct usbd_descriptors desc; + struct usbdf_driver * func; + uint8_t * ifc; + + desc.sod = usbdc.desces.ls_fs->sod; + desc.eod = usbdc.desces.ls_fs->eod; + if (NULL == (ifc = usb_find_desc(desc.sod, desc.eod, USB_DT_INTERFACE))) { + return false; + } + + while (ifc[2] != ifc_id || ifc[3] != alt_set) { + desc.sod = usb_desc_next(desc.sod); + ifc = usb_find_desc(desc.sod, desc.eod, USB_DT_INTERFACE); + if (NULL == ifc) { + return false; + } + } + + desc.sod = ifc; + func = (struct usbdf_driver *)usbdc.func_list.head; + + while (NULL != func) { + if (func->ctrl(func, USBDF_DISABLE, &desc)) { + func = func->next; + } else if (ERR_NONE == func->ctrl(func, USBDF_ENABLE, &desc)) { + usbdc_xfer(0, NULL, 0, 0); + return true; + } else { + return false; + } + } + + return false; +} + +/** + * \brief Process the standard Set request + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_set_req(const uint8_t ep, struct usb_req *req) +{ + switch (req->bRequest) { + case USB_REQ_SET_ADDRESS: + case USB_REQ_SET_CONFIG: + if (ERR_NONE == usbdc_xfer(ep, NULL, 0, true)) { + return true; + } else { + return false; + } + case USB_REQ_CLEAR_FTR: + return usbdc_clear_ftr_req(ep, req); + case USB_REQ_SET_FTR: + return usbdc_set_ftr_req(ep, req); + case USB_REQ_SET_INTERFACE: + return usbdc_set_interface(req->wValue, req->wIndex); + default: + return false; + } +} + +/** Invoke all registered SOF callbacks. */ +static void usbdc_sof_notify(void) +{ + struct usbdc_sof_handler *sof = (struct usbdc_sof_handler *)usbdc.handlers.sof_list.head; + + while (sof != NULL) { + if (NULL != sof->cb) { + sof->cb(); + } + sof = sof->next; + } +} + +/** Invoke all registered Change notification callbacks. */ +static void usbdc_change_notify(enum usbdc_change_type change, uint32_t value) +{ + struct usbdc_change_handler *cg = (struct usbdc_change_handler *)usbdc.handlers.change_list.head; + + while (cg != NULL) { + if (NULL != cg->cb) { + cg->cb(change, value); + } + cg = cg->next; + } +} + +/** Invoke all registered request callbacks until request handled. */ +static bool usbdc_request_handler(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage) +{ + struct usbdc_req_handler *h = (struct usbdc_req_handler *)usbdc.handlers.req_list.head; + int32_t rc; + + while (h != NULL) { + if (NULL != h->cb) { + rc = h->cb(ep, req, stage); + if (0 == rc) { + return true; + } else if (ERR_NOT_FOUND != rc) { + return false; + } + } + h = h->next; + } + return false; +} + +/** + * \brief Callback invoked on USB device SOF + */ +static void usbd_sof_cb(void) +{ + usbdc_sof_notify(); +} + +/** + * \brief Callback invoked when control request is received + * \param[in] ep Endpoint address. + * \param[in] req Pointer to the request. + * \return Operation status. + * \retval true Request is handled OK. + * \retval false Request not supported. + */ +static bool usbdc_cb_ctl_req(const uint8_t ep, struct usb_req *req) +{ + if (usbdc_request_handler(ep, req, USB_SETUP_STAGE)) { + return true; + } + + // STD request handling + switch (req->bmRequestType & (USB_REQT_TYPE_MASK | USB_REQT_DIR_IN)) { + case USB_REQT_TYPE_STANDARD: + return usbdc_set_req(ep, req); + case (USB_REQT_TYPE_STANDARD | USB_REQT_DIR_IN): + return usbdc_get_req(ep, req); + default: + return false; + } +} + +/** + * \brief When control status stage is end + * \param[in] req Pointer to the request. + */ +static void usbdc_ctrl_status_end(const struct usb_req *req) +{ + switch (req->bRequest) { + case USB_REQ_SET_CONFIG: + usbdc.cfg_value = req->wValue; + usbdc_set_config(); + usbdc.state = req->wValue ? USBD_S_CONFIG : USBD_S_ADDRESS; + usbdc_change_notify(USBDC_C_STATE, usbdc.state); + break; + case USB_REQ_SET_ADDRESS: + usbdc_set_address(req->wValue); + usbdc.state = req->wValue ? USBD_S_ADDRESS : USBD_S_DEFAULT; + usbdc_change_notify(USBDC_C_STATE, usbdc.state); + break; + default: + break; + } +} + +/** + * \brief When control data stage is end + * \param[in] req Pointer to the request. + */ +static bool usbdc_ctrl_data_end(struct usb_req *req) +{ + usbdc_request_handler(0, req, USB_DATA_STAGE); + return false; +} + +/** + * \brief Callback invoked when control data done or status done + * \param[in] ep Endpoint number with direction on bit 8. + * \param[in] code Status code. + * \param[in] req Pointer to the control setup request. + * \return Data has error or not. + * \retval true There is data error, protocol error. + * \retval false There is no data error. + */ +static bool usbdc_cb_ctl_done(const uint8_t ep, const enum usb_xfer_code code, struct usb_req *req) +{ + (void)ep; + + switch (code) { + case USB_XFER_DONE: + usbdc_ctrl_status_end(req); + break; + case USB_XFER_DATA: + return usbdc_ctrl_data_end(req); + default: + break; + } + return false; +} + +/** + * \brief USB Device Core Reset + */ +void usbdc_reset(void) +{ + usbdc_unconfig(); + + usbdc.state = USBD_S_DEFAULT; + usbdc.cfg_value = 0; + + // Setup EP0 + usb_d_ep_deinit(0); + usb_d_ep0_init(usbdc.ctrl_size); + usb_d_ep_register_callback(0, USB_D_EP_CB_SETUP, (FUNC_PTR)usbdc_cb_ctl_req); + usb_d_ep_register_callback(0, USB_D_EP_CB_XFER, (FUNC_PTR)usbdc_cb_ctl_done); + usb_d_ep_enable(0); +} + +/** + * \brief Callback invoked on USB device events + * \param[in] ev Event code. + * \param[in] param Event parameter for event handling. + */ +static void usbd_event_cb(const enum usb_event ev, const uint32_t param) +{ + (void)param; + + switch (ev) { + case USB_EV_VBUS: + usbdc_change_notify(USBDC_C_CONN, param); + break; + + case USB_EV_RESET: + usbdc_reset(); + break; + + default: + break; + } +} + +/** + * \brief Issue USB device transfer + */ +int32_t usbdc_xfer(uint8_t ep, uint8_t *buf, uint32_t size, bool zlp) +{ + struct usb_d_transfer xfer = {(uint8_t *)buf, size, ep, zlp}; + return usb_d_ep_transfer(&xfer); +} + +/** + * \brief Register the handler + */ +void usbdc_register_handler(enum usbdc_handler_type type, const struct usbdc_handler *h) +{ + switch (type) { + case USBDC_HDL_SOF: + list_insert_at_end(&usbdc.handlers.sof_list, (void *)h); + break; + case USBDC_HDL_REQ: + list_insert_at_end(&usbdc.handlers.req_list, (void *)h); + break; + case USBDC_HDL_CHANGE: + list_insert_at_end(&usbdc.handlers.change_list, (void *)h); + break; + default: + break; + } +} + +/** + * \brief Unregister the handler + */ +void usbdc_unregister_handler(enum usbdc_handler_type type, const struct usbdc_handler *h) +{ + switch (type) { + case USBDC_HDL_SOF: + list_delete_element(&usbdc.handlers.sof_list, (void *)h); + break; + case USBDC_HDL_REQ: + list_delete_element(&usbdc.handlers.req_list, (void *)h); + break; + case USBDC_HDL_CHANGE: + list_delete_element(&usbdc.handlers.change_list, (void *)h); + break; + default: + break; + } +} + +/** + * \brief Initialize the USB device core driver + */ +int32_t usbdc_init(uint8_t *ctrl_buf) +{ + ASSERT(ctrl_buf); + + int32_t rc; + + rc = usb_d_init(); + if (rc < 0) { + return rc; + } + + memset(&usbdc, 0, sizeof(usbdc)); + usbdc.ctrl_buf = ctrl_buf; + usb_d_register_callback(USB_D_CB_SOF, (FUNC_PTR)usbd_sof_cb); + usb_d_register_callback(USB_D_CB_EVENT, (FUNC_PTR)usbd_event_cb); + + return 0; +} + +/** + * \brief De-initialize the USB device core driver + */ +int32_t usbdc_deinit(void) +{ + usb_d_deinit(); + return 0; +} + +/** + * \brief Register/unregister function support of a USB device function + * + * Must be invoked when USB device is stopped. + */ +void usbdc_register_function(struct usbdf_driver *func) +{ + list_insert_at_end(&usbdc.func_list, func); +} + +/** + * \brief Unregister function support of a USB device function + * + * Must be invoked when USB device is stopped. + */ +void usbdc_unregister_function(struct usbdf_driver *func) +{ + list_delete_element(&usbdc.func_list, func); +} + +/** + * \brief Validate the descriptor + */ +int32_t usbdc_validate_desces(struct usbd_descriptors *desces) +{ + uint8_t *sod, *eod; + if (desces == NULL) { + return ERR_NOT_FOUND; + } + sod = usb_find_desc(desces->sod, desces->eod, USB_DT_DEVICE); + if (sod == NULL) { + return ERR_BAD_DATA; + } + sod = usb_find_desc(desces->sod, desces->eod, USB_DT_CONFIG); + if (sod == NULL) { + return ERR_BAD_DATA; + } + eod = sod + usb_cfg_desc_total_len(sod); + if (eod > desces->eod) { + return ERR_BAD_DATA; + } + return 0; +} + +/** + * \brief Validate the descriptor + */ +int32_t usbdc_check_desces(struct usbdc_descriptors *desces) +{ +#ifdef CONF_USBD_HS_SP + int32_t rc; + if (desces->hs == NULL && desces->ls_fs == NULL) { + return ERR_NOT_FOUND; + } + if (desces->hs) { + rc = usbdc_validate_desces(desces->hs); + if (rc < 0) { + return rc; + } + } +#endif + return usbdc_validate_desces(desces->ls_fs); +} + +/** + * \brief Start the USB device driver with specific descriptors set + */ +int32_t usbdc_start(struct usbd_descriptors *desces) +{ + if (usbdc.state >= USBD_S_POWER) { + return ERR_BUSY; + } + + if (desces) { + usbdc.desces.ls_fs = desces; + } else { + return ERR_BAD_DATA; + } + + usbdc.ctrl_size = desces->sod[7]; + usbdc.state = USBD_S_POWER; + usb_d_enable(); + return ERR_NONE; +} + +/** + * \brief Stop the USB device driver + */ +int32_t usbdc_stop(void) +{ + usb_d_disable(); + usbdc.state = USBD_S_OFF; + return ERR_NONE; +} + +/** + * \brief Attach the USB device to host + */ +void usbdc_attach(void) +{ + usb_d_attach(); +} + +/** + * \brief Detach the USB device from host + */ +void usbdc_detach(void) +{ + usb_d_detach(); +} + +/** + * \brief Send remote wakeup to host + */ +void usbdc_remotewakeup(void) +{ + usb_d_send_remotewakeup(); + usbdc.state = USBD_S_POWER; +} + +/** + * \brief Return USB Device endpoint0 buffer + */ +uint8_t *usbdc_get_ctrl_buffer(void) +{ + return usbdc.ctrl_buf; +} + +/** + * \brief Return current USB state + */ +uint8_t usbdc_get_state(void) +{ + if (usbdc.state & USBD_S_SUSPEND) { + return USBD_S_SUSPEND; + } + return usbdc.state; +} + +/** + * \brief Return version + */ +uint32_t usbdc_get_version(void) +{ + return USBDC_VERSION; +} diff --git a/atmel-samd/asf4/samd21/usb/device/usbdc.h b/atmel-samd/asf4/samd21/usb/device/usbdc.h new file mode 100644 index 000000000..515d28f1b --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/device/usbdc.h @@ -0,0 +1,246 @@ +/** + * \file + * + * \brief USB Device Stack Core Layer Definition. + * + * Copyright (C) 2015-2016 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _USB_USBDC_H_ +#define _USB_USBDC_H_ + +#include "usb_includes.h" +#include "usb_protocol.h" +#include "hal_usb_device.h" + +/** USB device states. */ +enum usbd_state { + USBD_S_OFF = 0, + USBD_S_POWER = 1, + USBD_S_DEFAULT = 2, + USBD_S_ADDRESS = 3, + USBD_S_CONFIG = 4, + USBD_S_SUSPEND = 0x10 +}; + +/** USB device core handler type. */ +enum usbdc_handler_type { USBDC_HDL_SOF, USBDC_HDL_REQ, USBDC_HDL_CHANGE }; + +/** USB device core change notification type. */ +enum usbdc_change_type { + /** Change of connection, detected by vbus. */ + USBDC_C_CONN, + /** Change of state, by RESET, SetAddress(), SetConfig(). */ + USBDC_C_STATE, + /** Change of power. */ + USBDC_C_POWER, + /** Change of remote wakeup setting. */ + USBDC_C_REMOTE_WAKEUP +}; + +/** Power change. */ +enum usbdc_power_type { USBDC_ACTIVE, USBDC_SLEEP, USBDC_SUSPEND }; + +/** USB device general function control code. */ +enum usbdf_control { + /** Enable the function. + * int32_t ctrl(usbdf, USBDF_ENABLE, struct usbd_descriptors *desc); + * Parameter holds interface descriptor and + * configuration descriptor end position. + */ + USBDF_ENABLE, + /** Disable the function. + * int32_t ctrl(usbdf, USBDF_DISABLE, struct usbd_descriptors *desc); + * Parameter holds interface descriptor and + * configuration descriptor end position. + * Input NULL to force disable the function anyway. + */ + USBDF_DISABLE, + /** Get interface alternate setting. + * int32_t ctrl(usbdf, USBDF_GET_IFACE, struct usb_req *req); + * Parameter holds interface number who should return + * the alternate setting. + */ + USBDF_GET_IFACE +}; + +/** Describes a list of USB descriptors. */ +struct usbd_descriptors { + /** Pointer to Start of Descriptors. */ + uint8_t *sod; + /** Pointer to End of Descriptors. */ + uint8_t *eod; +}; + +/** Describes the USB device core descriptors. */ +struct usbdc_descriptors { + struct usbd_descriptors *ls_fs; +#ifdef CONF_USBD_HS_SP + struct usbd_descriptors *hs; +#endif +}; + +/** Describes a list of core handler descriptor. */ +struct usbdc_handler { + /** Pointer to next handler. */ + struct usbdc_handler *next; + /** Pointer to handler function. */ + FUNC_PTR func; +}; + +/** Forward declaration for USB device function driver. */ +struct usbdf_driver; + +/** SOF handling function. */ +typedef void (*usbdc_sof_cb_t)(void); + +/** REQ handling function. */ +typedef int32_t (*usbdc_req_cb_t)(uint8_t ep, struct usb_req *req, enum usb_ctrl_stage stage); + +/** Change notification callback function. */ +typedef void (*usbdc_change_cb_t)(enum usbdc_change_type change, uint32_t value); + +/** Control function for USB device general function driver. */ +typedef int32_t (*usbdf_control_cb_t)(struct usbdf_driver *drv, enum usbdf_control ctrl, void *param); + +/** USB device general function driver descriptor. */ +struct usbdf_driver { + /** Pointer to next function.*/ + struct usbdf_driver *next; + /** Pointer to control function.*/ + usbdf_control_cb_t ctrl; + /** Pointer to function driver specific data. */ + void *func_data; +}; + +/** + * \brief Register the handler + * \param[in] type USB device core handler type. + * \param[in] h Pointer to usb device core handler. + */ +void usbdc_register_handler(enum usbdc_handler_type type, const struct usbdc_handler *h); + +/** + * \brief Unregister the handler + * \param[in] type USB device core handler type. + * \param[in] h Pointer to usb device core handler. + */ +void usbdc_unregister_handler(enum usbdc_handler_type type, const struct usbdc_handler *h); + +/** + * \brief Initialize the USB device core driver + * \param[in] ctrl_buf Pointer to a buffer to be used by usb device ctrl endpoint + * Note: the size of ctrl_buf should not be less than the size of EP0 + * \return Operation status. + */ +int32_t usbdc_init(uint8_t *ctrl_buf); + +/** + * \brief Deinitialize the USB device core driver + * \return Operation status. + */ +int32_t usbdc_deinit(void); + +/** + * \brief Register function support of a USB device function + * \param[in] func Pointer to usb device function driver structure + */ +void usbdc_register_function(struct usbdf_driver *func); + +/** + * \brief Unregister function support of a USB device function + * \param[in] func Pointer to usb device function driver structure + */ +void usbdc_unregister_function(struct usbdf_driver *func); + +/** + * \brief Validate the descriptors + * \param[in] desces Pointer to usb device core descriptors + * \return Operation status. + */ +int32_t usbdc_validate_desces(struct usbd_descriptors *desces); + +/** + * \brief Issue USB device data transfer + * \param[in] ep endpointer address. + * \param[in] buf Pointer to data transfer buffer. + * \param[in] size the size of data transfer. + * \param[in] zlp flag to indicate zero length packet. + * \return Operation status. + */ +int32_t usbdc_xfer(uint8_t ep, uint8_t *buf, uint32_t size, bool zlp); + +/** + * \brief Start the USB device driver with specific descriptors set + * \param[in] desces Pointer to usb device core descriptors + * \return Operation status. + */ +int32_t usbdc_start(struct usbd_descriptors *desces); + +/** + * \brief Stop the USB device driver + * \return Operation status. + */ +int32_t usbdc_stop(void); + +/** + * \brief Attach the USB device to host + */ +void usbdc_attach(void); + +/** + * \brief Detach the USB device from host + */ +void usbdc_detach(void); + +/** + * \brief Send remote wakeup to host + */ +void usbdc_remotewakeup(void); + +/** + * \brief Return USB device ctrl end pointer buffer start address + */ +uint8_t *usbdc_get_ctrl_buffer(void); + +/** + * \brief Return current USB state + */ +uint8_t usbdc_get_state(void); + +/** + * \brief Return version + */ +uint32_t usbdc_get_version(void); + +#endif /* USBDC_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/usb_atmel.h b/atmel-samd/asf4/samd21/usb/usb_atmel.h new file mode 100644 index 000000000..3ca7a2927 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/usb_atmel.h @@ -0,0 +1,189 @@ +/** + * \file + * + * \brief All USB VIDs and PIDs from Atmel USB applications + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> + */ + +#ifndef _USB_ATMEL_H_ +#define _USB_ATMEL_H_ + +/** + * \defgroup usb_group USB Stack + * + * This stack includes the USB Device Stack, USB Host Stack and common + * definitions. + * @{ + */ + +//! @} + +/** + * \ingroup usb_group + * \defgroup usb_atmel_ids_group Atmel USB Identifiers + * + * This module defines Atmel PID and VIDs constants. + * + * @{ + */ + +//! \name Vendor Identifier assigned by USB org to ATMEL +#define USB_VID_ATMEL 0x03EB + +//! \name Product Identifier assigned by ATMEL to AVR applications +//! @{ + +//! \name The range from 2000h to 20FFh is reserved to the old PID for C51, MEGA, and others. +//! @{ +#define USB_PID_ATMEL_MEGA_HIDGENERIC 0x2013 +#define USB_PID_ATMEL_MEGA_HIDKEYBOARD 0x2017 +#define USB_PID_ATMEL_MEGA_CDC 0x2018 +#define USB_PID_ATMEL_MEGA_AUDIO_IN 0x2019 +#define USB_PID_ATMEL_MEGA_MS 0x201A +#define USB_PID_ATMEL_MEGA_AUDIO_IN_OUT 0x201B +#define USB_PID_ATMEL_MEGA_HIDMOUSE 0x201C +#define USB_PID_ATMEL_MEGA_HIDMOUSE_CERTIF_U4 0x201D +#define USB_PID_ATMEL_MEGA_CDC_MULTI 0x201E +#define USB_PID_ATMEL_MEGA_MS_HIDMS_HID_USBKEY 0x2022 +#define USB_PID_ATMEL_MEGA_MS_HIDMS_HID_STK525 0x2023 +#define USB_PID_ATMEL_MEGA_MS_2 0x2029 +#define USB_PID_ATMEL_MEGA_MS_HIDMS 0x202A +#define USB_PID_ATMEL_MEGA_MS_3 0x2032 +#define USB_PID_ATMEL_MEGA_LIBUSB 0x2050 +//! @} + +//! \name The range 2100h to 21FFh is reserved to PIDs for AVR Tools. +//! @{ +#define USB_PID_ATMEL_XPLAINED 0x2122 +#define USB_PID_ATMEL_XMEGA_USB_ZIGBIT_2_4GHZ 0x214A +#define USB_PID_ATMEL_XMEGA_USB_ZIGBIT_SUBGHZ 0x214B +//! @} + +//! \name The range 2300h to 23FFh is reserved to PIDs for demo from ASF1.7=> +//! @{ +#define USB_PID_ATMEL_UC3_ENUM 0x2300 +#define USB_PID_ATMEL_UC3_MS 0x2301 +#define USB_PID_ATMEL_UC3_MS_SDRAM_LOADER 0x2302 +#define USB_PID_ATMEL_UC3_EVK1100_CTRLPANEL 0x2303 +#define USB_PID_ATMEL_UC3_HID 0x2304 +#define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID 0x2305 +#define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID_MS 0x2306 +#define USB_PID_ATMEL_UC3_CDC 0x2307 +#define USB_PID_ATMEL_UC3_AUDIO_MICRO 0x2308 +#define USB_PID_ATMEL_UC3_CDC_DEBUG 0x2310 // Virtual Com (debug interface) on EVK11xx +#define USB_PID_ATMEL_UC3_AUDIO_SPEAKER_MICRO 0x2311 +#define USB_PID_ATMEL_UC3_CDC_MSC 0x2312 +//! @} + +//! \name The range 2400h to 24FFh is reserved to PIDs for ASF applications +//! @{ +#define USB_PID_ATMEL_ASF_HIDMOUSE 0x2400 +#define USB_PID_ATMEL_ASF_HIDKEYBOARD 0x2401 +#define USB_PID_ATMEL_ASF_HIDGENERIC 0x2402 +#define USB_PID_ATMEL_ASF_MSC 0x2403 +#define USB_PID_ATMEL_ASF_CDC 0x2404 +#define USB_PID_ATMEL_ASF_PHDC 0x2405 +#define USB_PID_ATMEL_ASF_HIDMTOUCH 0x2406 +#define USB_PID_ATMEL_ASF_MSC_HIDMOUSE 0x2420 +#define USB_PID_ATMEL_ASF_MSC_HIDS_CDC 0x2421 +#define USB_PID_ATMEL_ASF_MSC_HIDKEYBOARD 0x2422 +#define USB_PID_ATMEL_ASF_VENDOR_CLASS 0x2423 +#define USB_PID_ATMEL_ASF_MSC_CDC 0x2424 +#define USB_PID_ATMEL_ASF_TWO_CDC 0x2425 +#define USB_PID_ATMEL_ASF_SEVEN_CDC 0x2426 +#define USB_PID_ATMEL_ASF_XPLAIN_BC_POWERONLY 0x2430 +#define USB_PID_ATMEL_ASF_XPLAIN_BC_TERMINAL 0x2431 +#define USB_PID_ATMEL_ASF_XPLAIN_BC_TOUCH 0x2432 +#define USB_PID_ATMEL_ASF_AUDIO_SPEAKER 0x2433 +#define USB_PID_ATMEL_ASF_XMEGA_B1_XPLAINED 0x2434 +//! @} + +//! \name The range 2F00h to 2FFFh is reserved to official PIDs for AVR bootloaders +//! Note, !!!! don't use this range for demos or examples !!!! +//! @{ +#define USB_PID_ATMEL_DFU_ATXMEGA64C3 0x2FD6 +#define USB_PID_ATMEL_DFU_ATXMEGA128C3 0x2FD7 +#define USB_PID_ATMEL_DFU_ATXMEGA16C4 0x2FD8 +#define USB_PID_ATMEL_DFU_ATXMEGA32C4 0x2FD9 +#define USB_PID_ATMEL_DFU_ATXMEGA256C3 0x2FDA +#define USB_PID_ATMEL_DFU_ATXMEGA384C3 0x2FDB +#define USB_PID_ATMEL_DFU_ATUCL3_L4 0x2FDC +#define USB_PID_ATMEL_DFU_ATXMEGA64A4U 0x2FDD +#define USB_PID_ATMEL_DFU_ATXMEGA128A4U 0x2FDE + +#define USB_PID_ATMEL_DFU_ATXMEGA64B3 0x2FDF +#define USB_PID_ATMEL_DFU_ATXMEGA128B3 0x2FE0 +#define USB_PID_ATMEL_DFU_ATXMEGA64B1 0x2FE1 +#define USB_PID_ATMEL_DFU_ATXMEGA256A3BU 0x2FE2 +#define USB_PID_ATMEL_DFU_ATXMEGA16A4U 0x2FE3 +#define USB_PID_ATMEL_DFU_ATXMEGA32A4U 0x2FE4 +#define USB_PID_ATMEL_DFU_ATXMEGA64A3U 0x2FE5 +#define USB_PID_ATMEL_DFU_ATXMEGA128A3U 0x2FE6 +#define USB_PID_ATMEL_DFU_ATXMEGA192A3U 0x2FE7 +#define USB_PID_ATMEL_DFU_ATXMEGA64A1U 0x2FE8 +#define USB_PID_ATMEL_DFU_ATUC3D 0x2FE9 +#define USB_PID_ATMEL_DFU_ATXMEGA128B1 0x2FEA +#define USB_PID_ATMEL_DFU_AT32UC3C 0x2FEB +#define USB_PID_ATMEL_DFU_ATXMEGA256A3U 0x2FEC +#define USB_PID_ATMEL_DFU_ATXMEGA128A1U 0x2FED +#define USB_PID_ATMEL_DFU_ATMEGA8U2 0x2FEE +#define USB_PID_ATMEL_DFU_ATMEGA16U2 0x2FEF +#define USB_PID_ATMEL_DFU_ATMEGA32U2 0x2FF0 +#define USB_PID_ATMEL_DFU_AT32UC3A3 0x2FF1 +#define USB_PID_ATMEL_DFU_ATMEGA32U6 0x2FF2 +#define USB_PID_ATMEL_DFU_ATMEGA16U4 0x2FF3 +#define USB_PID_ATMEL_DFU_ATMEGA32U4 0x2FF4 +#define USB_PID_ATMEL_DFU_AT32AP7200 0x2FF5 +#define USB_PID_ATMEL_DFU_AT32UC3B 0x2FF6 +#define USB_PID_ATMEL_DFU_AT90USB82 0x2FF7 +#define USB_PID_ATMEL_DFU_AT32UC3A 0x2FF8 +#define USB_PID_ATMEL_DFU_AT90USB64 0x2FF9 +#define USB_PID_ATMEL_DFU_AT90USB162 0x2FFA +#define USB_PID_ATMEL_DFU_AT90USB128 0x2FFB +// 2FFCh to 2FFFh used by C51 family products +//! @} + +//! @} + +//! @} + +#endif // _USB_ATMEL_H_ diff --git a/atmel-samd/asf4/samd21/usb/usb_debug.h b/atmel-samd/asf4/samd21/usb/usb_debug.h new file mode 100644 index 000000000..4d8893208 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/usb_debug.h @@ -0,0 +1,47 @@ +/** + * \file + * + * \brief USB Debug Files. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _USB_DEBUG_H_ +#define _USB_DEBUG_H_ + +#define udbg_print(...) + +#endif diff --git a/atmel-samd/asf4/samd21/usb/usb_includes.h b/atmel-samd/asf4/samd21/usb/usb_includes.h new file mode 100644 index 000000000..b3874d31e --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/usb_includes.h @@ -0,0 +1,137 @@ +/** + * \file + * + * \brief USB Include Header Files. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (C) 2015 - 2017 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _USB_INCLUDES_H_ +#define _USB_INCLUDES_H_ + +#ifdef USB_USER_INCLUDES + +#include "usb_user_includes.h" + +#else +/* Include START headers */ +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <utils.h> +#include <utils_list.h> +#include <utils_assert.h> +#include <hal_atomic.h> + +typedef uint16_t le16_t; +typedef uint32_t le32_t; +typedef uint16_t be16_t; +typedef uint32_t be32_t; + +#if (defined __GNUC__) || (defined __CC_ARM) +#define is_constant(exp) __builtin_constant_p(exp) +#else +#define is_constant(exp) (0) +#endif + +/*! \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define swap_u16(u16) ((uint16_t)(((uint16_t)(u16) >> 8) | ((uint16_t)(u16) << 8))) + +/*! \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#if (defined __GNUC__) +#define swap_u32(u32) \ + (is_constant(u32) \ + ? ((uint32_t)(((uint32_t)swap_u16((uint32_t)(u32) >> 16)) | ((uint32_t)swap_u16((uint32_t)(u32)) << 16))) \ + : ((uint32_t)__builtin_bswap32((uint32_t)(u32)))) +#else +#define swap_u32(u32) \ + ((uint32_t)(((uint32_t)swap_u16((uint32_t)(u32) >> 16)) | ((uint32_t)swap_u16((uint32_t)(u32)) << 16))) +#endif + +/** Get a value from/to LE16 data */ +#define LE16(x) (x) +/** Get a value from/to LE32 data */ +#define LE32(x) (x) +/** Get a value from/to BE16 data */ +#define BE16(x) swap_u16(x) +/** Get a value from/to BE32 data */ +#define BE32(x) swap_u32(x) + +/** Get byte 0 for BE 16-bit value */ +#define BE16B0(a) ((uint8_t)((a) >> 8)) +/** Get byte 1 for BE 16-bit value */ +#define BE16B1(a) ((uint8_t)((a) >> 0)) + +/** Get byte 0 for BE 32-bit value */ +#define BE32B0(a) ((uint8_t)((a) >> 24)) +/** Get byte 1 for BE 32-bit value */ +#define BE32B1(a) ((uint8_t)((a) >> 16)) +/** Get byte 2 for BE 32-bit value */ +#define BE32B2(a) ((uint8_t)((a) >> 8)) +/** Get byte 3 for BE 32-bit value */ +#define BE32B3(a) ((uint8_t)((a) >> 0)) + +/** Get byte 0 for LE 16-bit value */ +#define LE16B0(a) ((uint8_t)((a) >> 0)) +/** Get byte 1 for LE 16-bit value */ +#define LE16B1(a) ((uint8_t)((a) >> 8)) + +/** Get byte 0 for LE 32-bit value */ +#define LE32B0(a) ((uint8_t)((a) >> 0)) +/** Get byte 1 for LE 32-bit value */ +#define LE32B1(a) ((uint8_t)((a) >> 8)) +/** Get byte 2 for LE 32-bit value */ +#define LE32B2(a) ((uint8_t)((a) >> 16)) +/** Get byte 3 for LE 32-bit value */ +#define LE32B3(a) ((uint8_t)((a) >> 24)) + +#endif /* USB_USER_INCLUDES */ + +#endif /* _USB_INCLUDES_H_ */ diff --git a/atmel-samd/asf4/samd21/usb/usb_protocol.c b/atmel-samd/asf4/samd21/usb/usb_protocol.c new file mode 100644 index 000000000..534e4d1d9 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/usb_protocol.c @@ -0,0 +1,146 @@ +/** + * \file + * + * \brief USB protocol implementation. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#define CONF_NO_ASSERT_CHECK + +#include "usb_protocol.h" + +#ifdef CONF_NO_ASSERT_CHECK +#define _param_error_check(cond) +#define _desc_len_check() \ + if (usb_desc_len(desc) < 2) { \ + /* Encounter an invalid descriptor. */ \ + return NULL; \ + } +#else +#define _param_error_check(cond) ASSERT(cond) +#define _desc_len_check() ASSERT(usb_desc_len(desc) >= 2) +#endif + +uint8_t *usb_find_desc(uint8_t *desc, uint8_t *eof, uint8_t type) +{ + _param_error_check(desc && eof && (desc < eof)); + + while (desc < eof) { + _desc_len_check(); + if (type == usb_desc_type(desc)) { + return desc; + } + desc = usb_desc_next(desc); + } + return NULL; +} + +uint8_t *usb_find_iface_after(uint8_t *desc, uint8_t *eof, uint8_t iface_n) +{ + _param_error_check(desc && eof && (desc < eof)); + + while (desc < eof) { + _desc_len_check(); + if (USB_DT_INTERFACE == usb_desc_type(desc)) { + if (iface_n != desc[2]) { + return desc; + } + } + desc = usb_desc_next(desc); + } + return eof; +} + +uint8_t *usb_find_ep_desc(uint8_t *desc, uint8_t *eof) +{ + _param_error_check(desc && eof && (desc < eof)); + + while (desc < eof) { + _desc_len_check(); + if (USB_DT_INTERFACE == usb_desc_type(desc)) { + break; + } + if (USB_DT_ENDPOINT == usb_desc_type(desc)) { + return desc; + } + desc = usb_desc_next(desc); + } + return NULL; +} + +uint8_t *usb_find_cfg_desc(uint8_t *desc, uint8_t *eof, uint8_t cfg_value) +{ + _param_error_check(desc && eof && (desc < eof)); + + desc = usb_find_desc(desc, eof, USB_DT_CONFIG); + if (!desc) { + return NULL; + } + while (desc < eof) { + _desc_len_check(); + if (desc[1] != USB_DT_CONFIG) { + break; + } + if (desc[5] == cfg_value) { + return desc; + } + desc = usb_cfg_desc_next(desc); + } + return NULL; +} + +uint8_t *usb_find_str_desc(uint8_t *desc, uint8_t *eof, uint8_t str_index) +{ + uint8_t i; + + _param_error_check(desc && eof && (desc < eof)); + + for (i = 0; desc < eof;) { + desc = usb_find_desc(desc, eof, USB_DT_STRING); + if (desc) { + _desc_len_check(); + if (i == str_index) { + return desc; + } + i++; + desc = usb_desc_next(desc); + } else { + return NULL; + } + } + return NULL; +} diff --git a/atmel-samd/asf4/samd21/usb/usb_protocol.h b/atmel-samd/asf4/samd21/usb/usb_protocol.h new file mode 100644 index 000000000..bb8d1ecd5 --- /dev/null +++ b/atmel-samd/asf4/samd21/usb/usb_protocol.h @@ -0,0 +1,765 @@ +/** + * \file + * + * \brief USB protocol definitions. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _USB_PROTOCOL_H_ +#define _USB_PROTOCOL_H_ + +#include "usb_includes.h" + +/** + * \ingroup usb_group + * \defgroup usb_protocol_group USB Protocol Definitions + * + * This module defines constants and data structures provided by the USB + * 2.0 specification. + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __CC_ARM +#pragma anon_unions +#endif + +/*! Value for field bcdUSB */ +#define USB_V2_0 (0x0200) /*!< USB Specification version 2.00 */ +#define USB_V2_1 (0x0201) /*!< USB Specification version 2.01 (support BOS) */ + +/*! \name Generic definitions (Class, subclass and protocol) + */ +/*! @{ */ +#define USB_CLASS_NO (0x00) +#define USB_SUBCLASS_NO (0x00) +#define USB_PROTOCOL_NO (0x00) +/*! @} */ + +/*! \name IAD (Interface Association Descriptor) constants */ +/*! @{ */ +#define USB_CLASS_IAD (0xEF) +#define USB_SUBCLASS_IAD (0x02) +#define USB_PROTOCOL_IAD (0x01) +/*! @} */ + +/** + * \brief USB request data transfer direction (bmRequestType) + */ +#define USB_REQT_DIR_OUT (0 << 7) /*!< Host to device */ +#define USB_REQT_DIR_H2D (0 << 7) /*!< Host to device */ +#define USB_REQT_DIR_IN (1 << 7) /*!< Device to host */ +#define USB_REQT_DIR_D2H (1 << 7) /*!< Device to host */ +#define USB_REQT_DIR_MASK (1 << 7) /*!< Mask */ + +/** + * \brief USB request types (bmRequestType) + */ +#define USB_REQT_TYPE_STANDARD (0 << 5) /*!< Standard request */ +#define USB_REQT_TYPE_CLASS (1 << 5) /*!< Class-specific request */ +#define USB_REQT_TYPE_VENDOR (2 << 5) /*!< Vendor-specific request */ +#define USB_REQT_TYPE_MASK (3 << 5) /*!< Mask */ + +/** + * \brief USB recipient codes (bmRequestType) + */ +#define USB_REQT_RECIP_DEVICE (0 << 0) /*!< Recipient device */ +#define USB_REQT_RECIP_INTERFACE (1 << 0) /*!< Recipient interface */ +#define USB_REQT_RECIP_ENDPOINT (2 << 0) /*!< Recipient endpoint */ +#define USB_REQT_RECIP_OTHER (3 << 0) /*!< Recipient other */ +#define USB_REQT_RECIP_MASK (0x1F) /*!< Mask */ + +/** + * \brief Standard USB control transfer stages. + */ +enum usb_ctrl_stage { USB_SETUP_STAGE = 0, USB_DATA_STAGE = 1, USB_STATUS_STAGE = 2 }; + +/** + * \brief Standard USB requests (bRequest) + */ +enum usb_req_code { + USB_REQ_GET_STATUS = 0, + USB_REQ_CLEAR_FTR = 1, + USB_REQ_SET_FTR = 3, + USB_REQ_SET_ADDRESS = 5, + USB_REQ_GET_DESC = 6, + USB_REQ_SET_DESC = 7, + USB_REQ_GET_CONFIG = 8, + USB_REQ_SET_CONFIG = 9, + USB_REQ_GET_INTERFACE = 10, + USB_REQ_SET_INTERFACE = 11, + USB_REQ_SYNCH_FRAME = 12, + USB_REQ_SET_SEL = 48, + USB_REQ_ISOCH_DELAY = 49 +}; + +/** + * \brief Standard USB device status flags + * + */ +enum usb_dev_status { + USB_DEV_STAT_BUS_POWERED = 0, + USB_DEV_STAT_SELF_POWERED = 1, + USB_DEV_STAT_REMOTEWAKEUP = 2, + USB_DEV_STAT_U1_ENABLE = 4, + USB_DEV_STAT_U2_ENABLE = 8, + USB_DEV_STAT_LTM_ENABLE = 16 +}; + +/** + * \brief Standard USB Interface status flags + * + */ +enum usb_interface_status { + USB_IFACE_STAT_RESERVED = 0, + USB_IFACE_STAT_REMOTEWAKE_CAP = 1, + USB_IFACE_STAT_REMOTEWAKE = 2 +}; + +/** + * \brief Standard USB endpoint status flags + * + */ +enum usb_endpoint_status { USB_EP_STAT_HALT = 1 }; + +/** + * \brief Standard USB device feature flags + * + * \note valid for SetFeature request. + */ +enum usb_device_feature { + USB_DEV_FTR_REMOTE_WAKEUP = 1, /*!< Remote wakeup enabled */ + USB_DEV_FTR_TEST_MODE = 2, /*!< USB test mode */ + USB_DEV_FTR_OTG_B_HNP_ENABLE = 3, + USB_DEV_FTR_OTG_A_HNP_SP = 4, + USB_DEV_FTR_OTG_A_ALT_HNP_SP = 5, + USB_DEV_FTR_U1_ENABLE = 48, + USB_DEV_FTR_U2_ENABLE = 49, + USB_DEV_FTR_LTM_ENABLE = 50 +}; + +/** + * \brief Test Mode possible on HS USB device + * + * \note valid for USB_DEV_FTR_TEST_MODE request. + */ +enum usb_device_hs_test_mode { + USB_DEV_TEST_MODE_J = 1, + USB_DEV_TEST_MODE_K = 2, + USB_DEV_TEST_MODE_SE0_NAK = 3, + USB_DEV_TEST_MODE_PACKET = 4, + USB_DEV_TEST_MODE_FORCE_ENABLE = 5 +}; + +/** + * \brief Standard Feature Selectors for Interface + */ +enum usb_iface_feature { USB_IFACE_FTR_FUNC_SUSP = 0 }; + +/** + * \brief Standard USB endpoint feature/status flags + */ +enum usb_endpoint_feature { USB_EP_FTR_HALT = 0 }; + +/** + * \brief Standard USB Test Mode Selectors + */ +enum usb_test_mode_selector { + USB_TEST_J = 0x01, + USB_TEST_K = 0x02, + USB_TEST_SE0_NAK = 0x03, + USB_TEST_PACKET = 0x04, + USB_TEST_FORCE_ENABLE = 0x05 +}; + +/** + * \brief Standard USB descriptor types + */ +enum usb_descriptor_type { + USB_DT_DEVICE = 1, + USB_DT_CONFIG = 2, + USB_DT_STRING = 3, + USB_DT_INTERFACE = 4, + USB_DT_ENDPOINT = 5, + USB_DT_DEVICE_QUALIFIER = 6, + USB_DT_OTHER_SPEED_CONFIG = 7, + USB_DT_INTERFACE_POWER = 8, + USB_DT_OTG = 9, + USB_DT_DEBUG = 10, + USB_DT_IAD = 11, + USB_DT_BOS = 15, + USB_DT_DEV_CAP = 16, + USB_DT_SS_EP_COMPANION = 48 +}; + +/** + * \brief Capability types + */ +enum usb_capability_type { + USB_CAPT_WIRELESS = 1, + USB_CAPT_2_0_EXT = 2, + USB_CAPT_SUPER_SPEED = 3, + USB_CAPT_CONTAINER_ID = 4 +}; + +/** + * \brief USB 2.0 Extension attributes + */ +enum usb_2_0_ext_attr { USB_2_0_EXT_LPM_SP = 1 }; + +/** + * \brief USB SuperSpeed Capability attributes + */ +enum usb_ss_cap_attr { USB_SS_LTM_SP }; + +/** + * \brief USB Speed Supports + */ +enum usb_speed_sp { + USB_SPEED_LOW_SP = 1, + USB_SPEED_LS_SP = 1, + USB_SPEED_FULL_SP = 2, + USB_SPEED_FS_SP = 2, + USB_SPEED_HIGH_SP = 4, + USB_SPEED_HS_SP = 4, + USB_SPEED_SUPER_SP = 8, + USB_SPEED_SS_SP = 8 +}; + +/** + * \brief Standard USB endpoint transfer types + */ +enum usb_ep_type { + USB_EP_TYPE_CONTROL = 0x00, + USB_EP_TYPE_ISOCHRONOUS = 0x01, + USB_EP_TYPE_BULK = 0x02, + USB_EP_TYPE_INTERRUPT = 0x03, + USB_EP_TYPE_MASK = 0x03u +}; + +/** + * \brief USB endpoint interrupt types + */ +enum usb_ep_int_type { USB_EP_INT_T_PERIODIC = 0x00u, USB_EP_INT_T_NOTIFICATION = 0x01u, USB_EP_INT_T_MASK = 0x03u }; + +/** + * \brief Standard USB endpoint synchronization types + */ +enum usb_ep_sync_type { + USB_EP_SYNC_T_NO = 0x00u, + USB_EP_SYNC_T_ASYNC = 0x02u, + USB_EP_SYNC_T_ADAPTIVE = 0x02u, + USB_EP_SYNC_T_SYNC = 0x03u, + USB_EP_SYNC_T_MASK = 0x03u +}; + +/** + * \brief Standard USB endpoint usage types + */ +enum usb_ep_usage_type { + USB_EP_USAGE_T_DATA = 0x00u, + USB_EP_USAGE_T_FEEDBACK = 0x01u, + USB_EP_USAGE_T_FEEDBACK_DATA = 0x02u, + USB_EP_USAGE_T_MASK = 0x03u +}; + +/** + * \brief Standard USB language IDs for string descriptors + */ +enum usb_langid { + USB_LANGID_EN_US = 0x0409 /*!< English (United States) */ +}; + +/** + * \brief Mask selecting the index part of an endpoint address + */ +#define USB_EP_ADDR_MASK 0x0f +/** + * \brief Endpoint transfer direction is IN + */ +#define USB_EP_DIR_IN 0x80 +/** + * \brief Endpoint transfer direction is OUT + */ +#define USB_EP_DIR_OUT 0x00 + +/** + * \brief Maximum length in bytes of a USB descriptor + * + * The maximum length of a USB descriptor is limited by the 8-bit + * bLength field. + */ +#define USB_DESC_LEN_MAX 255 + +/* + * 2-byte alignment requested for all USB structures. + */ +COMPILER_PACK_SET(1) + +/** + * \brief A USB Device SETUP request + * + * The data payload of SETUP packets always follows this structure. + */ +typedef struct usb_req { + uint8_t bmRequestType; + uint8_t bRequest; + union { + le16_t wValue; + struct { + uint8_t l; + uint8_t h; + } wValueBytes; + }; + union { + le16_t wIndex; + struct { + uint8_t l; + uint8_t h; + } wIndexBytes; + }; + union { + le16_t wLength; + struct { + uint8_t l; + uint8_t h; + } wLengthBytes; + }; +} usb_req_t; + +/** + * \brief Standard USB device descriptor structure + */ +typedef struct usb_dev_desc { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + le16_t idVendor; + le16_t idProduct; + le16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} usb_dev_desc_t; + +/** + * \brief Binary device Object Store (BOS) descriptor structure + */ +typedef struct usb_bos_desc { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumDeviceCaps; +} usb_bos_desc_t; + +/** + * \brief Device Capability Descriptor structure + */ +typedef struct usb_cap_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t Vars[1]; +} usb_cap_desc_t; + +/** + * \brief USB 2.0 Extension Descriptor structure + */ +typedef struct usb_2_0_ext { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint32_t bmAttributes; +} usb_2_0_ext_t; + +/** + * \brief LPM Device Capabilities descriptor structure + */ +typedef struct usb_2_0_ext usb_lpm_cap_desc_t; + +/** + * \brief SuperSpeed USB Device Capability structure + */ +typedef struct usb_ss_cap_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bmAttributes; + le16_t wSpeedsSupported; + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint8_t bU2DevExitLat; +} usb_ss_cap_desc_t; + +/** + * \brief USB Container ID Descriptor structure + */ +typedef struct usb_container_id_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t ContainerID[16]; +} usb_container_id_desc_t; + +/** + * \brief Standard USB device qualifier descriptor structure + * + * This descriptor contains information about the device when running at + * the "other" speed (i.e. if the device is currently operating at high + * speed, this descriptor can be used to determine what would change if + * the device was operating at full speed.) + */ +typedef struct usb_dev_qual_desc { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +} usb_dev_qual_desc_t; + +/** + * \brief Standard USB configuration descriptor structure + */ +typedef struct usb_config_desc { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} usb_config_desc_t; + +#define USB_CONFIG_ATTR_MUST_SET (1 << 7) /*!< Must always be set */ +#define USB_CONFIG_ATTR_BUS_POWERED (0 << 6) /*!< Bus-powered */ +#define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) /*!< Self-powered */ +#define USB_CONFIG_ATTR_REMOTE_WAKEUP (1 << 5) /*!< remote wakeup supported */ + +#define USB_CONFIG_MAX_POWER(ma) (((ma) + 1) / 2) /*!< Max power in mA */ + +/** + * \brief Standard USB association descriptor structure + */ +typedef struct usb_iad_desc { + uint8_t bLength; /*!< Size of this descriptor in bytes */ + uint8_t bDescriptorType; /*!< Interface descriptor type */ + uint8_t bFirstInterface; /*!< Number of interface */ + uint8_t bInterfaceCount; /*!< value to select alternate setting */ + uint8_t bFunctionClass; /*!< Class code assigned by the USB */ + uint8_t bFunctionSubClass; /*!< Sub-class code assigned by the USB */ + uint8_t bFunctionProtocol; /*!< Protocol code assigned by the USB */ + uint8_t iFunction; /*!< Index of string descriptor */ +} usb_iad_desc_t; + +/** + * \brief Standard USB interface descriptor structure + */ +typedef struct usb_iface_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_iface_desc_t; + +/** + * \brief Standard USB endpoint descriptor structure + */ +typedef struct usb_ep_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + le16_t wMaxPacketSize; + uint8_t bInterval; +} usb_ep_desc_t; + +/** + * \brief SuperSpeed Endpoint Companion descriptor structure + */ +typedef struct usb_ss_ep_comp_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bmAttributes; + le16_t wBytesPerInterval; +} usb_ss_ep_comp_desc_t; + +/** + * \brief LPM Token bmAttributes structure + */ +typedef struct usb_lpm_attributes { + uint8_t bLinkState : 4; + uint8_t HIRD : 4; + uint8_t bRemoteWake : 1; + uint8_t Reserved : 2; +} usb_lpm_attributes_t; + +/** + * \brief A standard USB string descriptor structure + */ +typedef struct usb_str_desc { + uint8_t bLength; + uint8_t bDescriptorType; +} usb_str_desc_t; + +typedef struct usb_str_langid_desc { + usb_str_desc_t desc; + le16_t string[1]; +} usb_str_langid_desc_t; + +COMPILER_PACK_RESET() + +/** \name Macros to build USB standard descriptors */ +/*@{*/ + +/** Build bytes for USB device descriptor. */ +#define USB_DEV_DESC_BYTES(bcdUSB, \ + bDeviceClass, \ + bDeviceSubClass, \ + bDeviceProtocol, \ + bMaxPacketSize0, \ + idVendor, \ + idProduct, \ + bcdDevice, \ + iManufacturer, \ + iProduct, \ + iSerialNumber, \ + bNumConfigurations) \ + 18, /* bLength */ \ + 0x01, /* bDescriptorType: DEVICE */ \ + LE_BYTE0(bcdUSB), LE_BYTE1(bcdUSB), bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0, \ + LE_BYTE0(idVendor), LE_BYTE1(idVendor), LE_BYTE0(idProduct), LE_BYTE1(idProduct), LE_BYTE0(bcdDevice), \ + LE_BYTE1(bcdDevice), iManufacturer, iProduct, iSerialNumber, bNumConfigurations + +#define USB_DEV_DESC_LEN 18 + +/** Build bytes for USB configuration descriptor. */ +#define USB_CONFIG_DESC_BYTES( \ + wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration, bmAttributes, bMaxPower) \ + 9, /* bLength */ \ + 0x02, /* bDescriptorType: CONFIGURATION */ \ + LE_BYTE0(wTotalLength), LE_BYTE1(wTotalLength), bNumInterfaces, bConfigurationValue, iConfiguration, \ + bmAttributes, bMaxPower + +#define USB_CONFIG_DESC_LEN 9 + +/** Build bytes for USB IAD descriptor. */ +#define USB_IAD_DESC_BYTES( \ + bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol, iFunction) \ + 8, /* bLength */ \ + USB_DT_IAD, /* bDescriptorType */ \ + bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol, iFunction + +#define USB_IAD_DESC_LEN 8 + +/** Build bytes for USB interface descriptor. */ +#define USB_IFACE_DESC_BYTES(bInterfaceNumber, \ + bAlternateSetting, \ + bNumEndpoints, \ + bInterfaceClass, \ + bInterfaceSubClass, \ + bInterfaceProtocol, \ + iInterface) \ + 9, /* bLength */ \ + 0x04, /* bDescriptorType: INTERFACE */ \ + bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, \ + iInterface + +#define USB_IFACE_DESC_LEN 9 + +/** Build bytes for USB endpoint descriptor. */ +#define USB_ENDP_DESC_BYTES(bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \ + 7, /* bLength */ \ + 0x05, /* bDescriptorType: ENDPOINT */ \ + bEndpointAddress, bmAttributes, LE_BYTE0(wMaxPacketSize), LE_BYTE1(wMaxPacketSize), bInterval + +#define USB_ENDP_DESC_LEN 7 + +/*@}*/ + +/** \brief Get a word (calculate by little endian 16-bit data) + * \param[in] ptr Byte pointer to the address to get data + * \return a 16-bit word + */ +static inline uint16_t usb_get_u16(const uint8_t *ptr) +{ + return (ptr[0] + (ptr[1] << 8)); +} + +/** \brief Get a double word (calculate by little endian 32-bit data) + * \param[in] ptr Byte pointer to the address to get data + * \return a 32-bit word + */ +static inline uint32_t usb_get_u32(const uint8_t *ptr) +{ + return (ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24)); +} + +/** \brief Get descriptor length + * \param[in] desc Byte pointer to the descriptor start address + * \return descriptor length + */ +static inline uint8_t usb_desc_len(const uint8_t *desc) +{ + return desc[0]; +} + +/** \brief Get descriptor type + * \param[in] desc Byte pointer to the descriptor start address + * \return descriptor type + */ +static inline uint8_t usb_desc_type(const uint8_t *desc) +{ + return desc[1]; +} + +/** \brief Get next USB descriptor + * \param[in] desc Byte pointer to the descriptor start address + * \return Byte pointer to the next descriptor + */ +static inline uint8_t *usb_desc_next(uint8_t *desc) +{ + return (desc + usb_desc_len(desc)); +} + +/** \brief Get idVendor of USB Device Descriptor + * \param[in] dev_desc Byte pointer to the descriptor start address + * \return 16-bit idVendor value + */ +static inline uint16_t usb_dev_desc_vid(const uint8_t *dev_desc) +{ + return usb_get_u16(dev_desc + 8); +} + +/** \brief Get idProduct of USB Device Descriptor + * \param[in] dev_desc Byte pointer to the descriptor start address + * \return 16-bit idProduct value + */ +static inline uint16_t usb_dev_desc_pid(const uint8_t *dev_desc) +{ + return usb_get_u16(dev_desc + 10); +} + +/** \brief Get wTotalLength of USB Configuration Descriptor + * \param[in] cfg_desc Byte pointer to the descriptor start address + * \return 16-bit total length of configuration list + */ +static inline uint16_t usb_cfg_desc_total_len(const uint8_t *cfg_desc) +{ + return usb_get_u16(cfg_desc + 2); +} + +/** \brief Get Next USB Descriptor After the Configuration Descriptors list + * \param[in] cfg_desc Byte pointer to the descriptor start address + * \return Byte pointer to descriptor after configuration end + */ +static inline uint8_t *usb_cfg_desc_next(uint8_t *cfg_desc) +{ + return (cfg_desc + usb_cfg_desc_total_len(cfg_desc)); +} + +/** \brief Find specific USB Descriptor by its type + * \param[in] desc Byte pointer to the descriptor start address + * \param[in] eof Byte pointer to the descriptor end address + * \param[in] type The descriptor type expected + * \return Pointer to the descriptor + * \retval NULL if not found + */ +uint8_t *usb_find_desc(uint8_t *desc, uint8_t *eof, uint8_t type); + +/** Get interface descriptor next to the specified one (by interface number) + * \param[in] desc Byte pointer to the descriptor start address + * \param[in] eof Byte pointer to the descriptor end address + * \param[in] iface_n The interface number to check + * \return Pointer to the descriptor + * \retval >= eof if not found + */ +uint8_t *usb_find_iface_after(uint8_t *desc, uint8_t *eof, uint8_t iface_n); + +/** Find endpoint descriptor, breaks if interface descriptor detected + * \param[in] desc Byte pointer to the descriptor start address + * \param[in] eof Byte pointer to the descriptor end address + * \return Pointer to the descriptor + * \retval NULL if not found + */ +uint8_t *usb_find_ep_desc(uint8_t *desc, uint8_t *eof); + +/** Find configuration descriptor by its configuration number + * \param[in] desc Byte pointer to the descriptor start address + * \param[in] eof Byte pointer to the descriptor end address + * \param[in] cfg_value The configure value expected + * \return Pointer to the descriptor + * \retval NULL if not found + */ +uint8_t *usb_find_cfg_desc(uint8_t *desc, uint8_t *eof, uint8_t cfg_value); + +/** Find string descriptor by its index + * \param[in] desc Byte pointer to the descriptor start address + * \param[in] eof Byte pointer to the descriptor end address + * \param[in] str_index The string index expected + * \return Pointer to the descriptor + * \retval NULL if not found + */ +uint8_t *usb_find_str_desc(uint8_t *desc, uint8_t *eof, uint8_t str_index); + +#ifdef __cplusplus +} +#endif + +/*! @} */ + +#endif /* _USB_PROTOCOL_H_ */ |
