/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define KERNEL_LAND #include #undef KERNEL_LAND #include #include #include #include #include #include #include #include "acl.h" int32 api_version = B_CUR_DRIVER_API_VERSION; typedef PortListener BluetoothRawDataPort; // Modules references net_buffer_module_info* gBufferModule = NULL; struct bluetooth_core_data_module_info* btCoreData = NULL; static mutex sListLock; static sem_id sLinkChangeSemaphore; static DoublyLinkedList sDeviceList; BluetoothRawDataPort* BluetoothRXPort; // forward declarations status_t HciPacketHandler(void* data, int32 code, size_t size); bluetooth_device* FindDeviceByID(hci_id hid) { bluetooth_device* device; DoublyLinkedList::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) { // new buffer incoming 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]) { // the whole packet is here so it can be already posted. 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); // Create the buffer -> TODO: this allocation can fail 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 { // Continuation of a packet 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: // TODO: device descriptor has been fetched better not // pass id again 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]); } } } // in case in the pipe there is info about the next buffer 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; } // #pragma mark - 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; // not yet used device->hooks = hooks; device->supportedPacketTypes = (HCI_DM1 | HCI_DH1 | HCI_HV1); device->linkMode = (HCI_LM_ACCEPT); device->mtu = L2CAP_MTU_MINIMUM; // TODO: ensure specs min value MutexLocker _(&sListLock); if (sDeviceList.IsEmpty()) device->index = HCI_DEVICE_INDEX_OFFSET; // REVIEW: dev index else { device->index = (sDeviceList.Tail())->index + 1; // REVIEW! 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; } // PostACL 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; // TODO: CodeHandler 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); // TODO: ATOMIC! any other thread should stop here do { // Divide packet if big enough curr_frame = next_frame; if (curr_frame->size > device->mtu) { next_frame = gBufferModule->split(curr_frame, device->mtu); } else { next_frame = NULL; } // Attach acl header { NetBufferPrepend bufferHeader(curr_frame); status_t status = bufferHeader.Status(); if (status < B_OK) { // free the buffer continue; } bufferHeader->handle = pack_acl_handle_flags(handle, flag, 0); bufferHeader->alen = curr_frame->size - sizeof(struct hci_acl_header); } // Send to driver curr_frame->protocol = BT_ACL; TRACE("%s: Tolower nbuf %p!\n", __func__, curr_frame); // We could pass a cookie and avoid the driver fetch the Id 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::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; // static C++ objects are not initialized in the module startup 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__); // we Cannot do much here ... avoid registering } 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"); // status = InitializeAclConnectionThread(); 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); // status_t status = QuitAclConnectionThread(); 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 };