xref: /haiku/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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
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
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
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
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
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
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
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
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
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
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
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