Open FFBoard
Open source force feedback firmware
usbd_control.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if CFG_TUD_ENABLED
30
31#include "dcd.h"
32#include "tusb.h"
33#include "device/usbd_pvt.h"
34
35//--------------------------------------------------------------------+
36// Callback weak stubs (called if application does not provide)
37//--------------------------------------------------------------------+
38TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
39 (void) rhport;
40 (void) request;
41}
42
43//--------------------------------------------------------------------+
44// MACRO CONSTANT TYPEDEF
45//--------------------------------------------------------------------+
46
47#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
49#endif
50
51enum {
53 EDPT_CTRL_IN = 0x80
54};
55
56typedef struct {
58 uint8_t* buffer;
59 uint16_t data_len;
60 uint16_t total_xferred;
63
65
66CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
67tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE];
68
69//--------------------------------------------------------------------+
70// Application API
71//--------------------------------------------------------------------+
72
73// Queue ZLP status transaction
74static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const* request) {
75 // Opposite to endpoint in Data Phase
76 uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
77 return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
78}
79
80// Status phase
82 _ctrl_xfer.request = (*request);
83 _ctrl_xfer.buffer = NULL;
86
87 return _status_stage_xact(rhport, request);
88}
89
90// Queue a transaction in Data Stage
91// Each transaction has up to Endpoint0's max packet size.
92// This function can also transfer an zero-length packet
93static bool _data_stage_xact(uint8_t rhport) {
94 uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred,
95 CFG_TUD_ENDPOINT0_SIZE);
96
97 uint8_t ep_addr = EDPT_CTRL_OUT;
98
100 ep_addr = EDPT_CTRL_IN;
101 if (xact_len) {
102 TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len));
103 }
104 }
105
106 return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len);
107}
108
109// Transmit data to/from the control endpoint.
110// If the request's wLength is zero, a status packet is sent instead.
111bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, void* buffer, uint16_t len) {
112 _ctrl_xfer.request = (*request);
113 _ctrl_xfer.buffer = (uint8_t*) buffer;
116
117 if (request->wLength > 0U) {
118 if (_ctrl_xfer.data_len > 0U) {
119 TU_ASSERT(buffer);
120 }
121
122// TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len);
123
124 // Data stage
125 TU_ASSERT(_data_stage_xact(rhport));
126 } else {
127 // Status stage
128 TU_ASSERT(_status_stage_xact(rhport, request));
129 }
130
131 return true;
132}
133
134//--------------------------------------------------------------------+
135// USBD API
136//--------------------------------------------------------------------+
137void usbd_control_reset(void);
140bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
141
143 tu_varclr(&_ctrl_xfer);
144}
145
146// Set complete callback
149}
150
151// for dcd_set_address where DCD is responsible for status response
153 _ctrl_xfer.request = (*request);
154 _ctrl_xfer.buffer = NULL;
157}
158
159// callback when a transaction complete on
160// - DATA stage of control endpoint or
161// - Status stage
162bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
163 (void) result;
164
165 // Endpoint Address is opposite to direction bit, this is Status Stage complete event
166 if (tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction) {
167 TU_ASSERT(0 == xferred_bytes);
168
169 // invoke optional dcd hook if available
171
173 // TODO refactor with usbd_driver_print_control_complete_name
175 }
176
177 return true;
178 }
179
181 TU_VERIFY(_ctrl_xfer.buffer);
182 memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes);
183 TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2);
184 }
185
186 _ctrl_xfer.total_xferred += (uint16_t) xferred_bytes;
187 _ctrl_xfer.buffer += xferred_bytes;
188
189 // Data Stage is complete when all request's length are transferred or
190 // a short packet is sent including zero-length packet.
192 (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE)) {
193 // DATA stage is complete
194 bool is_ok = true;
195
196 // invoke complete callback if set
197 // callback can still stall control in status phase e.g out data does not make sense
199 #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
201 #endif
202
204 }
205
206 if (is_ok) {
207 // Send status
208 TU_ASSERT(_status_stage_xact(rhport, &_ctrl_xfer.request));
209 } else {
210 // Stall both IN and OUT control endpoint
213 }
214 } else {
215 // More data to transfer
216 TU_ASSERT(_data_stage_xact(rhport));
217 }
218
219 return true;
220}
221
222#endif
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_ft9xx.c:905
uint8_t const * buffer
Definition: midi_device.h:100
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint16_t wLength
Definition: audio.h:840
uint16_t total_xferred
Definition: usbd_control.c:60
usbd_control_xfer_cb_t complete_cb
Definition: usbd_control.c:61
tusb_control_request_t request
Definition: usbd_control.c:57
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
static TU_ATTR_ALWAYS_INLINE int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count)
Definition: tusb_common.h:114
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
xfer_result_t
Definition: tusb_types.h:236
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
@ CONTROL_STAGE_ACK
Definition: tusb_types.h:270
@ CONTROL_STAGE_DATA
Definition: tusb_types.h:269
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: usbd.c:1309
static bool _data_stage_xact(uint8_t rhport)
Definition: usbd_control.c:93
tu_static usbd_control_xfer_t _ctrl_xfer
Definition: usbd_control.c:64
@ EDPT_CTRL_IN
Definition: usbd_control.c:53
@ EDPT_CTRL_OUT
Definition: usbd_control.c:52
static bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const *request)
Definition: usbd_control.c:74
void usbd_control_set_request(tusb_control_request_t const *request)
Definition: usbd_control.c:152
bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: usbd_control.c:162
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const *request, void *buffer, uint16_t len)
Definition: usbd_control.c:111
void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback)
Definition: usbd.c:392
TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request)
Definition: usbd_control.c:38
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]
Definition: usbd_control.c:67
bool tud_control_status(uint8_t rhport, tusb_control_request_t const *request)
Definition: usbd_control.c:81
void usbd_control_reset(void)
Definition: usbd_control.c:142
void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp)
Definition: usbd_control.c:147
bool(* usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: usbd_pvt.h:68
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259