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