- Move bluetooth net_device module to a independent module HCI, remake API interfaces

- Move functionality for assembling ACL/events packets of the driver to this module
- Move h2generic driver to c++ (not style)
- Pass checkstyle.py to all commited files.
Fixes:
- Wrong condition for finishing l2cap packet segmentation.
- Place NetBuffersPrependers in a inner scope to avoid Sycing twice in destructor.
- Avoid keeping trace of l2cap responses of any other kind of thread.
- Do not free net_buffers of for Frame containers.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35117 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Ruiz Dorantes
2010-01-17 15:46:36 +00:00
parent 9b178bf778
commit 9760dcae20
26 changed files with 1157 additions and 1259 deletions
-35
View File
@@ -1,35 +0,0 @@
/*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BTHCI_MODULE_H_
#define _BTHCI_MODULE_H_
/* includes */
#include <bluetooth/HCI/btHCI.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include <net_buffer.h>
/* defines */
#define BT_HCI_MODULE_NAME "bus_managers/hci/v1"
/* TODO: Possible definition of a bus manager of whatever is gonna be on the top */
typedef struct bt_hci_module_info {
/* registration */
status_t (*RegisterDriver)(bt_hci_transport* desc, hci_id *id /*out*/,
bt_hci_device* cookie /*out*/ );
status_t (*UnregisterDriver)(hci_id id);
/* Transferences to be called from drivers */
status_t (*PostACL)(hci_id id, net_buffer* nbuf);
status_t (*PostSCO)(hci_id id, net_buffer* nbuf);
/* Management */
bt_hci_device* (*GetHciDevice)(hci_id id);
} bt_hci_module_info ;
#endif // _BTHCI_MODULE_H_
+117 -50
View File
@@ -7,53 +7,46 @@
#include <bluetooth/HCI/btHCI.h> #include <bluetooth/HCI/btHCI.h>
#include <util/DoublyLinkedList.h>
#include <net_buffer.h> #include <net_buffer.h>
#include <Drivers.h> #include <Drivers.h>
typedef enum { ANCILLYANT = (1<<0),
RUNNING = (1<<1), typedef enum {
LEAVING = (1<<2), ANCILLYANT = (1<<0),
SENDING = (1<<3), RUNNING = (1<<1),
PROCESSING = (1<<4) LEAVING = (1<<2),
} bt_transport_status_t; SENDING = (1<<3),
PROCESSING = (1<<4)
} bt_transport_status_t;
typedef uint8 bt_stat_t; typedef uint8 bt_stat_t;
typedef struct bt_hci_statistics { typedef struct bt_hci_statistics {
bt_stat_t acceptedTX; bt_stat_t acceptedTX;
bt_stat_t rejectedTX; bt_stat_t rejectedTX;
bt_stat_t successfulTX; bt_stat_t successfulTX;
bt_stat_t errorTX; bt_stat_t errorTX;
bt_stat_t acceptedRX; bt_stat_t acceptedRX;
bt_stat_t rejectedRX; bt_stat_t rejectedRX;
bt_stat_t successfulRX; bt_stat_t successfulRX;
bt_stat_t errorRX; bt_stat_t errorRX;
bt_stat_t commandTX; bt_stat_t commandTX;
bt_stat_t eventRX; bt_stat_t eventRX;
bt_stat_t aclTX; bt_stat_t aclTX;
bt_stat_t aclRX; bt_stat_t aclRX;
bt_stat_t scoTX; bt_stat_t scoTX;
bt_stat_t scoRX; bt_stat_t scoRX;
bt_stat_t escoTX; bt_stat_t escoTX;
bt_stat_t escoRX; bt_stat_t escoRX;
bt_stat_t bytesRX; bt_stat_t bytesRX;
bt_stat_t bytesTX; bt_stat_t bytesTX;
} bt_hci_statistics; } bt_hci_statistics;
/* TODO: Possible hooks which drivers will have to provide */
typedef struct bt_hci_transport {
status_t (*SendCommand)(hci_id hci_dev, net_buffer *snbuf);
status_t (*SendPacket)(hci_id hci_dev, net_buffer *nbuf );
status_t (*SendSCO)(hci_id hci_dev, net_buffer *nbuf );
status_t (*DeliverStatistics)(bt_hci_statistics *statistics);
transport_type kind;
char name[B_OS_NAME_LENGTH];
} bt_hci_transport;
typedef struct bt_hci_device { typedef struct bt_hci_device {
transport_type kind; transport_type kind;
@@ -61,35 +54,109 @@ typedef struct bt_hci_device {
} bt_hci_device; } bt_hci_device;
/* Here the transport driver have some flags that */ /* Hooks which drivers will have to provide.
/* can be used to inform the upper layer about some */ * The structure is meant to be allocated in driver side and
/* special behaouvior to perform */ * provided to the HCI where it will fill the remaining fields
*/
typedef struct bt_hci_transport_hooks {
#define BT_IGNORE_THIS_DEVICE (1<<0) // to be filled by driver
#define BT_SCO_NOT_WORKING (1<<1) status_t (*SendCommand)(hci_id hciId, void* command);
#define BT_WILL_NEED_A_RESET (1<<2) status_t (*SendACL)(hci_id hciId, net_buffer* nbuf );
#define BT_DIGIANSWER (1<<4) status_t (*SendSCO)(hci_id hciId, net_buffer* nbuf );
status_t (*SendESCO)(hci_id hciId, net_buffer* nbuf );
/* Mandatory IOCTLS to be */ status_t (*DeliverStatistics)(hci_id hciId, bt_hci_statistics* statistics);
transport_type kind;
} bt_hci_transport_hooks;
typedef struct bt_hci_device_information {
uint32 flags;
uint16 vendorId;
uint16 deviceId;
char name[B_OS_NAME_LENGTH];
} bt_hci_device_information;
#ifdef __cplusplus
struct bluetooth_device : DoublyLinkedListLinkImpl<bluetooth_device> {
net_buffer* fBuffersRx[HCI_NUM_PACKET_TYPES];
size_t fExpectedPacketSize[HCI_NUM_PACKET_TYPES];
hci_id index;
int fd;
bt_hci_device_information* info;
bt_hci_transport_hooks* hooks;
uint16 mtu;
};
#else
struct bluetooth_device;
#endif
#define BT_HCI_MODULE_NAME "bluetooth/hci/v1"
// Possible definition of a bus manager
typedef struct bt_hci_module_info {
module_info info;
// Registration in Stack
status_t (*RegisterDriver)(bt_hci_transport_hooks* hooks,
bluetooth_device** device);
status_t (*UnregisterDriver)(hci_id id);
bluetooth_device* (*FindDeviceByID)(hci_id id);
// to be called from transport driver
status_t (*PostTransportPacket)(hci_id hid, bt_packet_t type,
void* data, size_t count);
// To be called from upper layers
status_t (*PostACL)(hci_id hciId, net_buffer* buffer);
status_t (*PostSCO)(hci_id hciId, net_buffer* buffer);
status_t (*PostESCO)(hci_id hciId, net_buffer* buffer);
} bt_hci_module_info ;
/* Here the transport driver have some flags that
* can be used to inform the upper layer about some
* special behaouvior to perform */
#define BT_IGNORE_THIS_DEVICE (1 << 0)
#define BT_SCO_NOT_WORKING (1 << 1)
#define BT_WILL_NEED_A_RESET (1 << 2)
#define BT_DIGIANSWER (1 << 4)
// Mandatory IOCTLS
#define BT_IOCTLS_OFFSET 3000 #define BT_IOCTLS_OFFSET 3000
enum { enum {
ISSUE_BT_COMMAND = B_DEVICE_OP_CODES_END + BT_IOCTLS_OFFSET, //12999 ISSUE_BT_COMMAND = B_DEVICE_OP_CODES_END + BT_IOCTLS_OFFSET, // 12999
GET_STATS, GET_STATS,
GET_NOTIFICATION_PORT, GET_NOTIFICATION_PORT,
GET_HCI_ID, GET_HCI_ID,
BT_UP BT_UP
}; };
#define PACK_PORTCODE(type,hid,data) ((type&0xFF)<<24|(hid&0xFF)<<16|(data&0xFFFF)) #define PACK_PORTCODE(type,hid,data) ((type & 0xFF) << 24 | (hid & 0xFF) << 16 | (data & 0xFFFF))
#define GET_PORTCODE_TYPE(code) ((code&0xFF000000)>>24) #define GET_PORTCODE_TYPE(code) ((code & 0xFF000000) >> 24)
#define GET_PORTCODE_HID(code) ((code&0x00FF0000)>>16) #define GET_PORTCODE_HID(code) ((code & 0x00FF0000) >> 16)
#define GET_PORTCODE_DATA(code) ((code&0x0000FFFF)) #define GET_PORTCODE_DATA(code) ((code & 0x0000FFFF))
/* Port drivers can use to send information (1 for all for /* Port drivers can use to send information (1 for all for
at moment refer to ioctl GET_NOTIFICATION_PORT)*/ at moment refer to ioctl GET_NOTIFICATION_PORT)*/
#define BT_USERLAND_PORT_NAME "Kernel-User Event" #define BT_USERLAND_PORT_NAME "BT Kernel-User Event"
#define BT_RX_PORT_NAME "BT Kernel RX assembly"
#define BLUETOOTH_CONNECTION_PORT "bluetooth connection port" #define BLUETOOTH_CONNECTION_PORT "bluetooth connection port"
#define BLUETOOTH_CONNECTION_SCHED_PORT "bluetooth con sched port" #define BLUETOOTH_CONNECTION_SCHED_PORT "bluetooth con sched port"
+188 -173
View File
@@ -1,173 +1,188 @@
/* /*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef _BTCOREDATA_H #ifndef _BTCOREDATA_H
#define _BTCOREDATA_H #define _BTCOREDATA_H
#include <module.h> #include <module.h>
#include <lock.h> #include <lock.h>
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <util/DoublyLinkedQueue.h> #include <util/DoublyLinkedQueue.h>
#include <net_buffer.h> #include <net_buffer.h>
#include <net_device.h> #include <net_device.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
#include <bluetooth/HCI/btHCI.h> #include <bluetooth/HCI/btHCI.h>
#include <l2cap.h> #include <bluetooth/HCI/btHCI_transport.h>
#include <l2cap.h>
#define BT_CORE_DATA_MODULE_NAME "bluetooth/btCoreData/v1"
#define BT_CORE_DATA_MODULE_NAME "bluetooth/btCoreData/v1"
struct L2capChannel;
struct L2capFrame; struct L2capChannel;
struct L2capEndpoint; struct L2capFrame;
struct L2capEndpoint;
typedef enum _connection_status {
HCI_CONN_CLOSED, typedef enum _connection_status {
HCI_CONN_OPEN, HCI_CONN_CLOSED,
} connection_status; HCI_CONN_OPEN,
} connection_status;
#ifdef __cplusplus
#ifdef __cplusplus
struct HciConnection : DoublyLinkedListLinkImpl<HciConnection> {
HciConnection(); struct HciConnection : DoublyLinkedListLinkImpl<HciConnection> {
virtual ~HciConnection(); HciConnection();
virtual ~HciConnection();
hci_id Hid;
struct net_device* ndevice; hci_id Hid;
net_buffer* currentRxPacket; bluetooth_device* ndevice;
ssize_t currentRxExpectedLength; net_buffer* currentRxPacket;
bdaddr_t destination; ssize_t currentRxExpectedLength;
uint16 handle; bdaddr_t destination;
int type; uint16 handle;
uint16 mtu; int type;
connection_status status; /* ACL connection state */ uint16 mtu;
uint16 lastCid; connection_status status;
uint8 lastIdent; uint16 lastCid;
DoublyLinkedList<L2capChannel> ChannelList; uint8 lastIdent;
DoublyLinkedList<L2capFrame> ExpectedResponses; DoublyLinkedList<L2capChannel> ChannelList;
DoublyLinkedList<L2capFrame> OutGoingFrames; DoublyLinkedList<L2capFrame> ExpectedResponses;
mutex fLock; DoublyLinkedList<L2capFrame> OutGoingFrames;
mutex fLockExpected; mutex fLock;
}; mutex fLockExpected;
};
#else
#else
struct HciConnection;
struct HciConnection;
#endif
#endif
typedef enum _channel_status {
L2CAP_CHAN_CLOSED, /* channel closed */ typedef enum _channel_status {
L2CAP_CHAN_W4_L2CAP_CON_RSP, /* wait for L2CAP resp. */ L2CAP_CHAN_CLOSED, /* channel closed */
L2CAP_CHAN_W4_L2CA_CON_RSP, /* wait for upper resp. */ L2CAP_CHAN_W4_L2CAP_CON_RSP, /* wait for L2CAP resp. */
L2CAP_CHAN_CONFIG, /* L2CAP configuration */ L2CAP_CHAN_W4_L2CA_CON_RSP, /* wait for upper resp. */
L2CAP_CHAN_OPEN, /* channel open */ L2CAP_CHAN_CONFIG, /* L2CAP configuration */
L2CAP_CHAN_W4_L2CAP_DISCON_RSP, /* wait for L2CAP discon. */ L2CAP_CHAN_OPEN, /* channel open */
L2CAP_CHAN_W4_L2CA_DISCON_RSP /* wait for upper discon. */ L2CAP_CHAN_W4_L2CAP_DISCON_RSP, /* wait for L2CAP discon. */
} channel_status; L2CAP_CHAN_W4_L2CA_DISCON_RSP /* wait for upper discon. */
} channel_status;
#ifdef __cplusplus
#ifdef __cplusplus
typedef struct _ChannelConfiguration {
typedef struct _ChannelConfiguration {
uint16 imtu; /* incoming channel MTU */
l2cap_flow_t iflow; /* incoming flow control */ uint16 imtu; /* incoming channel MTU */
uint16 omtu; /* outgoing channel MTU */ l2cap_flow_t iflow; /* incoming flow control */
l2cap_flow_t oflow; /* outgoing flow control */ uint16 omtu; /* outgoing channel MTU */
l2cap_flow_t oflow; /* outgoing flow control */
uint16 flush_timo; /* flush timeout */
uint16 link_timo; /* link timeout */ uint16 flush_timo; /* flush timeout */
uint16 link_timo; /* link timeout */
} ChannelConfiguration;
} ChannelConfiguration;
struct L2capChannel : DoublyLinkedListLinkImpl<L2capChannel> {
HciConnection* conn; struct L2capChannel : DoublyLinkedListLinkImpl<L2capChannel> {
uint16 scid; HciConnection* conn;
uint16 dcid; uint16 scid;
uint16 psm; uint16 dcid;
uint8 ident; uint16 psm;
uint8 cfgState; uint8 ident;
uint8 cfgState;
channel_status state;
ChannelConfiguration* configuration; channel_status state;
L2capEndpoint* endpoint; ChannelConfiguration* configuration;
}; L2capEndpoint* endpoint;
};
#endif
#endif
typedef enum _frametype {
L2CAP_C_FRAME, // signals typedef enum _frametype {
L2CAP_G_FRAME, // CL packets L2CAP_C_FRAME, // signals
L2CAP_B_FRAME, // CO packets L2CAP_G_FRAME, // CL packets
L2CAP_B_FRAME, // CO packets
L2CAP_I_FRAME,
L2CAP_S_FRAME L2CAP_I_FRAME,
} frame_type; L2CAP_S_FRAME
} frame_type;
#ifdef __cplusplus
#ifdef __cplusplus
struct L2capFrame : DoublyLinkedListLinkImpl<L2capFrame> {
struct L2capFrame : DoublyLinkedListLinkImpl<L2capFrame> {
HciConnection* conn;
L2capChannel* channel; HciConnection* conn;
L2capChannel* channel;
uint16 flags; /* command flags */
#define L2CAP_CMD_PENDING (1 << 0) /* command is pending */ uint16 flags; /* command flags */
#define L2CAP_CMD_PENDING (1 << 0) /* command is pending */
uint8 code; /* L2CAP command opcode */
uint8 ident; /* L2CAP command ident */ uint8 code; /* L2CAP command opcode */
uint8 ident; /* L2CAP command ident */
frame_type type;
frame_type type;
net_buffer* buffer; // contains 1 l2cap / mutliple acls
net_buffer* buffer; // contains 1 l2cap / mutliple acls
//TODO :struct callout timo; /* RTX/ERTX timeout */
}; // TODO :struct callout timo; /* RTX/ERTX timeout */
};
#endif
#endif
struct bluetooth_core_data_module_info {
module_info info; struct bluetooth_core_data_module_info {
module_info info;
status_t (*PostEvent)(struct net_device* ndev, void* event, size_t size);
struct HciConnection* (*AddConnection)(uint16 handle, int type, bdaddr_t* dst, hci_id hid); status_t (*PostEvent)(bluetooth_device* ndev, void* event,
size_t size);
/*status_t (*RemoveConnection)(bdaddr_t destination, hci_id hid);*/ struct HciConnection* (*AddConnection)(uint16 handle, int type,
status_t (*RemoveConnection)(uint16 handle, hci_id hid); bdaddr_t* dst, hci_id hid);
hci_id (*RouteConnection)(bdaddr_t* destination); // status_t (*RemoveConnection)(bdaddr_t destination, hci_id hid);
status_t (*RemoveConnection)(uint16 handle, hci_id hid);
void (*SetAclBuffer)(struct HciConnection* conn, net_buffer* nbuf);
void (*SetAclExpectedSize)(struct HciConnection* conn, size_t size); hci_id (*RouteConnection)(bdaddr_t* destination);
void (*AclPutting)(struct HciConnection* conn, size_t size);
bool (*AclComplete)(struct HciConnection* conn); void (*SetAclBuffer)(struct HciConnection* conn,
bool (*AclOverFlowed)(struct HciConnection* conn); net_buffer* nbuf);
void (*SetAclExpectedSize)(struct HciConnection* conn,
struct HciConnection* (*ConnectionByHandle)(uint16 handle, hci_id hid); size_t size);
struct HciConnection* (*ConnectionByDestination)(bdaddr_t* destination, hci_id hid); void (*AclPutting)(struct HciConnection* conn,
size_t size);
struct L2capChannel* (*AddChannel)(struct HciConnection* conn, uint16 psm); bool (*AclComplete)(struct HciConnection* conn);
void (*RemoveChannel)(struct HciConnection* conn, uint16 scid); bool (*AclOverFlowed)(struct HciConnection* conn);
struct L2capChannel* (*ChannelBySourceID)(struct HciConnection* conn, uint16 sid);
uint16 (*ChannelAllocateCid)(struct HciConnection* conn); struct HciConnection* (*ConnectionByHandle)(uint16 handle, hci_id hid);
uint16 (*ChannelAllocateIdent)(struct HciConnection* conn); struct HciConnection* (*ConnectionByDestination)(bdaddr_t* destination,
hci_id hid);
struct L2capFrame* (*SignalByIdent)(struct HciConnection* conn, uint8 ident);
status_t (*TimeoutSignal)(struct L2capFrame* frame, uint32 timeo); struct L2capChannel* (*AddChannel)(struct HciConnection* conn,
status_t (*UnTimeoutSignal)(struct L2capFrame* frame); uint16 psm);
struct L2capFrame* (*SpawnFrame)(struct HciConnection* conn, struct L2capChannel* channel, net_buffer* buffer, frame_type frame); void (*RemoveChannel)(struct HciConnection* conn,
struct L2capFrame* (*SpawnSignal)(struct HciConnection* conn, struct L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code); uint16 scid);
status_t (*AcknowledgeSignal)(struct L2capFrame* frame); struct L2capChannel* (*ChannelBySourceID)(struct HciConnection* conn,
status_t (*QueueSignal)(struct L2capFrame* frame); uint16 sid);
uint16 (*ChannelAllocateCid)(struct HciConnection* conn);
}; uint16 (*ChannelAllocateIdent)(struct HciConnection* conn);
inline bool ExistConnectionByDestination(bdaddr_t* destination, hci_id hid); struct L2capFrame* (*SignalByIdent)(struct HciConnection* conn,
inline bool ExistConnectionByHandle(uint16 handle, hci_id hid); uint8 ident);
status_t (*TimeoutSignal)(struct L2capFrame* frame, uint32 timeo);
#endif // _BTCOREDATA_H status_t (*UnTimeoutSignal)(struct L2capFrame* frame);
struct L2capFrame* (*SpawnFrame)(struct HciConnection* conn,
struct L2capChannel* channel, net_buffer* buffer, frame_type frame);
struct L2capFrame* (*SpawnSignal)(struct HciConnection* conn,
struct L2capChannel* channel, net_buffer* buffer,
uint8 ident, uint8 code);
status_t (*AcknowledgeSignal)(struct L2capFrame* frame);
status_t (*QueueSignal)(struct L2capFrame* frame);
};
inline bool ExistConnectionByDestination(bdaddr_t* destination, hci_id hid);
inline bool ExistConnectionByHandle(uint16 handle, hci_id hid);
#endif // _BTCOREDATA_H
+11 -12
View File
@@ -1,12 +1,11 @@
/* /*
* Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef _BTMODULES_H #ifndef _BTMODULES_H
#define _BTMODULES_H #define _BTMODULES_H
#define NET_BLUETOOTH_DEVICE_NAME "network/devices/bluetooth/v1" #define NET_BLUETOOTH_L2CAP_NAME "network/protocols/l2cap/v1"
#define NET_BLUETOOTH_L2CAP_NAME "network/protocols/l2cap/v1"
#endif // _BCOREDATA_H
#endif // _BCOREDATA_H
+1
View File
@@ -1,3 +1,4 @@
SubDir HAIKU_TOP src add-ons kernel bluetooth ; SubDir HAIKU_TOP src add-ons kernel bluetooth ;
SubInclude HAIKU_TOP src add-ons kernel bluetooth btCoreData ; SubInclude HAIKU_TOP src add-ons kernel bluetooth btCoreData ;
SubInclude HAIKU_TOP src add-ons kernel bluetooth hci ;
@@ -15,10 +15,11 @@
#include <btDebug.h> #include <btDebug.h>
DoublyLinkedList<HciConnection> sConnectionList; DoublyLinkedList<HciConnection> sConnectionList;
net_buffer_module_info *gBufferModule = NULL; net_buffer_module_info* gBufferModule = NULL;
inline bool inline bool
ExistConnectionByDestination(bdaddr_t *destination, hci_id hid = -1) ExistConnectionByDestination(bdaddr_t* destination, hci_id hid = -1)
{ {
return (ConnectionByDestination(destination, hid) != NULL); return (ConnectionByDestination(destination, hid) != NULL);
} }
@@ -27,7 +28,7 @@ ExistConnectionByDestination(bdaddr_t *destination, hci_id hid = -1)
inline bool inline bool
ExistConnectionByHandle(uint16 handle, hci_id hid) ExistConnectionByHandle(uint16 handle, hci_id hid)
{ {
return (ConnectionByHandle(handle,hid)); return (ConnectionByHandle(handle, hid));
} }
@@ -37,39 +38,48 @@ DumpHciConnections(int argc, char** argv)
HciConnection* conn; HciConnection* conn;
L2capChannel* chan; L2capChannel* chan;
L2capFrame* frame; L2capFrame* frame;
DoublyLinkedList<HciConnection>::Iterator iterator = sConnectionList.GetIterator(); DoublyLinkedList<HciConnection>::Iterator iterator
= sConnectionList.GetIterator();
while (iterator.HasNext()) { while (iterator.HasNext()) {
conn = iterator.Next(); conn = iterator.Next();
kprintf("LocalDevice=%lx Destination=%s handle=%#x type=%d outqueue=%ld expected=%ld\n", kprintf("LocalDevice=%lx Destination=%s handle=%#x type=%d"
conn->Hid, bdaddrUtils::ToString(conn->destination), "outqueue=%ld expected=%ld\n", conn->Hid,
conn->handle, conn->type, conn->OutGoingFrames.Count() , conn->ExpectedResponses.Count()); bdaddrUtils::ToString(conn->destination), conn->handle, conn->type,
conn->OutGoingFrames.Count() , conn->ExpectedResponses.Count());
// each channel // each channel
kprintf("\tChannels\n"); kprintf("\tChannels\n");
DoublyLinkedList<L2capChannel>::Iterator channelIterator = conn->ChannelList.GetIterator(); DoublyLinkedList<L2capChannel>::Iterator channelIterator
= conn->ChannelList.GetIterator();
while (channelIterator.HasNext()) { while (channelIterator.HasNext()) {
chan = channelIterator.Next(); chan = channelIterator.Next();
kprintf("\t\tscid=%x dcid=%x state=%x cfg=%x\n", chan->scid, kprintf("\t\tscid=%x dcid=%x state=%x cfg=%x\n", chan->scid,
chan->dcid, chan->state, chan->cfgState); chan->dcid, chan->state, chan->cfgState);
} }
// Each outgoing // Each outgoing
kprintf("\n\tOutGoingFrames\n"); kprintf("\n\tOutGoingFrames\n");
DoublyLinkedList<L2capFrame>::Iterator frameIterator = conn->OutGoingFrames.GetIterator(); DoublyLinkedList<L2capFrame>::Iterator frameIterator
= conn->OutGoingFrames.GetIterator();
while (frameIterator.HasNext()) { while (frameIterator.HasNext()) {
frame = frameIterator.Next(); frame = frameIterator.Next();
kprintf("\t\tscid=%x code=%x ident=%x type=%x, buffer=%p\n", frame->channel->scid, kprintf("\t\tscid=%x code=%x ident=%x type=%x, buffer=%p\n",
frame->code, frame->ident, frame->type, frame->buffer); frame->channel->scid, frame->code, frame->ident,
frame->type, frame->buffer);
} }
// Each expected // Each expected
kprintf("\n\tExpectedFrames\n"); kprintf("\n\tExpectedFrames\n");
DoublyLinkedList<L2capFrame>::Iterator frameExpectedIterator = conn->ExpectedResponses.GetIterator(); DoublyLinkedList<L2capFrame>::Iterator frameExpectedIterator
= conn->ExpectedResponses.GetIterator();
while (frameExpectedIterator.HasNext()) { while (frameExpectedIterator.HasNext()) {
frame = frameExpectedIterator.Next(); frame = frameExpectedIterator.Next();
kprintf("\t\tscid=%x code=%x ident=%x type=%x, buffer=%p\n", frame->channel->scid, kprintf("\t\tscid=%x code=%x ident=%x type=%x, buffer=%p\n",
frame->code, frame->ident, frame->type, frame->buffer); frame->channel->scid, frame->code, frame->ident,
frame->type, frame->buffer);
} }
} }
@@ -77,9 +87,8 @@ DumpHciConnections(int argc, char** argv)
} }
status_t status_t
PostEvent(net_device* ndev, void* event, size_t size) PostEvent(bluetooth_device* ndev, void* event, size_t size)
{ {
struct hci_event_header* outgoingEvent = (struct hci_event_header*) event; struct hci_event_header* outgoingEvent = (struct hci_event_header*) event;
status_t err; status_t err;
@@ -88,41 +97,49 @@ PostEvent(net_device* ndev, void* event, size_t size)
switch (outgoingEvent->ecode) { switch (outgoingEvent->ecode) {
case HCI_EVENT_CONN_COMPLETE: case HCI_EVENT_CONN_COMPLETE:
{ {
struct hci_ev_conn_complete* data = (struct hci_ev_conn_complete*)(outgoingEvent+1); struct hci_ev_conn_complete* data
//TODO: XXX parse handle field = (struct hci_ev_conn_complete*)(outgoingEvent + 1);
HciConnection* conn = AddConnection(data->handle, BT_ACL, &data->bdaddr, ndev->index);
// TODO: XXX parse handle field
HciConnection* conn = AddConnection(data->handle, BT_ACL,
&data->bdaddr, ndev->index);
if (conn == NULL) if (conn == NULL)
panic("no mem for conn desc"); panic("no mem for conn desc");
conn->ndevice = ndev; conn->ndevice = ndev;
debugf("Registered connection handle=%#x\n",data->handle); debugf("Registered connection handle=%#x\n",data->handle);
break;
} break; }
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
{ {
struct hci_ev_disconnection_complete_reply* data = struct hci_ev_disconnection_complete_reply* data;
(struct hci_ev_disconnection_complete_reply*)(outgoingEvent+1);
data = (struct hci_ev_disconnection_complete_reply*)
(outgoingEvent + 1);
RemoveConnection(data->handle, ndev->index); RemoveConnection(data->handle, ndev->index);
debugf("unRegistered connection handle=%#x\n",data->handle); debugf("unRegistered connection handle=%#x\n",data->handle);
} break; break;
}
} }
// forward to bluetooth server // forward to bluetooth server
port_id port = find_port(BT_USERLAND_PORT_NAME); port_id port = find_port(BT_USERLAND_PORT_NAME);
if (port != B_NAME_NOT_FOUND) { if (port != B_NAME_NOT_FOUND) {
err = write_port_etc(port, PACK_PORTCODE(BT_EVENT, ndev->index, -1), err = write_port_etc(port, PACK_PORTCODE(BT_EVENT, ndev->index, -1),
event, size, B_TIMEOUT, 1*1000*1000); event, size, B_TIMEOUT, 1 * 1000 * 1000);
if (err != B_OK) if (err != B_OK)
debugf("Error posting userland %s\n", strerror(err)); debugf("Error posting userland %s\n", strerror(err));
} else { } else {
flowf("ERROR:bluetooth_server not found for posting\n"); flowf("ERROR:bluetooth_server not found for posting\n");
err = B_NAME_NOT_FOUND; err = B_NAME_NOT_FOUND;
} }
return err; return err;
} }
@@ -136,12 +153,12 @@ bcd_std_ops(int32 op, ...)
case B_MODULE_INIT: case B_MODULE_INIT:
new (&sConnectionList) DoublyLinkedList<HciConnection>; new (&sConnectionList) DoublyLinkedList<HciConnection>;
add_debugger_command("btConnections", &DumpHciConnections, add_debugger_command("btConnections", &DumpHciConnections,
"Lists Bluetooth Connections with RemoteDevices & channels"); "Lists Bluetooth Connections with RemoteDevices & channels");
status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); status = get_module(NET_BUFFER_MODULE_NAME,
if (status < B_OK) { (module_info **)&gBufferModule);
if (status < B_OK)
return status; return status;
}
return B_OK; return B_OK;
@@ -159,6 +176,7 @@ bcd_std_ops(int32 op, ...)
return B_ERROR; return B_ERROR;
} }
bluetooth_core_data_module_info sBCDModule = { bluetooth_core_data_module_info sBCDModule = {
{ {
BT_CORE_DATA_MODULE_NAME, BT_CORE_DATA_MODULE_NAME,
@@ -167,7 +185,7 @@ bluetooth_core_data_module_info sBCDModule = {
}, },
PostEvent, PostEvent,
AddConnection, AddConnection,
/* RemoveConnection,*/ // RemoveConnection,
RemoveConnection, RemoveConnection,
RouteConnection, RouteConnection,
@@ -198,7 +216,7 @@ bluetooth_core_data_module_info sBCDModule = {
}; };
module_info *modules[] = { module_info* modules[] = {
(module_info *)&sBCDModule, (module_info*)&sBCDModule,
NULL NULL
}; };
+16
View File
@@ -0,0 +1,16 @@
SubDir HAIKU_TOP src add-ons kernel bluetooth hci ;
UsePrivateKernelHeaders ;
UsePrivateHeaders 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 hci :
bluetooth.cpp
acl.cpp
;
@@ -38,14 +38,14 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
{ {
status_t error = B_OK; status_t error = B_OK;
/* Check ACL data packet. Driver should ensure report complete ACL packets */ // Check ACL data packet. Driver should ensure report complete ACL packets
if (nbuf->size < sizeof(struct hci_acl_header)) { if (nbuf->size < sizeof(struct hci_acl_header)) {
debugf("Transport driver has reported invalid ACL data packet, too small, length=%ld\n", nbuf->size); debugf("Invalid ACL data packet, small length=%ld\n", nbuf->size);
gBufferModule->free(nbuf); gBufferModule->free(nbuf);
return (EMSGSIZE); return (EMSGSIZE);
} }
/* Strip ACL data packet header */ // Strip ACL data packet header
NetBufferHeaderReader<struct hci_acl_header> aclHeader(nbuf); NetBufferHeaderReader<struct hci_acl_header> aclHeader(nbuf);
status_t status = aclHeader.Status(); status_t status = aclHeader.Status();
if (status < B_OK) { if (status < B_OK) {
@@ -54,26 +54,25 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
} }
/* Get ACL connection handle, PB flag and payload length */ // Get ACL connection handle, PB flag and payload length
aclHeader->handle = le16toh(aclHeader->handle); aclHeader->handle = le16toh(aclHeader->handle);
uint16 con_handle = get_acl_handle(aclHeader->handle); uint16 con_handle = get_acl_handle(aclHeader->handle);
uint16 pb = get_acl_pb_flag(aclHeader->handle); uint16 pb = get_acl_pb_flag(aclHeader->handle);
uint16 length = le16toh(aclHeader->alen); uint16 length = le16toh(aclHeader->alen);
aclHeader.Remove(); aclHeader.Remove();
debugf("got ACL data packet, con_handle=%#x, PB=%#x, length=%d\n", con_handle, pb, length); debugf("ACL data packet, handle=%#x, PB=%#x, length=%d\n",
con_handle, pb, length);
/* a) Ensure there is HCI connection // a) Ensure there is HCI connection
b) Get connection descriptor // b) Get connection descriptor
c) veryfy the status of the connection // c) veryfy the status of the connection
*/
HciConnection* conn = btCoreData->ConnectionByHandle(con_handle, hid); HciConnection* conn = btCoreData->ConnectionByHandle(con_handle, hid);
if (conn == NULL) { if (conn == NULL) {
//debugf("unexpected ACL!Connection does not exist!schedule! con_handle=%#x\n", con_handle); debugf("Uexpected handle=%#x does not exist!\n", con_handle);
panic("unexpected ACL!Connection does not exist!schedule!\n");
conn = btCoreData->AddConnection(con_handle, BT_ACL, BDADDR_NULL, hid); conn = btCoreData->AddConnection(con_handle, BT_ACL, BDADDR_NULL, hid);
} }
@@ -85,10 +84,11 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
} }
/* Process packet */ // Process packet
if (pb == HCI_ACL_PACKET_START) { if (pb == HCI_ACL_PACKET_START) {
if (conn->currentRxPacket != NULL) { if (conn->currentRxPacket != NULL) {
debugf("dropping incomplete L2CAP packet, got %ld bytes, want %d bytes\n", conn->currentRxPacket->size, length ); debugf("Dropping incomplete L2CAP packet, got %ld want %d \n",
conn->currentRxPacket->size, length );
gBufferModule->free(conn->currentRxPacket); gBufferModule->free(conn->currentRxPacket);
conn->currentRxPacket = NULL; conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0; conn->currentRxExpectedLength = 0;
@@ -96,7 +96,8 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
// Get L2CAP header, ACL header was dimissed // Get L2CAP header, ACL header was dimissed
if (nbuf->size < sizeof(l2cap_hdr_t)) { if (nbuf->size < sizeof(l2cap_hdr_t)) {
debugf("invalid L2CAP packet start fragment. Packet too small, length=%ld\n", nbuf->size); debugf("Invalid L2CAP start fragment, small, length=%ld\n",
nbuf->size);
gBufferModule->free(nbuf); gBufferModule->free(nbuf);
return (EMSGSIZE); return (EMSGSIZE);
} }
@@ -112,9 +113,10 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
l2capHeader->length = le16toh(l2capHeader->length); l2capHeader->length = le16toh(l2capHeader->length);
l2capHeader->dcid = le16toh(l2capHeader->dcid); l2capHeader->dcid = le16toh(l2capHeader->dcid);
debugf("staring new L2CAP packet, con_handle=%#x, length=%d\n", con_handle, le16toh(l2capHeader->length)); debugf("New L2CAP, handle=%#x length=%d\n", con_handle,
le16toh(l2capHeader->length));
/* Start new L2CAP packet */ // Start new L2CAP packet
conn->currentRxPacket = nbuf; conn->currentRxPacket = nbuf;
conn->currentRxExpectedLength = l2capHeader->length + sizeof(l2cap_hdr_t); conn->currentRxExpectedLength = l2capHeader->length + sizeof(l2cap_hdr_t);
@@ -125,7 +127,7 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
return (EINVAL); return (EINVAL);
} }
/* Add fragment to the L2CAP packet */ // Add fragment to the L2CAP packet
gBufferModule->merge(conn->currentRxPacket, nbuf, true); gBufferModule->merge(conn->currentRxPacket, nbuf, true);
} else { } else {
@@ -134,12 +136,14 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
return (EINVAL); return (EINVAL);
} }
conn->currentRxExpectedLength -= length; /* substract the length of content of the ACL packet*/ // substract the length of content of the ACL packet
conn->currentRxExpectedLength -= length;
if (conn->currentRxExpectedLength < 0) { if (conn->currentRxExpectedLength < 0) {
debugf("packet length mismatch. Got %ld bytes, expected %ld bytes\n", conn->currentRxPacket->size, debugf("Mismatch. Got %ld, expected %ld\n",
conn->currentRxExpectedLength); conn->currentRxPacket->size, conn->currentRxExpectedLength);
gBufferModule->free(conn->currentRxPacket); gBufferModule->free(conn->currentRxPacket);
conn->currentRxPacket = NULL; conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0; conn->currentRxExpectedLength = 0;
@@ -152,7 +156,8 @@ AclAssembly(net_buffer* nbuf, hci_id hid)
conn->currentRxPacket = NULL; conn->currentRxPacket = NULL;
conn->currentRxExpectedLength = 0; conn->currentRxExpectedLength = 0;
} else { } else {
debugf("Expected %ld current acl apports %d\n", conn->currentRxExpectedLength, length); debugf("Expected %ld current adds %d\n",
conn->currentRxExpectedLength, length);
} }
return error; return error;
@@ -163,12 +168,12 @@ status_t
PostToUpper(HciConnection* conn, net_buffer* buf) PostToUpper(HciConnection* conn, net_buffer* buf)
{ {
if (L2cap == NULL) if (L2cap == NULL)
if (get_module(NET_BLUETOOTH_L2CAP_NAME,(module_info**)&L2cap) != B_OK) { if (get_module(NET_BLUETOOTH_L2CAP_NAME,(module_info**)&L2cap) != B_OK) {
debugf("cannot get module \"%s\"\n", NET_BLUETOOTH_L2CAP_NAME); debugf("cannot get module \"%s\"\n", NET_BLUETOOTH_L2CAP_NAME);
return B_ERROR; return B_ERROR;
} // TODO: someone put it } // TODO: someone put it
return L2cap->receive_data((net_buffer*)conn);// XXX:HACK -> pass handle in type return L2cap->receive_data((net_buffer*)conn);// XXX pass handle in type
} }
@@ -23,44 +23,45 @@
#include <NetBufferUtilities.h> #include <NetBufferUtilities.h>
#define BT_DEBUG_THIS_MODULE #define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME "bluetooth_device" #define SUBMODULE_NAME "hci"
#define SUBMODULE_COLOR 34 #define SUBMODULE_COLOR 34
#include <btDebug.h> #include <btDebug.h>
#include <btCoreData.h> #include <btCoreData.h>
#include <btModules.h> #include <btModules.h>
#include <CodeHandler.h> #include <CodeHandler.h>
#define KERNEL_LAND
#include <PortListener.h>
#undef KERNEL_LAND
#include <bluetooth/HCI/btHCI.h> #include <bluetooth/HCI/btHCI.h>
#include <bluetooth/HCI/btHCI_acl.h> #include <bluetooth/HCI/btHCI_acl.h>
#include <bluetooth/HCI/btHCI_command.h> #include <bluetooth/HCI/btHCI_command.h>
#include <bluetooth/HCI/btHCI_event.h> #include <bluetooth/HCI/btHCI_event.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include <bluetooth/HCI/btHCI_sco.h> #include <bluetooth/HCI/btHCI_sco.h>
#include <bluetooth/bdaddrUtils.h> #include <bluetooth/bdaddrUtils.h>
#include "acl.h" #include "acl.h"
struct bluetooth_device : net_device, DoublyLinkedListLinkImpl<bluetooth_device> { typedef PortListener<void,
HCI_MAX_FRAME_SIZE, // Event Body can hold max 255 + 2 header
net_buffer* fBuffersRx[HCI_NUM_PACKET_TYPES]; 24 // Some devices have sent chunks of 24 events(inquiry result)
size_t fExpectedPacketSize[HCI_NUM_PACKET_TYPES]; > BluetoothRawDataPort;
int fd;
uint16 mtu;
};
/* Modules references */ // Modules references
net_buffer_module_info* gBufferModule = NULL; net_buffer_module_info* gBufferModule = NULL;
static net_stack_module_info* sStackModule = NULL;
struct bluetooth_core_data_module_info* btCoreData = NULL; struct bluetooth_core_data_module_info* btCoreData = NULL;
static mutex sListLock; static mutex sListLock;
static DoublyLinkedList<bluetooth_device> sDeviceList;
static sem_id sLinkChangeSemaphore; static sem_id sLinkChangeSemaphore;
static DoublyLinkedList<bluetooth_device> sDeviceList;
BluetoothRawDataPort* BluetoothRXPort;
// forward declarations // forward declarations
status_t bluetooth_receive_data(net_device* _device, net_buffer** _buffer); status_t HciPacketHandler(void* data, int32 code, size_t size);
bluetooth_device* bluetooth_device*
@@ -68,11 +69,12 @@ FindDeviceByID(hci_id hid)
{ {
bluetooth_device* device; bluetooth_device* device;
DoublyLinkedList<bluetooth_device>::Iterator iterator = sDeviceList.GetIterator(); DoublyLinkedList<bluetooth_device>::Iterator iterator
while (iterator.HasNext()) { = sDeviceList.GetIterator();
while (iterator.HasNext()) {
device = iterator.Next(); device = iterator.Next();
if (device->index == (uint32 )hid) if (device->index == hid)
return device; return device;
} }
@@ -81,9 +83,21 @@ FindDeviceByID(hci_id hid)
status_t status_t
Assemble(net_device* netDevice, bt_packet_t type, void* data, size_t count) 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)
{ {
bluetooth_device* bluetoothDevice = (bluetooth_device*)netDevice;
net_buffer* nbuf = bluetoothDevice->fBuffersRx[type]; net_buffer* nbuf = bluetoothDevice->fBuffersRx[type];
size_t currentPacketLen = 0; size_t currentPacketLen = 0;
@@ -95,15 +109,17 @@ Assemble(net_device* netDevice, bt_packet_t type, void* data, size_t count)
switch (type) { switch (type) {
case BT_EVENT: case BT_EVENT:
if (count >= HCI_EVENT_HDR_SIZE) { if (count >= HCI_EVENT_HDR_SIZE) {
struct hci_event_header* headerPkt struct hci_event_header* headerPacket
= (struct hci_event_header*)data; = (struct hci_event_header*)data;
bluetoothDevice->fExpectedPacketSize[type] bluetoothDevice->fExpectedPacketSize[type]
= HCI_EVENT_HDR_SIZE + headerPkt->elen; = HCI_EVENT_HDR_SIZE + headerPacket->elen;
if (count > bluetoothDevice->fExpectedPacketSize[type]) { if (count >= bluetoothDevice->fExpectedPacketSize[type]) {
// the whole packet is here so it can be already posted. // the whole packet is here so it can be already posted.
flowf("EVENT posted in HCI!!!\n");
btCoreData->PostEvent(bluetoothDevice, data, btCoreData->PostEvent(bluetoothDevice, data,
bluetoothDevice->fExpectedPacketSize[type]); bluetoothDevice->fExpectedPacketSize[type]);
} else { } else {
nbuf = gBufferModule->create( nbuf = gBufferModule->create(
bluetoothDevice->fExpectedPacketSize[type]); bluetoothDevice->fExpectedPacketSize[type]);
@@ -113,7 +129,7 @@ Assemble(net_device* netDevice, bt_packet_t type, void* data, size_t count)
} }
} else { } else {
flowf("EVENT frame corrupted\n"); panic("EVENT frame corrupted\n");
return EILSEQ; return EILSEQ;
} }
break; break;
@@ -132,7 +148,7 @@ Assemble(net_device* netDevice, bt_packet_t type, void* data, size_t count)
nbuf->protocol = type; nbuf->protocol = type;
} else { } else {
flowf("ACL frame corrupted\n"); panic("ACL frame corrupted\n");
return EILSEQ; return EILSEQ;
} }
break; break;
@@ -152,22 +168,25 @@ Assemble(net_device* netDevice, bt_packet_t type, void* data, size_t count)
// Continuation of a packet // Continuation of a packet
currentPacketLen = bluetoothDevice->fExpectedPacketSize[type] - nbuf->size; currentPacketLen = bluetoothDevice->fExpectedPacketSize[type] - nbuf->size;
} }
if (nbuf != NULL) { if (nbuf != NULL) {
currentPacketLen = min_c(currentPacketLen, count); currentPacketLen = min_c(currentPacketLen, count);
gBufferModule->append(nbuf, data, currentPacketLen); gBufferModule->append(nbuf, data, currentPacketLen);
if ((bluetoothDevice->fExpectedPacketSize[type] - nbuf->size) == 0 ) { if ((bluetoothDevice->fExpectedPacketSize[type] - nbuf->size) == 0) {
switch (nbuf->protocol) { switch (nbuf->protocol) {
case BT_EVENT: case BT_EVENT:
btCoreData->PostEvent(netDevice, data, panic("need to send full buffer to btdatacore!\n");
btCoreData->PostEvent(bluetoothDevice, data,
bluetoothDevice->fExpectedPacketSize[type]); bluetoothDevice->fExpectedPacketSize[type]);
break; break;
case BT_ACL: case BT_ACL:
bluetooth_receive_data(netDevice, &nbuf); // TODO: device descriptor has been fetched better not
// pass id again
flowf("ACL parsed in ACL!\n");
AclAssembly(nbuf, bluetoothDevice->index);
break; break;
default: default:
@@ -197,12 +216,18 @@ Assemble(net_device* netDevice, bt_packet_t type, void* data, size_t count)
status_t status_t
HciPacketHandler(void* data, int32 code, size_t size) HciPacketHandler(void* data, int32 code, size_t size)
{ {
bluetooth_device* bluetoothDevice hci_id deviceId = Bluetooth::CodeHandler::Device(code);
= FindDeviceByID(Bluetooth::CodeHandler::Device(code));
bluetooth_device* bluetoothDevice = FindDeviceByID(deviceId);
debugf("to assemble %ld bytes of %ld\n", size, deviceId);
if (bluetoothDevice != NULL) if (bluetoothDevice != NULL)
return Assemble(bluetoothDevice, Bluetooth::CodeHandler::Protocol(code), return Assemble(bluetoothDevice, Bluetooth::CodeHandler::Protocol(code),
data, size); data, size);
else {
debugf("Device %ld could not be matched\n", deviceId);
}
return B_ERROR; return B_ERROR;
} }
@@ -212,31 +237,22 @@ HciPacketHandler(void* data, int32 code, size_t size)
status_t status_t
bluetooth_init(const char* name, net_device** _device) RegisterDriver(bt_hci_transport_hooks* hooks, bluetooth_device** _device)
{ {
debugf("Initializing bluetooth device %s\n",name);
// TODO: make sure this is a device in /dev/bluetooth
if (strncmp(name, "bluetooth/h", 11))
return B_BAD_VALUE;
if (gBufferModule == NULL) { // lazy allocation
status_t status = get_module(NET_BUFFER_MODULE_NAME,
(module_info**)&gBufferModule);
if (status < B_OK)
return status;
}
bluetooth_device* device = new (std::nothrow) bluetooth_device; bluetooth_device* device = new (std::nothrow) bluetooth_device;
if (device == NULL) { if (device == NULL)
put_module(NET_BUFFER_MODULE_NAME);
return B_NO_MEMORY; return B_NO_MEMORY;
for (int index = 0; index < HCI_NUM_PACKET_TYPES; index++) {
device->fBuffersRx[index] = NULL;
device->fExpectedPacketSize[index] = 0;
} }
memset(device, 0, sizeof(bluetooth_device)); device->info = NULL; // not yet used
device->hooks = hooks;
// Fill device->mtu = L2CAP_MTU_MINIMUM; // TODO: ensure specs min value
strcpy(device->name, name);
MutexLocker _(&sListLock); MutexLocker _(&sListLock);
@@ -244,92 +260,58 @@ bluetooth_init(const char* name, net_device** _device)
device->index = HCI_DEVICE_INDEX_OFFSET; // REVIEW: dev index device->index = HCI_DEVICE_INDEX_OFFSET; // REVIEW: dev index
else else
device->index = (sDeviceList.Tail())->index + 1; // REVIEW! device->index = (sDeviceList.Tail())->index + 1; // REVIEW!
flowf("List not empty\n");
// TODO: add to list whould be done in up hook
sDeviceList.Add(device); sDeviceList.Add(device);
debugf("Device %s %lx\n", device->name, device->index ); debugf("Device %lx\n", device->index );
*_device = device; *_device = device;
return B_OK; return B_OK;
} }
status_t status_t
bluetooth_uninit(net_device* _device) UnregisterDriver(hci_id id)
{ {
bluetooth_device* device = (bluetooth_device*)_device; bluetooth_device* device = FindDeviceByID(id);
debugf("index %lx\n",device->index); if (device == NULL)
return B_ERROR;
// if the device is still part of the list, remove it
if (device->GetDoublyLinkedListLink()->next != NULL if (device->GetDoublyLinkedListLink()->next != NULL
|| device->GetDoublyLinkedListLink()->previous != NULL || device->GetDoublyLinkedListLink()->previous != NULL
|| device == sDeviceList.Head()) || device == sDeviceList.Head())
sDeviceList.Remove(device); sDeviceList.Remove(device);
put_module(NET_BUFFER_MODULE_NAME);
delete device; delete device;
return B_OK; return B_OK;
} }
// PostACL
status_t status_t
bluetooth_up(net_device* _device) PostACL(hci_id hciId, net_buffer* buffer)
{ {
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
device->fd = open(device->name, O_RDWR);
if (device->fd < 0)
goto err;
return B_OK;
err:
close(device->fd);
device->fd = -1;
return errno;
}
void
bluetooth_down(net_device* _device)
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
close(device->fd);
device->fd = -1;
}
status_t
bluetooth_control(net_device* _device, int32 op, void* argument,
size_t length)
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
// Forward the call to the driver
return ioctl(device->fd, op, argument, length);
}
status_t
bluetooth_send_data(net_device* _device, net_buffer* buffer)
{
bluetooth_device* device = (bluetooth_device*)_device;
net_buffer* curr_frame = NULL; net_buffer* curr_frame = NULL;
net_buffer* next_frame = buffer; net_buffer* next_frame = buffer;
uint16 handle = buffer->type; // TODO: CodeHandler
uint8 flag = HCI_ACL_PACKET_START; uint8 flag = HCI_ACL_PACKET_START;
debugf("index %ld try to send bt packet of %lu bytes (flags %ld):\n", if (buffer == NULL)
panic("passing null buffer");
uint16 handle = buffer->type; // TODO: CodeHandler
bluetooth_device* device = FindDeviceByID(hciId);
if (device == NULL) {
debugf("No device %lx", hciId);
return B_ERROR;
}
debugf("index %lx try to send bt packet of %lu bytes (flags %ld):\n",
device->index, buffer->size, buffer->flags); device->index, buffer->size, buffer->flags);
// TODO: ATOMIC! any other thread should stop here // TODO: ATOMIC! any other thread should stop here
@@ -337,116 +319,50 @@ bluetooth_send_data(net_device* _device, net_buffer* buffer)
// Divide packet if big enough // Divide packet if big enough
curr_frame = next_frame; curr_frame = next_frame;
if (next_frame->size > device->mtu) { if (curr_frame->size > device->mtu) {
next_frame = gBufferModule->split(curr_frame, device->mtu); next_frame = gBufferModule->split(curr_frame, device->mtu);
} else { } else {
next_frame = NULL; next_frame = NULL;
} }
// Attach acl header // Attach acl header
NetBufferPrepend<struct hci_acl_header> bufferHeader(curr_frame); {
status_t status = bufferHeader.Status(); NetBufferPrepend<struct hci_acl_header> bufferHeader(curr_frame);
if (status < B_OK) { status_t status = bufferHeader.Status();
// free the buffer if (status < B_OK) {
continue; // free the buffer
continue;
}
bufferHeader->handle = pack_acl_handle_flags(handle, flag, 0);
bufferHeader->alen = curr_frame->size - sizeof(struct hci_acl_header);
} }
bufferHeader->handle = pack_acl_handle_flags(handle, flag, 0); // Send to driver
bufferHeader->alen = curr_frame->size - sizeof(struct hci_acl_header);
bufferHeader.Sync();
// Send to driver XXX: another interlayer trick
debugf("tolower nbuf %p\n",curr_frame);
curr_frame->protocol = BT_ACL; curr_frame->protocol = BT_ACL;
((status_t(*)(hci_id id, net_buffer* nbuf))device->media)(device->index,
curr_frame);
debugf("Tolower nbuf %p!\n", 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; flag = HCI_ACL_PACKET_FRAGMENT;
} while (next_frame == NULL); } while (next_frame != NULL);
return B_OK; return B_OK;
} }
status_t status_t
bluetooth_receive_data(net_device* _device, net_buffer** _buffer) PostSCO(hci_id hciId, net_buffer* buffer)
{ {
bluetooth_device* device = (bluetooth_device*)_device; return B_ERROR;
status_t status = B_OK;
debugf("index %ld packet of %lu bytes (flags %ld):\n",
device->index, (*_buffer)->size, (*_buffer)->flags);
if (device->fd == -1)
return B_FILE_ERROR;
switch ((*_buffer)->protocol) {
case BT_ACL:
status = AclAssembly(*_buffer, device->index);
break;
default:
panic("Protocol not supported");
break;
}
return status;
} }
status_t status_t
bluetooth_set_mtu(net_device* _device, size_t mtu) PostESCO(hci_id hciId, net_buffer* buffer)
{ {
bluetooth_device* device = (bluetooth_device*)_device; return B_ERROR;
debugf("index %ld mtu %ld\n",device->index, mtu);
device->mtu = mtu;
return B_OK;
}
status_t
bluetooth_set_promiscuous(net_device* _device, bool promiscuous)
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld promiscuous %d\n",device->index, promiscuous);
return EOPNOTSUPP;
}
status_t
bluetooth_set_media(net_device* device, uint32 media)
{
debugf("index %ld media %ld\n",device->index, media);
return EOPNOTSUPP;
}
status_t
bluetooth_add_multicast(struct net_device* _device, const sockaddr* _address)
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
return EOPNOTSUPP;
}
status_t
bluetooth_remove_multicast(struct net_device* _device, const sockaddr* _address)
{
bluetooth_device* device = (bluetooth_device*)_device;
debugf("index %ld\n",device->index);
return EOPNOTSUPP;
} }
@@ -455,11 +371,12 @@ dump_bluetooth_devices(int argc, char** argv)
{ {
bluetooth_device* device; bluetooth_device* device;
DoublyLinkedList<bluetooth_device>::Iterator iterator = sDeviceList.GetIterator(); DoublyLinkedList<bluetooth_device>::Iterator iterator
= sDeviceList.GetIterator();
while (iterator.HasNext()) { while (iterator.HasNext()) {
device = iterator.Next(); device = iterator.Next();
kprintf("\tname=%s index=%#lx @%p\n", device->name, device->index, device); kprintf("\tindex=%#lx @%p hooks=%p\n",device->index, device, device->hooks);
} }
return 0; return 0;
@@ -477,9 +394,9 @@ bluetooth_std_ops(int32 op, ...)
{ {
status_t status; status_t status;
status = get_module(NET_STACK_MODULE_NAME,(module_info**)&sStackModule); status = get_module(NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule);
if (status < B_OK) { if (status < B_OK) {
flowf("problem getting netstack module\n"); panic("no way Dude we need that!");
return status; return status;
} }
@@ -492,6 +409,17 @@ bluetooth_std_ops(int32 op, ...)
new (&sDeviceList) DoublyLinkedList<bluetooth_device>; new (&sDeviceList) DoublyLinkedList<bluetooth_device>;
// static C++ objects are not initialized in the module startup // 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) {
flowf("RX thread creation failed!\n");
// we Cannot do much here ... avoid registering
} else {
flowf("RX thread launched!\n");
}
sLinkChangeSemaphore = create_sem(0, "bt sem"); sLinkChangeSemaphore = create_sem(0, "bt sem");
if (sLinkChangeSemaphore < B_OK) { if (sLinkChangeSemaphore < B_OK) {
put_module(NET_STACK_MODULE_NAME); put_module(NET_STACK_MODULE_NAME);
@@ -515,6 +443,7 @@ bluetooth_std_ops(int32 op, ...)
delete_sem(sLinkChangeSemaphore); delete_sem(sLinkChangeSemaphore);
mutex_destroy(&sListLock); mutex_destroy(&sListLock);
put_module(NET_BUFFER_MODULE_NAME);
put_module(NET_STACK_MODULE_NAME); put_module(NET_STACK_MODULE_NAME);
put_module(BT_CORE_DATA_MODULE_NAME); put_module(BT_CORE_DATA_MODULE_NAME);
remove_debugger_command("btLocalDevices", &dump_bluetooth_devices); remove_debugger_command("btLocalDevices", &dump_bluetooth_devices);
@@ -529,24 +458,19 @@ bluetooth_std_ops(int32 op, ...)
} }
net_device_module_info sBluetoothModule = { bt_hci_module_info sBluetoothModule = {
{ {
NET_BLUETOOTH_DEVICE_NAME, BT_HCI_MODULE_NAME,
B_KEEP_LOADED, B_KEEP_LOADED,
bluetooth_std_ops bluetooth_std_ops
}, },
bluetooth_init, RegisterDriver,
bluetooth_uninit, UnregisterDriver,
bluetooth_up, FindDeviceByID,
bluetooth_down, PostTransportPacket,
bluetooth_control, PostACL,
bluetooth_send_data, PostSCO,
bluetooth_receive_data, PostESCO
bluetooth_set_mtu,
bluetooth_set_promiscuous,
bluetooth_set_media,
bluetooth_add_multicast,
bluetooth_remove_multicast,
}; };
@@ -18,11 +18,11 @@ if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
} }
KernelAddon h2generic : KernelAddon h2generic :
h2generic.c h2generic.cpp
h2transactions.c h2transactions.cpp
h2upper.c h2upper.cpp
h2util.c h2util.cpp
snet_buffer.c snet_buffer.cpp
$(r5_src) $(r5_src)
; ;
@@ -1,10 +1,7 @@
/* /*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
*/ */
#ifndef _H2CFG_H_ #ifndef _H2CFG_H_
#define _H2CFG_H_ #define _H2CFG_H_
@@ -16,20 +13,19 @@
#define BT_DRIVER_SUPPORTS_ESCO 0 #define BT_DRIVER_SUPPORTS_ESCO 0
// TODO: move exclusive header for drivers
#define BT_DRIVER_RXCOVERAGE (BT_DRIVER_SUPPORTS_EVT + BT_DRIVER_SUPPORTS_ACL \
+ BT_DRIVER_SUPPORTS_SCO + BT_DRIVER_SUPPORTS_ESCO)
#define BT_DRIVER_TXCOVERAGE (BT_DRIVER_SUPPORTS_CMD + BT_DRIVER_SUPPORTS_ACL \
+ BT_DRIVER_SUPPORTS_SCO + BT_DRIVER_SUPPORTS_ESCO)
/* TODO: move exclusive header for drivers*/ #if BT_DRIVER_RXCOVERAGE < 1 || BT_DRIVER_TXCOVERAGE < 1
#define BT_DRIVER_RXCOVERAGE (BT_DRIVER_SUPPORTS_EVT+BT_DRIVER_SUPPORTS_ACL+BT_DRIVER_SUPPORTS_SCO+BT_DRIVER_SUPPORTS_ESCO)
#define BT_DRIVER_TXCOVERAGE (BT_DRIVER_SUPPORTS_CMD+BT_DRIVER_SUPPORTS_ACL+BT_DRIVER_SUPPORTS_SCO+BT_DRIVER_SUPPORTS_ESCO)
#if BT_DRIVER_RXCOVERAGE<1 || BT_DRIVER_TXCOVERAGE<1
#error incomplete Bluetooth driver Commands and Events should be implemented #error incomplete Bluetooth driver Commands and Events should be implemented
#endif #endif
#define BT_SURVIVE_WITHOUT_HCI #define BT_SURVIVE_WITHOUT_HCI
//#define BT_SURVIVE_WITHOUT_NET_BUFFERS //#define BT_SURVIVE_WITHOUT_NET_BUFFERS
////////////////////////////////////
#ifndef BLUETOOTH_DEVICE_TRANSPORT #ifndef BLUETOOTH_DEVICE_TRANSPORT
#error BLUETOOTH_DEVICE_TRANSPORT must be defined to build the publishing path #error BLUETOOTH_DEVICE_TRANSPORT must be defined to build the publishing path
#endif #endif
@@ -38,8 +34,11 @@
#error BLUETOOTH_DEVICE_NAME must be defined to build the publishing path #error BLUETOOTH_DEVICE_NAME must be defined to build the publishing path
#endif #endif
#define BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_TRANSPORT BLUETOOTH_DEVICE_NAME #define BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_TRANSPORT \
#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_TRANSPORT "/" BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_NAME
#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_TRANSPORT "/" \
BLUETOOTH_DEVICE_DEVFS_NAME
#endif #endif
@@ -17,8 +17,6 @@
#include "snet_buffer.h" #include "snet_buffer.h"
#include <bluetooth/bluetooth_util.h> #include <bluetooth/bluetooth_util.h>
#include <bluetooth/HCI/btHCI.h>
#include <bluetooth/HCI/btHCI_module.h>
#define BT_DEBUG_THIS_MODULE #define BT_DEBUG_THIS_MODULE
#define SUBMODULE_NAME BLUETOOTH_DEVICE_DEVFS_NAME #define SUBMODULE_NAME BLUETOOTH_DEVICE_DEVFS_NAME
@@ -34,20 +32,20 @@
int32 api_version = B_CUR_DRIVER_API_VERSION; int32 api_version = B_CUR_DRIVER_API_VERSION;
/* Modules */ // Modules
static char* usb_name = B_USB_MODULE_NAME; static char* usb_name = B_USB_MODULE_NAME;
static char* hci_name = BT_HCI_MODULE_NAME; static char* hci_name = BT_HCI_MODULE_NAME;
static char* btDevices_name = NET_BLUETOOTH_DEVICE_NAME; static char* btDevices_name = BT_HCI_MODULE_NAME;
usb_module_info* usb = NULL; usb_module_info* usb = NULL;
bt_hci_module_info* hci = NULL; bt_hci_module_info* hci = NULL; // TODO remove / clean
struct net_device_module_info* btDevices = NULL; struct bt_hci_module_info* btDevices = NULL;
struct net_buffer_module_info* nb = NULL; struct net_buffer_module_info* nb = NULL;
struct bluetooth_core_data_module_info* btCoreData = NULL; struct bluetooth_core_data_module_info* btCoreData = NULL;
// Driver Global data // Driver Global data
static char *publish_names[MAX_BT_GENERIC_USB_DEVICES]; static char* publish_names[MAX_BT_GENERIC_USB_DEVICES];
int32 dev_count = 0; // number of connected devices int32 dev_count = 0; // number of connected devices
static bt_usb_dev* bt_usb_devices[MAX_BT_GENERIC_USB_DEVICES]; static bt_usb_dev* bt_usb_devices[MAX_BT_GENERIC_USB_DEVICES];
@@ -55,10 +53,9 @@ sem_id dev_table_sem = -1; // sem to synchronize access to device table
status_t submit_nbuffer(hci_id hid, net_buffer* nbuf); status_t submit_nbuffer(hci_id hid, net_buffer* nbuf);
usb_support_descriptor supported_devices[] = usb_support_descriptor supported_devices[] = {
{ // Generic Bluetooth USB device
// Generic Bluetooth USB device // Class, SubClass, and Protocol codes that describe a Bluetooth device
// Class, SubClass, and Protocol codes that describe a Bluetooth device
{ UDCLASS_WIRELESS, UDSUBCLASS_RF, UDPROTO_BLUETOOTH , 0 , 0 }, { UDCLASS_WIRELESS, UDSUBCLASS_RF, UDPROTO_BLUETOOTH , 0 , 0 },
// Broadcom BCM2035 // Broadcom BCM2035
@@ -67,14 +64,14 @@ usb_support_descriptor supported_devices[] =
// Devices taken from the linux Driver // Devices taken from the linux Driver
// AVM BlueFRITZ! USB v2.0 // AVM BlueFRITZ! USB v2.0
{ 0, 0, 0, 0x057c , 0x3800 }, { 0, 0, 0, 0x057c, 0x3800 },
// Bluetooth Ultraport Module from IBM // Bluetooth Ultraport Module from IBM
{ 0, 0, 0, 0x04bf , 0x030a }, { 0, 0, 0, 0x04bf, 0x030a },
// ALPS Modules with non-standard id // ALPS Modules with non-standard id
{ 0, 0, 0, 0x044e , 0x3001 }, { 0, 0, 0, 0x044e, 0x3001 },
{ 0, 0, 0, 0x044e , 0x3002 }, { 0, 0, 0, 0x044e, 0x3002 },
// Ericsson with non-standard id // Ericsson with non-standard id
{ 0, 0, 0, 0x0bdb , 0x1002 } { 0, 0, 0, 0x0bdb, 0x1002 }
}; };
/* add a device to the list of connected devices */ /* add a device to the list of connected devices */
@@ -93,13 +90,13 @@ spawn_device(usb_device* usb_dev)
flowf("add_device()\n"); flowf("add_device()\n");
// 16 usb dongles... // 16 usb dongles...
if (dev_count >= MAX_BT_GENERIC_USB_DEVICES) { if (dev_count >= MAX_BT_GENERIC_USB_DEVICES) {
flowf("device table full\n"); flowf("device table full\n");
goto exit; goto exit;
} }
/* try the allocation */ // try the allocation
new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev)); new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev));
if (new_bt_dev == NULL) { if (new_bt_dev == NULL) {
flowf("no memory\n"); flowf("no memory\n");
@@ -107,41 +104,43 @@ spawn_device(usb_device* usb_dev)
} }
memset(new_bt_dev, 0, sizeof(bt_usb_dev)); memset(new_bt_dev, 0, sizeof(bt_usb_dev));
/* We will need this sem for some flow control */ // We will need this sem for some flow control
new_bt_dev->cmd_complete = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "cmd_complete"); new_bt_dev->cmd_complete = create_sem(1,
BLUETOOTH_DEVICE_DEVFS_NAME "cmd_complete");
if (new_bt_dev->cmd_complete < 0) { if (new_bt_dev->cmd_complete < 0) {
err = new_bt_dev->cmd_complete; err = new_bt_dev->cmd_complete;
goto bail0; goto bail0;
} }
/* and this for something else */ // and this for something else
new_bt_dev->lock = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "lock"); new_bt_dev->lock = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "lock");
if (new_bt_dev->lock < 0) { if (new_bt_dev->lock < 0) {
err = new_bt_dev->lock; err = new_bt_dev->lock;
goto bail1; goto bail1;
} }
/* find a free slot and fill out the name */ // find a free slot and fill out the name
acquire_sem(dev_table_sem); acquire_sem(dev_table_sem);
for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
if (bt_usb_devices[i] == NULL) { if (bt_usb_devices[i] == NULL) {
bt_usb_devices[i] = new_bt_dev; bt_usb_devices[i] = new_bt_dev;
sprintf(new_bt_dev->name, "%s/%ld", BLUETOOTH_DEVICE_PATH, i); sprintf(new_bt_dev->name, "%s/%ld", BLUETOOTH_DEVICE_PATH, i);
new_bt_dev->num = i; new_bt_dev->num = i;
debugf("added device %p %ld %s\n", bt_usb_devices[i] ,new_bt_dev->num,new_bt_dev->name); debugf("added device %p %ld %s\n", bt_usb_devices[i],
new_bt_dev->num, new_bt_dev->name);
break; break;
} }
} }
release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
/* In the case we cannot us */ // In the case we cannot us
if (bt_usb_devices[i] != new_bt_dev) { if (bt_usb_devices[i] != new_bt_dev) {
flowf("Device could not be added\n"); flowf("Device could not be added\n");
goto bail2; goto bail2;
} }
new_bt_dev->dev = usb_dev; new_bt_dev->dev = usb_dev;
/* TODO am i actually gonna use this? */ // TODO: currently only server opens
new_bt_dev->open_count = 0; new_bt_dev->open_count = 0;
dev_count++; dev_count++;
@@ -158,7 +157,7 @@ exit:
} }
/* remove a device from the list of connected devices */ // remove a device from the list of connected devices
static void static void
kill_device(bt_usb_dev* bdev) kill_device(bt_usb_dev* bdev)
{ {
@@ -180,40 +179,38 @@ kill_device(bt_usb_dev* bdev)
bt_usb_dev* bt_usb_dev*
fetch_device(bt_usb_dev* dev, hci_id hid) fetch_device(bt_usb_dev* dev, hci_id hid)
{ {
int i; int i;
// debugf("(%p) or %d\n", dev, hid); // debugf("(%p) or %d\n", dev, hid);
acquire_sem(dev_table_sem); acquire_sem(dev_table_sem);
if (dev != NULL) if (dev != NULL)
for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
/* somehow the device is still around */ if (bt_usb_devices[i] == dev) {
if (bt_usb_devices[i] == dev) { release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); return bt_usb_devices[i];
return bt_usb_devices[i]; }
}
} }
else else
for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
/* somehow the device is still around */ if (bt_usb_devices[i] != NULL && bt_usb_devices[i]->hdev == hid) {
if (bt_usb_devices[i] != NULL && bt_usb_devices[i]->hdev == hid) { release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); return bt_usb_devices[i];
return bt_usb_devices[i]; }
}
} }
release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
return NULL; return NULL;
} }
#if 0 #if 0
#pragma mark - #pragma mark -
#endif #endif
// called by USB Manager when device is added to the USB
/* called by USB Manager when device is added to the USB */
#ifdef HAIKU_TARGET_PLATFORM_HAIKU #ifdef HAIKU_TARGET_PLATFORM_HAIKU
static status_t static status_t
device_added(usb_device dev, void** cookie) device_added(usb_device dev, void** cookie)
@@ -227,9 +224,9 @@ device_added(usb_device* dev, void** cookie)
const usb_interface_info* uif; const usb_interface_info* uif;
const usb_endpoint_info* ep; const usb_endpoint_info* ep;
status_t err = B_ERROR; status_t err = B_ERROR;
bt_usb_dev* new_bt_dev = spawn_device(dev); bt_usb_dev* new_bt_dev = spawn_device(dev);
int e; int e;
debugf("device_added(%ld, %p)\n", dev, new_bt_dev); debugf("device_added(%ld, %p)\n", dev, new_bt_dev);
@@ -239,9 +236,9 @@ device_added(usb_device* dev, void** cookie)
goto bail_no_mem; goto bail_no_mem;
} }
/* we only have 1 configuration number 0 */ // we only have 1 configuration number 0
config = usb->get_nth_configuration(dev, 0); config = usb->get_nth_configuration(dev, 0);
//dump_usb_configuration_info(config); // dump_usb_configuration_info(config);
if (config == NULL) { if (config == NULL) {
flowf("couldn't get default config.\n"); flowf("couldn't get default config.\n");
err = B_ERROR; err = B_ERROR;
@@ -250,7 +247,7 @@ device_added(usb_device* dev, void** cookie)
debugf("found %ld alt interfaces.\n", config->interface->alt_count); debugf("found %ld alt interfaces.\n", config->interface->alt_count);
/* set first interface */ // set first interface
interface = &config->interface->alt[0]; interface = &config->interface->alt[0];
err = usb->set_alt_interface(new_bt_dev->dev, interface); err = usb->set_alt_interface(new_bt_dev->dev, interface);
@@ -259,17 +256,18 @@ device_added(usb_device* dev, void** cookie)
goto bail; goto bail;
} }
/* call set_configuration() only after calling set_alt_interface()*/ // call set_configuration() only after calling set_alt_interface()
err = usb->set_configuration(dev, config); err = usb->set_configuration(dev, config);
if (err != B_OK) { if (err != B_OK) {
debugf("set_configuration() returned %ld.\n", err); debugf("set_configuration() returned %ld.\n", err);
goto bail; goto bail;
} }
/* Place to find out whats our concrete device and set up some special info to our driver */ // Place to find out whats our concrete device and set up some special
/* TODO: if this code increases too much reconsider this implementation*/ // info to our driver. If this code increases too much reconsider
// this implementation
desc = usb->get_device_descriptor(dev); desc = usb->get_device_descriptor(dev);
if (desc->vendor_id == 0x0a5c if (desc->vendor_id == 0x0a5c
&& (desc->product_id == 0x200a && (desc->product_id == 0x200a
|| desc->product_id == 0x2009 || desc->product_id == 0x2009
|| desc->product_id == 0x2035)) { || desc->product_id == 0x2035)) {
@@ -278,18 +276,19 @@ device_added(usb_device* dev, void** cookie)
} }
/* /*
else if ( desc->vendor_id == YOUR_VENDOR_HERE && desc->product_id == YOUR_PRODUCT_HERE ) { else if ( desc->vendor_id == YOUR_VENDOR_HERE
&& desc->product_id == YOUR_PRODUCT_HERE ) {
YOUR_SPECIAL_FLAGS_HERE YOUR_SPECIAL_FLAGS_HERE
} }
*/ */
if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE){ if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE) {
err = ENODEV; err = ENODEV;
goto bail; goto bail;
} }
// security check // security check
if (config->interface->active->descr->interface_number > 0){ if (config->interface->active->descr->interface_number > 0) {
debugf("Strange condition happened %d\n", debugf("Strange condition happened %d\n",
config->interface->active->descr->interface_number); config->interface->active->descr->interface_number);
err = B_ERROR; err = B_ERROR;
@@ -297,7 +296,7 @@ device_added(usb_device* dev, void** cookie)
} }
debugf("Found %ld interfaces. Expected 3\n", config->interface_count); debugf("Found %ld interfaces. Expected 3\n", config->interface_count);
/* Find endpoints that we need */ // Find endpoints that we need
uif = config->interface->active; uif = config->interface->active;
for (e = 0; e < uif->descr->num_endpoints; e++) { for (e = 0; e < uif->descr->num_endpoints; e++) {
@@ -328,21 +327,22 @@ device_added(usb_device* dev, void** cookie)
} }
} }
if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep || !new_bt_dev->intr_in_ep) { if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep
|| !new_bt_dev->intr_in_ep) {
flowf("Minimal # endpoints for BT not found\n"); flowf("Minimal # endpoints for BT not found\n");
goto bail; goto bail;
} }
// Look into the devices suported to understand this // Look into the devices suported to understand this
if (new_bt_dev->driver_info & BT_DIGIANSWER) if (new_bt_dev->driver_info & BT_DIGIANSWER)
new_bt_dev->ctrl_req = USB_TYPE_VENDOR; new_bt_dev->ctrl_req = USB_TYPE_VENDOR;
else else
new_bt_dev->ctrl_req = USB_TYPE_CLASS; new_bt_dev->ctrl_req = USB_TYPE_CLASS;
new_bt_dev->connected = true; new_bt_dev->connected = true;
/* set the cookie that will be passed to other USB // set the cookie that will be passed to other USB
hook functions (currently device_removed() is the only other) */ // hook functions (currently device_removed() is the only other)
*cookie = new_bt_dev; *cookie = new_bt_dev;
debugf("Ok %p\n", new_bt_dev); debugf("Ok %p\n", new_bt_dev);
return B_OK; return B_OK;
@@ -356,20 +356,20 @@ bail_no_mem:
} }
/* called by USB Manager when device is removed from the USB */ // Called by USB Manager when device is removed from the USB
static status_t static status_t
device_removed(void* cookie) device_removed(void* cookie)
{ {
bt_usb_dev* bdev = (bt_usb_dev*) fetch_device(cookie, 0); bt_usb_dev* bdev = fetch_device((bt_usb_dev*)cookie, 0);
debugf("device_removed(%p)\n", bdev); debugf("device_removed(%p)\n", bdev);
if (bdev == NULL) { if (bdev == NULL) {
flowf(" not present in driver?\n"); flowf(" not present in driver?\n");
return B_ERROR; return B_ERROR;
} }
if (!TEST_AND_CLEAR(&bdev->state, RUNNING)) if (!TEST_AND_CLEAR(&bdev->state, RUNNING))
flowf("wasnt running?\n"); flowf("wasnt running?\n");
flowf("Cancelling queues...\n"); flowf("Cancelling queues...\n");
@@ -394,8 +394,17 @@ device_removed(void* cookie)
} }
static usb_notify_hooks notify_hooks = static bt_hci_transport_hooks bluetooth_hooks = {
{ NULL,
&submit_nbuffer,
&submit_nbuffer,
NULL,
NULL,
H2
};
static usb_notify_hooks notify_hooks = {
&device_added, &device_added,
&device_removed &device_removed
}; };
@@ -412,21 +421,21 @@ submit_nbuffer(hci_id hid, net_buffer* nbuf)
bdev = fetch_device(NULL, hid); bdev = fetch_device(NULL, hid);
debugf("index=%lx nbuf=%p bdev=%p\n",hid, nbuf, bdev); debugf("index=%lx nbuf=%p bdev=%p\n",hid, nbuf, bdev);
if (bdev != NULL) { if (bdev != NULL) {
switch (nbuf->protocol) { switch (nbuf->protocol) {
case BT_COMMAND: case BT_COMMAND:
// not issued this way // not issued this way
break; break;
case BT_ACL: case BT_ACL:
return submit_tx_acl(bdev, nbuf); return submit_tx_acl(bdev, nbuf);
break; break;
default: default:
panic("submit_nbuffer: no protocol"); panic("submit_nbuffer: no protocol");
break; break;
} }
} }
@@ -435,9 +444,9 @@ submit_nbuffer(hci_id hid, net_buffer* nbuf)
} }
/* implements the POSIX open() */ // implements the POSIX open()
static status_t static status_t
device_open(const char *name, uint32 flags, void **cookie) device_open(const char* name, uint32 flags, void **cookie)
{ {
status_t err = ENODEV; status_t err = ENODEV;
bt_usb_dev* bdev = NULL; bt_usb_dev* bdev = NULL;
@@ -463,8 +472,8 @@ device_open(const char *name, uint32 flags, void **cookie)
// Set RUNNING // Set RUNNING
if (TEST_AND_SET(&bdev->state, RUNNING)) { if (TEST_AND_SET(&bdev->state, RUNNING)) {
flowf("dev already running! - reOpened device!\n"); flowf("dev already running! - reOpened device!\n");
return B_ERROR; return B_ERROR;
} }
acquire_sem(bdev->lock); acquire_sem(bdev->lock);
@@ -481,30 +490,28 @@ device_open(const char *name, uint32 flags, void **cookie)
} }
// dumping the USB frames // dumping the USB frames
init_room(&bdev->eventRoom); init_room(&bdev->eventRoom);
init_room(&bdev->aclRoom); init_room(&bdev->aclRoom);
//init_room(new_bt_dev->scoRoom); // init_room(new_bt_dev->scoRoom);
list_init(&bdev->snetBufferRecycleTrash); list_init(&bdev->snetBufferRecycleTrash);
// Allocate set and register the HCI device // Allocate set and register the HCI device
if (btDevices != NULL) { if (btDevices != NULL) {
struct net_device* ndev; bluetooth_device* ndev;
// TODO: Fill the transport descriptor // TODO: Fill the transport descriptor
err = btDevices->init_device(bdev->name, &ndev); err = btDevices->RegisterDriver(&bluetooth_hooks, &ndev);
if (err == B_OK) {
bdev->hdev = hdev = ndev->index; // get the index
bdev->ndev = ndev; // get the net_device
ndev->media = (uint32)submit_nbuffer; //XXX: interlayer-Hack if (err == B_OK) {
bdev->hdev = hdev = ndev->index; // Get the index
bdev->ndev = ndev; // Get the net_device
} else { } else {
hdev = bdev->num; /* XXX: Lets try to go on*/ hdev = bdev->num; // XXX: Lets try to go on
} }
} else { } else {
hdev = bdev->num; /* XXX: Lets try to go on*/ hdev = bdev->num; // XXX: Lets try to go on
} }
bdev->hdev = hdev; bdev->hdev = hdev;
@@ -518,9 +525,10 @@ device_open(const char *name, uint32 flags, void **cookie)
/* called when a client calls POSIX close() on the driver, but I/O /* called when a client calls POSIX close() on the driver, but I/O
** requests may still be pending */ * requests may still be pending
*/
static status_t static status_t
device_close(void *cookie) device_close(void* cookie)
{ {
int32 i; int32 i;
void* item; void* item;
@@ -539,57 +547,56 @@ device_close(void *cookie)
usb->cancel_queued_transfers(bdev->intr_in_ep->handle); usb->cancel_queued_transfers(bdev->intr_in_ep->handle);
flowf("Cancelling possible EVENTS\n"); flowf("Cancelling possible EVENTS\n");
} }
if (bdev->bulk_in_ep!=NULL) { if (bdev->bulk_in_ep!=NULL) {
usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); usb->cancel_queued_transfers(bdev->bulk_in_ep->handle);
flowf("Cancelling possible ACL in\n"); flowf("Cancelling possible ACL in\n");
} }
if (bdev->bulk_out_ep!=NULL) { if (bdev->bulk_out_ep!=NULL) {
usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); usb->cancel_queued_transfers(bdev->bulk_out_ep->handle);
flowf("Cancelling possible ACL out\n"); flowf("Cancelling possible ACL out\n");
} }
} }
// TX // TX
for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) {
if (i == BT_COMMAND) if (i == BT_COMMAND)
while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) { while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) {
snb_free(item); snb_free((snet_buffer*)item);
} }
else else
while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) { while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) {
nb_destroy(item); nb_destroy((net_buffer*)item);
} }
} }
// RX // RX
for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) {
nb_destroy(bdev->nbufferRx[i]); nb_destroy(bdev->nbufferRx[i]);
} }
snb_free(bdev->eventRx); snb_free(bdev->eventRx);
purge_room(&bdev->eventRoom); purge_room(&bdev->eventRoom);
purge_room(&bdev->aclRoom); purge_room(&bdev->aclRoom);
/* Device no longer in our Stack*/ // Device no longer in our Stack
if (btDevices != NULL) if (btDevices != NULL)
btDevices->uninit_device(bdev->ndev); btDevices->UnregisterDriver(bdev->hdev);
// unSet RUNNING // unSet RUNNING
if (TEST_AND_CLEAR(&bdev->state, RUNNING)) { if (TEST_AND_CLEAR(&bdev->state, RUNNING)) {
debugf(" %s not running?\n",bdev->name); debugf(" %s not running?\n",bdev->name);
return B_ERROR; return B_ERROR;
} }
return B_OK; return B_OK;
} }
/* called after device_close(), when all pending I/O requests have // Called after device_close(), when all pending I / O requests have returned
* returned */
static status_t static status_t
device_free (void *cookie) device_free (void* cookie)
{ {
status_t err = B_OK; status_t err = B_OK;
bt_usb_dev* bdev = (bt_usb_dev*)cookie; bt_usb_dev* bdev = (bt_usb_dev*)cookie;
@@ -605,9 +612,9 @@ device_free (void *cookie)
} }
/* implements the POSIX ioctl() */ // implements the POSIX ioctl()
static status_t static status_t
device_control(void *cookie, uint32 msg, void *params, size_t size) device_control(void* cookie, uint32 msg, void* params, size_t size)
{ {
status_t err = B_ERROR; status_t err = B_ERROR;
bt_usb_dev* bdev = (bt_usb_dev*)cookie; bt_usb_dev* bdev = (bt_usb_dev*)cookie;
@@ -634,7 +641,7 @@ device_control(void *cookie, uint32 msg, void *params, size_t size)
switch (msg) { switch (msg) {
case ISSUE_BT_COMMAND: case ISSUE_BT_COMMAND:
#ifdef BT_IOCTLS_PASS_SIZE #ifdef BT_IOCTLS_PASS_SIZE
if (size == 0) { if (size == 0) {
flowf("Invalid size control\n"); flowf("Invalid size control\n");
err = B_BAD_VALUE; err = B_BAD_VALUE;
break; break;
@@ -644,10 +651,10 @@ device_control(void *cookie, uint32 msg, void *params, size_t size)
(*(size_t**)&params)++; (*(size_t**)&params)++;
#endif #endif
// TODO: Reuse from some TXcompleted queue // TODO: Reuse from some TXcompleted queue
//snbuf = snb_create(size); // snbuf = snb_create(size);
snbuf = snb_fetch(&bdev->snetBufferRecycleTrash, size); snbuf = snb_fetch(&bdev->snetBufferRecycleTrash, size);
snb_put(snbuf, params, size); snb_put(snbuf, params, size);
err = submit_tx_command(bdev, snbuf); err = submit_tx_command(bdev, snbuf);
debugf("command launched %ld\n", err); debugf("command launched %ld\n", err);
@@ -655,10 +662,10 @@ device_control(void *cookie, uint32 msg, void *params, size_t size)
case BT_UP: case BT_UP:
// EVENTS // EVENTS
err = submit_rx_event(bdev); err = submit_rx_event(bdev);
if (err != B_OK) { if (err != B_OK) {
CLEAR_BIT(bdev->state, ANCILLYANT); CLEAR_BIT(bdev->state, ANCILLYANT);
flowf("Queuing failed device stops running\n"); flowf("Queuing failed device stops running\n");
break; break;
} }
@@ -667,10 +674,10 @@ device_control(void *cookie, uint32 msg, void *params, size_t size)
for (i = 0; i < MAX_ACL_IN_WINDOW; i++) { for (i = 0; i < MAX_ACL_IN_WINDOW; i++) {
err = submit_rx_acl(bdev); err = submit_rx_acl(bdev);
if (err != B_OK && i == 0) { if (err != B_OK && i == 0) {
CLEAR_BIT(bdev->state, ANCILLYANT); // Set the flaq in the HCI world CLEAR_BIT(bdev->state, ANCILLYANT); // Set the flaq in the HCI world
flowf("Queuing failed device stops running\n"); flowf("Queuing failed device stops running\n");
break; break;
} }
} }
#endif #endif
@@ -683,13 +690,13 @@ device_control(void *cookie, uint32 msg, void *params, size_t size)
break; break;
case GET_STATS: case GET_STATS:
memcpy(params, &bdev->stat, sizeof(bt_hci_statistics)); memcpy(params, &bdev->stat, sizeof(bt_hci_statistics));
err = B_OK; err = B_OK;
break; break;
case GET_HCI_ID: case GET_HCI_ID:
*(hci_id*)params = bdev->hdev; *(hci_id*)params = bdev->hdev;
err = B_OK; err = B_OK;
break; break;
@@ -704,9 +711,9 @@ device_control(void *cookie, uint32 msg, void *params, size_t size)
} }
/* implements the POSIX read() */ // implements the POSIX read()
static status_t static status_t
device_read(void *cookie, off_t pos, void *buf, size_t *count) device_read(void* cookie, off_t pos, void* buffer, size_t* count)
{ {
debugf("Reading... count = %ld\n", *count); debugf("Reading... count = %ld\n", *count);
@@ -715,15 +722,16 @@ device_read(void *cookie, off_t pos, void *buf, size_t *count)
} }
/* implements the POSIX write() */ // implements the POSIX write()
static status_t static status_t
device_write(void *cookie, off_t pos, const void *buf, size_t *count) device_write(void* cookie, off_t pos, const void* buffer, size_t* count)
{ {
flowf("device_write()\n"); flowf("device_write()\n");
return B_ERROR; return B_ERROR;
} }
#if 0 #if 0
#pragma mark - #pragma mark -
#endif #endif
@@ -734,25 +742,27 @@ dump_driver(int argc, char** argv)
{ {
int i; int i;
snet_buffer* item = NULL; snet_buffer* item = NULL;
for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
if (bt_usb_devices[i] != NULL) { if (bt_usb_devices[i] != NULL) {
kprintf("%s : \n", bt_usb_devices[i]->name); kprintf("%s : \n", bt_usb_devices[i]->name);
kprintf("\taclroom = %d\teventroom = %d\tcommand & events =%d\n", snb_packets(&bt_usb_devices[i]->eventRoom) kprintf("\taclroom = %d\teventroom = %d\tcommand & events =%d\n",
, snb_packets(&bt_usb_devices[i]->aclRoom) snb_packets(&bt_usb_devices[i]->eventRoom),
, snb_packets(&bt_usb_devices[i]->snetBufferRecycleTrash) ); snb_packets(&bt_usb_devices[i]->aclRoom),
snb_packets(&bt_usb_devices[i]->snetBufferRecycleTrash));
while ((item = list_get_next_item(&bt_usb_devices[i]->snetBufferRecycleTrash, item)) != NULL)
while ((item = (snet_buffer*)list_get_next_item(
&bt_usb_devices[i]->snetBufferRecycleTrash, item)) != NULL)
snb_dump(item); snb_dump(item);
} }
} }
return 0; return 0;
} }
/* called each time the driver is loaded by the kernel */ // called each time the driver is loaded by the kernel
status_t status_t
init_driver(void) init_driver(void)
{ {
@@ -806,15 +816,15 @@ init_driver(void)
} }
for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) {
bt_usb_devices[j] = NULL; bt_usb_devices[j] = NULL;
} }
/* After here device_added and publish devices hooks are called // Note: After here device_added and publish devices hooks are called
be carefull USB devs */
usb->register_driver(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL); usb->register_driver(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL);
usb->install_notify(BLUETOOTH_DEVICE_DEVFS_NAME, &notify_hooks); usb->install_notify(BLUETOOTH_DEVICE_DEVFS_NAME, &notify_hooks);
add_debugger_command("bth2generic", &dump_driver, "Lists H2 Transport device info"); add_debugger_command("bth2generic", &dump_driver,
"Lists H2 Transport device info");
return B_OK; return B_OK;
@@ -830,12 +840,12 @@ err_release2:
put_module(btDevices_name); put_module(btDevices_name);
err_release3: err_release3:
put_module(BT_CORE_DATA_MODULE_NAME); put_module(BT_CORE_DATA_MODULE_NAME);
return B_ERROR; return B_ERROR;
} }
/* called just before the kernel unloads the driver */ // called just before the kernel unloads the driver
void void
uninit_driver(void) uninit_driver(void)
{ {
@@ -849,10 +859,10 @@ uninit_driver(void)
free(publish_names[j]); free(publish_names[j]);
if (bt_usb_devices[j] != NULL) { if (bt_usb_devices[j] != NULL) {
// if (connected_dev != NULL) { // if (connected_dev != NULL) {
// debugf("Device %p still exists.\n", connected_dev); // debugf("Device %p still exists.\n", connected_dev);
// } // }
debugf("%s still present?\n",bt_usb_devices[j]->name); debugf("%s still present?\n",bt_usb_devices[j]->name);
kill_device(bt_usb_devices[j]); kill_device(bt_usb_devices[j]);
} }
} }
@@ -861,7 +871,7 @@ uninit_driver(void)
remove_debugger_command("bth2generic", &dump_driver); remove_debugger_command("bth2generic", &dump_driver);
/* Releasing modules */ // Releasing modules
put_module(usb_name); put_module(usb_name);
put_module(hci_name); put_module(hci_name);
// TODO: netbuffers // TODO: netbuffers
@@ -900,18 +910,18 @@ publish_devices(void)
release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
publish_names[i] = NULL; publish_names[i] = NULL;
debugf("published %ld devices\n", i); debugf("published %ld devices\n", i);
// TODO: this method might make better memory use // TODO: this method might make better memory use
// dev_names = (char**)malloc(sizeof (char*) * (dev_count+1)); // dev_names = (char**)malloc(sizeof(char*) * (dev_count + 1));
// if (dev_names) { // if (dev_names) {
// for (i = 0; i < MAX_NUM_DEVS; i++) { // for (i = 0; i < MAX_NUM_DEVS; i++) {
// if ((dev != NULL) && // if ((dev != NULL) // dev + \n
// (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH)+2/* num + \n */))) { // && (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH) + 2))) {
// sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num); // sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num);
// debugf("publishing \"%s\"\n", dev_names[i]); // debugf("publishing \"%s\"\n", dev_names[i]);
// } // }
// } // }
return (const char**)publish_names; return (const char**)publish_names;
} }
@@ -21,13 +21,13 @@
#include <util/list.h> #include <util/list.h>
#include <bluetooth/HCI/btHCI.h> #include <bluetooth/HCI/btHCI.h>
#include <bluetooth/HCI/btHCI_module.h> #include <bluetooth/HCI/btHCI_transport.h>
#include <btCoreData.h> #include <btCoreData.h>
#include "snet_buffer.h" #include "snet_buffer.h"
/* USB definitions for the generic device*/ // USB definitions for the generic device move to h2cfg
#define UDCLASS_WIRELESS 0xe0 #define UDCLASS_WIRELESS 0xe0
#define UDSUBCLASS_RF 0x01 #define UDSUBCLASS_RF 0x01
#define UDPROTO_BLUETOOTH 0x01 #define UDPROTO_BLUETOOTH 0x01
@@ -45,7 +45,7 @@
extern usb_module_info* usb; extern usb_module_info* usb;
extern bt_hci_module_info* hci; extern bt_hci_module_info* hci;
extern struct net_device_module_info* btDevices; extern struct bt_hci_module_info* btDevices;
extern struct net_buffer_module_info* nb; extern struct net_buffer_module_info* nb;
extern struct bluetooth_core_data_module_info* btCoreData; extern struct bluetooth_core_data_module_info* btCoreData;
@@ -64,9 +64,9 @@ struct bt_usb_dev {
#else #else
usb_device* dev; /* opaque handle */ usb_device* dev; /* opaque handle */
#endif #endif
hci_id hdev; /* HCI device id*/ hci_id hdev; /* HCI device id*/
struct net_device* ndev; bluetooth_device* ndev;
char name[B_OS_NAME_LENGTH]; char name[B_OS_NAME_LENGTH];
bool connected; /* is the device plugged into the USB? */ bool connected; /* is the device plugged into the USB? */
int32 open_count; /* number of clients of the device */ int32 open_count; /* number of clients of the device */
@@ -83,35 +83,36 @@ struct bt_usb_dev {
uint32 state; uint32 state;
bt_hci_statistics stat; bt_hci_statistics stat;
const usb_endpoint_info *bulk_in_ep; const usb_endpoint_info* bulk_in_ep;
uint16 max_packet_size_bulk_in; uint16 max_packet_size_bulk_in;
const usb_endpoint_info *bulk_out_ep; const usb_endpoint_info* bulk_out_ep;
uint16 max_packet_size_bulk_out; uint16 max_packet_size_bulk_out;
const usb_endpoint_info *intr_in_ep; const usb_endpoint_info* intr_in_ep;
uint16 max_packet_size_intr_in; uint16 max_packet_size_intr_in;
#ifdef BLUETOOTH_SUPPORTS_SCO #ifdef BLUETOOTH_SUPPORTS_SCO
const usb_endpoint_info *iso_in_ep; const usb_endpoint_info *iso_in_ep;
const usb_endpoint_info *iso_out_ep; const usb_endpoint_info *iso_out_ep;
#endif #endif
/* This so called rooms, are for dumping the USB RX frames /* This so called rooms, are for dumping the USB RX frames
and try to reuse the allocations. see util submodule */ * and try to reuse the allocations. see util submodule
*/
struct list eventRoom; struct list eventRoom;
struct list aclRoom; struct list aclRoom;
// Tx buffers: net_buffers for BT_ACL and snet_buffers for BT_COMMAND // Tx buffers: net_buffers for BT_ACL and snet_buffers for BT_COMMAND
// in the same array // in the same array
struct list nbuffersTx[BT_DRIVER_TXCOVERAGE]; struct list nbuffersTx[BT_DRIVER_TXCOVERAGE];
uint32 nbuffersPendingTx[BT_DRIVER_TXCOVERAGE]; uint32 nbuffersPendingTx[BT_DRIVER_TXCOVERAGE];
// Rx buffer // Rx buffer
net_buffer* nbufferRx[BT_DRIVER_RXCOVERAGE]; /* Wasting 1 pointer for BT_EVENT */ net_buffer* nbufferRx[BT_DRIVER_RXCOVERAGE];
snet_buffer* eventRx; /* <- which we hold here */ snet_buffer* eventRx;
// for who ever needs preallocated buffers // for who ever needs preallocated buffers
struct list snetBufferRecycleTrash; struct list snetBufferRecycleTrash;
}; };
@@ -40,119 +40,10 @@ void event_complete(void* cookie, status_t status, void* data, size_t actual_len
static status_t static status_t
assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void* data, int count) assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void* data, int count)
{ {
net_buffer* nbuf = NULL;
snet_buffer* snbuf = NULL;
size_t currentPacketLen = 0;
size_t expectedPacketLen = 0;
#ifdef DUMP_BUFFERS
int16 index;
#endif
bdev->stat.bytesRX += count; bdev->stat.bytesRX += count;
if (type == BT_EVENT) return btDevices->PostTransportPacket(bdev->hdev, type, data, count);
snbuf = bdev->eventRx;
else
nbuf = bdev->nbufferRx[type];
while (count) {
//debugf("count %d nb=%p sb=%p type=%d\n", count, nbuf, snbuf, type);
if ((type != BT_EVENT && nbuf == NULL)
|| (type == BT_EVENT && (snbuf == NULL || snb_completed(snbuf)))) {
/* new buffer incoming */
switch (type) {
case BT_EVENT:
if (count >= HCI_EVENT_HDR_SIZE) {
struct hci_event_header* headerPkt = data;
expectedPacketLen = HCI_EVENT_HDR_SIZE + headerPkt->elen;
snbuf = bdev->eventRx = snb_fetch(&bdev->snetBufferRecycleTrash,
expectedPacketLen);
#ifdef DUMP_BUFFERS
debugf("## Incoming EVENT frame %p len = %d ", snbuf, count);
for (index = 0 ; index < count; index++)
dprintf("%x:",((uint8*)data)[index]);
dprintf(" ## \n");
#endif
} else {
flowf("EVENT frame corrupted\n");
return EILSEQ;
}
break;
case BT_ACL:
if (count >= HCI_ACL_HDR_SIZE) {
struct hci_acl_header* headerPkt = data;
expectedPacketLen = HCI_ACL_HDR_SIZE
+ B_LENDIAN_TO_HOST_INT16(headerPkt->alen);
// Create the buffer -> TODO: this allocation can fail
bdev->nbufferRx[type] = nbuf = nb->create(expectedPacketLen);
nbuf->protocol = type;
#ifdef DUMP_BUFFERS
debugf("## Incoming ACL frame %p len = %d ", nbuf, count);
for (index = 0 ; index < count; index++)
dprintf("%x:",((uint8*)data)[index]);
dprintf(" ## \n");
#endif
} else {
flowf("ACL frame corrupted\n");
return EILSEQ;
}
break;
case BT_SCO:
break;
default:
panic("unknown packet type in assembly");
break;
}
currentPacketLen = expectedPacketLen;
} else {
// Continuation of a packet
if (type != BT_EVENT)
currentPacketLen = get_expected_size(nbuf) - nbuf->size;
else
currentPacketLen = snb_remaining_to_put(snbuf);
}
currentPacketLen = min(currentPacketLen, count);
if (type == BT_EVENT)
snb_put(snbuf, data, currentPacketLen);
else
nb->append(nbuf, data, currentPacketLen);
// Complete frame?
if (type == BT_EVENT && snb_completed(snbuf)) {
post_packet_up(bdev, type, snbuf);
snbuf = bdev->eventRx = NULL;
}
if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) {
post_packet_up(bdev, type, nbuf);
bdev->nbufferRx[type] = nbuf = NULL;
} else {
#if DEBUG_ACL
if (type == BT_ACL)
debugf("ACL Packet not filled size=%ld expected=%ld\n",
nbuf->size, get_expected_size(nbuf));
#endif
}
/* in case in the pipe there is info about the next buffer ... */
count -= currentPacketLen;
data += currentPacketLen;
}
return B_OK;
} }
@@ -160,7 +51,6 @@ assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void* data, int count)
#pragma mark --- RX Complete --- #pragma mark --- RX Complete ---
#endif #endif
void void
#ifndef HAIKU_TARGET_PLATFORM_HAIKU #ifndef HAIKU_TARGET_PLATFORM_HAIKU
event_complete(void* cookie, uint32 status, void* data, uint32 actual_len) event_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
@@ -168,8 +58,8 @@ event_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
event_complete(void* cookie, status_t status, void* data, size_t actual_len) event_complete(void* cookie, status_t status, void* data, size_t actual_len)
#endif #endif
{ {
bt_usb_dev* bdev = cookie; bt_usb_dev* bdev = (bt_usb_dev*)cookie;
//bt_usb_dev* bdev = fetch_device(cookie, 0); -> safer/slower option // bt_usb_dev* bdev = fetch_device(cookie, 0); -> safer / slower option
status_t error; status_t error;
debugf("cookie@%p status=%s len=%ld\n", cookie, strerror(status), actual_len); debugf("cookie@%p status=%s len=%ld\n", cookie, strerror(status), actual_len);
@@ -177,13 +67,13 @@ event_complete(void* cookie, status_t status, void* data, size_t actual_len)
if (bdev == NULL) if (bdev == NULL)
return; return;
if (status == B_CANCELED || status == B_DEV_CRC_ERROR) // or not running anymore... if (status == B_CANCELED || status == B_DEV_CRC_ERROR)
return; return; // or not running anymore...
if (status != B_OK || actual_len == 0) if (status != B_OK || actual_len == 0)
goto resubmit; goto resubmit;
if (assembly_rx(cookie, BT_EVENT, data, actual_len) == B_OK) { if (assembly_rx(bdev, BT_EVENT, data, actual_len) == B_OK) {
bdev->stat.successfulTX++; bdev->stat.successfulTX++;
} else { } else {
bdev->stat.errorRX++; bdev->stat.errorRX++;
@@ -191,8 +81,8 @@ event_complete(void* cookie, status_t status, void* data, size_t actual_len)
resubmit: resubmit:
error = usb->queue_interrupt(bdev->intr_in_ep->handle, data, error = usb->queue_interrupt(bdev->intr_in_ep->handle, data,
max(HCI_MAX_EVENT_SIZE, bdev->max_packet_size_intr_in), event_complete, bdev); max_c(HCI_MAX_EVENT_SIZE, bdev->max_packet_size_intr_in), event_complete, bdev);
if (error != B_OK) { if (error != B_OK) {
reuse_room(&bdev->eventRoom, data); reuse_room(&bdev->eventRoom, data);
@@ -211,20 +101,20 @@ acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len) acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len)
#endif #endif
{ {
bt_usb_dev* bdev = cookie; bt_usb_dev* bdev = (bt_usb_dev*)cookie;
//bt_usb_dev* bdev = fetch_device(cookie, 0); -> safer/slower option // bt_usb_dev* bdev = fetch_device(cookie, 0); -> safer / slower option
status_t error; status_t error;
if (bdev == NULL) if (bdev == NULL)
return; return;
if (status == B_CANCELED || status == B_DEV_CRC_ERROR) // or not running anymore... if (status == B_CANCELED || status == B_DEV_CRC_ERROR)
return; return; // or not running anymore...
if (status != B_OK || actual_len == 0) if (status != B_OK || actual_len == 0)
goto resubmit; goto resubmit;
if (assembly_rx(cookie, BT_ACL, data, actual_len) == B_OK) { if (assembly_rx(bdev, BT_ACL, data, actual_len) == B_OK) {
bdev->stat.successfulRX++; bdev->stat.successfulRX++;
} else { } else {
bdev->stat.errorRX++; bdev->stat.errorRX++;
@@ -233,10 +123,10 @@ acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len)
resubmit: resubmit:
error = usb->queue_bulk(bdev->bulk_in_ep->handle, data, error = usb->queue_bulk(bdev->bulk_in_ep->handle, data,
max(HCI_MAX_FRAME_SIZE, bdev->max_packet_size_bulk_in), max_c(HCI_MAX_FRAME_SIZE, bdev->max_packet_size_bulk_in),
acl_rx_complete, (void*) bdev); acl_rx_complete, (void*) bdev);
if (error != B_OK) { if (error != B_OK) {
reuse_room(&bdev->aclRoom, data); reuse_room(&bdev->aclRoom, data);
bdev->stat.rejectedRX++; bdev->stat.rejectedRX++;
debugf("RX acl resubmittion failed %s\n", strerror(error)); debugf("RX acl resubmittion failed %s\n", strerror(error));
@@ -245,6 +135,7 @@ resubmit:
} }
} }
#if 0 #if 0
#pragma mark --- RX --- #pragma mark --- RX ---
#endif #endif
@@ -252,7 +143,7 @@ resubmit:
status_t status_t
submit_rx_event(bt_usb_dev* bdev) submit_rx_event(bt_usb_dev* bdev)
{ {
size_t size = max(HCI_MAX_EVENT_SIZE, bdev->max_packet_size_intr_in); size_t size = max_c(HCI_MAX_EVENT_SIZE, bdev->max_packet_size_intr_in);
void* buf = alloc_room(&bdev->eventRoom, size); void* buf = alloc_room(&bdev->eventRoom, size);
status_t status; status_t status;
@@ -276,8 +167,8 @@ submit_rx_event(bt_usb_dev* bdev)
status_t status_t
submit_rx_acl(bt_usb_dev* bdev) submit_rx_acl(bt_usb_dev* bdev)
{ {
size_t size = max(HCI_MAX_FRAME_SIZE, bdev->max_packet_size_bulk_in); size_t size = max_c(HCI_MAX_FRAME_SIZE, bdev->max_packet_size_bulk_in);
void* buf = alloc_room(&bdev->aclRoom, size); void* buf = alloc_room(&bdev->aclRoom, size);
status_t status; status_t status;
@@ -301,10 +192,11 @@ submit_rx_acl(bt_usb_dev* bdev)
status_t status_t
submit_rx_sco(bt_usb_dev* bdev) submit_rx_sco(bt_usb_dev* bdev)
{ {
/* not yet implemented */ // not yet implemented
return B_ERROR; return B_ERROR;
} }
#if 0 #if 0
#pragma mark --- TX Complete --- #pragma mark --- TX Complete ---
#endif #endif
@@ -317,7 +209,7 @@ command_complete(void* cookie, status_t status, void* data, size_t actual_len)
#endif #endif
{ {
snet_buffer* snbuf = (snet_buffer*)cookie; snet_buffer* snbuf = (snet_buffer*)cookie;
bt_usb_dev* bdev = snb_cookie(snbuf); bt_usb_dev* bdev = (bt_usb_dev*)snb_cookie(snbuf);
debugf("status = %ld len = %ld @%p\n", status, actual_len, data); debugf("status = %ld len = %ld @%p\n", status, actual_len, data);
@@ -326,13 +218,13 @@ command_complete(void* cookie, status_t status, void* data, size_t actual_len)
bdev->stat.bytesTX += actual_len; bdev->stat.bytesTX += actual_len;
} else { } else {
bdev->stat.errorTX++; bdev->stat.errorTX++;
// the packet has been lost,too late to requeue it? // the packet has been lost, too late to requeue it
} }
snb_park(&bdev->snetBufferRecycleTrash, snbuf); snb_park(&bdev->snetBufferRecycleTrash, snbuf);
#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS #ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
// TODO: check just the empty queues? // TODO: check just the empty queues
schedTxProcessing(bdev); schedTxProcessing(bdev);
#endif #endif
} }
@@ -348,22 +240,24 @@ acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len)
net_buffer* nbuf = (net_buffer*)cookie; net_buffer* nbuf = (net_buffer*)cookie;
bt_usb_dev* bdev = GET_DEVICE(nbuf); bt_usb_dev* bdev = GET_DEVICE(nbuf);
debugf("fetched=%p status=%ld nbuftype %lx B%p\n", bdev, status, nbuf->type, data); debugf("fetched=%p status=%ld type %lx %p\n", bdev, status, nbuf->type, data);
if (status == B_OK) { if (status == B_OK) {
bdev->stat.successfulTX++; bdev->stat.successfulTX++;
bdev->stat.bytesTX += actual_len; bdev->stat.bytesTX += actual_len;
} else { } else {
bdev->stat.errorTX++; bdev->stat.errorTX++;
// the packet has been lost,too late to requeue it? // the packet has been lost, too late to requeue it
} }
nb_destroy(nbuf); nb_destroy(nbuf);
#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS #ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
schedTxProcessing(bdev); schedTxProcessing(bdev);
#endif #endif
} }
#if 0 #if 0
#pragma mark --- TX --- #pragma mark --- TX ---
#endif #endif
@@ -376,23 +270,23 @@ submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf)
uint16 wIndex = 0; uint16 wIndex = 0;
uint16 value = 0; uint16 value = 0;
uint16 wLength = B_HOST_TO_LENDIAN_INT16(snb_size(snbuf)); uint16 wLength = B_HOST_TO_LENDIAN_INT16(snb_size(snbuf));
status_t error; status_t error;
if (!GET_BIT(bdev->state, RUNNING)) { if (!GET_BIT(bdev->state, RUNNING)) {
return B_DEV_NOT_READY; return B_DEV_NOT_READY;
} }
/* set cookie */ // set cookie
snb_set_cookie(snbuf, bdev); snb_set_cookie(snbuf, bdev);
debugf("@%p\n", snb_get(snbuf)); debugf("@%p\n", snb_get(snbuf));
error = usb->queue_request(bdev->dev, bRequestType, bRequest, error = usb->queue_request(bdev->dev, bRequestType, bRequest,
value, wIndex, wLength, snb_get(snbuf), value, wIndex, wLength, snb_get(snbuf),
#ifndef HAIKU_TARGET_PLATFORM_HAIKU #ifndef HAIKU_TARGET_PLATFORM_HAIKU
wLength, //??? wLength,
#endif #endif
command_complete, (void*) snbuf); command_complete, (void*) snbuf);
if (error != B_OK) { if (error != B_OK) {
bdev->stat.rejectedTX++; bdev->stat.rejectedTX++;
@@ -407,21 +301,20 @@ submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf)
status_t status_t
submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf) submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf)
{ {
int32 index;
status_t error; status_t error;
/* set cookie */ // set cookie
SET_DEVICE(nbuf, bdev->hdev); SET_DEVICE(nbuf, bdev->hdev);
if (!GET_BIT(bdev->state, RUNNING)) { if (!GET_BIT(bdev->state, RUNNING)) {
return B_DEV_NOT_READY; return B_DEV_NOT_READY;
} }
/*
debugf("### Outgoing ACL: len = %ld\n", nbuf->size); debugf("### Outgoing ACL: len = %ld\n", nbuf->size);
for (index = 0 ; index < nbuf->size; index++ ) { for (uint32 index = 0 ; index < nbuf->size; index++ ) {
dprintf("%x:",((uint8*)nb_get_whole_buffer(nbuf))[index]); dprintf("%x:",((uint8*)nb_get_whole_buffer(nbuf))[index]);
} }
flowf("### \n"); */
error = usb->queue_bulk(bdev->bulk_out_ep->handle, nb_get_whole_buffer(nbuf), error = usb->queue_bulk(bdev->bulk_out_ep->handle, nb_get_whole_buffer(nbuf),
nbuf->size, acl_tx_complete, (void*)nbuf); nbuf->size, acl_tx_complete, (void*)nbuf);
@@ -444,6 +337,6 @@ submit_tx_sco(bt_usb_dev* bdev)
return B_DEV_NOT_READY; return B_DEV_NOT_READY;
} }
/* not yet implemented */ // not yet implemented
return B_ERROR; return B_ERROR;
} }
@@ -1,8 +1,6 @@
/* /*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
*/ */
#ifndef _H2TRANSACTION_H_ #ifndef _H2TRANSACTION_H_
@@ -1,187 +0,0 @@
/*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* Copyright 2008 Mika Lindqvist, monni1995_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include "h2generic.h"
#include "h2upper.h"
#include "h2transactions.h"
#include "snet_buffer.h"
#define BT_DEBUG_THIS_MODULE
#include <btDebug.h>
/* TODO: split for commands and comunication (ACL&SCO) */
void
sched_tx_processing(bt_usb_dev* bdev)
{
net_buffer* nbuf;
snet_buffer* snbuf;
status_t err;
debugf("(%p)\n", bdev)
if (!TEST_AND_SET(&bdev->state, PROCESSING)) {
// We are not processing in another thread so... START!!
do {
/* Do while this bit is on... so someone should set it before we
* stop the iterations
*/
CLEAR_BIT(bdev->state, SENDING);
// check Commands
#ifdef EMPTY_COMMAND_QUEUE
while (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND])) {
#else
if (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND])) {
#endif
snbuf = list_remove_head_item(&bdev->nbuffersTx[BT_COMMAND]);
err = submit_tx_command(bdev, snbuf);
if (err != B_OK) {
// re-head it
list_insert_item_before(&bdev->nbuffersTx[BT_COMMAND],
list_get_first_item(&bdev->nbuffersTx[BT_COMMAND]), snbuf);
}
}
// check ACl
#define EMPTY_ACL_QUEUE
#ifdef EMPTY_ACL_QUEUE
while (!list_is_empty(&bdev->nbuffersTx[BT_ACL])) {
#else
if (!list_is_empty(&bdev->nbuffersTx[BT_ACL])) {
#endif
nbuf = list_remove_head_item(&bdev->nbuffersTx[BT_ACL]);
err = submit_tx_acl(bdev, nbuf);
if (err != B_OK) {
/* re-head it*/
list_insert_item_before(&bdev->nbuffersTx[BT_ACL],
list_get_first_item(&bdev->nbuffersTx[BT_ACL]), nbuf);
}
}
if (!list_is_empty(&bdev->nbuffersTx[BT_SCO])) {
/* TODO to be implemented */
}
} while (GET_BIT(bdev->state, SENDING));
CLEAR_BIT(bdev->state, PROCESSING);
} else {
/* We are processing so MARK that we need to still go on with that ... */
SET_BIT(bdev->state, SENDING);
}
}
status_t
post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf)
{
status_t err = B_ERROR;
debugf("Frame up type=%d\n", type);
if (type == BT_EVENT) {
snet_buffer* snbuf = (snet_buffer*)buf;
btCoreData->PostEvent(bdev->ndev, snb_get(snbuf), (size_t)snb_size(snbuf));
snb_park(&bdev->snetBufferRecycleTrash, snbuf);
debugf("to btDataCore len=%d\n", snb_size(snbuf));
} else {
net_buffer* nbuf = (net_buffer*) buf;
/* No need to free the buffer at allocation is gonna be reused */
btDevices->receive_data(bdev->ndev, &nbuf);
flowf("to net_device\n");
}
return err;
}
status_t
send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf)
{
bt_usb_dev* bdev = fetch_device(NULL, hid);
status_t err = B_OK;
if (bdev == NULL)
return B_ERROR;
// TODO: check if device is actually ready for this
// TODO: Lock Device
if (nbuf != NULL) {
if (type != nbuf->protocol) // a bit strict maybe?
panic("Upper layer has not filled correctly a packet");
switch (type) {
case BT_COMMAND:
case BT_ACL:
case BT_SCO:
list_add_item(&bdev->nbuffersTx[type],nbuf);
bdev->nbuffersPendingTx[type]++;
break;
default:
debugf("Unknown packet type for sending %d\n",type);
// TODO: free the net_buffer -> no, allow upper layer
// handle it with the given error
err = B_BAD_VALUE;
break;
}
} else {
flowf("tx sched provoked");
}
// TODO: check if device is actually ready for this
// TODO: unlock device
/* sched in All cases even if nbuf is null (hidden way to provoke
* re-scheduling)
*/
sched_tx_processing(bdev);
return err;
}
status_t
send_command(hci_id hid, snet_buffer* snbuf)
{
bt_usb_dev* bdev = fetch_device(NULL, hid);
status_t err = B_OK;
if (bdev == NULL)
return B_ERROR;
// TODO: check if device is actually ready for this
// TODO: mutex?
if (snbuf != NULL) {
list_add_item(&bdev->nbuffersTx[BT_COMMAND],snbuf);
bdev->nbuffersPendingTx[BT_COMMAND]++;
} else {
err = B_BAD_VALUE;
flowf("tx sched provoked");
}
// TODO: check if device is actually ready for this
// TODO: mutex?
/* sched in All cases even if nbuf is null (hidden way to provoke
* re-scheduling)
*/
sched_tx_processing(bdev);
return err;
}
@@ -0,0 +1,189 @@
/*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* Copyright 2008 Mika Lindqvist, monni1995_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/HCI/btHCI_transport.h>
#include "h2generic.h"
#include "h2upper.h"
#include "h2transactions.h"
#include "snet_buffer.h"
#define BT_DEBUG_THIS_MODULE
#include <btDebug.h>
// TODO: split for commands and comunication (ACL & SCO)
void
sched_tx_processing(bt_usb_dev* bdev)
{
net_buffer* nbuf;
snet_buffer* snbuf;
status_t err;
debugf("(%p)\n", bdev)
if (!TEST_AND_SET(&bdev->state, PROCESSING)) {
// We are not processing in another thread so... START!!
do {
/* Do while this bit is on... so someone should set it before we
* stop the iterations
*/
CLEAR_BIT(bdev->state, SENDING);
// check Commands
#ifdef EMPTY_COMMAND_QUEUE
while (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND])) {
#else
if (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND])) {
#endif
snbuf = (snet_buffer*)
list_remove_head_item(&bdev->nbuffersTx[BT_COMMAND]);
err = submit_tx_command(bdev, snbuf);
if (err != B_OK) {
// re-head it
list_insert_item_before(&bdev->nbuffersTx[BT_COMMAND],
list_get_first_item(&bdev->nbuffersTx[BT_COMMAND]),
snbuf);
}
}
// check ACl
#define EMPTY_ACL_QUEUE
#ifdef EMPTY_ACL_QUEUE
while (!list_is_empty(&bdev->nbuffersTx[BT_ACL])) {
#else
if (!list_is_empty(&bdev->nbuffersTx[BT_ACL])) {
#endif
nbuf = (net_buffer*)
list_remove_head_item(&bdev->nbuffersTx[BT_ACL]);
err = submit_tx_acl(bdev, nbuf);
if (err != B_OK) {
// re-head it
list_insert_item_before(&bdev->nbuffersTx[BT_ACL],
list_get_first_item(&bdev->nbuffersTx[BT_ACL]),
nbuf);
}
}
if (!list_is_empty(&bdev->nbuffersTx[BT_SCO])) {
// TODO to be implemented
}
} while (GET_BIT(bdev->state, SENDING));
CLEAR_BIT(bdev->state, PROCESSING);
} else {
// We are processing so MARK that we need to still go on with that
SET_BIT(bdev->state, SENDING);
}
}
#if 0
// DEPRECATED
status_t
post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf)
{
status_t err = B_ERROR;
debugf("Frame up type=%d\n", type);
if (type == BT_EVENT) {
snet_buffer* snbuf = (snet_buffer*)buf;
btCoreData->PostEvent(bdev->ndev, snb_get(snbuf),
(size_t)snb_size(snbuf));
snb_park(&bdev->snetBufferRecycleTrash, snbuf);
debugf("to btDataCore len=%d\n", snb_size(snbuf));
} else {
net_buffer* nbuf = (net_buffer*) buf;
// No need to free the buffer at allocation is gonna be reused
btDevices->receive_data(bdev->ndev, &nbuf);
flowf("to net_device\n");
}
return err;
}
#endif
status_t
send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf)
{
bt_usb_dev* bdev = fetch_device(NULL, hid);
status_t err = B_OK;
if (bdev == NULL)
return B_ERROR;
// TODO: check if device is actually ready for this
// TODO: Lock Device
if (nbuf != NULL) {
if (type != nbuf->protocol) // a bit strict maybe
panic("Upper layer has not filled correctly a packet");
switch (type) {
case BT_COMMAND:
case BT_ACL:
case BT_SCO:
list_add_item(&bdev->nbuffersTx[type],nbuf);
bdev->nbuffersPendingTx[type]++;
break;
default:
debugf("Unknown packet type for sending %d\n",type);
// TODO: free the net_buffer -> no, allow upper layer
// handle it with the given error
err = B_BAD_VALUE;
break;
}
} else {
flowf("tx sched provoked");
}
// TODO: check if device is actually ready for this
// TODO: unlock device
// sched in any case even if nbuf is null (provoke re-scheduling)
sched_tx_processing(bdev);
return err;
}
status_t
send_command(hci_id hid, snet_buffer* snbuf)
{
bt_usb_dev* bdev = fetch_device(NULL, hid);
status_t err = B_OK;
if (bdev == NULL)
return B_ERROR;
// TODO: check if device is actually ready for this
// TODO: mutex
if (snbuf != NULL) {
list_add_item(&bdev->nbuffersTx[BT_COMMAND],snbuf);
bdev->nbuffersPendingTx[BT_COMMAND]++;
} else {
err = B_BAD_VALUE;
flowf("tx sched provoked");
}
// TODO: check if device is actually ready for this
// TODO: mutex
/* sched in All cases even if nbuf is null (hidden way to provoke
* re-scheduling)
*/
sched_tx_processing(bdev);
return err;
}
@@ -1,10 +1,7 @@
/* /*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
*/ */
#ifndef _H2UPPER_H_ #ifndef _H2UPPER_H_
#define _H2UPPER_H_ #define _H2UPPER_H_
@@ -12,10 +9,10 @@
#include "h2generic.h" #include "h2generic.h"
status_t post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf); status_t post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf);
status_t send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf); status_t send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf);
status_t send_command(hci_id hid, snet_buffer* snbuf); status_t send_command(hci_id hid, snet_buffer* snbuf);
void sched_tx_processing(bt_usb_dev* bdev); void sched_tx_processing(bt_usb_dev* bdev);
#endif #endif
@@ -22,21 +22,20 @@
void* void*
nb_get_whole_buffer(net_buffer* nbuf) nb_get_whole_buffer(net_buffer* nbuf)
{ {
void* conPointer; void* conPointer;
status_t err; status_t err;
#if 0 #if 0
/* the job could be already done */ // the job could be already done
// !!! it could be trash from other upper protocols... // !!! it could be trash from other upper protocols...
if (nbuf->COOKIEFIELD != NULL) if (nbuf->COOKIEFIELD != NULL)
return (void*)nbuf->COOKIEFIELD; return (void*)nbuf->COOKIEFIELD;
#endif #endif
err = nb->direct_access(nbuf, 0, nbuf->size, &conPointer); err = nb->direct_access(nbuf, 0, nbuf->size, &conPointer);
if (err != B_OK) { if (err != B_OK) {
snooze(3*1000*1000);
panic("expected to be contiguous"); panic("expected to be contiguous");
#if 0 #if 0
/* pity, we are gonna need a realocation */ // We are gonna need a realocation
nbuf->COOKIEFIELD = (uint32) malloc(nbuf->size); nbuf->COOKIEFIELD = (uint32) malloc(nbuf->size);
if (nbuf->COOKIEFIELD == NULL) if (nbuf->COOKIEFIELD == NULL)
goto fail; goto fail;
@@ -65,7 +64,7 @@ nb_destroy(net_buffer* nbuf)
if (nbuf == NULL) if (nbuf == NULL)
return; return;
#if 0 #if 0
/* Free possible allocated */ // Free possible allocated
if (nbuf->COOKIEFIELD != NULL) if (nbuf->COOKIEFIELD != NULL)
free((void*)nbuf->COOKIEFIELD); free((void*)nbuf->COOKIEFIELD);
#endif #endif
@@ -77,10 +76,10 @@ nb_destroy(net_buffer* nbuf)
// Extract the expected size of the packet // Extract the expected size of the packet
// TODO: This might be inefficient as at the moment of the creation of the net_buffer // TODO: This might be inefficient as at the moment of the creation
// this information is known and it could be stored in any of the net_buffer fields // of the net_buffer this information is known and it could be stored
// but I still dont know how many of those am i gonna have free.... #if 0
size_t ssize_t
get_expected_size(net_buffer* nbuf) get_expected_size(net_buffer* nbuf)
{ {
@@ -114,14 +113,17 @@ get_expected_size(net_buffer* nbuf)
break; break;
} }
return B_ERROR; return -1;
} }
#endif
#if 0 #if 0
#pragma mark - room util - #pragma mark - room util -
#endif #endif
inline void
void
init_room(struct list* l) init_room(struct list* l)
{ {
list_init(l); list_init(l);
@@ -142,7 +144,7 @@ alloc_room(struct list* l, size_t size)
} }
inline void void
reuse_room(struct list* l, void* room) reuse_room(struct list* l, void* room)
{ {
list_add_item(l, room); list_add_item(l, room);
@@ -1,10 +1,7 @@
/* /*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
*/ */
#ifndef _H2UTIL_H_ #ifndef _H2UTIL_H_
#define _H2UTIL_H_ #define _H2UTIL_H_
@@ -14,7 +11,8 @@
/* net buffer utils for ACL, to be reviewed */ /* net buffer utils for ACL, to be reviewed */
#define DEVICEFIELD type #define DEVICEFIELD type
#define SET_DEVICE(nbuf,hid) (nbuf->DEVICEFIELD=(nbuf->DEVICEFIELD&0xFFFFFF00)|(hid&0xFF)) #define SET_DEVICE(nbuf, hid) \
(nbuf->DEVICEFIELD=(nbuf->DEVICEFIELD & 0xFFFFFF00) | (hid & 0xFF))
#define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0xFF)) #define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0xFF))
#define COOKIEFIELD flags #define COOKIEFIELD flags
@@ -23,10 +21,10 @@ void nb_destroy(net_buffer* nbuf);
size_t get_expected_size(net_buffer* nbuf); size_t get_expected_size(net_buffer* nbuf);
/* Room utils */ /* Room utils */
inline void init_room(struct list* l); void init_room(struct list* l);
void* alloc_room(struct list* l, size_t size); void* alloc_room(struct list* l, size_t size);
inline void reuse_room(struct list* l, void* room); void reuse_room(struct list* l, void* room);
void purge_room(struct list* l); void purge_room(struct list* l);
/* list utils */ /* list utils */
#define list_purge(x) purge_room(x) #define list_purge(x) purge_room(x)
@@ -12,16 +12,16 @@
#include <KernelExport.h> #include <KernelExport.h>
struct snet_buffer { struct snet_buffer {
struct list_link link; struct list_link link;
uint8* buffer; uint8* buffer;
uint16 allocatedSize; uint16 allocatedSize;
uint16 expectedSize; uint16 expectedSize;
uint16 puttingSize; uint16 puttingSize;
uint16 pullingSize; uint16 pullingSize;
void* cookie; void* cookie;
}; };
@@ -29,10 +29,10 @@ struct snet_buffer {
snet_buffer* snet_buffer*
snb_create(uint16 size) snb_create(uint16 size)
{ {
/* TODO: pointer checking */ // TODO: pointer checking
#ifdef SNB_BUFFER_ATTACHED #ifdef SNB_BUFFER_ATTACHED
/* Allocating these 2 buffers together might prevent memory fragmentation? */ // Allocating these 2 buffers together might prevent memory fragmentation
snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size); snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size);
snb->buffer = ((uint8*)snb) + sizeof(snet_buffer); snb->buffer = ((uint8*)snb) + sizeof(snet_buffer);
#else #else
@@ -50,7 +50,7 @@ snb_create(uint16 size)
void void
snb_put(snet_buffer* snb, void* data, uint16 size) snb_put(snet_buffer* snb, void* data, uint16 size)
{ {
/* TODO: check overflow */ // TODO: check overflow
memcpy( &snb->buffer[snb->puttingSize], data, size); memcpy( &snb->buffer[snb->puttingSize], data, size);
snb->puttingSize+=size; snb->puttingSize+=size;
} }
@@ -59,14 +59,14 @@ snb_put(snet_buffer* snb, void* data, uint16 size)
void* void*
snb_pull(snet_buffer* snb, uint16 size) snb_pull(snet_buffer* snb, uint16 size)
{ {
/* TODO: check overflow */ // TODO: check overflow
snb->pullingSize+=size; snb->pullingSize+=size;
return &snb->buffer[snb->pullingSize-size]; return &snb->buffer[snb->pullingSize - size];
} }
inline void void
snb_reset(snet_buffer* snb) snb_reset(snet_buffer* snb)
{ {
snb->puttingSize = snb->pullingSize = 0; snb->puttingSize = snb->pullingSize = 0;
@@ -89,83 +89,88 @@ snb_free(snet_buffer* snb)
} }
inline void* void*
snb_get(snet_buffer* snb) snb_get(snet_buffer* snb)
{ {
/* TODO: pointer checking */ // TODO: pointer checking
return snb->buffer; return snb->buffer;
} }
inline uint16 uint16
snb_size(snet_buffer* snb) snb_size(snet_buffer* snb)
{ {
/* TODO: pointer checking */ // TODO: pointer checking
return snb->expectedSize; return snb->expectedSize;
} }
inline void* void*
snb_cookie(snet_buffer* snb) snb_cookie(snet_buffer* snb)
{ {
/* TODO: pointer checking */ // TODO: pointer checking
return snb->cookie; return snb->cookie;
} }
inline void void
snb_set_cookie(snet_buffer* snb, void* cookie) snb_set_cookie(snet_buffer* snb, void* cookie)
{ {
/* TODO: pointer checking */ // TODO: pointer checking
snb->cookie = cookie; snb->cookie = cookie;
} }
/* Return true if we canot "put" more data in the buffer */ // Return true if we canot "put" more data in the buffer
inline bool snb_completed(snet_buffer* snb) bool
snb_completed(snet_buffer* snb)
{ {
return (snb->expectedSize == snb->puttingSize); return (snb->expectedSize == snb->puttingSize);
} }
/* Return true if we cannot pull more more data from the buffer */ // Return true if we cannot pull more more data from the buffer
inline bool snb_finished(snet_buffer* snb) bool
snb_finished(snet_buffer* snb)
{ {
return (snb->expectedSize == snb->pullingSize); return (snb->expectedSize == snb->pullingSize);
} }
inline uint16 snb_remaining_to_put(snet_buffer* snb) uint16
snb_remaining_to_put(snet_buffer* snb)
{ {
return (snb->expectedSize - snb->puttingSize); return (snb->expectedSize - snb->puttingSize);
} }
inline uint16 snb_remaining_to_pull(snet_buffer* snb) uint16
snb_remaining_to_pull(snet_buffer* snb)
{ {
return (snb->expectedSize - snb->pullingSize); return (snb->expectedSize - snb->pullingSize);
} }
/*
ISSUE1: Number of packets in the worst case(we always need a bigger
buffer than before) increases, never decreases:
/* ISSUE1: Number of packets in the worst case(we always need a bigger SOL1: Delete the smallest when the queue is bigger than X elements
buffer than before) increases, never decreases: SOL2: ?
SOL1: Delete the smallest when the queue is bigger than X elements ISSUE2: If the queue is not gonna be used for long time. Memory c
SOL2: ? ould be freed
ISSUE2: If the queue is not gonna be used for long time. Memory c SOL1: Provide purge func.
ould be freed SOL2: ?
*/
SOL1: Provide purge func.
SOL2: ?
*/
static snet_buffer* static snet_buffer*
snb_attempt_reuse(snet_buffer* snb, uint16 size) snb_attempt_reuse(snet_buffer* snb, uint16 size)
{ {
if ( snb == NULL || (snb->allocatedSize < size) ) { if (snb == NULL || (snb->allocatedSize < size)) {
/* Impossible or not worth, Creating a new one */ // Impossible or not worth, Creating a new one
snb_free(snb); snb_free(snb);
return snb_create(size); return snb_create(size);
@@ -183,15 +188,15 @@ snb_park(struct list* l, snet_buffer* snb)
{ {
snet_buffer* item = NULL; snet_buffer* item = NULL;
/* insert it by order */ // insert it by order
while ((item = list_get_next_item(l, item)) != NULL) { while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) {
/* This one has allocated more than us place us back*/ // This one has allocated more than us place us back
if (item->allocatedSize > snb->allocatedSize) { if (item->allocatedSize > snb->allocatedSize) {
list_insert_item_before(l, item, snb); list_insert_item_before(l, item, snb);
return; return;
} }
} }
/* no buffer bigger than us(or empty).. then at the end*/ // no buffer bigger than us(or empty).. then at the end
list_add_item(l, snb); list_add_item(l, snb);
} }
@@ -203,16 +208,18 @@ snb_fetch(struct list* l, uint16 size)
snet_buffer* newitem = NULL; snet_buffer* newitem = NULL;
if (!list_is_empty(l)) if (!list_is_empty(l))
while ((item = list_get_next_item(l, item)) != NULL) { while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) {
if (item->allocatedSize >= size) { if (item->allocatedSize >= size) {
/* This one is for us*/ // This one is for us
break; break;
} }
} }
newitem = snb_attempt_reuse(item, size); newitem = snb_attempt_reuse(item, size);
/* the resulting reused one is the same as we fetched? => remove it from list*/ /* the resulting reused one is the same
* as we fetched? => remove it from list
*/
if (item == newitem) { if (item == newitem) {
list_remove_item(l, item); list_remove_item(l, item);
} }
@@ -227,7 +234,7 @@ snb_packets(struct list* l)
uint16 count = 0; uint16 count = 0;
snet_buffer* item = NULL; snet_buffer* item = NULL;
while ((item = list_get_next_item(l, item)) != NULL) while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL)
count++; count++;
return count; return count;
@@ -237,5 +244,6 @@ snb_packets(struct list* l)
void void
snb_dump(snet_buffer* snb) snb_dump(snet_buffer* snb)
{ {
kprintf("item=%p\tprev=%p\tnext=%p\tallocated=%d\n", snb, snb->link.prev, snb->link.next, snb->allocatedSize); kprintf("item=%p\tprev=%p\tnext=%p\tallocated=%d\n", snb, snb->link.prev,
snb->link.next, snb->allocatedSize);
} }
@@ -16,7 +16,7 @@
* *
* So snet_buffers are ONLY meant to be used when: * So snet_buffers are ONLY meant to be used when:
* 1) You know exactily the maximun/final size of the frame * 1) You know exactily the maximun/final size of the frame
* before allocating it, and you will never exceed it. * before allocating it, and you will never exceed it.
* 2) You are not supposed to prepend data, only append. * 2) You are not supposed to prepend data, only append.
* *
*/ */
@@ -31,43 +31,43 @@ struct snet_buffer;
typedef struct snet_buffer snet_buffer; typedef struct snet_buffer snet_buffer;
/* Creates a snb_buffer allocating size space for its full content */ /* Creates a snb_buffer allocating size space for its full content */
snet_buffer* snb_create(uint16 size); snet_buffer* snb_create(uint16 size);
/* Free the snb_buffer*/ /* Free the snb_buffer*/
void snb_free(snet_buffer* snb); void snb_free(snet_buffer* snb);
/* Free the snb_buffer*/ /* Free the snb_buffer*/
void* snb_get(snet_buffer* snb); void* snb_get(snet_buffer* snb);
/* Size of the snb_buffer*/ /* Size of the snb_buffer*/
uint16 snb_size(snet_buffer* snb); uint16 snb_size(snet_buffer* snb);
/* Cookie of the snb_buffer*/ /* Cookie of the snb_buffer*/
void* snb_cookie(snet_buffer* snb); void* snb_cookie(snet_buffer* snb);
/* Get Cookie of the snb_buffer*/ /* Get Cookie of the snb_buffer*/
void snb_set_cookie(snet_buffer* snb, void* cookie); void snb_set_cookie(snet_buffer* snb, void* cookie);
/* Place the memory given by data to the "tail" of the snb */ /* Place the memory given by data to the "tail" of the snb */
void snb_put(snet_buffer* snb, void* data, uint16 size); void snb_put(snet_buffer* snb, void* data, uint16 size);
/* Returns a header chunk of size data */ /* Returns a header chunk of size data */
void* snb_pull(snet_buffer* snb, uint16 size); void* snb_pull(snet_buffer* snb, uint16 size);
/* Discards all data put or pulled from the buffer */ /* Discards all data put or pulled from the buffer */
void snb_reset(snet_buffer* snb); void snb_reset(snet_buffer* snb);
/* Return true if we canot "put" more data in the buffer */ /* Return true if we canot "put" more data in the buffer */
bool snb_completed(snet_buffer* snb); bool snb_completed(snet_buffer* snb);
/* Return true if we cannot pull more more data from the buffer */ /* Return true if we cannot pull more more data from the buffer */
bool snb_finished(snet_buffer* snb); bool snb_finished(snet_buffer* snb);
/* Return the amount of data we can still put in the buffer */ /* Return the amount of data we can still put in the buffer */
uint16 snb_remaining_to_put(snet_buffer* snb); uint16 snb_remaining_to_put(snet_buffer* snb);
/* Return the amount of data we can still pull in the buffer */ /* Return the amount of data we can still pull in the buffer */
uint16 snb_remaining_to_pull(snet_buffer* snb); uint16 snb_remaining_to_pull(snet_buffer* snb);
/* These to functions are provided to avoid memory fragmentation /* These to functions are provided to avoid memory fragmentation
* allocating and freeing many snb_buffers and its possible overhead. * allocating and freeing many snb_buffers and its possible overhead.
* Thypical scenario would be * Thypical scenario would be
* that you create a snb_buffer to send data, once you send you free it, * that you create a snb_buffer to send data, once you send you free it,
* and need another one to hold the response. The idea would be once you send * and need another one to hold the response. The idea would be once you send
* that buffer, to snb_park the buffer, and whenever you need to allocate another * that buffer, to snb_park the buffer, and whenever you need to allocate
* one snb_fetch it. That funcion will reuse most appropiated previous used one * another one snb_fetch it. That funcion will reuse most appropiated
* snb_buff by its memory use. * previous used one snb_buff by its memory use.
*/ */
void snb_park(struct list* l, snet_buffer* snb); void snb_park(struct list* l, snet_buffer* snb);
snet_buffer* snb_fetch(struct list* l, uint16 size); snet_buffer* snb_fetch(struct list* l, uint16 size);
+1 -1
View File
@@ -2,4 +2,4 @@ SubDir HAIKU_TOP src add-ons kernel network devices ;
SubInclude HAIKU_TOP src add-ons kernel network devices ethernet ; SubInclude HAIKU_TOP src add-ons kernel network devices ethernet ;
SubInclude HAIKU_TOP src add-ons kernel network devices loopback ; SubInclude HAIKU_TOP src add-ons kernel network devices loopback ;
SubInclude HAIKU_TOP src add-ons kernel network devices bluetooth ;
@@ -1,27 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel network devices bluetooth ;
SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku {
UseHeaders [ FStandardOSHeaders ] : true ;
# Needed for <support/Errors.h> and maybe other stuff.
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
# We need the public network headers also when not compiling for Haiku.
# Unfortunately we get more than we want, namely all POSIX headers.
}
UsePrivateKernelHeaders ;
UsePrivateHeaders net bluetooth ;
KernelAddon bluetooth :
bluetooth.cpp
acl.cpp
;
# Installation
#HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/devices
# : bluetooth ;
#Package haiku-networkingkit-cvs :
# haiku :
# boot home config add-ons kernel haiku_network protocols ;
@@ -39,11 +39,11 @@
status_t status_t
l2cap_receive(HciConnection* conn, net_buffer* buffer) l2cap_receive(HciConnection* conn, net_buffer* buffer)
{ {
status_t error = B_OK; status_t error = B_OK;
uint16 dcid; uint16 dcid;
uint16 length; uint16 length;
/* Check packet */ // Check packet
if (buffer->size < sizeof(l2cap_hdr_t)) { if (buffer->size < sizeof(l2cap_hdr_t)) {
debugf("invalid L2CAP packet. Packet too small, len=%ld\n", buffer->size); debugf("invalid L2CAP packet. Packet too small, len=%ld\n", buffer->size);
gBufferModule->free(buffer); gBufferModule->free(buffer);
@@ -51,7 +51,7 @@ l2cap_receive(HciConnection* conn, net_buffer* buffer)
} }
/* Get L2CAP header */ // Get L2CAP header
NetBufferHeaderReader<l2cap_hdr_t> bufferHeader(buffer); NetBufferHeaderReader<l2cap_hdr_t> bufferHeader(buffer);
status_t status = bufferHeader.Status(); status_t status = bufferHeader.Status();
if (status < B_OK) { if (status < B_OK) {
@@ -61,28 +61,28 @@ l2cap_receive(HciConnection* conn, net_buffer* buffer)
length = bufferHeader->length = le16toh(bufferHeader->length); length = bufferHeader->length = le16toh(bufferHeader->length);
dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid); dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid);
bufferHeader.Remove(); /* pulling */ bufferHeader.Remove(); // pulling
/* Check payload size */ // Check payload size
if (length != buffer->size ) { if (length != buffer->size ) {
debugf("invalid L2CAP packet. Payload length mismatch, packetlen=%d, nebufferlen=%ld\n", debugf("Payload length mismatch, packetlen=%d, bufferlen=%ld\n",
length, buffer->size); length, buffer->size);
gBufferModule->free(buffer); gBufferModule->free(buffer);
return EMSGSIZE; return EMSGSIZE;
} }
/* Process packet */ // Process packet
switch (dcid) { switch (dcid) {
case L2CAP_SIGNAL_CID: /* L2CAP command */ case L2CAP_SIGNAL_CID: // L2CAP command
error = l2cap_process_signal_cmd(conn, buffer); error = l2cap_process_signal_cmd(conn, buffer);
break; break;
case L2CAP_CLT_CID: /* Connectionless packet case L2CAP_CLT_CID: // Connectionless packet
error = l2cap_cl_receive(buffer);*/ // error = l2cap_cl_receive(buffer);
flowf("CL FRAME!!\n"); flowf("CL FRAME!!\n");
break; break;
default: /* Data packet */ default: // Data packet
error = l2cap_co_receive(conn, buffer, dcid); error = l2cap_co_receive(conn, buffer, dcid);
break; break;
} }
@@ -92,7 +92,7 @@ l2cap_receive(HciConnection* conn, net_buffer* buffer)
} }
struct net_device_module_info* btDevices = NULL; struct bt_hci_module_info* btDevices = NULL;
#if 0 #if 0
#pragma mark - thread conn sched - #pragma mark - thread conn sched -
@@ -105,6 +105,7 @@ void
purge_connection(HciConnection* conn) purge_connection(HciConnection* conn)
{ {
L2capFrame* frame; L2capFrame* frame;
bool containerCanBeDestroyed;
debugf("handle=%d\n", conn->handle); debugf("handle=%d\n", conn->handle);
@@ -118,42 +119,44 @@ purge_connection(HciConnection* conn)
// Here is the place to decide how many l2cap signals we want to have // Here is the place to decide how many l2cap signals we want to have
// per l2cap packet. 1 ATM // per l2cap packet. 1 ATM
if (frame->type == L2CAP_C_FRAME) { if (frame->type == L2CAP_C_FRAME && IS_SIGNAL_REQ(frame->code)) {
btCoreData->TimeoutSignal(frame, bluetooth_l2cap_rtx_timeout); btCoreData->TimeoutSignal(frame, bluetooth_l2cap_rtx_timeout);
btCoreData->QueueSignal(frame); btCoreData->QueueSignal(frame);
} containerCanBeDestroyed = false;
} else
containerCanBeDestroyed = true;
// Add the l2cap header // Add the l2cap header
if (frame->buffer == NULL) if (frame->buffer == NULL)
panic("Malformed frame in ongoing queue"); panic("Malformed frame in ongoing queue");
NetBufferPrepend<l2cap_hdr_t> bufferHeader(frame->buffer); {
status_t status = bufferHeader.Status(); NetBufferPrepend<l2cap_hdr_t> bufferHeader(frame->buffer);
if (status < B_OK) { status_t status = bufferHeader.Status();
debugf("l2cap header could not be prepended!! frame code=%d\n", frame->code); if (status < B_OK) {
return; debugf("header could not be prepended! code=%d\n", frame->code);
return;
}
// fill
bufferHeader->length = htole16(frame->buffer->size - sizeof(l2cap_hdr_t));
switch (frame->type) {
case L2CAP_C_FRAME:
bufferHeader->dcid = L2CAP_SIGNAL_CID;
break;
case L2CAP_G_FRAME:
bufferHeader->dcid = L2CAP_CLT_CID;
break;
default:
bufferHeader->dcid = frame->channel->dcid;
break;
}
} }
// fill
bufferHeader->length = htole16(frame->buffer->size - sizeof(l2cap_hdr_t));
switch (frame->type) {
case L2CAP_C_FRAME:
bufferHeader->dcid = L2CAP_SIGNAL_CID;
break;
case L2CAP_G_FRAME:
bufferHeader->dcid = L2CAP_CLT_CID;
break;
default:
bufferHeader->dcid = frame->channel->dcid;
break;
}
bufferHeader.Sync();
if (btDevices == NULL) if (btDevices == NULL)
if (get_module(NET_BLUETOOTH_DEVICE_NAME, (module_info**)&btDevices) != B_OK) { if (get_module(BT_HCI_MODULE_NAME, (module_info**)&btDevices) != B_OK) {
panic("l2cap: cannot get dev module"); panic("l2cap: cannot get dev module");
} // TODO: someone put it } // TODO: someone put it
@@ -161,7 +164,13 @@ purge_connection(HciConnection* conn)
debugf("dev %p frame %p tolower\n", conn->ndevice, frame->buffer); debugf("dev %p frame %p tolower\n", conn->ndevice, frame->buffer);
frame->buffer->type = conn->handle; frame->buffer->type = conn->handle;
btDevices->send_data(conn->ndevice, frame->buffer); btDevices->PostACL(conn->ndevice->index, frame->buffer);
// Only in the case that we need a response the frame container needs
// to be kept: Request C-Frames
if (containerCanBeDestroyed) {
delete frame;
}
// frame = conn->OutGoingFrames.RemoveHead(); // frame = conn->OutGoingFrames.RemoveHead();
// } // }
@@ -170,7 +179,7 @@ purge_connection(HciConnection* conn)
static status_t static status_t
connection_thread(void *) connection_thread(void*)
{ {
int32 code; int32 code;
ssize_t ssizePort; ssize_t ssizePort;
@@ -187,24 +196,24 @@ connection_thread(void *)
while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) { while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) {
if (ssizePort <= 0) { if (ssizePort <= 0) {
debugf("Error %s\n", strerror(ssizePort)); debugf("Error %s\n", strerror(ssizePort));
snooze(500*1000); snooze(500 * 1000);
continue; continue;
} }
if (ssizePort > (ssize_t) sizeof(conn)) { if (ssizePort > (ssize_t) sizeof(conn)) {
debugf("Message too big %ld\n", ssizePort); debugf("Message too big %ld\n", ssizePort);
snooze(500*1000); snooze(500 * 1000);
continue; continue;
} }
ssizeRead = read_port(fPort, &code, &conn, ssizePort); ssizeRead = read_port(fPort, &code, &conn, ssizePort);
if (ssizeRead != ssizePort) { if (ssizeRead != ssizePort) {
debugf("Missmatch size port=%ld read=%ld\n", ssizePort, ssizeRead); debugf("Missmatch size port=%ld read=%ld\n", ssizePort, ssizeRead);
snooze(500*1000); snooze(500 * 1000);
continue; continue;
} }
purge_connection(conn); purge_connection(conn);
@@ -263,8 +272,6 @@ SchedConnectionPurgeThread(HciConnection* conn)
status_t error = write_port(port, (uint32) conn, &temp, sizeof(conn)); status_t error = write_port(port, (uint32) conn, &temp, sizeof(conn));
//debugf("error post %s port=%ld size=%ld\n", strerror(error), port, sizeof(conn));
if (error != B_OK) if (error != B_OK)
panic("BT Connection sched failed"); panic("BT Connection sched failed");