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