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