blob: 8ef609622f87f3a4c2b7c18c6e89d6b7772a7363 [file] [log] [blame]
Austin Schuh41baf202022-01-01 14:33:40 -08001/*
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 (TUSB_OPT_DEVICE_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;
45 uint8_t ep_acl_out;
46 uint8_t ep_voice[2]; // Not used yet
47 uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT];
48
49 // Endpoint Transfer buffer
50 CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd;
51 CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE];
52
53} btd_interface_t;
54
55//--------------------------------------------------------------------+
56// INTERNAL OBJECT & FUNCTION DECLARATION
57//--------------------------------------------------------------------+
58CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf;
59
60static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
61{
62 // skip if previous transfer not complete
63 TU_VERIFY(!usbd_edpt_busy(TUD_OPT_RHPORT, ep));
64
65 TU_ASSERT(usbd_edpt_xfer(TUD_OPT_RHPORT, ep, data, len));
66
67 return true;
68}
69
70//--------------------------------------------------------------------+
71// READ API
72//--------------------------------------------------------------------+
73
74
75//--------------------------------------------------------------------+
76// WRITE API
77//--------------------------------------------------------------------+
78
79bool tud_bt_event_send(void *event, uint16_t event_len)
80{
81 return bt_tx_data(_btd_itf.ep_ev, event, event_len);
82}
83
84bool tud_bt_acl_data_send(void *event, uint16_t event_len)
85{
86 return bt_tx_data(_btd_itf.ep_acl_in, event, event_len);
87}
88
89//--------------------------------------------------------------------+
90// USBD Driver API
91//--------------------------------------------------------------------+
92void btd_init(void)
93{
94 tu_memclr(&_btd_itf, sizeof(_btd_itf));
95}
96
97void btd_reset(uint8_t rhport)
98{
99 (void)rhport;
100}
101
102uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
103{
104 tusb_desc_endpoint_t const *desc_ep;
105 uint16_t drv_len = 0;
106 // Size of single alternative of ISO interface
107 const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t);
108 // Size of hci interface
109 const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t);
110 // Ensure this is BT Primary Controller
111 TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
112 TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
113 TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
114
115 TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size);
116
117 _btd_itf.itf_num = itf_desc->bInterfaceNumber;
118
119 desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
120
121 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
122 TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
123 _btd_itf.ep_ev = desc_ep->bEndpointAddress;
124
125 // Open endpoint pair
126 TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out,
127 &_btd_itf.ep_acl_in), 0);
128
129 itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep)));
130
131 // Prepare for incoming data from host
132 TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0);
133
134 drv_len = hci_itf_size;
135
136 // Ensure this is still BT Primary Controller
137 TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
138 TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
139 TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
140 TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len);
141
142 uint8_t dir;
143
144 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
145 TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
146 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
147 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
148 _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
149 // Store endpoint size for alternative
150 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
151
152 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
153 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
154 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
155 _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
156 // Store endpoint size for alternative
157 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
158 drv_len += iso_alt_itf_size;
159
160 for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) {
161 // Make sure rest of alternatives matches
162 itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep);
163 if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE ||
164 TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass ||
165 TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass ||
166 TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol)
167 {
168 // Not an Iso interface instance
169 break;
170 }
171 TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
172
173 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
174 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
175 // Verify that alternative endpoint are same as first ones
176 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
177 _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
178 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
179
180 desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
181 dir = tu_edpt_dir(desc_ep->bEndpointAddress);
182 // Verify that alternative endpoint are same as first ones
183 TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
184 _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
185 _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
186 drv_len += iso_alt_itf_size;
187 }
188
189 return drv_len;
190}
191
192// Invoked when a control transfer occurred on an interface of this class
193// Driver response accordingly to the request and the transfer stage (setup/data/ack)
194// return false to stall control endpoint (e.g unsupported request)
195bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
196{
197 (void)rhport;
198
199 if ( stage == CONTROL_STAGE_SETUP )
200 {
201 if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
202 request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE)
203 {
204 // HCI command packet addressing for single function Primary Controllers
205 TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0);
206 }
207 else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE)
208 {
209 if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex)
210 {
211 // TODO: Set interface it would involve changing size of endpoint size
212 }
213 else
214 {
215 // HCI command packet for Primary Controller function in a composite device
216 TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num);
217 }
218 }
219 else return false;
220
221 return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd));
222 }
223 else if ( stage == CONTROL_STAGE_DATA )
224 {
225 // Handle class request only
226 TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
227
228 if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd)));
229 }
230
231 return true;
232}
233
234bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
235{
236 (void)result;
237
238 // received new data from host
239 if (ep_addr == _btd_itf.ep_acl_out)
240 {
241 if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes);
242
243 // prepare for next data
244 TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE));
245 }
246 else if (ep_addr == _btd_itf.ep_ev)
247 {
248 if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes);
249 }
250 else if (ep_addr == _btd_itf.ep_acl_in)
251 {
252 if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes);
253 }
254
255 return true;
256}
257
258#endif