1 /*
2 * Copyright (C) 2020 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "usbh_bluetooth.c"
39
40 #include "usbh_bluetooth.h"
41 #include "btstack_debug.h"
42 #include "hci.h"
43 #include "btstack_util.h"
44 #include "bluetooth.h"
45
46 typedef struct {
47 uint8_t acl_in_ep;
48 uint8_t acl_in_pipe;
49 uint16_t acl_in_len;
50 uint32_t acl_in_frame;
51 uint8_t acl_out_ep;
52 uint8_t acl_out_pipe;
53 uint16_t acl_out_len;
54 uint8_t event_in_ep;
55 uint8_t event_in_pipe;
56 uint16_t event_in_len;
57 uint32_t event_in_frame;
58 } USB_Bluetooth_t;
59
60 static enum {
61 USBH_OUT_OFF,
62 USBH_OUT_IDLE,
63 USBH_OUT_CMD,
64 USBH_OUT_ACL_SEND,
65 USBH_OUT_ACL_POLL,
66 } usbh_out_state;
67
68 static enum {
69 USBH_IN_OFF,
70 USBH_IN_SUBMIT_REQUEST,
71 USBH_IN_POLL,
72 } usbh_in_state;
73
74 // higher-layer callbacks
75 static void (*usbh_packet_sent)(void);
76 static void (*usbh_packet_received)(uint8_t packet_type, uint8_t * packet, uint16_t size);
77
78 // class state
79 static USB_Bluetooth_t usb_bluetooth;
80
81 // outgoing
82 static const uint8_t * cmd_packet;
83 static uint16_t cmd_len;
84
85 static const uint8_t * acl_packet;
86 static uint16_t acl_len;
87
88 // incoming
89 static uint16_t hci_event_offset;
90 static uint8_t hci_event[258];
91
92 static uint16_t hci_acl_in_offset;
93 static uint8_t hci_acl_in_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_ACL_BUFFER_SIZE];
94 static uint8_t * hci_acl_in_packet = &hci_acl_in_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
95
96
usbh_bluetooth_start_acl_in_transfer(USBH_HandleTypeDef * phost,USB_Bluetooth_t * usb)97 USBH_StatusTypeDef usbh_bluetooth_start_acl_in_transfer(USBH_HandleTypeDef *phost, USB_Bluetooth_t * usb){
98 uint16_t acl_in_transfer_size = btstack_min(usb->acl_in_len, HCI_ACL_BUFFER_SIZE - hci_acl_in_offset);
99 usb->acl_in_frame = phost->Timer;
100 return USBH_BulkReceiveData(phost, &hci_acl_in_packet[hci_acl_in_offset], acl_in_transfer_size, usb->acl_in_pipe);
101 }
102
USBH_Bluetooth_InterfaceInit(USBH_HandleTypeDef * phost)103 USBH_StatusTypeDef USBH_Bluetooth_InterfaceInit(USBH_HandleTypeDef *phost){
104 log_info("USBH_Bluetooth_InterfaceInit");
105
106 // dump everything
107 uint8_t interface_index = 0;
108 USBH_InterfaceDescTypeDef * interface = &phost->device.CfgDesc.Itf_Desc[interface_index];
109 uint8_t num_endpoints = interface->bNumEndpoints;
110 uint8_t ep_index;
111 int16_t acl_in = -1;
112 int16_t acl_out = -1;
113 int16_t event_in = -1;
114 for (ep_index=0;ep_index<num_endpoints;ep_index++){
115 USBH_EpDescTypeDef * ep_desc = &interface->Ep_Desc[ep_index];
116 printf("Interface %u, endpoint #%u: address 0x%02x, attributes 0x%02x, packet size %u, poll %u\n",
117 interface_index, ep_index, ep_desc->bEndpointAddress, ep_desc->bmAttributes, ep_desc->wMaxPacketSize, ep_desc->bInterval);
118 // type interrupt, direction incoming
119 if (((ep_desc->bEndpointAddress & USB_EP_DIR_MSK) == USB_EP_DIR_MSK) && (ep_desc->bmAttributes == USB_EP_TYPE_INTR)){
120 event_in = ep_index;
121 puts("-> HCI Event");
122 }
123 // type bulk, direction incoming
124 if (((ep_desc->bEndpointAddress & USB_EP_DIR_MSK) == USB_EP_DIR_MSK) && (ep_desc->bmAttributes == USB_EP_TYPE_BULK)){
125 acl_in = ep_index;
126 puts("-> HCI ACL IN");
127 }
128 // type bulk, direction incoming
129 if (((ep_desc->bEndpointAddress & USB_EP_DIR_MSK) == 0) && (ep_desc->bmAttributes == USB_EP_TYPE_BULK)){
130 acl_out = ep_index;
131 puts("-> HCI ACL OUT");
132 }
133 }
134
135 // all found
136 if ((acl_in < 0) && (acl_out < 0) && (event_in < 0)) {
137 log_info("Could not find all endpoints");
138 return USBH_FAIL;
139 }
140
141 // setup
142 memset(&usb_bluetooth, 0, sizeof(USB_Bluetooth_t));
143 phost->pActiveClass->pData = (void*) &usb_bluetooth;
144
145 // Command
146 usbh_out_state = USBH_OUT_OFF;
147
148 // Event In
149 USB_Bluetooth_t * usb = &usb_bluetooth;
150 usb->event_in_ep = interface->Ep_Desc[event_in].bEndpointAddress;
151 usb->event_in_len = interface->Ep_Desc[event_in].wMaxPacketSize;
152 usb->event_in_pipe = USBH_AllocPipe(phost, usb->event_in_ep);
153 usbh_in_state = USBH_IN_OFF;
154
155 /* Open pipe for IN endpoint */
156 USBH_OpenPipe(phost, usb->event_in_pipe, usb->event_in_ep, phost->device.address,
157 phost->device.speed, USB_EP_TYPE_INTR, interface->Ep_Desc[event_in].wMaxPacketSize);
158
159 USBH_LL_SetToggle(phost, usb->event_in_ep, 0U);
160
161 // ACL In
162 usb->acl_in_ep = interface->Ep_Desc[acl_in].bEndpointAddress;
163 usb->acl_in_len = interface->Ep_Desc[acl_in].wMaxPacketSize;
164 usb->acl_in_pipe = USBH_AllocPipe(phost, usb->acl_in_ep);
165 USBH_OpenPipe(phost, usb->acl_in_pipe, usb->acl_in_ep, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, usb->acl_in_len);
166 USBH_LL_SetToggle(phost, usb->acl_in_pipe, 0U);
167 hci_acl_in_offset = 0;
168 usbh_bluetooth_start_acl_in_transfer(phost, usb);
169
170 // ACL Out
171 usb->acl_out_ep = interface->Ep_Desc[acl_out].bEndpointAddress;
172 usb->acl_out_len = interface->Ep_Desc[acl_out].wMaxPacketSize;
173 usb->acl_out_pipe = USBH_AllocPipe(phost, usb->acl_out_ep);
174 USBH_OpenPipe(phost, usb->acl_out_pipe, usb->acl_out_ep, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, usb->acl_out_len);
175 USBH_LL_SetToggle(phost, usb->acl_out_pipe, 0U);
176
177 return USBH_OK;
178 }
179
USBH_Bluetooth_InterfaceDeInit(USBH_HandleTypeDef * phost)180 USBH_StatusTypeDef USBH_Bluetooth_InterfaceDeInit(USBH_HandleTypeDef *phost){
181 log_info("USBH_Bluetooth_InterfaceDeInit");
182 usbh_out_state = USBH_OUT_OFF;
183 usbh_in_state = USBH_IN_OFF;
184 return USBH_OK;
185 }
186
USBH_Bluetooth_ClassRequest(USBH_HandleTypeDef * phost)187 USBH_StatusTypeDef USBH_Bluetooth_ClassRequest(USBH_HandleTypeDef *phost){
188 // ready!
189 usbh_out_state = USBH_OUT_IDLE;
190 usbh_in_state = USBH_IN_SUBMIT_REQUEST;
191 // notify host stack
192 (*usbh_packet_sent)();
193 return USBH_OK;
194 }
195
USBH_Bluetooth_Process(USBH_HandleTypeDef * phost)196 USBH_StatusTypeDef USBH_Bluetooth_Process(USBH_HandleTypeDef *phost){
197 USBH_StatusTypeDef status;
198 USBH_URBStateTypeDef urb_state;
199 USB_Bluetooth_t * usb = (USB_Bluetooth_t *) phost->pActiveClass->pData;
200 uint16_t transfer_size;
201 switch (usbh_out_state){
202 case USBH_OUT_CMD:
203 // just send HCI Reset naively
204 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_CLASS;
205 phost->Control.setup.b.bRequest = 0;
206 phost->Control.setup.b.wValue.w = 0;
207 phost->Control.setup.b.wIndex.w = 0U;
208 phost->Control.setup.b.wLength.w = cmd_len;
209 status = USBH_CtlReq(phost, (uint8_t *) cmd_packet, cmd_len);
210 if (status == USBH_OK) {
211 usbh_out_state = USBH_OUT_IDLE;
212 // notify host stack
213 (*usbh_packet_sent)();
214 }
215 break;
216 case USBH_OUT_ACL_SEND:
217 transfer_size = btstack_min(usb->acl_out_len, acl_len);
218 USBH_BulkSendData(phost, (uint8_t *) acl_packet, transfer_size, usb->acl_out_pipe, 1);
219 usbh_out_state = USBH_OUT_ACL_POLL;
220 break;
221 case USBH_OUT_ACL_POLL:
222 urb_state = USBH_LL_GetURBState(phost, usb->acl_out_pipe);
223 switch (urb_state){
224 case USBH_URB_IDLE:
225 break;
226 case USBH_URB_NOTREADY:
227 usbh_out_state = USBH_OUT_ACL_SEND;
228 break;
229 case USBH_URB_DONE:
230 transfer_size = btstack_min(usb->acl_out_len, acl_len);
231 acl_len -= transfer_size;
232 if (acl_len == 0){
233 usbh_out_state = USBH_OUT_IDLE;
234 // notify host stack
235 (*usbh_packet_sent)();
236 } else {
237 acl_packet += transfer_size;
238 usbh_out_state = USBH_OUT_ACL_SEND;
239 }
240 break;
241 default:
242 log_info("URB State ACL Out: %02x", urb_state);
243 break;
244 }
245 break;
246 default:
247 break;
248 }
249
250 uint8_t event_transfer_size;
251 uint16_t event_size;
252 switch (usbh_in_state){
253 case USBH_IN_SUBMIT_REQUEST:
254 event_transfer_size = btstack_min( usb->event_in_len, sizeof(hci_event) - hci_event_offset);
255 USBH_InterruptReceiveData(phost, &hci_event[hci_event_offset], event_transfer_size, usb->event_in_pipe);
256 usb->event_in_frame = phost->Timer;
257 usbh_in_state = USBH_IN_POLL;
258 break;
259 case USBH_IN_POLL:
260 urb_state = USBH_LL_GetURBState(phost, usb->event_in_pipe);
261 switch (urb_state){
262 case USBH_URB_IDLE:
263 break;
264 case USBH_URB_DONE:
265 usbh_in_state = USBH_IN_SUBMIT_REQUEST;
266 event_transfer_size = USBH_LL_GetLastXferSize(phost, usb->event_in_pipe);
267 hci_event_offset += event_transfer_size;
268 if (hci_event_offset < 2) break;
269 event_size = 2 + hci_event[1];
270 // event complete
271 if (hci_event_offset >= event_size){
272 hci_event_offset = 0;
273 (*usbh_packet_received)(HCI_EVENT_PACKET, hci_event, event_size);
274 }
275 break;
276 default:
277 log_info("URB State Event: %02x", urb_state);
278 break;
279 }
280 if ((phost->Timer - usb->event_in_frame) > 2){
281 usbh_in_state = USBH_IN_SUBMIT_REQUEST;
282 }
283 break;
284 default:
285 break;
286 }
287
288 // ACL In
289 uint16_t acl_transfer_size;
290 uint16_t acl_size;
291 urb_state = USBH_LL_GetURBState(phost, usb->acl_in_pipe);
292 switch (urb_state){
293 case USBH_URB_IDLE:
294 // If state stays IDLE for longer than a full frame, something went wrong with submitting the request,
295 // just re-submits the request
296 if ((phost->Timer - usb->acl_in_frame) > 2){
297 status = usbh_bluetooth_start_acl_in_transfer(phost, usb);
298 btstack_assert(status == USBH_OK);
299 }
300 break;
301 case USBH_URB_NOTREADY:
302 // The original USB Host code re-submits the request when it receives a NAK, resulting in about 80% MCU load
303 // With our patch, NOTREADY is returned, which allows to re-submit the request in the next frame.
304 if (phost->Timer != usb->acl_in_frame){
305 status = usbh_bluetooth_start_acl_in_transfer(phost, usb);
306 btstack_assert(status == USBH_OK);
307 } break;
308 case USBH_URB_DONE:
309 acl_transfer_size = USBH_LL_GetLastXferSize(phost, usb->acl_in_pipe);
310 hci_acl_in_offset += acl_transfer_size;
311 if (hci_acl_in_offset < 4) break;
312 acl_size = 4 + little_endian_read_16(hci_acl_in_packet, 2);
313 // acl complete
314 if (hci_acl_in_offset > acl_size){
315 printf("Extra HCI EVENT!\n");
316 }
317 if (hci_acl_in_offset >= acl_size){
318 (*usbh_packet_received)(HCI_ACL_DATA_PACKET, hci_acl_in_packet, acl_size);
319 hci_acl_in_offset = 0;
320 }
321 usbh_bluetooth_start_acl_in_transfer(phost, usb);
322 break;
323 default:
324 log_info("URB State Event: %02x", urb_state);
325 break;
326 }
327
328 return USBH_OK;
329 }
330
USBH_Bluetooth_SOFProcess(USBH_HandleTypeDef * phost)331 USBH_StatusTypeDef USBH_Bluetooth_SOFProcess(USBH_HandleTypeDef *phost){
332 return USBH_OK;
333 }
334
usbh_bluetooth_set_packet_sent(void (* callback)(void))335 void usbh_bluetooth_set_packet_sent(void (*callback)(void)){
336 usbh_packet_sent = callback;
337 }
338
339
usbh_bluetooth_set_packet_received(void (* callback)(uint8_t packet_type,uint8_t * packet,uint16_t size))340 void usbh_bluetooth_set_packet_received(void (*callback)(uint8_t packet_type, uint8_t * packet, uint16_t size)){
341 usbh_packet_received = callback;
342 }
343
usbh_bluetooth_can_send_now(void)344 bool usbh_bluetooth_can_send_now(void){
345 return usbh_out_state == USBH_OUT_IDLE;;
346 }
347
usbh_bluetooth_send_cmd(const uint8_t * packet,uint16_t len)348 void usbh_bluetooth_send_cmd(const uint8_t * packet, uint16_t len){
349 btstack_assert(usbh_out_state == USBH_OUT_IDLE);
350 cmd_packet = packet;
351 cmd_len = len;
352 usbh_out_state = USBH_OUT_CMD;
353 }
354
usbh_bluetooth_send_acl(const uint8_t * packet,uint16_t len)355 void usbh_bluetooth_send_acl(const uint8_t * packet, uint16_t len){
356 btstack_assert(usbh_out_state == USBH_OUT_IDLE);
357 acl_packet = packet;
358 acl_len = len;
359 usbh_out_state = USBH_OUT_ACL_SEND;
360 }
361
362 USBH_ClassTypeDef Bluetooth_Class = {
363 "Bluetooth",
364 USB_BLUETOOTH_CLASS,
365 USBH_Bluetooth_InterfaceInit,
366 USBH_Bluetooth_InterfaceDeInit,
367 USBH_Bluetooth_ClassRequest,
368 USBH_Bluetooth_Process,
369 USBH_Bluetooth_SOFProcess,
370 NULL,
371 };
372
373