Commit 9b0fd54f authored by swym's avatar swym Committed by Rahix
Browse files

feat(epicardium): Add ESB module

usb/epc_usb
====
Contains device-independent USB implementation, services MAXUSB stack
and is given the actual USB descriptors & callbacks on initialization.
Handles USB events and configures/deconfigures the device accordingly
during the USB setup procedure.

usb/mass_storage & cdcacm
====
Contain device-specific implementations, service MAXUSB's device class
APIs for cdcacm and mass storage.
Here, mass storage is independent of the underlying storage device.

modules/usb
====
Public apic_usb API, configuration and storage device management.
Defines the actual USB device descriptors and services the upc_usb API.

If we want to add SD card functionality, this would be the place to add
it.
parent ef12c8bb
......@@ -52,7 +52,7 @@
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTimerPendFunctionCall 1
/* Allow static allocation of data structures */
#define configSUPPORT_STATIC_ALLOCATION 1
......
/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*
* $Id: main.c 32120 2017-11-28 23:51:11Z lorne.smith $
*
*******************************************************************************
*/
/**
* @file main.c
* @brief USB CDC-ACM example
* @details This project creates a virtual COM port, which loops back data sent to it.
* Load the project, connect a cable from the PC to the USB connector
* on the Evaluation Kit, and observe that the PC now recognizes a new COM port.
* A driver for the COM port, if needed, is located in the Driver/ subdirectory.
*
*/
#include <stdio.h>
#include <stddef.h>
#include "mxc_config.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "board.h"
#include "led.h"
#include "usb.h"
#include "usb_event.h"
#include "enumerate.h"
#include "cdc_acm.h"
#include "descriptors.h"
#include "modules/modules.h"
#include "modules/log.h"
#include <errno.h>
/***** Definitions *****/
#define EVENT_ENUM_COMP MAXUSB_NUM_EVENTS
#define BUFFER_SIZE 64
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
/***** Global Data *****/
//SWYM: rename to CDC_xy or put into struct CDC_state
volatile int configured; //SWYM: actually unused...
volatile int suspended;
volatile unsigned int event_flags;
int remote_wake_en;
/***** Function Prototypes *****/
static int setconfig_callback(usb_setup_pkt *sud, void *cbdata);
static int setfeature_callback(usb_setup_pkt *sud, void *cbdata);
static int clrfeature_callback(usb_setup_pkt *sud, void *cbdata);
static int event_callback(maxusb_event_t evt, void *data);
static void usb_app_sleep(void);
static void usb_app_wakeup(void);
static int usb_read_callback(void);
//static void echo_usb(void);
/***** File Scope Variables *****/
/* This EP assignment must match the Configuration Descriptor */
static const acm_cfg_t acm_cfg = {
1, /* EP OUT */
MXC_USBHS_MAX_PACKET, /* OUT max packet size */
2, /* EP IN */
MXC_USBHS_MAX_PACKET, /* IN max packet size */
3, /* EP Notify */
MXC_USBHS_MAX_PACKET, /* Notify max packet size */
};
static volatile int usb_read_complete;
int usb_startup_cb()
{
const sys_cfg_usbhs_t sys_usbhs_cfg = NULL;
return SYS_USBHS_Init(&sys_usbhs_cfg);
}
int usb_shutdown_cb()
{
return SYS_USBHS_Shutdown();
}
/* User-supplied function to delay usec micro-seconds */
void delay_us(unsigned int usec)
{
/* mxc_delay() takes unsigned long, so can't use it directly */
mxc_delay(usec);
}
/******************************************************************************/
int cdcacm_init(void)
{
maxusb_cfg_options_t usb_opts;
/* Initialize state */
configured = 0;
suspended = 0;
event_flags = 0;
remote_wake_en = 0;
/* Start out in full speed */
usb_opts.enable_hs = 0;
usb_opts.delay_us =
delay_us; /* Function which will be used for delays */
usb_opts.init_callback = usb_startup_cb;
usb_opts.shutdown_callback = usb_shutdown_cb;
/* Initialize the usb module */
if (usb_init(&usb_opts) != 0) {
LOG_ERR("cdcacm", "usb_init() failed");
return -EIO;
}
/* Initialize the enumeration module */
if (enum_init() != 0) {
LOG_ERR("cdcacm", "enum_init() failed");
return -EIO;
}
/* Register enumeration data */
enum_register_descriptor(
ENUM_DESC_DEVICE, (uint8_t *)&device_descriptor, 0
);
enum_register_descriptor(
ENUM_DESC_CONFIG, (uint8_t *)&config_descriptor, 0
);
enum_register_descriptor(ENUM_DESC_STRING, lang_id_desc, 0);
enum_register_descriptor(ENUM_DESC_STRING, mfg_id_desc, 1);
enum_register_descriptor(ENUM_DESC_STRING, prod_id_desc, 2);
/* Handle configuration */
enum_register_callback(ENUM_SETCONFIG, setconfig_callback, NULL);
/* Handle feature set/clear */
enum_register_callback(ENUM_SETFEATURE, setfeature_callback, NULL);
enum_register_callback(ENUM_CLRFEATURE, clrfeature_callback, NULL);
/* Initialize the class driver */
if (acm_init(&config_descriptor.comm_interface_descriptor) != 0) {
LOG_ERR("cdcacm", "acm_init() failed");
return -EIO;
}
/* Register callbacks */
usb_event_enable(MAXUSB_EVENT_NOVBUS, event_callback, NULL);
usb_event_enable(MAXUSB_EVENT_VBUS, event_callback, NULL);
acm_register_callback(ACM_CB_READ_READY, usb_read_callback);
usb_read_complete = 0;
/* Start with USB in low power mode */
usb_app_sleep();
/* TODO: Fix priority */
NVIC_SetPriority(USB_IRQn, 6);
NVIC_EnableIRQ(USB_IRQn);
return 0;
}
int cdcacm_num_read_avail(void)
{
return acm_canread();
}
uint8_t cdcacm_read(void)
{
while (acm_canread() <= 0) {
}
uint8_t buf;
acm_read(&buf, 1);
return buf;
}
void cdcacm_write(uint8_t *data, int len)
{
static int lockup_disable = 0;
if (acm_present() && !lockup_disable) {
int ret = acm_write(data, len);
if (ret < 0) {
lockup_disable = 1;
LOG_ERR("cdcacm", "fifo lockup detected");
} else if (ret != len) {
LOG_WARN(
"cdcacm", "write length mismatch, got %d", ret
);
}
}
}
/******************************************************************************/
#if 0
static void echo_usb(void)
{
int chars;
uint8_t buffer[BUFFER_SIZE];
if ((chars = acm_canread()) > 0) {
if (chars > BUFFER_SIZE) {
chars = BUFFER_SIZE;
}
// Read the data from USB
if (acm_read(buffer, chars) != chars) {
printf("acm_read() failed\n");
return;
}
// Echo it back
if (acm_present()) {
if (acm_write(buffer, chars) != chars) {
printf("acm_write() failed\n");
}
}
}
}
#endif
/******************************************************************************/
static int setconfig_callback(usb_setup_pkt *sud, void *cbdata)
{
/* Confirm the configuration value */
if (sud->wValue ==
config_descriptor.config_descriptor.bConfigurationValue) {
configured = 1;
MXC_SETBIT(&event_flags, EVENT_ENUM_COMP);
return acm_configure(&acm_cfg); /* Configure the device class */
} else if (sud->wValue == 0) {
configured = 0;
return acm_deconfigure();
}
return -1;
}
/******************************************************************************/
static int setfeature_callback(usb_setup_pkt *sud, void *cbdata)
{
if (sud->wValue == FEAT_REMOTE_WAKE) {
remote_wake_en = 1;
} else {
// Unknown callback
return -1;
}
return 0;
}
/******************************************************************************/
static int clrfeature_callback(usb_setup_pkt *sud, void *cbdata)
{
if (sud->wValue == FEAT_REMOTE_WAKE) {
remote_wake_en = 0;
} else {
// Unknown callback
return -1;
}
return 0;
}
/******************************************************************************/
static void usb_app_sleep(void)
{
/* TODO: Place low-power code here */
suspended = 1;
}
/******************************************************************************/
static void usb_app_wakeup(void)
{
/* TODO: Place low-power code here */
suspended = 0;
}
/******************************************************************************/
static int event_callback(maxusb_event_t evt, void *data)
{
/* Set event flag */
MXC_SETBIT(&event_flags, evt);
switch (evt) {
case MAXUSB_EVENT_NOVBUS:
usb_event_disable(MAXUSB_EVENT_BRST);
usb_event_disable(MAXUSB_EVENT_SUSP);
usb_event_disable(MAXUSB_EVENT_DPACT);
usb_disconnect();
configured = 0;
enum_clearconfig();
acm_deconfigure();
usb_app_sleep();
break;
case MAXUSB_EVENT_VBUS:
usb_event_clear(MAXUSB_EVENT_BRST);
usb_event_enable(MAXUSB_EVENT_BRST, event_callback, NULL);
usb_event_clear(MAXUSB_EVENT_SUSP);
usb_event_enable(MAXUSB_EVENT_SUSP, event_callback, NULL);
usb_connect();
usb_app_sleep();
break;
case MAXUSB_EVENT_BRST:
usb_app_wakeup();
enum_clearconfig();
acm_deconfigure();
configured = 0;
suspended = 0;
break;
case MAXUSB_EVENT_SUSP:
usb_app_sleep();
break;
case MAXUSB_EVENT_DPACT:
usb_app_wakeup();
break;
default:
break;
}
return 0;
}
/******************************************************************************/
static int usb_read_callback(void)
{
usb_read_complete = 1;
return 0;
}
/******************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
void USB_IRQHandler(void)
{
usb_event_handler();
if (serial_task_id != NULL) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(
serial_task_id, &xHigherPriorityTaskWoken
);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
/******************************************************************************/
/* TODO: We probably need to fix something related to this */
#if 0
void SysTick_Handler(void)
{
mxc_delay_handler();
}
#endif /* 0 */
/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*
* Description: Communications Device Class ACM (Serial Port) over USB
* $Id: descriptors.h 36682 2018-08-06 21:14:03Z michael.bayern $
*
*******************************************************************************
*/
#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_
#include <stdint.h>
#include "usb.h"
#include "hid_kbd.h"
usb_device_descriptor_t __attribute__((aligned(4))) device_descriptor = {
0x12, /* bLength = 18 */
0x01, /* bDescriptorType = Device */
0x0110, /* bcdUSB USB spec rev (BCD) */
0x02, /* bDeviceClass = comm class (2) */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 is 64 bytes */
0x0B6A, /* idVendor (Maxim Integrated) */
0x003C, /* idProduct */
0x0100, /* bcdDevice */
0x01, /* iManufacturer Descriptor ID */
0x02, /* iProduct Descriptor ID */
0x00, /* iSerialNumber = (0) No string */
0x01 /* bNumConfigurations */
};
__attribute__((aligned(4)))
struct __attribute__((packed)) {
usb_configuration_descriptor_t config_descriptor;
usb_interface_descriptor_t comm_interface_descriptor;
uint8_t header_functional_descriptor[5];
uint8_t call_management_descriptor[5];
uint8_t acm_functional_descriptor[4];
uint8_t union_functional_descriptor[5];
usb_endpoint_descriptor_t endpoint_descriptor_3;
usb_interface_descriptor_t data_interface_descriptor;
usb_endpoint_descriptor_t endpoint_descriptor_1;
usb_endpoint_descriptor_t endpoint_descriptor_2;
} config_descriptor =
{
{
0x09, /* bLength = 9 */
0x02, /* bDescriptorType = Config (2) */
0x0043, /* wTotalLength(L/H) */
0x02, /* bNumInterfaces */
0x01, /* bConfigValue */
0x00, /* iConfiguration */
0xE0, /* bmAttributes (self-powered, remote wakeup) */
0x01, /* MaxPower is 2ma (units are 2ma/bit) */
},
{ /* First Interface Descriptor For Comm Class Interface */
0x09, /* bLength = 9 */
0x04, /* bDescriptorType = Interface (4) */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints (one for OUT) */
0x02, /* bInterfaceClass = Communications Interface Class (2) */
0x02, /* bInterfaceSubClass = Abstract Control Model (2) */
0x01, /* bInterfaceProtocol = Common "AT" commands (1), no class specific protocol (0) */
0x00, /* iInterface */
},
{ /* Header Functional Descriptor */
0x05, /* bFunctionalLength = 5 */
0x24, /* bDescriptorType */
0x00, /* bDescriptorSubtype */
0x10, 0x01, /* bcdCDC */
},
{ /* Call Management Descriptor */
0x05, /* bFunctionalLength = 5 */
0x24, /* bDescriptorType */
0x01, /* bDescriptorSubtype */
0x03, /* bmCapabilities = Device handles call management itself (0x01), management over data class (0x02) */
0x01, /* bmDataInterface */
},
{ /* Abstract Control Management Functional Descriptor */
0x04, /* bFunctionalLength = 4 */
0x24, /* bDescriptorType */
0x02, /* bDescriptorSubtype */
0x02, /* bmCapabilities */
},
{ /* Union Functional Descriptor */
0x05, /* bFunctionalLength = 5 */
0x24, /* bDescriptorType */
0x06, /* bDescriptorSubtype */
0x00, /* bmMasterInterface */
0x01, /* bmSlaveInterface0 */
},
{ /* IN Endpoint 3 (Descriptor #1) */
0x07, /* bLength */
0x05, /* bDescriptorType (Endpoint) */
0x83, /* bEndpointAddress (EP3-IN) */
0x03, /* bmAttributes (interrupt) */
0x0040, /* wMaxPacketSize */
0xff, /* bInterval (milliseconds) */
},
{ /* Second Interface Descriptor For Data Interface */
0x09, /* bLength */
0x04, /* bDescriptorType (Interface) */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x0a, /* bInterfaceClass = Data Interface (10) */
0x00, /* bInterfaceSubClass = none (0) */
0x00, /* bInterfaceProtocol = No class specific protocol (0) */
0x00, /* biInterface = No Text String (0) */
},
{ /* OUT Endpoint 1 (Descriptor #2) */
0x07, /* bLength */
0x05, /* bDescriptorType (Endpoint) */
0x01, /* bEndpointAddress (EP1-OUT) */
0x02, /* bmAttributes (bulk) */
0x0040, /* wMaxPacketSize */
0x00, /* bInterval (N/A) */
},
{ /* IN Endpoint 2 (Descriptor #3) */
0x07, /* bLength */
0x05, /* bDescriptorType (Endpoint) */
0x82, /* bEndpointAddress (EP2-IN) */
0x02, /* bmAttributes (bulk) */
0x0040, /* wMaxPacketSize */
0x00 /* bInterval (N/A) */
}
};
__attribute__((aligned(4)))
uint8_t lang_id_desc[] = {
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, 0x04 /* bString = wLANGID (see usb_20.pdf 9.6.7 String) */
};
__attribute__((aligned(4)))
uint8_t mfg_id_desc[] = {
0x22, /* bLength */
0x03, /* bDescriptorType */
'M', 0,
'a', 0,
'x', 0,
'i', 0,
'm', 0,
' ', 0,
'I', 0,
'n', 0,
't', 0,
'e', 0,
'g', 0,
'r', 0,
'a', 0,
't', 0,
'e', 0,
'd', 0,
};
__attribute__((aligned(4)))
uint8_t prod_id_desc[] = {
0x22, /* bLength */
0x03, /* bDescriptorType */
'M', 0,
'A', 0,
'X', 0,
'3', 0,
'2', 0,
'6', 0,
'6', 0,
'5', 0,
' ', 0,
'C', 0,
'D', 0,
'C', 0,
'-', 0,
'A', 0,
'C', 0,
'M', 0,
};
/* Not currently used (see device descriptor), but could be enabled if desired */
__attribute__((aligned(4)))
uint8_t serial_id_desc[] = {
0x14, /* bLength */
0x03, /* bDescriptorType */
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'1', 0
};
#endif /* _DESCRIPTORS_H_ */
......@@ -131,6 +131,10 @@ typedef _Bool bool;
#define API_MAX86150_GET_DATA 0x0101
#define API_MAX86150_SET_LED_AMPLITUDE 0x0102
#define API_USB_SHUTDOWN 0x110
#define API_USB_STORAGE 0x111
#define API_USB_CDCACM 0x112
/* clang-format on */