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
28void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len);
29void acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len);
30void command_complete(void* cookie, status_t status, void* data, size_t actual_len);
31void event_complete(void* cookie, status_t status, void* data, size_t actual_len);
32
33
34static status_t
35assembly_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
48void
49event_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
73resubmit:
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
90void
91acl_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
112resubmit:
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
132status_t
133submit_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
157status_t
158submit_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
181status_t
182submit_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
193void
194command_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
218void
219acl_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
246status_t
247submit_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
279status_t
280submit_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
310status_t
311submit_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