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 "h2upper.h"
9
10#include <string.h>
11
12#include <bluetooth/bluetooth.h>
13#include <bluetooth/HCI/btHCI_transport.h>
14#include <kernel.h>
15
16#include "h2debug.h"
17#include "h2generic.h"
18#include "h2transactions.h"
19#include "snet_buffer.h"
20
21
22// TODO: split for commands and comunication (ACL & SCO)
23void
24sched_tx_processing(bt_usb_dev* bdev)
25{
26	net_buffer* nbuf;
27	snet_buffer* snbuf;
28	status_t err;
29
30	TRACE("%s: (%p)\n", __func__, bdev);
31
32	if (!TEST_AND_SET(&bdev->state, PROCESSING)) {
33		// We are not processing in another thread so... START!!
34
35		do {
36			/* Do while this bit is on... so someone should set it before we
37			 * stop the iterations
38			 */
39			bdev->state = CLEAR_BIT(bdev->state, SENDING);
40			// check Commands
41	#ifdef EMPTY_COMMAND_QUEUE
42			while (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND])) {
43	#else
44			if (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND])) {
45	#endif
46				snbuf = (snet_buffer*)
47					list_remove_head_item(&bdev->nbuffersTx[BT_COMMAND]);
48				err = submit_tx_command(bdev, snbuf);
49				if (err != B_OK) {
50					// re-head it
51					list_insert_item_before(&bdev->nbuffersTx[BT_COMMAND],
52						list_get_first_item(&bdev->nbuffersTx[BT_COMMAND]),
53						snbuf);
54				}
55			}
56
57			// check ACl
58	#define EMPTY_ACL_QUEUE
59	#ifdef EMPTY_ACL_QUEUE
60			while (!list_is_empty(&bdev->nbuffersTx[BT_ACL])) {
61	#else
62			if (!list_is_empty(&bdev->nbuffersTx[BT_ACL])) {
63	#endif
64				nbuf = (net_buffer*)
65					list_remove_head_item(&bdev->nbuffersTx[BT_ACL]);
66				err = submit_tx_acl(bdev, nbuf);
67				if (err != B_OK) {
68					// re-head it
69					list_insert_item_before(&bdev->nbuffersTx[BT_ACL],
70							list_get_first_item(&bdev->nbuffersTx[BT_ACL]),
71							nbuf);
72				}
73			}
74
75			if (!list_is_empty(&bdev->nbuffersTx[BT_SCO])) {
76				// TODO to be implemented
77			}
78
79		} while (GET_BIT(bdev->state, SENDING));
80
81		bdev->state = CLEAR_BIT(bdev->state, PROCESSING);
82
83	} else {
84		// We are processing so MARK that we need to still go on with that
85		bdev->state = SET_BIT(bdev->state, SENDING);
86	}
87}
88
89
90#if 0
91// DEPRECATED
92status_t
93post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf)
94{
95	status_t err = B_ERROR;
96
97	debugf("Frame up type=%d\n", type);
98
99	if (type == BT_EVENT) {
100		snet_buffer* snbuf = (snet_buffer*)buf;
101		btCoreData->PostEvent(bdev->ndev, snb_get(snbuf),
102			(size_t)snb_size(snbuf));
103		snb_park(&bdev->snetBufferRecycleTrash, snbuf);
104		debugf("to btDataCore len=%d\n", snb_size(snbuf));
105	} else {
106		net_buffer* nbuf = (net_buffer*) buf;
107		// No need to free the buffer at allocation is gonna be reused
108		btDevices->receive_data(bdev->ndev, &nbuf);
109		TRACE("to net_device\n");
110	}
111
112	return err;
113}
114#endif
115
116
117status_t
118send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf)
119{
120	bt_usb_dev* bdev = fetch_device(NULL, hid);
121	status_t err = B_OK;
122
123	if (bdev == NULL)
124		return B_ERROR;
125
126	// TODO: check if device is actually ready for this
127	// TODO: Lock Device
128
129	if (nbuf != NULL) {
130		if (type != nbuf->protocol) // a bit strict maybe
131			panic("Upper layer has not filled correctly a packet");
132
133		switch (type) {
134			case BT_COMMAND:
135			case BT_ACL:
136			case BT_SCO:
137				list_add_item(&bdev->nbuffersTx[type], nbuf);
138				bdev->nbuffersPendingTx[type]++;
139			break;
140			default:
141				ERROR("%s: Unknown packet type for sending %d\n", __func__,
142					type);
143				// TODO: free the net_buffer -> no, allow upper layer
144				// handle it with the given error
145				err = B_BAD_VALUE;
146			break;
147		}
148	} else {
149		TRACE("%s: tx sched provoked", __func__);
150	}
151
152	// TODO: check if device is actually ready for this
153	// TODO: unlock device
154
155	// sched in any case even if nbuf is null (provoke re-scheduling)
156	sched_tx_processing(bdev);
157
158	return err;
159}
160
161
162status_t
163send_command(hci_id hid, snet_buffer* snbuf)
164{
165	bt_usb_dev* bdev = fetch_device(NULL, hid);
166	status_t err = B_OK;
167
168	if (bdev == NULL)
169		return B_ERROR;
170
171	// TODO: check if device is actually ready for this
172	// TODO: mutex
173
174	if (snbuf != NULL) {
175		list_add_item(&bdev->nbuffersTx[BT_COMMAND], snbuf);
176		bdev->nbuffersPendingTx[BT_COMMAND]++;
177	} else {
178		err = B_BAD_VALUE;
179		TRACE("%s: tx sched provoked", __func__);
180	}
181
182	// TODO: check if device is actually ready for this
183	// TODO: mutex
184
185	/* sched in All cases even if nbuf is null (hidden way to provoke
186	 * re-scheduling)
187	 */
188	sched_tx_processing(bdev);
189
190	return err;
191}
192