#include "samd51j18a.h"
#include <string.h>
#include <stdlib.h>
#include "conf_usb.h"
#include "udd.h"
#include "usb.h"
#include "status_codes.h"
#ifdef USB_DEVICE_HS_SUPPORT
# error The High speed mode is not supported on this part, please remove USB_DEVICE_HS_SUPPORT in conf_usb.h
#endif
#ifndef UDC_REMOTEWAKEUP_LPM_ENABLE
# define UDC_REMOTEWAKEUP_LPM_ENABLE()
#endif
#ifndef UDC_REMOTEWAKEUP_LPM_DISABLE
# define UDC_REMOTEWAKEUP_LPM_DISABLE()
#endif
#ifndef UDC_SUSPEND_LPM_EVENT
# define UDC_SUSPEND_LPM_EVENT()
#endif
#ifdef USB_DEBUG
# define dbg_print printf
#else
# define dbg_print(...)
#endif
#define UDD_ENDPOINT_MAX_TRANS ((8 * 1024) - 1)
struct usb_module usb_device;
#define UDD_CLOCK_GEN 0
static inline void udd_wait_clock_ready(void) {}
#define udd_sleep_mode(arg)
UDC_BSS(4)
uint8_t udd_ctrl_buffer[USB_DEVICE_EP_CTRL_SIZE];
typedef enum {
UDD_EPCTRL_SETUP = 0, UDD_EPCTRL_DATA_OUT = 1, UDD_EPCTRL_DATA_IN = 2, UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP = 3, UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP = 4, UDD_EPCTRL_STALL_REQ = 5, } udd_ctrl_ep_state_t;
udd_ctrl_request_t udd_g_ctrlreq;
static udd_ctrl_ep_state_t udd_ep_control_state;
static uint16_t udd_ctrl_prev_payload_nb_trans;
static uint16_t udd_ctrl_payload_nb_trans;
#if (defined USB_DEVICE_LOW_SPEED)
UDC_BSS(4) uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][8];
#elif (defined USB_DEVICE_HS_SUPPORT)
UDC_BSS(4) uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][512];
#else
UDC_BSS(4) uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][64];
#endif
typedef struct {
union {
udd_callback_trans_t call_trans;
udd_callback_halt_cleared_t call_nohalt;
};
uint8_t *buf;
iram_size_t buf_size;
iram_size_t nb_trans;
uint16_t ep_size;
uint8_t busy : 1;
uint8_t b_shortpacket : 1;
uint8_t b_use_out_cache_buffer : 1;
} udd_ep_job_t;
static udd_ep_job_t udd_ep_job[2 * USB_DEVICE_MAX_EP];
static udd_ep_job_t *udd_ep_get_job(udd_ep_id_t ep) {
if ((ep == 0) || (ep == 0x80)) {
return NULL;
} else {
return &udd_ep_job[(2 * (ep & USB_EP_ADDR_MASK) + ((ep & USB_EP_DIR_IN) ? 1 : 0)) - 2];
}
}
static void udd_ep_trans_in_next(void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
udd_ep_id_t ep = ep_callback_para->endpoint_address;
uint16_t ep_size, nb_trans;
uint16_t next_trans;
udd_ep_id_t ep_num;
udd_ep_job_t * ptr_job;
ptr_job = udd_ep_get_job(ep);
ep_num = ep & USB_EP_ADDR_MASK;
ep_size = ptr_job->ep_size;
nb_trans = ep_callback_para->sent_bytes;
ptr_job->nb_trans += nb_trans;
if (ptr_job->nb_trans != ptr_job->buf_size) {
next_trans = ptr_job->buf_size - ptr_job->nb_trans;
if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ep_size);
}
ptr_job->b_shortpacket = ptr_job->b_shortpacket && (0 == (next_trans % ep_size));
usb_device_endpoint_write_buffer_job(&usb_device, ep_num, &ptr_job->buf[ptr_job->nb_trans], next_trans);
return;
}
if (ptr_job->b_shortpacket) {
ptr_job->b_shortpacket = false;
usb_device_endpoint_write_buffer_job(&usb_device, ep_num, &ptr_job->buf[ptr_job->nb_trans], 0);
return;
}
ptr_job->busy = false;
if (NULL != ptr_job->call_trans) {
ptr_job->call_trans(UDD_EP_TRANSFER_OK, ptr_job->nb_trans, ep);
}
}
static void udd_ep_trans_out_next(void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
udd_ep_id_t ep = ep_callback_para->endpoint_address;
uint16_t ep_size, nb_trans;
uint16_t next_trans;
udd_ep_id_t ep_num;
udd_ep_job_t * ptr_job;
ptr_job = udd_ep_get_job(ep);
ep_num = ep & USB_EP_ADDR_MASK;
ep_size = ptr_job->ep_size;
nb_trans = ep_callback_para->received_bytes;
if (ptr_job->b_use_out_cache_buffer) {
memcpy(&ptr_job->buf[ptr_job->nb_trans], udd_ep_out_cache_buffer[ep_num - 1], ptr_job->buf_size % ep_size);
}
ptr_job->nb_trans += nb_trans;
if (ptr_job->nb_trans > ptr_job->buf_size) {
ptr_job->nb_trans = ptr_job->buf_size;
}
if ((nb_trans == ep_callback_para->out_buffer_size) && (ptr_job->nb_trans != ptr_job->buf_size)) {
next_trans = ptr_job->buf_size - ptr_job->nb_trans;
if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ep_size);
} else {
next_trans -= next_trans % ep_size;
}
if (next_trans < ep_size) {
ptr_job->b_use_out_cache_buffer = true;
usb_device_endpoint_read_buffer_job(&usb_device, ep_num, udd_ep_out_cache_buffer[ep_num - 1], ep_size);
} else {
usb_device_endpoint_read_buffer_job(&usb_device, ep_num, &ptr_job->buf[ptr_job->nb_trans], next_trans);
}
return;
}
ptr_job->busy = false;
if (NULL != ptr_job->call_trans) {
ptr_job->call_trans(UDD_EP_TRANSFER_OK, ptr_job->nb_trans, ep);
}
}
static void udd_ep_transfer_process(struct usb_module *module_inst, void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
udd_ep_id_t ep = ep_callback_para->endpoint_address;
if (ep & USB_EP_DIR_IN) {
udd_ep_trans_in_next(pointer);
} else {
udd_ep_trans_out_next(pointer);
}
}
void udd_ep_abort(udd_ep_id_t ep) {
udd_ep_job_t *ptr_job;
usb_device_endpoint_abort_job(&usb_device, ep);
ptr_job = udd_ep_get_job(ep);
if (!ptr_job->busy) {
return;
}
ptr_job->busy = false;
if (NULL != ptr_job->call_trans) {
ptr_job->call_trans(UDD_EP_TRANSFER_ABORT, ptr_job->nb_trans, ep);
}
}
bool udd_is_high_speed(void) { return false; }
uint16_t udd_get_frame_number(void) { return usb_device_get_frame_number(&usb_device); }
uint16_t udd_get_micro_frame_number(void) { return usb_device_get_micro_frame_number(&usb_device); }
void udd_ep_free(udd_ep_id_t ep) {
struct usb_device_endpoint_config config_ep;
usb_device_endpoint_get_config_defaults(&config_ep);
uint8_t ep_num = ep & USB_EP_ADDR_MASK;
udd_ep_abort(ep);
config_ep.ep_address = ep;
config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_DISABLE;
usb_device_endpoint_set_config(&usb_device, &config_ep);
usb_device_endpoint_unregister_callback(&usb_device, ep_num, USB_DEVICE_ENDPOINT_CALLBACK_TRCPT);
usb_device_endpoint_disable_callback(&usb_device, ep, USB_DEVICE_ENDPOINT_CALLBACK_TRCPT);
}
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) {
struct usb_device_endpoint_config config_ep;
usb_device_endpoint_get_config_defaults(&config_ep);
config_ep.ep_address = ep;
if (MaxEndpointSize <= 8) {
config_ep.ep_size = USB_ENDPOINT_8_BYTE;
} else if (MaxEndpointSize <= 16) {
config_ep.ep_size = USB_ENDPOINT_16_BYTE;
} else if (MaxEndpointSize <= 32) {
config_ep.ep_size = USB_ENDPOINT_32_BYTE;
} else if (MaxEndpointSize <= 64) {
config_ep.ep_size = USB_ENDPOINT_64_BYTE;
} else if (MaxEndpointSize <= 128) {
config_ep.ep_size = USB_ENDPOINT_128_BYTE;
} else if (MaxEndpointSize <= 256) {
config_ep.ep_size = USB_ENDPOINT_256_BYTE;
} else if (MaxEndpointSize <= 512) {
config_ep.ep_size = USB_ENDPOINT_512_BYTE;
} else if (MaxEndpointSize <= 1023) {
config_ep.ep_size = USB_ENDPOINT_1023_BYTE;
} else {
return false;
}
udd_ep_job_t *ptr_job = udd_ep_get_job(ep);
ptr_job->ep_size = MaxEndpointSize;
bmAttributes = bmAttributes & USB_EP_TYPE_MASK;
if (USB_EP_TYPE_ISOCHRONOUS == bmAttributes) {
config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_ISOCHRONOUS;
} else if (USB_EP_TYPE_BULK == bmAttributes) {
config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_BULK;
} else if (USB_EP_TYPE_INTERRUPT == bmAttributes) {
config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_INTERRUPT;
} else {
return false;
}
uint8_t ep_num = ep & USB_EP_ADDR_MASK;
if (STATUS_OK != usb_device_endpoint_set_config(&usb_device, &config_ep)) {
return false;
}
usb_device_endpoint_register_callback(&usb_device, ep_num, USB_DEVICE_ENDPOINT_CALLBACK_TRCPT, udd_ep_transfer_process);
usb_device_endpoint_enable_callback(&usb_device, ep, USB_DEVICE_ENDPOINT_CALLBACK_TRCPT);
usb_device_endpoint_enable_callback(&usb_device, ep, USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL);
return true;
}
bool udd_ep_is_halted(udd_ep_id_t ep) { return usb_device_endpoint_is_halted(&usb_device, ep); }
bool udd_ep_set_halt(udd_ep_id_t ep) {
uint8_t ep_num = ep & USB_EP_ADDR_MASK;
if (USB_DEVICE_MAX_EP < ep_num) {
return false;
}
usb_device_endpoint_set_halt(&usb_device, ep);
udd_ep_abort(ep);
return true;
}
bool udd_ep_clear_halt(udd_ep_id_t ep) {
udd_ep_job_t *ptr_job;
uint8_t ep_num = ep & USB_EP_ADDR_MASK;
if (USB_DEVICE_MAX_EP < ep_num) {
return false;
}
ptr_job = udd_ep_get_job(ep);
usb_device_endpoint_clear_halt(&usb_device, ep);
if (ptr_job->busy == true) {
ptr_job->busy = false;
ptr_job->call_nohalt();
}
return true;
}
bool udd_ep_wait_stall_clear(udd_ep_id_t ep, udd_callback_halt_cleared_t callback) {
udd_ep_id_t ep_num;
udd_ep_job_t *ptr_job;
ep_num = ep & USB_EP_ADDR_MASK;
if (USB_DEVICE_MAX_EP < ep_num) {
return false;
}
ptr_job = udd_ep_get_job(ep);
if (ptr_job->busy == true) {
return false;
}
if (usb_device_endpoint_is_halted(&usb_device, ep)) {
ptr_job->busy = true;
ptr_job->call_nohalt = callback;
return true;
} else if (usb_device_endpoint_is_configured(&usb_device, ep)) {
callback();
return true;
} else {
return false;
}
}
static void udd_ctrl_stall_data(void) {
udd_ep_control_state = UDD_EPCTRL_STALL_REQ;
usb_device_endpoint_set_halt(&usb_device, USB_EP_DIR_IN);
usb_device_endpoint_clear_halt(&usb_device, USB_EP_DIR_OUT);
}
bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t *buf, iram_size_t buf_size, udd_callback_trans_t callback) {
udd_ep_id_t ep_num;
udd_ep_job_t *ptr_job;
uint32_t irqflags;
ep_num = ep & USB_EP_ADDR_MASK;
if ((USB_DEVICE_MAX_EP < ep_num) || (udd_ep_is_halted(ep))) {
return false;
}
ptr_job = udd_ep_get_job(ep);
irqflags = __get_PRIMASK();
__disable_irq();
__DMB();
if (ptr_job->busy == true) {
__DMB();
__set_PRIMASK(irqflags);
return false;
}
ptr_job->busy = true;
__DMB();
__set_PRIMASK(irqflags);
ptr_job->buf = buf;
ptr_job->buf_size = buf_size;
ptr_job->nb_trans = 0;
ptr_job->call_trans = callback;
ptr_job->b_shortpacket = b_shortpacket;
ptr_job->b_use_out_cache_buffer = false;
uint16_t next_trans;
if (ep & USB_EP_DIR_IN) {
if (0 != ptr_job->buf_size) {
next_trans = ptr_job->buf_size;
if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ptr_job->ep_size);
}
ptr_job->b_shortpacket = ptr_job->b_shortpacket && (0 == (next_trans % ptr_job->ep_size));
} else if (true == ptr_job->b_shortpacket) {
ptr_job->b_shortpacket = false;
next_trans = 0;
} else {
ptr_job->busy = false;
if (NULL != ptr_job->call_trans) {
ptr_job->call_trans(UDD_EP_TRANSFER_OK, 0, ep);
}
return true;
}
return (STATUS_OK == usb_device_endpoint_write_buffer_job(&usb_device, ep_num, &ptr_job->buf[0], next_trans));
} else {
if (0 != ptr_job->buf_size) {
next_trans = ptr_job->buf_size;
if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ptr_job->ep_size);
} else {
next_trans -= next_trans % ptr_job->ep_size;
}
if (next_trans < ptr_job->ep_size) {
ptr_job->b_use_out_cache_buffer = true;
return (STATUS_OK == usb_device_endpoint_read_buffer_job(&usb_device, ep_num, udd_ep_out_cache_buffer[ep_num - 1], ptr_job->ep_size));
} else {
return (STATUS_OK == usb_device_endpoint_read_buffer_job(&usb_device, ep_num, &ptr_job->buf[0], next_trans));
}
} else {
ptr_job->busy = false;
if (NULL != ptr_job->call_trans) {
ptr_job->call_trans(UDD_EP_TRANSFER_OK, 0, ep);
}
return true;
}
}
}
void udd_set_address(uint8_t address) { usb_device_set_address(&usb_device, address); }
uint8_t udd_getaddress(void) { return usb_device_get_address(&usb_device); }
void udd_send_remotewakeup(void) {
uint32_t try
= 5;
udd_wait_clock_ready();
udd_sleep_mode(UDD_STATE_IDLE);
while (2 != usb_get_state_machine_status(&usb_device) && try --) {
usb_device_send_remote_wake_up(&usb_device);
}
}
void udd_set_setup_payload(uint8_t *payload, uint16_t payload_size) {
udd_g_ctrlreq.payload = payload;
udd_g_ctrlreq.payload_size = payload_size;
}
static void udd_ctrl_fetch_ram(void) {
udd_g_ctrlreq.req.bmRequestType = udd_ctrl_buffer[0];
udd_g_ctrlreq.req.bRequest = udd_ctrl_buffer[1];
udd_g_ctrlreq.req.wValue = ((uint16_t)(udd_ctrl_buffer[3]) << 8) + udd_ctrl_buffer[2];
udd_g_ctrlreq.req.wIndex = ((uint16_t)(udd_ctrl_buffer[5]) << 8) + udd_ctrl_buffer[4];
udd_g_ctrlreq.req.wLength = ((uint16_t)(udd_ctrl_buffer[7]) << 8) + udd_ctrl_buffer[6];
}
static void udd_ctrl_send_zlp_in(void) {
udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP;
usb_device_endpoint_setup_buffer_job(&usb_device, udd_ctrl_buffer);
usb_device_endpoint_write_buffer_job(&usb_device, 0, udd_g_ctrlreq.payload, 0);
}
static void udd_ctrl_in_sent(void) {
static bool b_shortpacket = false;
uint16_t nb_remain;
nb_remain = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans;
if (0 == nb_remain) {
udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans;
if ((udd_g_ctrlreq.req.wLength == udd_ctrl_prev_payload_nb_trans) || b_shortpacket) {
udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP;
usb_device_endpoint_setup_buffer_job(&usb_device, udd_ctrl_buffer);
return;
}
if ((!udd_g_ctrlreq.over_under_run) || (!udd_g_ctrlreq.over_under_run())) {
} else {
udd_ctrl_payload_nb_trans = 0;
nb_remain = udd_g_ctrlreq.payload_size;
}
}
if (nb_remain >= USB_DEVICE_EP_CTRL_SIZE) {
nb_remain = USB_DEVICE_EP_CTRL_SIZE;
b_shortpacket = false;
} else {
b_shortpacket = true;
}
usb_device_endpoint_write_buffer_job(&usb_device, 0, udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans, nb_remain);
udd_ctrl_payload_nb_trans += nb_remain;
}
static void udd_ctrl_out_received(void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
uint16_t nb_data;
nb_data = ep_callback_para->received_bytes;
if (udd_g_ctrlreq.payload_size < (udd_ctrl_payload_nb_trans + nb_data)) {
nb_data = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans;
}
memcpy((uint8_t *)(udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans), udd_ctrl_buffer, nb_data);
udd_ctrl_payload_nb_trans += nb_data;
if ((USB_DEVICE_EP_CTRL_SIZE != nb_data) || (udd_g_ctrlreq.req.wLength <= (udd_ctrl_prev_payload_nb_trans + udd_ctrl_payload_nb_trans))) {
udd_g_ctrlreq.payload_size = udd_ctrl_payload_nb_trans;
if (NULL != udd_g_ctrlreq.over_under_run) {
if (!udd_g_ctrlreq.over_under_run()) {
udd_ep_control_state = UDD_EPCTRL_STALL_REQ;
udd_ep_set_halt(0);
return;
}
}
udd_ctrl_send_zlp_in();
return;
}
if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_nb_trans) {
if (!udd_g_ctrlreq.over_under_run) {
udd_ep_control_state = UDD_EPCTRL_STALL_REQ;
udd_ep_set_halt(0);
return;
}
if (!udd_g_ctrlreq.over_under_run()) {
udd_ep_control_state = UDD_EPCTRL_STALL_REQ;
udd_ep_set_halt(0);
return;
}
udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans;
udd_ctrl_payload_nb_trans = 0;
}
usb_device_endpoint_read_buffer_job(&usb_device, 0, udd_ctrl_buffer, USB_DEVICE_EP_CTRL_SIZE);
}
static void _usb_ep0_on_setup(struct usb_module *module_inst, void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
if (UDD_EPCTRL_SETUP != udd_ep_control_state) {
if (NULL != udd_g_ctrlreq.callback) {
udd_g_ctrlreq.callback();
}
udd_ep_control_state = UDD_EPCTRL_SETUP;
}
if (8 != ep_callback_para->received_bytes) {
udd_ctrl_stall_data();
return;
} else {
udd_ctrl_fetch_ram();
if (false == udc_process_setup()) {
udd_ctrl_stall_data();
return;
} else if (Udd_setup_is_in()) {
udd_ctrl_prev_payload_nb_trans = 0;
udd_ctrl_payload_nb_trans = 0;
udd_ep_control_state = UDD_EPCTRL_DATA_IN;
usb_device_endpoint_read_buffer_job(&usb_device, 0, udd_ctrl_buffer, USB_DEVICE_EP_CTRL_SIZE);
udd_ctrl_in_sent();
} else {
if (0 == udd_g_ctrlreq.req.wLength) {
udd_ctrl_send_zlp_in();
return;
} else {
udd_ctrl_prev_payload_nb_trans = 0;
udd_ctrl_payload_nb_trans = 0;
udd_ep_control_state = UDD_EPCTRL_DATA_OUT;
usb_device_endpoint_read_buffer_job(&usb_device, 0, udd_ctrl_buffer, USB_DEVICE_EP_CTRL_SIZE);
}
}
}
}
static void udd_ctrl_underflow(void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
if (UDD_EPCTRL_DATA_OUT == udd_ep_control_state) {
udd_ctrl_send_zlp_in();
} else if (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state) {
usb_device_endpoint_set_halt(&usb_device, ep_callback_para->endpoint_address);
}
}
static void udd_ctrl_overflow(void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
if (UDD_EPCTRL_DATA_IN == udd_ep_control_state) {
udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP;
} else if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) {
usb_device_endpoint_set_halt(&usb_device, ep_callback_para->endpoint_address);
}
}
static void _usb_ep0_on_tansfer_fail(struct usb_module *module_inst, void *pointer) {
struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter *)pointer;
if (ep_callback_para->endpoint_address & USB_EP_DIR_IN) {
udd_ctrl_underflow(pointer);
} else {
udd_ctrl_overflow(pointer);
}
}
static void _usb_ep0_on_tansfer_ok(struct usb_module *module_inst, void *pointer) {
if (UDD_EPCTRL_DATA_OUT == udd_ep_control_state) {
udd_ctrl_out_received(pointer);
} else if (UDD_EPCTRL_DATA_IN == udd_ep_control_state) {
udd_ctrl_in_sent();
} else {
if (NULL != udd_g_ctrlreq.callback) {
udd_g_ctrlreq.callback();
}
udd_ep_control_state = UDD_EPCTRL_SETUP;
}
}
static void udd_ctrl_ep_enable(struct usb_module *module_inst) {
struct usb_device_endpoint_config config_ep0;
usb_device_endpoint_get_config_defaults(&config_ep0);
config_ep0.ep_size = (enum usb_endpoint_size)(32 - clz(((uint32_t)Min(Max(USB_DEVICE_EP_CTRL_SIZE, 8), 1024) << 1) - 1) - 1 - 3);
usb_device_endpoint_set_config(module_inst, &config_ep0);
usb_device_endpoint_setup_buffer_job(module_inst, udd_ctrl_buffer);
usb_device_endpoint_register_callback(module_inst, 0, USB_DEVICE_ENDPOINT_CALLBACK_RXSTP, _usb_ep0_on_setup);
usb_device_endpoint_register_callback(module_inst, 0, USB_DEVICE_ENDPOINT_CALLBACK_TRCPT, _usb_ep0_on_tansfer_ok);
usb_device_endpoint_register_callback(module_inst, 0, USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL, _usb_ep0_on_tansfer_fail);
usb_device_endpoint_enable_callback(module_inst, 0, USB_DEVICE_ENDPOINT_CALLBACK_RXSTP);
usb_device_endpoint_enable_callback(module_inst, 0, USB_DEVICE_ENDPOINT_CALLBACK_TRCPT);
usb_device_endpoint_enable_callback(module_inst, 0, USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL);
#ifdef USB_DEVICE_LPM_SUPPORT
usb_device_set_lpm_mode(module_inst, USB_DEVICE_LPM_ACK);
#endif
udd_ep_control_state = UDD_EPCTRL_SETUP;
}
static void _usb_on_suspend(struct usb_module *module_inst, void *pointer) {
usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP);
udd_sleep_mode(UDD_STATE_SUSPEND);
#ifdef UDC_SUSPEND_EVENT
UDC_SUSPEND_EVENT();
#endif
}
#ifdef USB_DEVICE_LPM_SUPPORT
static void _usb_device_lpm_suspend(struct usb_module *module_inst, void *pointer) {
dbg_print("LPM_SUSP\n");
uint32_t *lpm_wakeup_enable;
lpm_wakeup_enable = (uint32_t *)pointer;
usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP);
usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP);
udd_sleep_mode(UDD_STATE_SUSPEND_LPM); if ((*lpm_wakeup_enable)) {
UDC_REMOTEWAKEUP_LPM_ENABLE();
}
if (!(*lpm_wakeup_enable)) {
UDC_REMOTEWAKEUP_LPM_DISABLE();
}
UDC_SUSPEND_LPM_EVENT();
}
#endif
static void _usb_on_sof_notify(struct usb_module *module_inst, void *pointer) {
udc_sof_notify();
#ifdef UDC_SOF_EVENT
UDC_SOF_EVENT();
#endif
}
static void _usb_on_bus_reset(struct usb_module *module_inst, void *pointer) {
udc_reset();
usb_device_set_address(module_inst, 0);
udd_ctrl_ep_enable(module_inst);
}
static void _usb_on_wakeup(struct usb_module *module_inst, void *pointer) {
udd_wait_clock_ready();
usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND);
#ifdef USB_DEVICE_LPM_SUPPORT
usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP, _usb_device_lpm_suspend);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP);
#endif
udd_sleep_mode(UDD_STATE_IDLE);
#ifdef UDC_RESUME_EVENT
UDC_RESUME_EVENT();
#endif
}
void udd_detach(void) {
usb_device_detach(&usb_device);
udd_sleep_mode(UDD_STATE_SUSPEND);
}
void udd_attach(void) {
udd_sleep_mode(UDD_STATE_IDLE);
usb_device_attach(&usb_device);
usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND, _usb_on_suspend);
usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_SOF, _usb_on_sof_notify);
usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_RESET, _usb_on_bus_reset);
usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP, _usb_on_wakeup);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_SOF);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_RESET);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP);
#ifdef USB_DEVICE_LPM_SUPPORT
usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP, _usb_device_lpm_suspend);
usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP);
#endif
}
void udd_enable(void) {
uint32_t irqflags;
irqflags = __get_PRIMASK();
__disable_irq();
__DMB();
struct usb_config config_usb;
usb_get_config_defaults(&config_usb);
config_usb.source_generator = UDD_CLOCK_GEN;
usb_init(&usb_device, USB, &config_usb);
usb_enable(&usb_device);
udd_wait_clock_ready();
udd_sleep_mode(UDD_STATE_SUSPEND);
#ifndef USB_DEVICE_ATTACH_AUTO_DISABLE
udd_attach();
#endif
__DMB();
__set_PRIMASK(irqflags);
}
void udd_disable(void) {
udd_detach();
udd_sleep_mode(UDD_STATE_OFF);
}