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