1 /*
2 * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
3 * Copyright 2008 Mika Lindqvist, monni1995_at_gmail.com
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7
8 #include "h2transactions.h"
9
10 #include <bluetooth/HCI/btHCI.h>
11 #include <bluetooth/HCI/btHCI_event.h>
12 #include <bluetooth/HCI/btHCI_acl.h>
13
14 #include <ByteOrder.h>
15 #include <kernel.h>
16 #include <string.h>
17
18 #include "h2debug.h"
19 #include "h2generic.h"
20 #include "h2upper.h"
21 #include "h2util.h"
22
23
24 //#define DUMP_BUFFERS
25
26 /* Forward declaration */
27
28 void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len);
29 void acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len);
30 void command_complete(void* cookie, status_t status, void* data, size_t actual_len);
31 void event_complete(void* cookie, status_t status, void* data, size_t actual_len);
32
33
34 static status_t
assembly_rx(bt_usb_dev * bdev,bt_packet_t type,void * data,int count)35 assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void* data, int count)
36 {
37 bdev->stat.bytesRX += count;
38
39 return btDevices->PostTransportPacket(bdev->hdev, type, data, count);
40
41 }
42
43
44 #if 0
45 #pragma mark --- RX Complete ---
46 #endif
47
48 void
event_complete(void * cookie,status_t status,void * data,size_t actual_len)49 event_complete(void* cookie, status_t status, void* data, size_t actual_len)
50 {
51 bt_usb_dev* bdev = (bt_usb_dev*)cookie;
52 // bt_usb_dev* bdev = fetch_device(cookie, 0); -> safer / slower option
53 status_t error;
54
55 TRACE("%s: cookie@%p status=%s len=%" B_PRIuSIZE "\n", __func__, cookie,
56 strerror(status), actual_len);
57
58 if (bdev == NULL)
59 return;
60
61 if (status == B_CANCELED || status == B_DEV_CRC_ERROR)
62 return; // or not running anymore...
63
64 if (status != B_OK || actual_len == 0)
65 goto resubmit;
66
67 if (assembly_rx(bdev, BT_EVENT, data, actual_len) == B_OK) {
68 bdev->stat.successfulTX++;
69 } else {
70 bdev->stat.errorRX++;
71 }
72
73 resubmit:
74
75 error = usb->queue_interrupt(bdev->intr_in_ep->handle, data,
76 max_c(HCI_MAX_EVENT_SIZE, bdev->max_packet_size_intr_in),
77 event_complete, bdev);
78
79 if (error != B_OK) {
80 reuse_room(&bdev->eventRoom, data);
81 bdev->stat.rejectedRX++;
82 ERROR("%s: RX event resubmittion failed %s\n", __func__,
83 strerror(error));
84 } else {
85 bdev->stat.acceptedRX++;
86 }
87 }
88
89
90 void
acl_rx_complete(void * cookie,status_t status,void * data,size_t actual_len)91 acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len)
92 {
93 bt_usb_dev* bdev = (bt_usb_dev*)cookie;
94 // bt_usb_dev* bdev = fetch_device(cookie, 0); -> safer / slower option
95 status_t error;
96
97 if (bdev == NULL)
98 return;
99
100 if (status == B_CANCELED || status == B_DEV_CRC_ERROR)
101 return; // or not running anymore...
102
103 if (status != B_OK || actual_len == 0)
104 goto resubmit;
105
106 if (assembly_rx(bdev, BT_ACL, data, actual_len) == B_OK) {
107 bdev->stat.successfulRX++;
108 } else {
109 bdev->stat.errorRX++;
110 }
111
112 resubmit:
113
114 error = usb->queue_bulk(bdev->bulk_in_ep->handle, data,
115 max_c(HCI_MAX_FRAME_SIZE, bdev->max_packet_size_bulk_in),
116 acl_rx_complete, (void*) bdev);
117
118 if (error != B_OK) {
119 reuse_room(&bdev->aclRoom, data);
120 bdev->stat.rejectedRX++;
121 ERROR("%s: RX acl resubmittion failed %s\n", __func__, strerror(error));
122 } else {
123 bdev->stat.acceptedRX++;
124 }
125 }
126
127
128 #if 0
129 #pragma mark --- RX ---
130 #endif
131
132 status_t
submit_rx_event(bt_usb_dev * bdev)133 submit_rx_event(bt_usb_dev* bdev)
134 {
135 size_t size = max_c(HCI_MAX_EVENT_SIZE, bdev->max_packet_size_intr_in);
136 void* buf = alloc_room(&bdev->eventRoom, size);
137 status_t status;
138
139 if (buf == NULL)
140 return ENOMEM;
141
142 status = usb->queue_interrupt(bdev->intr_in_ep->handle, buf, size,
143 event_complete, (void*)bdev);
144
145 if (status != B_OK) {
146 reuse_room(&bdev->eventRoom, buf); // reuse allocated one
147 bdev->stat.rejectedRX++;
148 } else {
149 bdev->stat.acceptedRX++;
150 TRACE("%s: Accepted RX Event %d\n", __func__, bdev->stat.acceptedRX);
151 }
152
153 return status;
154 }
155
156
157 status_t
submit_rx_acl(bt_usb_dev * bdev)158 submit_rx_acl(bt_usb_dev* bdev)
159 {
160 size_t size = max_c(HCI_MAX_FRAME_SIZE, bdev->max_packet_size_bulk_in);
161 void* buf = alloc_room(&bdev->aclRoom, size);
162 status_t status;
163
164 if (buf == NULL)
165 return ENOMEM;
166
167 status = usb->queue_bulk(bdev->bulk_in_ep->handle, buf, size,
168 acl_rx_complete, bdev);
169
170 if (status != B_OK) {
171 reuse_room(&bdev->aclRoom, buf); // reuse allocated
172 bdev->stat.rejectedRX++;
173 } else {
174 bdev->stat.acceptedRX++;
175 }
176
177 return status;
178 }
179
180
181 status_t
submit_rx_sco(bt_usb_dev * bdev)182 submit_rx_sco(bt_usb_dev* bdev)
183 {
184 // not yet implemented
185 return B_ERROR;
186 }
187
188
189 #if 0
190 #pragma mark --- TX Complete ---
191 #endif
192
193 void
command_complete(void * cookie,status_t status,void * data,size_t actual_len)194 command_complete(void* cookie, status_t status, void* data, size_t actual_len)
195 {
196 snet_buffer* snbuf = (snet_buffer*)cookie;
197 bt_usb_dev* bdev = (bt_usb_dev*)snb_cookie(snbuf);
198
199 TRACE("%s: len = %" B_PRIuSIZE " @%p\n", __func__, actual_len, data);
200
201 if (status == B_OK) {
202 bdev->stat.successfulTX++;
203 bdev->stat.bytesTX += actual_len;
204 } else {
205 bdev->stat.errorTX++;
206 // the packet has been lost, too late to requeue it
207 }
208
209 snb_park(&bdev->snetBufferRecycleTrash, snbuf);
210
211 #ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
212 // TODO: check just the empty queues
213 schedTxProcessing(bdev);
214 #endif
215 }
216
217
218 void
acl_tx_complete(void * cookie,status_t status,void * data,size_t actual_len)219 acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len)
220 {
221 net_buffer* nbuf = (net_buffer*)cookie;
222 bt_usb_dev* bdev = GET_DEVICE(nbuf);
223
224 //debugf("fetched=%p type %lx %p\n", bdev, nbuf->type, data);
225
226 if (status == B_OK) {
227 bdev->stat.successfulTX++;
228 bdev->stat.bytesTX += actual_len;
229 } else {
230 bdev->stat.errorTX++;
231 // the packet has been lost, too late to requeue it
232 }
233
234 nb_destroy(nbuf);
235
236 #ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
237 schedTxProcessing(bdev);
238 #endif
239 }
240
241
242 #if 0
243 #pragma mark --- TX ---
244 #endif
245
246 status_t
submit_tx_command(bt_usb_dev * bdev,snet_buffer * snbuf)247 submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf)
248 {
249 uint8 bRequestType = bdev->ctrl_req;
250 uint8 bRequest = 0;
251 uint16 wIndex = 0;
252 uint16 value = 0;
253 uint16 wLength = B_HOST_TO_LENDIAN_INT16(snb_size(snbuf));
254 status_t error;
255
256 if (!GET_BIT(bdev->state, RUNNING)) {
257 return B_DEV_NOT_READY;
258 }
259
260 // set cookie
261 snb_set_cookie(snbuf, bdev);
262
263 TRACE("%s: @%p\n", __func__, snb_get(snbuf));
264
265 error = usb->queue_request(bdev->dev, bRequestType, bRequest,
266 value, wIndex, wLength, snb_get(snbuf),
267 command_complete, (void*) snbuf);
268
269 if (error != B_OK) {
270 bdev->stat.rejectedTX++;
271 } else {
272 bdev->stat.acceptedTX++;
273 }
274
275 return error;
276 }
277
278
279 status_t
submit_tx_acl(bt_usb_dev * bdev,net_buffer * nbuf)280 submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf)
281 {
282 status_t error;
283
284 // set cookie
285 SET_DEVICE(nbuf, bdev->hdev);
286
287 if (!GET_BIT(bdev->state, RUNNING)) {
288 return B_DEV_NOT_READY;
289 }
290 /*
291 debugf("### Outgoing ACL: len = %ld\n", nbuf->size);
292 for (uint32 index = 0 ; index < nbuf->size; index++ ) {
293 dprintf("%x:",((uint8*)nb_get_whole_buffer(nbuf))[index]);
294 }
295 */
296
297 error = usb->queue_bulk(bdev->bulk_out_ep->handle, nb_get_whole_buffer(nbuf),
298 nbuf->size, acl_tx_complete, (void*)nbuf);
299
300 if (error != B_OK) {
301 bdev->stat.rejectedTX++;
302 } else {
303 bdev->stat.acceptedTX++;
304 }
305
306 return error;
307 }
308
309
310 status_t
submit_tx_sco(bt_usb_dev * bdev)311 submit_tx_sco(bt_usb_dev* bdev)
312 {
313
314 if (!GET_BIT(bdev->state, RUNNING)) {
315 return B_DEV_NOT_READY;
316 }
317
318 // not yet implemented
319 return B_ERROR;
320 }
321