diff options
author | Kévin Redon <kredon@sysmocom.de> | 2018-12-11 17:43:40 +0100 |
---|---|---|
committer | Kévin Redon <kredon@sysmocom.de> | 2019-01-09 15:33:36 +0100 |
commit | 8476b94ab008805db1e91d74fc47b1619953f48b (patch) | |
tree | aed8d9f0aaab2a07dc5c3c7d1bf7fae8ff396ead /usb |
use USB CDC Echo example project
this is the USB CDC Echo example project source code,
for the Microchip SAM E54 Xplained Pro development board,
based on the ATSAME54P20A micro-controller,
exported from the Atmel START website,
using the ASFv4 library.
Change-Id: Ic0e58e42d1a4076bc84a0a8d3509ec4b09a37f46
Diffstat (limited to 'usb')
-rw-r--r-- | usb/class/cdc/device/atmel_devices_cdc.cat | bin | 0 -> 8352 bytes | |||
-rw-r--r-- | usb/class/cdc/device/atmel_devices_cdc.inf | 182 | ||||
-rw-r--r-- | usb/class/cdc/device/cdcdf_acm.c | 379 | ||||
-rw-r--r-- | usb/class/cdc/device/cdcdf_acm.h | 108 | ||||
-rw-r--r-- | usb/class/cdc/device/cdcdf_acm_desc.h | 131 | ||||
-rw-r--r-- | usb/class/cdc/usb_protocol_cdc.h | 426 | ||||
-rw-r--r-- | usb/device/usbdc.c | 1027 | ||||
-rw-r--r-- | usb/device/usbdc.h | 249 | ||||
-rw-r--r-- | usb/usb_atmel.h | 179 | ||||
-rw-r--r-- | usb/usb_debug.h | 41 | ||||
-rw-r--r-- | usb/usb_includes.h | 131 | ||||
-rw-r--r-- | usb/usb_protocol.c | 161 | ||||
-rw-r--r-- | usb/usb_protocol.h | 782 |
13 files changed, 3796 insertions, 0 deletions
diff --git a/usb/class/cdc/device/atmel_devices_cdc.cat b/usb/class/cdc/device/atmel_devices_cdc.cat Binary files differnew file mode 100644 index 0000000..09a0673 --- /dev/null +++ b/usb/class/cdc/device/atmel_devices_cdc.cat diff --git a/usb/class/cdc/device/atmel_devices_cdc.inf b/usb/class/cdc/device/atmel_devices_cdc.inf new file mode 100644 index 0000000..d2df608 --- /dev/null +++ b/usb/class/cdc/device/atmel_devices_cdc.inf @@ -0,0 +1,182 @@ +; Windows 2000, XP, Vista, 7 and 8 (x32 and x64) setup file for Atmel CDC Devices +; Copyright (c) 2000-2013 ATMEL, Inc. + +[Version] +Signature = "$Windows NT$" +Class = Ports +ClassGuid = {4D36E978-E325-11CE-BFC1-08002BE10318} + +Provider = %Manufacturer% +LayoutFile = layout.inf +CatalogFile = atmel_devices_cdc.cat +DriverVer = 01/08/2013,6.0.0.0 + +;---------------------------------------------------------- +; Targets +;---------------------------------------------------------- +[Manufacturer] +%Manufacturer%=DeviceList, NTAMD64, NTIA64, NT + +[DeviceList] +%ATMEL_CDC_XPLAINED%=DriverInstall, USB\VID_03EB&PID_2122 +%ATMEL_CDC_USB_ZIGBIT_Sub%=DriverInstall, USB\VID_03EB&PID_214B +%ATMEL_CDC_USB_ZIGBIT_2_4%=DriverInstall, USB\VID_03EB&PID_214A +%ATMEL_CDC_SFW_EXAMPLE%=DriverInstall, USB\VID_03EB&PID_2307 +%ATMEL_CDC_EVK1XXX%=DriverInstall, USB\VID_03EB&PID_2310 +%ATMEL_CDC_ASF_EXAMPLE%=DriverInstall, USB\VID_03EB&PID_2404 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2%=DriverInstall, USB\VID_03EB&PID_2421&MI_00 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4%=DriverInstall, USB\VID_03EB&PID_2424&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM1%=DriverInstall, USB\VID_03EB&PID_2425&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM2%=DriverInstall, USB\VID_03EB&PID_2425&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM1%=DriverInstall, USB\VID_03EB&PID_2426&MI_00 +%ATMEL_CDC_ASF_EXAMPLE3_COM2%=DriverInstall, USB\VID_03EB&PID_2426&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM3%=DriverInstall, USB\VID_03EB&PID_2426&MI_04 +%ATMEL_CDC_ASF_EXAMPLE3_COM4%=DriverInstall, USB\VID_03EB&PID_2426&MI_06 +%ATMEL_CDC_ASF_EXAMPLE3_COM5%=DriverInstall, USB\VID_03EB&PID_2426&MI_08 +%ATMEL_CDC_ASF_EXAMPLE3_COM6%=DriverInstall, USB\VID_03EB&PID_2426&MI_0A +%ATMEL_CDC_ASF_EXAMPLE3_COM7%=DriverInstall, USB\VID_03EB&PID_2426&MI_0C + +[DeviceList.NTAMD64] +%ATMEL_CDC_XPLAINED%=DriverInstall.NTamd64, USB\VID_03EB&PID_2122 +%ATMEL_CDC_USB_ZIGBIT_Sub%=DriverInstall.NTamd64, USB\VID_03EB&PID_214B +%ATMEL_CDC_USB_ZIGBIT_2_4%=DriverInstall.NTamd64, USB\VID_03EB&PID_214A +%ATMEL_CDC_SFW_EXAMPLE%=DriverInstall.NTamd64, USB\VID_03EB&PID_2307 +%ATMEL_CDC_EVK1XXX%=DriverInstall.NTamd64, USB\VID_03EB&PID_2310 +%ATMEL_CDC_ASF_EXAMPLE%=DriverInstall.NTamd64, USB\VID_03EB&PID_2404 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2%=DriverInstall.NTamd64, USB\VID_03EB&PID_2421&MI_00 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4%=DriverInstall.NTamd64, USB\VID_03EB&PID_2424&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM1%=DriverInstall.NTamd64, USB\VID_03EB&PID_2425&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM2%=DriverInstall.NTamd64, USB\VID_03EB&PID_2425&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM1%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_00 +%ATMEL_CDC_ASF_EXAMPLE3_COM2%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM3%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_04 +%ATMEL_CDC_ASF_EXAMPLE3_COM4%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_06 +%ATMEL_CDC_ASF_EXAMPLE3_COM5%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_08 +%ATMEL_CDC_ASF_EXAMPLE3_COM6%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_0A +%ATMEL_CDC_ASF_EXAMPLE3_COM7%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_0C + +[DeviceList.NTIA64] +%ATMEL_CDC_XPLAINED%=DriverInstall.NTamd64, USB\VID_03EB&PID_2122 +%ATMEL_CDC_USB_ZIGBIT_Sub%=DriverInstall.NTamd64, USB\VID_03EB&PID_214B +%ATMEL_CDC_USB_ZIGBIT_2_4%=DriverInstall.NTamd64, USB\VID_03EB&PID_214A +%ATMEL_CDC_SFW_EXAMPLE%=DriverInstall.NTamd64, USB\VID_03EB&PID_2307 +%ATMEL_CDC_EVK1XXX%=DriverInstall.NTamd64, USB\VID_03EB&PID_2310 +%ATMEL_CDC_ASF_EXAMPLE%=DriverInstall.NTamd64, USB\VID_03EB&PID_2404 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2%=DriverInstall.NTamd64, USB\VID_03EB&PID_2421&MI_00 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4%=DriverInstall.NTamd64, USB\VID_03EB&PID_2424&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM1%=DriverInstall.NTamd64, USB\VID_03EB&PID_2425&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM2%=DriverInstall.NTamd64, USB\VID_03EB&PID_2425&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM1%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_00 +%ATMEL_CDC_ASF_EXAMPLE3_COM2%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM3%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_04 +%ATMEL_CDC_ASF_EXAMPLE3_COM4%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_06 +%ATMEL_CDC_ASF_EXAMPLE3_COM5%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_08 +%ATMEL_CDC_ASF_EXAMPLE3_COM6%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_0A +%ATMEL_CDC_ASF_EXAMPLE3_COM7%=DriverInstall.NTamd64, USB\VID_03EB&PID_2426&MI_0C + +[DeviceList.NT] +%ATMEL_CDC_XPLAINED%=DriverInstall.NT, USB\VID_03EB&PID_2122 +%ATMEL_CDC_USB_ZIGBIT_Sub%=DriverInstall.NT, USB\VID_03EB&PID_214B +%ATMEL_CDC_USB_ZIGBIT_2_4%=DriverInstall.NT, USB\VID_03EB&PID_214A +%ATMEL_CDC_SFW_EXAMPLE%=DriverInstall.NT, USB\VID_03EB&PID_2307 +%ATMEL_CDC_EVK1XXX%=DriverInstall.NT, USB\VID_03EB&PID_2310 +%ATMEL_CDC_ASF_EXAMPLE%=DriverInstall.NT, USB\VID_03EB&PID_2404 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2%=DriverInstall.NT, USB\VID_03EB&PID_2421&MI_00 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4%=DriverInstall.NT, USB\VID_03EB&PID_2424&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM1%=DriverInstall.NT, USB\VID_03EB&PID_2425&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM2%=DriverInstall.NT, USB\VID_03EB&PID_2425&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM1%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_00 +%ATMEL_CDC_ASF_EXAMPLE3_COM2%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_02 +%ATMEL_CDC_ASF_EXAMPLE3_COM3%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_04 +%ATMEL_CDC_ASF_EXAMPLE3_COM4%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_06 +%ATMEL_CDC_ASF_EXAMPLE3_COM5%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_08 +%ATMEL_CDC_ASF_EXAMPLE3_COM6%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_0A +%ATMEL_CDC_ASF_EXAMPLE3_COM7%=DriverInstall.NT, USB\VID_03EB&PID_2426&MI_0C + +;---------------------------------------------------------- +; Windows 2000, XP, Vista, Windows 7, Windows 8 - 32bit +;---------------------------------------------------------- +[Reader_Install.NTx86] + + +[DestinationDirs] +DefaultDestDir=12 +DriverInstall.NT.Copy=12 + +[DriverInstall.NT] +include=mdmcpq.inf +CopyFiles=DriverInstall.NT.Copy +AddReg=DriverInstall.NT.AddReg + +[DriverInstall.NT.Copy] +usbser.sys + +[DriverInstall.NT.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.NT.Services] +AddService = usbser, 0x00000002, DriverService.NT + +[DriverService.NT] +DisplayName = %Serial.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\usbser.sys +LoadOrderGroup = Base + +;---------------------------------------------------------- +; Windows XP, Vista, Windows 7, Windows 8 - 64bit +;---------------------------------------------------------- + +[DriverInstall.NTamd64] +include=mdmcpq.inf +CopyFiles=DriverCopyFiles.NTamd64 +AddReg=DriverInstall.NTamd64.AddReg + +[DriverCopyFiles.NTamd64] +usbser.sys,,,0x20 + +[DriverInstall.NTamd64.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.NTamd64.Services] +AddService=usbser, 0x00000002, DriverService.NTamd64 + +[DriverService.NTamd64] +DisplayName=%Serial.SvcDesc% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys + +;---------------------------------------------------------- +; String +;---------------------------------------------------------- + +[Strings] +Manufacturer = "ATMEL, Inc." +ATMEL_CDC_XPLAINED = "XPLAINED Virtual Com Port" +ATMEL_CDC_USB_ZIGBIT_Sub = "ZigBit SubGHz USBstick Com Port" +ATMEL_CDC_USB_ZIGBIT_2_4 = "ZigBit 2.4GHz USBstick Com Port" +ATMEL_CDC_SFW_EXAMPLE = "Communication Device Class SFW example" +ATMEL_CDC_EVK1XXX = "EVK1XXX Virtual Com Port" +ATMEL_CDC_ASF_EXAMPLE = "Communication Device Class ASF example" +ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2 = "Communication Device Class ASF composite example 2" +ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4 = "Communication Device Class ASF composite example 4" +ATMEL_CDC_ASF_EXAMPLE2_COM1 = "Communication Device Class ASF example2, COM1" +ATMEL_CDC_ASF_EXAMPLE2_COM2 = "Communication Device Class ASF example2, COM2" +ATMEL_CDC_ASF_EXAMPLE3_COM1 = "Communication Device Class ASF example3, COM1" +ATMEL_CDC_ASF_EXAMPLE3_COM2 = "Communication Device Class ASF example3, COM2" +ATMEL_CDC_ASF_EXAMPLE3_COM3 = "Communication Device Class ASF example3, COM3" +ATMEL_CDC_ASF_EXAMPLE3_COM4 = "Communication Device Class ASF example3, COM4" +ATMEL_CDC_ASF_EXAMPLE3_COM5 = "Communication Device Class ASF example3, COM5" +ATMEL_CDC_ASF_EXAMPLE3_COM6 = "Communication Device Class ASF example3, COM6" +ATMEL_CDC_ASF_EXAMPLE3_COM7 = "Communication Device Class ASF example3, COM7" + +Serial.SvcDesc = "USB Serial emulation driver" + diff --git a/usb/class/cdc/device/cdcdf_acm.c b/usb/class/cdc/device/cdcdf_acm.c new file mode 100644 index 0000000..2691cc8 --- /dev/null +++ b/usb/class/cdc/device/cdcdf_acm.c @@ -0,0 +1,379 @@ +/** + * \file + * + * \brief USB Device Stack CDC ACM Function Implementation. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \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/usb/class/cdc/device/cdcdf_acm.h b/usb/class/cdc/device/cdcdf_acm.h new file mode 100644 index 0000000..ad060bc --- /dev/null +++ b/usb/class/cdc/device/cdcdf_acm.h @@ -0,0 +1,108 @@ +/** + * \file + * + * \brief USB Device Stack CDC ACM Function Definition. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#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/usb/class/cdc/device/cdcdf_acm_desc.h b/usb/class/cdc/device/cdcdf_acm_desc.h new file mode 100644 index 0000000..ca29d33 --- /dev/null +++ b/usb/class/cdc/device/cdcdf_acm_desc.h @@ -0,0 +1,131 @@ +/** + * \file + * + * \brief USB Device Stack CDC ACM Function Descriptor Setting. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#ifndef USBDF_CDC_ACM_DESC_H_ +#define USBDF_CDC_ACM_DESC_H_ + +#include "usb_protocol.h" +#include "usb_protocol_cdc.h" +#include "usbd_config.h" + +#define CDCD_ACM_DEV_DESC \ + USB_DEV_DESC_BYTES(CONF_USB_CDCD_ACM_BCDUSB, \ + 0x02, \ + 0x00, \ + 0x00, \ + CONF_USB_CDCD_ACM_BMAXPKSZ0, \ + CONF_USB_CDCD_ACM_IDVENDER, \ + CONF_USB_CDCD_ACM_IDPRODUCT, \ + CONF_USB_CDCD_ACM_BCDDEVICE, \ + CONF_USB_CDCD_ACM_IMANUFACT, \ + CONF_USB_CDCD_ACM_IPRODUCT, \ + CONF_USB_CDCD_ACM_ISERIALNUM, \ + CONF_USB_CDCD_ACM_BNUMCONFIG) + +#define CDCD_ACM_DEV_QUAL_DESC \ + USB_DEV_QUAL_DESC_BYTES( \ + CONF_USB_CDCD_ACM_BCDUSB, 0x02, 0x00, 0x00, CONF_USB_CDCD_ACM_BMAXPKSZ0, CONF_USB_CDCD_ACM_BNUMCONFIG) + +#define CDCD_ACM_CFG_DESC \ + USB_CONFIG_DESC_BYTES(67, \ + 2, \ + CONF_USB_CDCD_ACM_BCONFIGVAL, \ + CONF_USB_CDCD_ACM_ICONFIG, \ + CONF_USB_CDCD_ACM_BMATTRI, \ + CONF_USB_CDCD_ACM_BMAXPOWER) + +#define CDCD_ACM_OTH_SPD_CFG_DESC \ + USB_OTH_SPD_CFG_DESC_BYTES(67, \ + 2, \ + CONF_USB_CDCD_ACM_BCONFIGVAL, \ + CONF_USB_CDCD_ACM_ICONFIG, \ + CONF_USB_CDCD_ACM_BMATTRI, \ + CONF_USB_CDCD_ACM_BMAXPOWER) + +#define CDCD_ACM_COMM_IFACE_DESCES \ + USB_IFACE_DESC_BYTES(CONF_USB_CDCD_ACM_COMM_BIFCNUM, \ + CONF_USB_CDCD_ACM_COMM_BALTSET, \ + 1, \ + 0x2, \ + 0x2, \ + 0x0, \ + CONF_USB_CDCD_ACM_COMM_IIFC), \ + 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_CDCD_ACM_COMM_BIFCNUM, 0x01), \ + USB_ENDP_DESC_BYTES(CONF_USB_CDCD_ACM_COMM_INT_EPADDR, \ + 3, \ + CONF_USB_CDCD_ACM_COMM_INT_MAXPKSZ, \ + CONF_USB_CDCD_ACM_COMM_INT_INTERVAL) + +#define CDCD_ACM_DATA_IFACE_DESCES \ + USB_IFACE_DESC_BYTES(CONF_USB_CDCD_ACM_DATA_BIFCNUM, \ + CONF_USB_CDCD_ACM_DATA_BALTSET, \ + 2, \ + 0x0A, \ + 0x0, \ + 0x0, \ + CONF_USB_CDCD_ACM_DATA_IIFC), \ + USB_ENDP_DESC_BYTES(CONF_USB_CDCD_ACM_DATA_BULKOUT_EPADDR, 2, CONF_USB_CDCD_ACM_DATA_BULKOUT_MAXPKSZ, 0), \ + USB_ENDP_DESC_BYTES(CONF_USB_CDCD_ACM_DATA_BULKIN_EPADDR, 2, CONF_USB_CDCD_ACM_DATA_BULKIN_MAXPKSZ, 0) + +#define CDCD_ACM_DATA_IFACE_DESCES_HS \ + USB_IFACE_DESC_BYTES(CONF_USB_CDCD_ACM_DATA_BIFCNUM, \ + CONF_USB_CDCD_ACM_DATA_BALTSET, \ + 2, \ + 0x0A, \ + 0x0, \ + 0x0, \ + CONF_USB_CDCD_ACM_DATA_IIFC), \ + USB_ENDP_DESC_BYTES(CONF_USB_CDCD_ACM_DATA_BULKOUT_EPADDR, 2, CONF_USB_CDCD_ACM_DATA_BULKOUT_MAXPKSZ_HS, 0), \ + USB_ENDP_DESC_BYTES(CONF_USB_CDCD_ACM_DATA_BULKIN_EPADDR, 2, CONF_USB_CDCD_ACM_DATA_BULKIN_MAXPKSZ_HS, 0) + +#define CDCD_ACM_STR_DESCES \ + CONF_USB_CDCD_ACM_LANGID_DESC \ + CONF_USB_CDCD_ACM_IMANUFACT_STR_DESC \ + CONF_USB_CDCD_ACM_IPRODUCT_STR_DESC \ + CONF_USB_CDCD_ACM_ISERIALNUM_STR_DESC \ + CONF_USB_CDCD_ACM_ICONFIG_STR_DESC + +/** USB Device descriptors and configuration descriptors */ +#define CDCD_ACM_DESCES_LS_FS \ + CDCD_ACM_DEV_DESC, CDCD_ACM_CFG_DESC, CDCD_ACM_COMM_IFACE_DESCES, CDCD_ACM_DATA_IFACE_DESCES, CDCD_ACM_STR_DESCES + +#define CDCD_ACM_HS_DESCES_LS_FS \ + CDCD_ACM_DEV_DESC, CDCD_ACM_DEV_QUAL_DESC, CDCD_ACM_CFG_DESC, CDCD_ACM_COMM_IFACE_DESCES, \ + CDCD_ACM_DATA_IFACE_DESCES, CDCD_ACM_OTH_SPD_CFG_DESC, CDCD_ACM_COMM_IFACE_DESCES, \ + CDCD_ACM_DATA_IFACE_DESCES_HS, CDCD_ACM_STR_DESCES + +#define CDCD_ACM_HS_DESCES_HS \ + CDCD_ACM_CFG_DESC, CDCD_ACM_COMM_IFACE_DESCES, CDCD_ACM_DATA_IFACE_DESCES_HS, CDCD_ACM_OTH_SPD_CFG_DESC, \ + CDCD_ACM_COMM_IFACE_DESCES, CDCD_ACM_DATA_IFACE_DESCES + +#endif /* USBDF_CDC_ACM_DESC_H_ */ diff --git a/usb/class/cdc/usb_protocol_cdc.h b/usb/class/cdc/usb_protocol_cdc.h new file mode 100644 index 0000000..29d882a --- /dev/null +++ b/usb/class/cdc/usb_protocol_cdc.h @@ -0,0 +1,426 @@ +/** + * \file + * + * \brief USB Communication Device Class (CDC) protocol definitions + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip 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 1 (mark) + CDC_PAR_SPACE = 4 //!< Parity forced to 0 (space) +}; +//@} + +//! \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() + +//! @} + +/** + * \brief Fill a CDC SetLineCoding request + * \param[out] req Pointer to the request to fill + * \param[in] iface Interface Number + */ +static inline void usb_fill_SetLineCoding_req(struct usb_req *req, uint8_t iface) +{ + req->bmRequestType = 0x21; + req->bRequest = USB_REQ_CDC_SET_LINE_CODING; + req->wValue = 0; + req->wIndex = iface; + req->wLength = sizeof(usb_cdc_line_coding_t); +} + +/** + * \brief Fill a CDC SetControlLineState request + * \param[out] req Pointer to the request to fill + * \param[in] iface Interface Number + * \param[in] ctrl Control Signal Bitmap + */ +static inline void usb_fill_SetControlLineState_req(struct usb_req *req, uint8_t iface, uint16_t ctrl) +{ + req->bmRequestType = 0x21; + req->bRequest = USB_REQ_CDC_SET_CONTROL_LINE_STATE; + req->wValue = ctrl; + req->wIndex = iface; + req->wLength = 0; +} + +#endif // _USB_PROTOCOL_CDC_H_ diff --git a/usb/device/usbdc.c b/usb/device/usbdc.c new file mode 100644 index 0000000..3cfd7bc --- /dev/null +++ b/usb/device/usbdc.c @@ -0,0 +1,1027 @@ +/** + * \file + * + * \brief USB Device Stack Core Layer Implementation. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \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; + /** Alternate interface used map */ + uint8_t ifc_alt_map; +}; + +/** + * \brief USB Device Core Driver Instance + */ +static struct usbdc_driver usbdc; + +/** + * \brief Process the GetDeviceDescriptor 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_dev_desc(const uint8_t ep, struct usb_req *req) +{ + uint8_t *dev_desc = NULL; + uint16_t length = req->wLength; + if (length > 0x12) { + length = 0x12; + } +#if CONF_USBD_HS_SP + if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) { + dev_desc = usb_find_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, USB_DT_DEVICE); + } else { + /* Obtain descriptor from FS descriptors */ + } +#endif + if (!dev_desc) { + dev_desc = usb_find_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, USB_DT_DEVICE); + } + if (!dev_desc) { + return false; + } + if (ERR_NONE != usbdc_xfer(ep, dev_desc, length, false)) { + return false; + } + return true; +} + +/** + * \brief Process the GetConfigurationDescriptor 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_cfg_desc(const uint8_t ep, struct usb_req *req) +{ + uint8_t *cfg_desc = NULL; + uint16_t total_len; + uint16_t length = req->wLength; + uint8_t index = req->wValue & 0x00FF; + bool need_zlp = !(length & (usbdc.ctrl_size - 1)); + +#if CONF_USBD_HS_SP + if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) { + cfg_desc = usb_find_cfg_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, index + 1); + } else { + /* Obtain descriptor from FS descriptors */ + } +#endif + if (!cfg_desc) { + 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; + } + if (ERR_NONE != usbdc_xfer(ep, cfg_desc, length, need_zlp)) { + return false; + } + return true; +} + +/** + * \brief Process the GetStringDescriptor 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_str_desc(const uint8_t ep, struct usb_req *req) +{ + uint8_t *str_desc; + uint16_t length = req->wLength; + uint8_t index = req->wValue & 0x00FF; + bool need_zlp = !(length & (usbdc.ctrl_size - 1)); + /* All string are in default descriptors block: FS/LS */ + str_desc = usb_find_str_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, index); + if (NULL == str_desc) { + return false; + } + if (length <= str_desc[0]) { + need_zlp = false; + } else { + length = str_desc[0]; + } + if (ERR_NONE != usbdc_xfer(ep, str_desc, length, need_zlp)) { + return false; + } + return true; +} + +#if CONF_USBD_HS_SP +/** + * \brief Process the GetDeviceQualifierDescriptor 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_devqual_desc(const uint8_t ep, struct usb_req *req) +{ + uint8_t *dev_desc = NULL; + uint16_t length = req->wLength; + if (length > 0x12) { + length = 0x12; + } + if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) { + dev_desc = usb_find_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, USB_DT_DEVICE_QUALIFIER); + } + if (!dev_desc) { + dev_desc = usb_find_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, USB_DT_DEVICE_QUALIFIER); + } + if (!dev_desc) { + return false; + } + if (ERR_NONE != usbdc_xfer(ep, dev_desc, length, false)) { + return false; + } + return true; +} + +/** + * \brief Process the GetOtherSpeedConfigurationDescriptor 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_othspdcfg_desc(const uint8_t ep, struct usb_req *req) +{ + uint8_t *cfg_desc = NULL; + uint16_t total_len; + uint16_t length = req->wLength; + uint8_t index = req->wValue & 0x00FF; + bool need_zlp = !(length & (usbdc.ctrl_size - 1)); + + if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) { + cfg_desc = usb_find_othspdcfg_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, index + 1); + } else { + /* Obtain descriptor from FS descriptors */ + } + if (!cfg_desc) { + cfg_desc = usb_find_othspdcfg_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; + } + if (ERR_NONE != usbdc_xfer(ep, cfg_desc, length, need_zlp)) { + return false; + } + return true; +} +#endif + +/** + * \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 type = (uint8_t)(req->wValue >> 8); + switch (type) { + case USB_DT_DEVICE: + return usbdc_get_dev_desc(ep, req); + case USB_DT_CONFIG: + return usbdc_get_cfg_desc(ep, req); +#if CONF_USBD_HS_SP + case USB_DT_DEVICE_QUALIFIER: + return usbdc_get_devqual_desc(ep, req); + case USB_DT_OTHER_SPEED_CONFIG: + return usbdc_get_othspdcfg_desc(ep, req); +#endif + case USB_DT_STRING: + return usbdc_get_str_desc(ep, req); + 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; + + if (!(usbdc.ifc_alt_map & (1 << req->wIndex))) { + /* Return 0 if alternate is not used */ + usbdc.ctrl_buf[0] = 0; + usbdc_xfer(0, usbdc.ctrl_buf, 1, false); + return true; + } + /* Check function drivers only if alternate is used */ + 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); + usbdc_xfer(ep, NULL, 0, true); + 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); + usbdc_xfer(ep, NULL, 0, true); + 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 + * \param[in] cfg_value Configuration Value + * \retval true Set configuration OK. + * \retval false Request error. + */ +static bool usbdc_set_config(uint8_t cfg_value) +{ + struct usbd_descriptors desc; + struct usbdf_driver * func; + uint8_t * cfg_desc = NULL; + uint16_t total_len; + uint8_t last_iface = 0xFF; + + if (cfg_value == 0) { + usbdc_unconfig(); + return true; + } + +#if CONF_USBD_HS_SP + if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) { + cfg_desc = usb_find_cfg_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, cfg_value); + } else { + /* Obtain descriptor from FS descriptors */ + } +#endif + if (!cfg_desc) { + cfg_desc = usb_find_cfg_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, cfg_value); + } + if (NULL == cfg_desc) { + return false; + } + + 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); + } + return true; +} + +/** + * \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 = NULL; + +#if CONF_USBD_HS_SP + if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) { + ifc = usb_find_cfg_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, usbdc.cfg_value); + } else { + /* Obtain descriptor from FS descriptors */ + } +#endif + if (!ifc) { + ifc = usb_find_cfg_desc(usbdc.desces.ls_fs->sod, usbdc.desces.ls_fs->eod, usbdc.cfg_value); + } + if (NULL == ifc) { + return false; + } + desc.sod = ifc; + desc.eod = ifc + usb_cfg_desc_total_len(ifc); + + 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)) { + if (alt_set) { + /* Alternate settings are used from now on */ + usbdc.ifc_alt_map |= 1 << ifc_id; + } + 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: + return (ERR_NONE == usbdc_xfer(ep, NULL, 0, true)); + case USB_REQ_SET_CONFIG: + if (!usbdc_set_config(req->wValue)) { + return false; + } + return (ERR_NONE == usbdc_xfer(ep, NULL, 0, true)); + 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 int32_t 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 -1; + } + } + 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) +{ + switch (usbdc_request_handler(ep, req, USB_SETUP_STAGE)) { + case true: + return true; + case -1: + return false; + default: + break; + } + + // 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) +{ + if (req->bmRequestType != USB_REQT_TYPE_STANDARD) { + return; + } + switch (req->bRequest) { + case USB_REQ_SET_CONFIG: + usbdc.cfg_value = req->wValue; + 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; + usbdc.ifc_alt_map = 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) +{ +#if 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; +#if CONF_USBD_HS_SP + usbdc.desces.hs = &desces[1]; +#endif + } 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/usb/device/usbdc.h b/usb/device/usbdc.h new file mode 100644 index 0000000..f741939 --- /dev/null +++ b/usb/device/usbdc.h @@ -0,0 +1,249 @@ +/** + * \file + * + * \brief USB Device Stack Core Layer Definition. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#ifndef _USB_USBDC_H_ +#define _USB_USBDC_H_ + +#include "usb_includes.h" +#include "usb_protocol.h" +#include "hal_usb_device.h" +#include "usbd_config.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; +#if 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 (FS/LS), + * or pointer to array of core descriptors (HS), the + * very first one includes device descriptor, FS/LS + * configuration descriptor, string descriptor, and + * may include device qualifier and other speed + * configuration descriptor; the second one includes + * high speed used descriptors. + * Note that string descriptor should be included in + * first place. + * \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/usb/usb_atmel.h b/usb/usb_atmel.h new file mode 100644 index 0000000..d7bbe59 --- /dev/null +++ b/usb/usb_atmel.h @@ -0,0 +1,179 @@ +/** + * \file + * + * \brief All USB VIDs and PIDs from Atmel USB applications + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip 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/usb/usb_debug.h b/usb/usb_debug.h new file mode 100644 index 0000000..b20c356 --- /dev/null +++ b/usb/usb_debug.h @@ -0,0 +1,41 @@ +/** + * \file + * + * \brief USB Debug Files. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#ifndef _USB_DEBUG_H_ +#define _USB_DEBUG_H_ + +#define udbg_print(...) + +#endif diff --git a/usb/usb_includes.h b/usb/usb_includes.h new file mode 100644 index 0000000..bcf99f7 --- /dev/null +++ b/usb/usb_includes.h @@ -0,0 +1,131 @@ +/** + * \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-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#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/usb/usb_protocol.c b/usb/usb_protocol.c new file mode 100644 index 0000000..9f6323e --- /dev/null +++ b/usb/usb_protocol.c @@ -0,0 +1,161 @@ +/** + * \file + * + * \brief USB protocol implementation. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#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_othspdcfg_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_OTHER_SPEED_CONFIG); + if (!desc) { + return NULL; + } + while (desc < eof) { + _desc_len_check(); + if (desc[1] != USB_DT_OTHER_SPEED_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/usb/usb_protocol.h b/usb/usb_protocol.h new file mode 100644 index 0000000..35e2833 --- /dev/null +++ b/usb/usb_protocol.h @@ -0,0 +1,782 @@ +/** + * \file + * + * \brief USB protocol definitions. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + */ + +#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_QUAL_DESC_BYTES( \ + bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0, bNumConfigurations) \ + 10, /* bLength */ \ + USB_DT_DEVICE_QUALIFIER, /* bDescriptorType: DEVICE_QUALIFIER */ \ + LE_BYTE0(bcdUSB), LE_BYTE1(bcdUSB), bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0, \ + bNumConfigurations, 0 + +#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_OTH_SPD_CFG_DESC_BYTES( \ + wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration, bmAttributes, bMaxPower) \ + 9, /* bLength */ \ + USB_DT_OTHER_SPEED_CONFIG, /* bDescriptorType: OTH_SPD_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 other speed 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_othspdcfg_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_ */ |