- Add bluetooth kernel module intented to manage all internal data structures

-Managing for HCI connections
    -Managing of L2cap Channels
    -Pending frames
    -Interface with KDL 



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28726 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Ruiz Dorantes 2008-11-25 18:20:40 +00:00
parent 72511e46a9
commit 18c7aa0c9d
9 changed files with 727 additions and 0 deletions

View File

@ -0,0 +1,3 @@
SubDir HAIKU_TOP src add-ons kernel bluetooth ;
SubInclude HAIKU_TOP src add-ons kernel bluetooth btCoreData ;

View File

@ -0,0 +1,183 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ConnectionInterface.h"
#include "ChannelInterface.h"
#include "FrameInterface.h"
#include <bluetooth/bdaddrUtils.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include <bluetooth/HCI/btHCI_event.h>
#define BT_DEBUG_THIS_MODULE
#include <btDebug.h>
DoublyLinkedList<HciConnection> sConnectionList;
net_buffer_module_info *gBufferModule = NULL;
inline bool
ExistConnectionByDestination(bdaddr_t *destination, hci_id hid = -1)
{
return (ConnectionByDestination(destination, hid) != NULL);
}
inline bool
ExistConnectionByHandle(uint16 handle, hci_id hid)
{
return (ConnectionByHandle(handle,hid));
}
static int
DumpHciConnections(int argc, char** argv)
{
HciConnection* conn;
L2capChannel* chan;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator();
while (iterator.HasNext()) {
conn = iterator.Next();
kprintf("\tLocalDevice=%lx Destination=%s handle=%#x type=%d outqueue=%ld expected=%ld\n",
conn->Hid, bdaddrUtils::ToString(conn->destination),
conn->handle, conn->type, conn->OutGoingFrames.Size() , conn->ExpectedResponses.Size());
// each channel
DoublyLinkedList<L2capChannel>::Iterator channelIterator = conn->ChannelList.GetIterator();
while (channelIterator.HasNext()) {
chan = channelIterator.Next();
kprintf("\t\tscid=%x dcid=%x state=%x cfg=%x\n", chan->scid,
chan->dcid, chan->state, chan->cfgState);
}
}
return 0;
}
status_t
PostEvent(net_device* ndev, void* event, size_t size)
{
struct hci_event_header* outgoingEvent = (struct hci_event_header*) event;
status_t err;
// Take actions on certain type of events.
switch (outgoingEvent->ecode) {
case HCI_EVENT_CONN_COMPLETE:
{
struct hci_ev_conn_complete* data = (struct hci_ev_conn_complete*)(outgoingEvent+1);
//TODO: XXX parse handle field
HciConnection* conn = AddConnection(data->handle, BT_ACL, &data->bdaddr, ndev->index);
if (conn == NULL)
panic("no mem for conn desc");
conn->ndevice = ndev;
debugf("Registered connection handle=%#x\n",data->handle);
} break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
{
struct hci_ev_disconnection_complete_reply* data =
(struct hci_ev_disconnection_complete_reply*)(outgoingEvent+1);
RemoveConnection(data->handle, ndev->index);
debugf("unRegistered connection handle=%#x\n",data->handle);
} break;
}
// forward to bluetooth server
port_id port = find_port(BT_USERLAND_PORT_NAME);
if (port != B_NAME_NOT_FOUND) {
err = write_port_etc(port, PACK_PORTCODE(BT_EVENT, ndev->index, -1),
event, size, B_TIMEOUT, 1*1000*1000);
if (err != B_OK)
debugf("Error posting userland %s\n", strerror(err));
} else {
flowf("ERROR:bluetooth_server not found for posting\n");
err = B_NAME_NOT_FOUND;
}
return err;
}
static status_t
bcd_std_ops(int32 op, ...)
{
status_t status;
switch (op) {
case B_MODULE_INIT:
new (&sConnectionList) DoublyLinkedList<HciConnection>;
add_debugger_command("btConnections", &DumpHciConnections,
"Lists Bluetooth Connections with RemoteDevices & channels");
status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
if (status < B_OK) {
return status;
}
return B_OK;
break;
case B_MODULE_UNINIT:
remove_debugger_command("btConnections", &DumpHciConnections);
put_module(NET_BUFFER_MODULE_NAME);
return B_OK;
break;
}
return B_ERROR;
}
bluetooth_core_data_module_info sBCDModule = {
{
BT_CORE_DATA_MODULE_NAME,
0,
bcd_std_ops
},
PostEvent,
AddConnection,
/* RemoveConnection,*/
RemoveConnection,
RouteConnection,
SetAclBuffer,
SetAclExpectedSize,
AclPutting,
AclComplete,
AclOverFlowed,
ConnectionByHandle,
ConnectionByDestination,
AddChannel,
RemoveChannel,
ChannelBySourceID,
ChannelAllocateCid,
ChannelAllocateIdent,
SignalByIdent,
TimeoutSignal,
unTimeoutSignal,
SpawmFrame,
SpawmSignal,
AcknowledgeSignal
};
module_info *modules[] = {
(module_info *)&sBCDModule,
NULL
};

View File

@ -0,0 +1,122 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <l2cap.h>
#include <bluetooth/HCI/btHCI_command.h>
#define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME "Channel"
#define SUBMODULE_COLOR 31
#include <btDebug.h>
#include "ChannelInterface.h"
#include "FrameInterface.h"
L2capChannel*
ChannelBySourceID(HciConnection *conn, uint16 scid)
{
L2capChannel* channel = NULL;
DoublyLinkedList<L2capChannel>::Iterator iterator = conn->ChannelList.GetIterator();
while (iterator.HasNext()) {
channel = iterator.Next();
if (channel->scid == scid)
return channel;
}
return NULL;
}
uint16
ChannelAllocateCid(HciConnection* conn)
{
uint16 cid = conn->lastCid ;
debugf("Starting search cid %d\n",cid);
do {
cid = (cid == L2CAP_LAST_CID)?L2CAP_FIRST_CID : cid + 1;
if(ChannelBySourceID(conn, cid) == NULL) {
conn->lastCid = cid;
return cid;
}
} while (cid != conn->lastCid);
return L2CAP_NULL_CID;
}
uint16
ChannelAllocateIdent(HciConnection* conn)
{
uint8 ident = conn->lastIdent + 1;
if (ident < L2CAP_FIRST_IDENT)
ident = L2CAP_FIRST_IDENT;
while (ident != conn->lastIdent) {
if (SignalByIdent(conn, ident) == NULL) {
conn->lastIdent = ident;
return ident;
}
ident ++;
if (ident < L2CAP_FIRST_IDENT)
ident = L2CAP_FIRST_IDENT;
}
return L2CAP_NULL_IDENT;
}
L2capChannel*
AddChannel(HciConnection* conn, uint16 psm)
{
L2capChannel* channel = new (std::nothrow) L2capChannel;
if (channel == NULL) {
flowf ("no mem for channel");
return (NULL);
}
/* Get a new Source CID */
channel->scid = ChannelAllocateCid(conn);
if (channel->scid != L2CAP_NULL_CID) {
/* Initialize channel */
channel->psm = psm;
channel->conn = conn;
channel->state = L2CAP_CHAN_CLOSED;
channel->cfgState = 0;
channel->endpoint = NULL;
// the last assigned CID should be the last in the list
// Think if keeping an ordered list will improve the search method
// as it is called in every reception
conn->ChannelList.Add(channel);
//conn->num_channels++;
// Any constance of the new channel created ...? ng_l2cap_con_ref(con);
} else {
flowf("no CID available\n");
delete channel;
channel = NULL;
}
return (channel);
}
void
RemoveChannel(HciConnection* conn, uint16 scid)
{
//TODO make it safer
conn->ChannelList.Remove(ChannelBySourceID(conn, scid));
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _CHANNEL_INTERFACE_H
#define _CHANNEL_INTERFACE_H
#include <util/DoublyLinkedList.h>
#include <l2cap.h>
#include <btCoreData.h>
L2capChannel* AddChannel(HciConnection* conn, uint16 psm);
void RemoveChannel(HciConnection* conn, uint16 scid);
L2capChannel* ChannelBySourceID(HciConnection* conn, uint16 scid);
uint16 ChannelAllocateCid(HciConnection* conn);
uint16 ChannelAllocateIdent(HciConnection* conn);
#endif // _CHANNELINTERFACE_H

View File

@ -0,0 +1,211 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <util/DoublyLinkedList.h>
#include <KernelExport.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/bluetooth_util.h>
#define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME "Connection"
#define SUBMODULE_COLOR 31
#include <btDebug.h>
#include <l2cap.h>
#include "ConnectionInterface.h"
void PurgeChannels(HciConnection* conn);
HciConnection*
AddConnection(uint16 handle, int type, bdaddr_t* dst, hci_id hid)
{
// Create connection descriptor
HciConnection* conn = ConnectionByHandle(handle, hid);
if (conn != NULL)
goto update;
conn = new (std::nothrow) HciConnection;
if (conn == NULL)
goto bail;
memset(conn, 0, sizeof(HciConnection));
conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0;
update:
// fill values
bacpy(&conn->destination, dst);
conn->type = type;
conn->handle = handle;
conn->Hid = hid;
conn->status = HCI_CONN_OPEN;
conn->mtu = L2CAP_MTU_MINIMUM; // TODO: give the mtu to the connection
conn->lastCid = L2CAP_FIRST_CID;
conn->lastIdent = L2CAP_FIRST_IDENT;
sConnectionList.Add(conn);
bail:
return conn;
}
status_t
RemoveConnection(bdaddr_t* destination, hci_id hid)
{
HciConnection* conn;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator();
while (iterator.HasNext()) {
conn = iterator.Next();
if (conn->Hid == hid && bacmp(&conn->destination, destination)==0) {
// if the device is still part of the list, remove it
if (conn->GetDoublyLinkedListLink()->next != NULL
|| conn->GetDoublyLinkedListLink()->previous != NULL
|| conn == sConnectionList.Head()) {
sConnectionList.Remove(conn);
delete conn;
return B_OK;
}
}
}
return B_ERROR;
}
status_t
RemoveConnection(uint16 handle, hci_id hid)
{
HciConnection* conn;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator();
while (iterator.HasNext()) {
conn = iterator.Next();
if (conn->Hid == hid && conn->handle == handle) {
// if the device is still part of the list, remove it
if (conn->GetDoublyLinkedListLink()->next != NULL
|| conn->GetDoublyLinkedListLink()->previous != NULL
|| conn == sConnectionList.Head()) {
sConnectionList.Remove(conn);
PurgeChannels(conn);
delete conn;
return B_OK;
}
}
}
return B_ERROR;
}
hci_id
RouteConnection(bdaddr_t* destination) {
HciConnection* conn;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator();
while (iterator.HasNext()) {
conn = iterator.Next();
if (bacmp(&conn->destination, destination)==0) {
return conn->Hid;
}
}
return -1;
}
HciConnection*
ConnectionByHandle(uint16 handle, hci_id hid)
{
HciConnection* conn;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator();
while (iterator.HasNext()) {
conn = iterator.Next();
if (conn->Hid == hid && conn->handle==handle) {
return conn;
}
}
return NULL;
}
HciConnection*
ConnectionByDestination(bdaddr_t* destination, hci_id hid)
{
HciConnection* conn;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator();
while (iterator.HasNext()) {
conn = iterator.Next();
if (conn->Hid == hid && bacmp(&conn->destination, destination)==0) {
return conn;
}
}
return NULL;
}
#if 0
#pragma mark - ACL helper funcs
#endif
void
SetAclBuffer(HciConnection* conn, net_buffer* nbuf)
{
conn->currentRxPacket = nbuf;
}
void
SetAclExpectedSize(HciConnection* conn, size_t size)
{
conn->currentRxExpectedLength = size;
}
void
AclPutting(HciConnection* conn, size_t size)
{
conn->currentRxExpectedLength -= size;
}
bool
AclComplete(HciConnection* conn)
{
return conn->currentRxExpectedLength == 0;
}
bool
AclOverFlowed(HciConnection* conn)
{
return conn->currentRxExpectedLength < 0;
}
#if 0
#pragma mark - private funcs
#endif
void
PurgeChannels(HciConnection* conn)
{
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _CONNECTION_INTERFACE_H
#define _CONNECTION_INTERFACE_H
#include <net_buffer.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/HCI/btHCI.h>
#include <btCoreData.h>
extern DoublyLinkedList<HciConnection> sConnectionList;
HciConnection* ConnectionByHandle(uint16 handle, hci_id hid);
HciConnection* ConnectionByDestination(bdaddr_t *destination, hci_id hid);
HciConnection* AddConnection(uint16 handle, int type, bdaddr_t *dst, hci_id hid);
status_t RemoveConnection(bdaddr_t *destination, hci_id hid);
status_t RemoveConnection(uint16 handle, hci_id hid);
hci_id RouteConnection(bdaddr_t *destination);
void SetAclBuffer(HciConnection* conn, net_buffer* nbuf);
void SetAclExpectedSize(HciConnection* conn, size_t size);
void AclPutting(HciConnection* conn, size_t size);
bool AclComplete(HciConnection* conn);
bool AclOverFlowed(HciConnection* conn);
#endif // _CONNECTION_INTERFACE_H

View File

@ -0,0 +1,107 @@
#include "FrameInterface.h"
#define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME "Frame"
#define SUBMODULE_COLOR 31
#include <btDebug.h>
L2capFrame*
SignalByIdent(HciConnection* conn, uint8 ident)
{
L2capFrame* frame;
DoublyLinkedList<L2capFrame>::Iterator iterator = conn->ExpectedResponses.GetIterator();
while (iterator.HasNext()) {
frame = iterator.Next();
if (frame->type == L2CAP_C_FRAME && frame->ident == ident) {
return frame;
}
}
return NULL;
}
status_t
TimeoutSignal(L2capFrame* frame, uint32 timeo)
{
if (frame != NULL)
return B_OK;
return B_ERROR;
}
status_t
unTimeoutSignal(L2capFrame* frame)
{
if (frame != NULL)
return B_OK;
return B_ERROR;
}
L2capFrame*
SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type type)
{
if (buffer == NULL)
panic("Null Buffer to outgoing queue");
L2capFrame* frame = new (std::nothrow) L2capFrame;
frame->conn = conn;
frame->channel = NULL; // TODO: needed?
frame->buffer = buffer;
frame->type = type;
conn->OutGoingFrames.Add(frame, true);
return frame;
}
L2capFrame*
SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code)
{
if (buffer == NULL)
panic("Null Buffer to outgoing queue");
L2capFrame* frame = new (std::nothrow) L2capFrame;
frame->conn = conn;
frame->channel = channel; // TODO: needed?
frame->buffer = buffer;
frame->type = L2CAP_C_FRAME;
frame->ident = ident;
frame->code = code;
conn->OutGoingFrames.Add(frame, true);
return frame;
}
status_t
AcknowledgeSignal(L2capFrame* frame)
{
if (frame != NULL) {
if (frame->type == L2CAP_C_FRAME) {
unTimeoutSignal(frame);
frame->conn->ExpectedResponses.Remove(frame);
}
gBufferModule->free(frame->buffer);
delete frame;
return B_OK;
}
return B_ERROR;
}

View File

@ -0,0 +1,28 @@
#ifndef _FRAME_INTERFACE_H
#define _FRAME_INTERFACE_H
#include <net_buffer.h>
#include <btCoreData.h>
extern net_buffer_module_info* gBufferModule;
L2capFrame*
SignalByIdent(HciConnection* conn, uint8 ident);
status_t
TimeoutSignal(L2capFrame* frame, uint32 timeo);
status_t
unTimeoutSignal(L2capFrame* frame);
L2capFrame*
SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type frame);
L2capFrame*
SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code);
status_t
AcknowledgeSignal(L2capFrame* frame);
#endif

View File

@ -0,0 +1,18 @@
SubDir HAIKU_TOP src add-ons kernel bluetooth btCoreData ;
UsePrivateHeaders kernel net bluetooth ;
UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ;
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
# disable debug output, if debugging is disabled
if $(DEBUG) = 0 {
SubDirCcFlags [ FDefines DEBUG_MAX_LEVEL_FLOW=0 DEBUG_MAX_LEVEL_INFO=0 ] ;
}
KernelAddon btCoreData :
ConnectionInterface.cpp
ChannelInterface.cpp
FrameInterface.cpp
BTCoreData.cpp
;