Open FFBoard
Open source force feedback firmware
bth_device.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2020 Jerzy Kasenberg
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 && CFG_TUD_BTH)
30
31//--------------------------------------------------------------------+
32// INCLUDE
33//--------------------------------------------------------------------+
34#include "bth_device.h"
35#include <device/usbd_pvt.h>
36
37//--------------------------------------------------------------------+
38// MACRO CONSTANT TYPEDEF
39//--------------------------------------------------------------------+
40typedef struct
41{
42 uint8_t itf_num;
43 uint8_t ep_ev;
44 uint8_t ep_acl_in;
46 uint8_t ep_acl_out;
47 uint8_t ep_voice[2]; // Not used yet
48 uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT];
49
50 // Previous amount of bytes sent when issuing ZLP
52
53 // Endpoint Transfer buffer
54 CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd;
55 CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE];
56
58
59//--------------------------------------------------------------------+
60// INTERNAL OBJECT & FUNCTION DECLARATION
61//--------------------------------------------------------------------+
62CFG_TUD_MEM_SECTION btd_interface_t _btd_itf;
63
64static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
65{
66 uint8_t const rhport = 0;
67
68 // skip if previous transfer not complete
69 TU_VERIFY(!usbd_edpt_busy(rhport, ep));
70
71 TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len));
72
73 return true;
74}
75
76//--------------------------------------------------------------------+
77// READ API
78//--------------------------------------------------------------------+
79
80
81//--------------------------------------------------------------------+
82// WRITE API
83//--------------------------------------------------------------------+
84
85bool tud_bt_event_send(void *event, uint16_t event_len)
86{
87 return bt_tx_data(_btd_itf.ep_ev, event, event_len);
88}
89
90bool tud_bt_acl_data_send(void *event, uint16_t event_len)
91{
92 return bt_tx_data(_btd_itf.ep_acl_in, event, event_len);
93}
94
95//--------------------------------------------------------------------+
96// USBD Driver API
97//--------------------------------------------------------------------+
98void btd_init(void) {
99 tu_memclr(&_btd_itf, sizeof(_btd_itf));
100}
101
102bool btd_deinit(void) {
103 return true;
104}
105
106void btd_reset(uint8_t rhport)
107{
108 (void)rhport;
109}
110
111uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
112{
113 tusb_desc_endpoint_t const *desc_ep;
114 uint16_t drv_len = 0;
115 // Size of single alternative of ISO interface
116 const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t);
117 // Size of hci interface
118 const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t);
119 // Ensure this is BT Primary Controller
120 TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
121 TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
122 TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
123
124 TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size);
125
127
128 desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
129
130 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
131 TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
133
134 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
135
136 // Open endpoint pair
137 TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *)desc_ep, 2,
140 0);
141
142 // Save acl in endpoint max packet size
143 tusb_desc_endpoint_t const *desc_ep_acl_in = desc_ep;
144 for (size_t p = 0; p < 2; p++) {
145 if (tu_edpt_dir(desc_ep_acl_in->bEndpointAddress) == TUSB_DIR_IN) {
147 break;
148 }
149 desc_ep_acl_in = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep_acl_in);
150 }
151
152 itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(desc_ep));
153
154 // Prepare for incoming data from host
155 TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0);
156
157 drv_len = hci_itf_size;
158
159 // Ensure this is still BT Primary Controller
160 TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
161 TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
162 TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
163 TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len);
164
165 uint8_t dir;
166
167 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
168 TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
169 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
170 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
171 _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
172 // Store endpoint size for alternative
173 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
174
175 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
176 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
177 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
178 _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
179 // Store endpoint size for alternative
180 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
181 drv_len += iso_alt_itf_size;
182
183 for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) {
184 // Make sure rest of alternatives matches
185 itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep);
186 if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE ||
188 TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass ||
189 TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol)
190 {
191 // Not an Iso interface instance
192 break;
193 }
194 TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
195
196 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
197 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
198 // Verify that alternative endpoint are same as first ones
199 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
200 _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
201 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
202
203 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
204 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
205 // Verify that alternative endpoint are same as first ones
206 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
207 _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
208 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
209 drv_len += iso_alt_itf_size;
210 }
211
212 return drv_len;
213}
214
215// Invoked when a control transfer occurred on an interface of this class
216// Driver response accordingly to the request and the transfer stage (setup/data/ack)
217// return false to stall control endpoint (e.g unsupported request)
218bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
219{
220 (void)rhport;
221
222 if ( stage == CONTROL_STAGE_SETUP )
223 {
226 {
227 // HCI command packet addressing for single function Primary Controllers
228 // also compatible with historical mode if enabled
229 TU_VERIFY((request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0) ||
230 (CFG_TUD_BTH_HISTORICAL_COMPATIBLE && request->bRequest == 0xe0));
231 }
233 {
235 {
236 // TODO: Set interface it would involve changing size of endpoint size
237 }
238 else
239 {
240 // HCI command packet for Primary Controller function in a composite device
241 TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num);
242 }
243 }
244 else return false;
245
246 return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd));
247 }
248 else if ( stage == CONTROL_STAGE_DATA )
249 {
250 // Handle class request only
252
253 if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd)));
254 }
255
256 return true;
257}
258
259bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
260 uint32_t xferred_bytes) {
261 // received new data from host
262 if (ep_addr == _btd_itf.ep_acl_out)
263 {
265
266 // prepare for next data
267 TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE));
268 }
269 else if (ep_addr == _btd_itf.ep_ev)
270 {
271 if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes);
272 }
273 else if (ep_addr == _btd_itf.ep_acl_in)
274 {
275 if ((result == XFER_RESULT_SUCCESS) && (xferred_bytes > 0) &&
276 ((xferred_bytes & (_btd_itf.ep_acl_in_pkt_sz - 1)) == 0)) {
277 // Save number of transferred bytes
278 _btd_itf.prev_xferred_bytes = xferred_bytes;
279
280 // Send zero-length packet
281 tud_bt_acl_data_send(NULL, 0);
282 } else if (tud_bt_acl_data_sent_cb) {
283 if (xferred_bytes == 0) {
284 xferred_bytes = _btd_itf.prev_xferred_bytes;
286 }
287 tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes);
288 }
289 }
290
291 return true;
292}
293
294#endif
bool tud_bt_event_send(void *event, uint16_t event_len)
Definition: bth_device.c:85
void btd_init(void)
Definition: bth_device.c:98
void btd_reset(uint8_t rhport)
Definition: bth_device.c:106
CFG_TUD_MEM_SECTION btd_interface_t _btd_itf
Definition: bth_device.c:62
bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: bth_device.c:218
static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
Definition: bth_device.c:64
bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: bth_device.c:259
uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: bth_device.c:111
bool btd_deinit(void)
Definition: bth_device.c:102
bool tud_bt_acl_data_send(void *event, uint16_t event_len)
Definition: bth_device.c:90
TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes)
TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes)
TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len)
static struct @612 data
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint16_t wValue
Definition: audio.h:934
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint16_t wLength
Definition: audio.h:840
uint16_t wIndex
Definition: audio.h:943
uint8_t bDescriptorType
Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
Definition: audio.h:657
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
Definition: tusb_types.h:349
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
Definition: tusb_types.h:350
uint8_t bRequest
Request type audio_cs_req_t.
Definition: audio.h:831
uint8_t bNumEndpoints
Number of endpoints used by this interface (excluding endpoint zero). If this value is zero,...
Definition: tusb_types.h:348
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
Definition: tusb_types.h:351
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
Definition: tusb_types.h:346
uint8_t bAlternateSetting
Value used to select this alternate setting for the interface identified in the prior field.
Definition: tusb_types.h:347
uint8_t ep_voice[2]
Definition: bth_device.c:47
uint8_t itf_num
Definition: bth_device.c:42
uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]
Definition: bth_device.c:48
uint8_t ep_acl_in
Definition: bth_device.c:44
CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd
Definition: bth_device.c:54
uint8_t ep_ev
Definition: bth_device.c:43
uint16_t ep_acl_in_pkt_sz
Definition: bth_device.c:45
uint32_t prev_xferred_bytes
Definition: bth_device.c:51
uint8_t ep_acl_out
Definition: bth_device.c:46
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]
Definition: bth_device.c:55
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_REQ_SET_INTERFACE
Definition: tusb_types.h:133
@ TUSB_CLASS_WIRELESS_CONTROLLER
Definition: tusb_types.h:178
xfer_result_t
Definition: tusb_types.h:236
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
@ TUSB_REQ_RCPT_DEVICE
Definition: tusb_types.h:151
@ TUSB_REQ_RCPT_INTERFACE
Definition: tusb_types.h:152
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
@ TUSB_XFER_INTERRUPT
Definition: tusb_types.h:62
@ TUSB_XFER_BULK
Definition: tusb_types.h:61
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_DATA
Definition: tusb_types.h:269
@ CONTROL_STAGE_SETUP
Definition: tusb_types.h:268
@ TUSB_REQ_TYPE_CLASS
Definition: tusb_types.h:145
struct TU_ATTR_PACKED tusb_desc_interface_t
USB Interface Descriptor.
static TU_ATTR_ALWAYS_INLINE uint8_t const * tu_desc_next(void const *desc)
Definition: tusb_types.h:531
@ TUSB_DESC_ENDPOINT
Definition: tusb_types.h:97
@ TUSB_DESC_INTERFACE
Definition: tusb_types.h:96
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: usbd.c:1309
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1277
bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1376
bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const *p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t *ep_out, uint8_t *ep_in)
Definition: usbd.c:1238
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const *request, void *buffer, uint16_t len)
Definition: usbd_control.c:111
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259
volatile uint8_t stage
Definition: usbh.c:265