* Copyright 2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*/
#include <new>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <lock.h>
#include <SupportDefs.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <net_buffer.h>
#include <net_device.h>
#include <net_stack.h>
#include <NetBufferUtilities.h>
#include <btDebug.h>
#include <btCoreData.h>
#include <btModules.h>
#include <CodeHandler.h>
#define KERNEL_LAND
#include <PortListener.h>
#undef KERNEL_LAND
#include <bluetooth/HCI/btHCI.h>
#include <bluetooth/HCI/btHCI_acl.h>
#include <bluetooth/HCI/btHCI_command.h>
#include <bluetooth/HCI/btHCI_event.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include <bluetooth/HCI/btHCI_sco.h>
#include <bluetooth/bdaddrUtils.h>
#include "acl.h"
int32 api_version = B_CUR_DRIVER_API_VERSION;
typedef PortListener<void,
HCI_MAX_FRAME_SIZE,
24
> BluetoothRawDataPort;
net_buffer_module_info* gBufferModule = NULL;
struct bluetooth_core_data_module_info* btCoreData = NULL;
static mutex sListLock;
static sem_id sLinkChangeSemaphore;
static DoublyLinkedList<bluetooth_device> sDeviceList;
BluetoothRawDataPort* BluetoothRXPort;
status_t HciPacketHandler(void* data, int32 code, size_t size);
bluetooth_device*
FindDeviceByID(hci_id hid)
{
bluetooth_device* device;
DoublyLinkedList<bluetooth_device>::Iterator iterator
= sDeviceList.GetIterator();
while (iterator.HasNext()) {
device = iterator.Next();
if (device->index == hid)
return device;
}
return NULL;
}
status_t
PostTransportPacket(hci_id hid, bt_packet_t type, void* data, size_t count)
{
uint32 code = 0;
Bluetooth::CodeHandler::SetDevice(&code, hid);
Bluetooth::CodeHandler::SetProtocol(&code, type);
return BluetoothRXPort->Trigger(code, data, count);
}
status_t
Assemble(bluetooth_device* bluetoothDevice, bt_packet_t type, void* data,
size_t count)
{
net_buffer* nbuf = bluetoothDevice->fBuffersRx[type];
size_t currentPacketLen = 0;
while (count) {
if (nbuf == NULL) {
switch (type) {
case BT_EVENT:
if (count >= HCI_EVENT_HDR_SIZE) {
struct hci_event_header* headerPacket
= (struct hci_event_header*)data;
bluetoothDevice->fExpectedPacketSize[type]
= HCI_EVENT_HDR_SIZE + headerPacket->elen;
if (count >= bluetoothDevice->fExpectedPacketSize[type]) {
ERROR("%s: EVENT posted in HCI!!!\n", __func__);
btCoreData->PostEvent(bluetoothDevice, data,
bluetoothDevice->fExpectedPacketSize[type]);
} else {
nbuf = gBufferModule->create(
bluetoothDevice->fExpectedPacketSize[type]);
bluetoothDevice->fBuffersRx[type] = nbuf;
nbuf->protocol = type;
}
} else {
panic("EVENT frame corrupted\n");
return EILSEQ;
}
break;
case BT_ACL:
if (count >= HCI_ACL_HDR_SIZE) {
struct hci_acl_header* headerPkt = (struct hci_acl_header*)data;
bluetoothDevice->fExpectedPacketSize[type] = HCI_ACL_HDR_SIZE
+ B_LENDIAN_TO_HOST_INT16(headerPkt->alen);
nbuf = gBufferModule->create(
bluetoothDevice->fExpectedPacketSize[type]);
bluetoothDevice->fBuffersRx[type] = nbuf;
nbuf->protocol = type;
} else {
panic("ACL frame corrupted\n");
return EILSEQ;
}
break;
case BT_SCO:
break;
default:
panic("unknown packet type in assembly");
break;
}
currentPacketLen = bluetoothDevice->fExpectedPacketSize[type];
} else {
currentPacketLen = bluetoothDevice->fExpectedPacketSize[type] - nbuf->size;
}
if (nbuf != NULL) {
currentPacketLen = min_c(currentPacketLen, count);
gBufferModule->append(nbuf, data, currentPacketLen);
if ((bluetoothDevice->fExpectedPacketSize[type] - nbuf->size) == 0) {
switch (nbuf->protocol) {
case BT_EVENT:
panic("need to send full buffer to btdatacore!\n");
btCoreData->PostEvent(bluetoothDevice, data,
bluetoothDevice->fExpectedPacketSize[type]);
break;
case BT_ACL:
TRACE("%s: ACL parsed in ACL!\n", __func__);
AclAssembly(nbuf, bluetoothDevice->index);
break;
default:
break;
}
bluetoothDevice->fBuffersRx[type] = nbuf = NULL;
bluetoothDevice->fExpectedPacketSize[type] = 0;
} else {
if (type == BT_ACL) {
TRACE("%s: ACL Packet not filled size %" B_PRIu32
" expected=%" B_PRIuSIZE "\n", __func__, nbuf->size,
bluetoothDevice->fExpectedPacketSize[type]);
}
}
}
count -= currentPacketLen;
data = (void*)((uint8*)data + currentPacketLen);
}
return B_OK;
}
status_t
HciPacketHandler(void* data, int32 code, size_t size)
{
hci_id deviceId = Bluetooth::CodeHandler::Device(code);
bluetooth_device* bluetoothDevice = FindDeviceByID(deviceId);
TRACE("%s: to assemble %" B_PRIuSIZE " bytes of 0x%" B_PRIx32 "\n",
__func__, size, deviceId);
if (bluetoothDevice != NULL) {
return Assemble(bluetoothDevice, Bluetooth::CodeHandler::Protocol(code),
data, size);
} else {
ERROR("%s: Device 0x%" B_PRIx32 " could not be matched\n", __func__,
deviceId);
}
return B_ERROR;
}
status_t
RegisterDriver(bt_hci_transport_hooks* hooks, bluetooth_device** _device)
{
bluetooth_device* device = new (std::nothrow) bluetooth_device;
if (device == NULL)
return B_NO_MEMORY;
for (int index = 0; index < HCI_NUM_PACKET_TYPES; index++) {
device->fBuffersRx[index] = NULL;
device->fExpectedPacketSize[index] = 0;
}
device->info = NULL;
device->hooks = hooks;
device->supportedPacketTypes = (HCI_DM1 | HCI_DH1 | HCI_HV1);
device->linkMode = (HCI_LM_ACCEPT);
device->mtu = L2CAP_MTU_MINIMUM;
MutexLocker _(&sListLock);
if (sDeviceList.IsEmpty())
device->index = HCI_DEVICE_INDEX_OFFSET;
else {
device->index = (sDeviceList.Tail())->index + 1;
TRACE("%s: List not empty\n", __func__);
}
sDeviceList.Add(device);
TRACE("%s: Device %" B_PRIx32 "\n", __func__, device->index);
*_device = device;
return B_OK;
}
status_t
UnregisterDriver(hci_id id)
{
bluetooth_device* device = FindDeviceByID(id);
if (device == NULL)
return B_ERROR;
if (device->GetDoublyLinkedListLink()->next != NULL
|| device->GetDoublyLinkedListLink()->previous != NULL
|| device == sDeviceList.Head())
sDeviceList.Remove(device);
delete device;
return B_OK;
}
status_t
PostACL(hci_id hciId, net_buffer* buffer)
{
net_buffer* curr_frame = NULL;
net_buffer* next_frame = buffer;
uint8 flag = HCI_ACL_PACKET_START;
if (buffer == NULL)
panic("passing null buffer");
uint16 handle = buffer->type;
bluetooth_device* device = FindDeviceByID(hciId);
if (device == NULL) {
ERROR("%s: No device 0x%" B_PRIx32 "\n", __func__, hciId);
return B_ERROR;
}
TRACE("%s: index 0x%" B_PRIx32 " try to send bt packet of %" B_PRIu32
" bytes (flags 0x%" B_PRIx32 "):\n", __func__, device->index,
buffer->size, buffer->flags);
do {
curr_frame = next_frame;
if (curr_frame->size > device->mtu) {
next_frame = gBufferModule->split(curr_frame, device->mtu);
} else {
next_frame = NULL;
}
{
NetBufferPrepend<struct hci_acl_header> bufferHeader(curr_frame);
status_t status = bufferHeader.Status();
if (status < B_OK) {
continue;
}
bufferHeader->handle = pack_acl_handle_flags(handle, flag, 0);
bufferHeader->alen = curr_frame->size - sizeof(struct hci_acl_header);
}
curr_frame->protocol = BT_ACL;
TRACE("%s: Tolower nbuf %p!\n", __func__, curr_frame);
device->hooks->SendACL(device->index, curr_frame);
flag = HCI_ACL_PACKET_FRAGMENT;
} while (next_frame != NULL);
return B_OK;
}
status_t
PostSCO(hci_id hciId, net_buffer* buffer)
{
return B_ERROR;
}
status_t
PostESCO(hci_id hciId, net_buffer* buffer)
{
return B_ERROR;
}
static int
dump_bluetooth_devices(int argc, char** argv)
{
bluetooth_device* device;
DoublyLinkedList<bluetooth_device>::Iterator iterator
= sDeviceList.GetIterator();
while (iterator.HasNext()) {
device = iterator.Next();
kprintf("\tindex=%" B_PRIx32 " @%p hooks=%p\n", device->index,
device, device->hooks);
}
return 0;
}
static status_t
bluetooth_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
status_t status;
status = get_module(NET_BUFFER_MODULE_NAME,
(module_info**)&gBufferModule);
if (status < B_OK) {
panic("no way Dude we need that!");
return status;
}
status = get_module(BT_CORE_DATA_MODULE_NAME,
(module_info**)&btCoreData);
if (status < B_OK) {
ERROR("%s: problem getting bt core data module\n", __func__);
return status;
}
new (&sDeviceList) DoublyLinkedList<bluetooth_device>;
BluetoothRXPort = new BluetoothRawDataPort(BT_RX_PORT_NAME,
(BluetoothRawDataPort::port_listener_func)&HciPacketHandler);
if (BluetoothRXPort->Launch() != B_OK) {
ERROR("%s: RX thread creation failed!\n", __func__);
} else {
TRACE("%s: RX thread launched!\n", __func__);
}
sLinkChangeSemaphore = create_sem(0, "bt sem");
if (sLinkChangeSemaphore < B_OK) {
put_module(NET_STACK_MODULE_NAME);
ERROR("%s: Link change semaphore failed\n", __func__);
return sLinkChangeSemaphore;
}
mutex_init(&sListLock, "bluetooth devices");
ERROR("%s: Connection Thread error\n", __func__);
add_debugger_command("btLocalDevices", &dump_bluetooth_devices,
"Lists Bluetooth LocalDevices registered in the Stack");
return B_OK;
}
case B_MODULE_UNINIT:
{
delete_sem(sLinkChangeSemaphore);
mutex_destroy(&sListLock);
put_module(NET_BUFFER_MODULE_NAME);
put_module(NET_STACK_MODULE_NAME);
put_module(BT_CORE_DATA_MODULE_NAME);
remove_debugger_command("btLocalDevices", &dump_bluetooth_devices);
return B_OK;
}
default:
return B_ERROR;
}
}
bt_hci_module_info sBluetoothModule = {
{
BT_HCI_MODULE_NAME,
B_KEEP_LOADED,
bluetooth_std_ops
},
RegisterDriver,
UnregisterDriver,
FindDeviceByID,
PostTransportPacket,
PostACL,
PostSCO,
PostESCO
};
module_info* modules[] = {
(module_info*)&sBluetoothModule,
NULL
};