Fix EOL
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26229 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
c8bc2d8897
commit
848c65ab3e
@ -1,43 +1,43 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2CFG_H_
|
||||
#define _H2CFG_H_
|
||||
|
||||
|
||||
#define BT_DRIVER_SUPPORTS_CMD 1
|
||||
#define BT_DRIVER_SUPPORTS_EVT 1
|
||||
#define BT_DRIVER_SUPPORTS_ESCO 0
|
||||
#define BT_DRIVER_SUPPORTS_SCO 0
|
||||
#define BT_DRIVER_SUPPORTS_ACL 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)
|
||||
|
||||
#if BT_DRIVER_RXCOVERAGE<1 || BT_DRIVER_TXCOVERAGE<1
|
||||
#error incomplete Bluetooth driver Commands and Events should be implemented
|
||||
#endif
|
||||
|
||||
#define BT_SURVIVE_WITHOUT_HCI
|
||||
#define BT_SURVIVE_WITHOUT_NET_BUFFERS
|
||||
|
||||
////////////////////////////////////
|
||||
|
||||
#ifndef BLUETOOTH_DEVICE_TRANSPORT
|
||||
#error BLUETOOTH_DEVICE_TRANSPORT must be defined to build the publishing path
|
||||
#endif
|
||||
|
||||
#ifndef BLUETOOTH_DEVICE_NAME
|
||||
#error BLUETOOTH_DEVICE_NAME must be defined to build the publishing path
|
||||
#endif
|
||||
|
||||
#define BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_TRANSPORT BLUETOOTH_DEVICE_NAME
|
||||
#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_DEVFS_NAME
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2CFG_H_
|
||||
#define _H2CFG_H_
|
||||
|
||||
|
||||
#define BT_DRIVER_SUPPORTS_CMD 1
|
||||
#define BT_DRIVER_SUPPORTS_EVT 1
|
||||
#define BT_DRIVER_SUPPORTS_ESCO 0
|
||||
#define BT_DRIVER_SUPPORTS_SCO 0
|
||||
#define BT_DRIVER_SUPPORTS_ACL 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)
|
||||
|
||||
#if BT_DRIVER_RXCOVERAGE<1 || BT_DRIVER_TXCOVERAGE<1
|
||||
#error incomplete Bluetooth driver Commands and Events should be implemented
|
||||
#endif
|
||||
|
||||
#define BT_SURVIVE_WITHOUT_HCI
|
||||
#define BT_SURVIVE_WITHOUT_NET_BUFFERS
|
||||
|
||||
////////////////////////////////////
|
||||
|
||||
#ifndef BLUETOOTH_DEVICE_TRANSPORT
|
||||
#error BLUETOOTH_DEVICE_TRANSPORT must be defined to build the publishing path
|
||||
#endif
|
||||
|
||||
#ifndef BLUETOOTH_DEVICE_NAME
|
||||
#error BLUETOOTH_DEVICE_NAME must be defined to build the publishing path
|
||||
#endif
|
||||
|
||||
#define BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_TRANSPORT BLUETOOTH_DEVICE_NAME
|
||||
#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_DEVFS_NAME
|
||||
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,458 +1,458 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h2generic.h"
|
||||
#include "h2transactions.h"
|
||||
#include "h2upper.h"
|
||||
#include "h2util.h"
|
||||
|
||||
#include <bluetooth/HCI/btHCI.h>
|
||||
#include <bluetooth/HCI/btHCI_event.h>
|
||||
#include <bluetooth/HCI/btHCI_acl.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define BT_DEBUG_THIS_MODULE
|
||||
#include <btDebug.h>
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
void acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
void acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
void command_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
void event_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
#else
|
||||
void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
void acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
void command_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
void event_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
#endif
|
||||
|
||||
|
||||
static status_t
|
||||
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;
|
||||
|
||||
bdev->stat.bytesRX += count;
|
||||
|
||||
if (type == BT_EVENT)
|
||||
snbuf = bdev->eventRx;
|
||||
else
|
||||
nbuf = bdev->nbufferRx[type];
|
||||
|
||||
while (count) {
|
||||
|
||||
debugf("count %d %p %p\n",count, nbuf, nb);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
} 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 */
|
||||
bdev->nbufferRx[type] = nbuf = nb->create(expectedPacketLen);
|
||||
nbuf->protocol = type;
|
||||
|
||||
|
||||
} else {
|
||||
flowf("ACL frame corrupted\n");
|
||||
return -EILSEQ;
|
||||
}
|
||||
break;
|
||||
|
||||
case BT_SCO:
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("unkown packet type in assembly");
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
if (nb == NULL) {
|
||||
port_id port;
|
||||
/* Coded for test purpose only we should panic here */
|
||||
debugf("net_buffers are not ready post manually %d/%d\n",count,expectedPacketLen);
|
||||
port = find_port(BT_USERLAND_PORT_NAME);
|
||||
if (port != B_NAME_NOT_FOUND) {
|
||||
(void)write_port(port, PACK_HEADER_PORT(bdev->num,type), data, count);
|
||||
return B_OK;
|
||||
}
|
||||
panic("Algorithm just ready to arrive here");
|
||||
return B_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
currentPacketLen = expectedPacketLen;
|
||||
|
||||
}
|
||||
else {
|
||||
/* Continuation */
|
||||
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)) {
|
||||
|
||||
flowf("Frame goes up!\n");
|
||||
post_packet_up(bdev, type, snbuf);
|
||||
snbuf = bdev->eventRx = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) {
|
||||
|
||||
flowf("Frame goes up!\n");
|
||||
post_packet_up(bdev, type, nbuf);
|
||||
bdev->nbufferRx[type] = nbuf = NULL;
|
||||
}
|
||||
|
||||
/* in case in the pipe there is info about the next buffer ... */
|
||||
count -= currentPacketLen;
|
||||
data += currentPacketLen;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- RX Complete ---
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
event_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
event_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
{
|
||||
|
||||
bt_usb_dev* bdev = cookie;
|
||||
status_t err;
|
||||
|
||||
/* TODO: or not running anymore */
|
||||
if (status == B_CANCELED)
|
||||
return;
|
||||
|
||||
if (status != B_OK || actual_len == 0)
|
||||
goto resubmit;
|
||||
|
||||
if ( assembly_rx(cookie, BT_EVENT, data, actual_len) == B_OK ) {
|
||||
bdev->stat.successfulTX++;
|
||||
} else {
|
||||
bdev->stat.errorRX++;
|
||||
}
|
||||
|
||||
resubmit:
|
||||
|
||||
err = usb->queue_interrupt(bdev->intr_in_ep->handle,
|
||||
data, bdev->max_packet_size_intr_in ,
|
||||
event_complete, bdev);
|
||||
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->eventRoom, data);
|
||||
bdev->stat.rejectedRX++;
|
||||
debugf("RX event resubmittion failed %s\n",strerror(err));
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
{
|
||||
bt_usb_dev* bdev = cookie;
|
||||
status_t err;
|
||||
|
||||
/* TODO: or not running anymore? */
|
||||
if (status == B_CANCELED)
|
||||
return;
|
||||
|
||||
if (status != B_OK || actual_len == 0)
|
||||
goto resubmit;
|
||||
|
||||
if ( assembly_rx(cookie, BT_ACL, data, actual_len) == B_OK ) {
|
||||
bdev->stat.successfulRX++;
|
||||
} else {
|
||||
bdev->stat.errorRX++;
|
||||
}
|
||||
|
||||
resubmit:
|
||||
|
||||
err = usb->queue_bulk(bdev->bulk_in_ep->handle, data,
|
||||
max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in),
|
||||
acl_rx_complete, (void*) bdev);
|
||||
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->aclRoom, data);
|
||||
bdev->stat.rejectedRX++;
|
||||
debugf("RX acl resubmittion failed %s\n", strerror(err));
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- RX ---
|
||||
#endif
|
||||
|
||||
|
||||
status_t
|
||||
submit_rx_event(bt_usb_dev* bdev)
|
||||
{
|
||||
status_t err;
|
||||
size_t size = bdev->max_packet_size_intr_in;
|
||||
void* buf = alloc_room(&bdev->eventRoom, size);
|
||||
|
||||
if (buf == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
err = usb->queue_interrupt(bdev->intr_in_ep->handle,
|
||||
buf, size ,
|
||||
event_complete, (void*) bdev);
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->eventRoom, buf);
|
||||
bdev->stat.rejectedRX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
debugf("Accepted RX Event %d\n", bdev->stat.acceptedRX);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
submit_rx_acl(bt_usb_dev* bdev)
|
||||
{
|
||||
|
||||
status_t err;
|
||||
size_t size = max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in);
|
||||
void* buf = alloc_room(&bdev->aclRoom, size);
|
||||
|
||||
if (buf == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
err = usb->queue_bulk(bdev->bulk_in_ep->handle, buf, size ,
|
||||
acl_rx_complete, bdev);
|
||||
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->aclRoom, buf);
|
||||
bdev->stat.rejectedRX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
submit_rx_sco(bt_usb_dev* bdev)
|
||||
{
|
||||
|
||||
/* not yet implemented */
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- TX Complete ---
|
||||
#endif
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
command_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
command_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
{
|
||||
snet_buffer* snbuf = (snet_buffer*) cookie;
|
||||
bt_usb_dev* bdev = snb_cookie(snbuf);
|
||||
|
||||
debugf("%ld %02x:%02x:%02x:\n", actual_len, ((uint8*)data)[0],((uint8*)data)[1],((uint8*)data)[2]);
|
||||
|
||||
if (status != B_OK) {
|
||||
|
||||
bdev->stat.successfulTX++;
|
||||
bdev->stat.bytesTX += actual_len;
|
||||
}
|
||||
else {
|
||||
bdev->stat.errorTX++;
|
||||
/* the packet has been lost */
|
||||
/* too late to requeue it? */
|
||||
}
|
||||
|
||||
snb_park(&bdev->snetBufferRecycleTrash, snbuf);
|
||||
|
||||
#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
|
||||
// TODO: check just the empty queues?
|
||||
schedTxProcessing(bdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
|
||||
{
|
||||
|
||||
net_buffer* nbuf = (net_buffer*) cookie;
|
||||
bt_usb_dev* bdev = GET_DEVICE(nbuf);
|
||||
|
||||
if (status != B_OK) {
|
||||
|
||||
bdev->stat.successfulTX++;
|
||||
bdev->stat.bytesTX += actual_len;
|
||||
}
|
||||
else {
|
||||
bdev->stat.errorTX++;
|
||||
/* the packet has been lost */
|
||||
/* too late to requeue it? */
|
||||
}
|
||||
|
||||
nb_destroy(nbuf);
|
||||
#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
|
||||
schedTxProcessing(bdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- TX ---
|
||||
#endif
|
||||
|
||||
status_t
|
||||
submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
uint8 bRequestType = bdev->ctrl_req;
|
||||
uint8 bRequest = 0;
|
||||
uint16 wIndex = 0;
|
||||
uint16 value = 0;
|
||||
uint16 wLength = B_HOST_TO_LENDIAN_INT16(snb_size(snbuf));
|
||||
|
||||
if (!GET_BIT(bdev->state, RUNNING) ) {
|
||||
return B_DEV_NOT_READY;
|
||||
}
|
||||
|
||||
/* set cookie */
|
||||
snb_set_cookie(snbuf, bdev);
|
||||
|
||||
err = usb->queue_request(bdev->dev, bRequestType, bRequest,
|
||||
value, wIndex, wLength,
|
||||
snb_get(snbuf), wLength //???
|
||||
,command_complete, (void*) snbuf);
|
||||
|
||||
if (err != B_OK ) {
|
||||
bdev->stat.rejectedTX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedTX++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t
|
||||
submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
/* set cookie */
|
||||
SET_DEVICE(nbuf,bdev->hdev);
|
||||
|
||||
if (!GET_BIT(bdev->state, RUNNING) ) {
|
||||
return B_DEV_NOT_READY;
|
||||
}
|
||||
|
||||
|
||||
err = usb->queue_bulk(bdev->bulk_out_ep->handle,
|
||||
nb_get_whole_buffer(nbuf), nbuf->size,
|
||||
acl_tx_complete, (void*) nbuf);
|
||||
|
||||
if (err != B_OK ) {
|
||||
bdev->stat.rejectedTX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedTX++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
submit_tx_sco(bt_usb_dev* bdev)
|
||||
{
|
||||
|
||||
if (!GET_BIT(bdev->state, RUNNING) ) {
|
||||
return B_DEV_NOT_READY;
|
||||
}
|
||||
|
||||
/* not yet implemented */
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "h2generic.h"
|
||||
#include "h2transactions.h"
|
||||
#include "h2upper.h"
|
||||
#include "h2util.h"
|
||||
|
||||
#include <bluetooth/HCI/btHCI.h>
|
||||
#include <bluetooth/HCI/btHCI_event.h>
|
||||
#include <bluetooth/HCI/btHCI_acl.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define BT_DEBUG_THIS_MODULE
|
||||
#include <btDebug.h>
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
void acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
void acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
void command_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
void event_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
|
||||
#else
|
||||
void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
void acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
void command_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
void event_complete(void* cookie, status_t status, void* data, size_t actual_len);
|
||||
#endif
|
||||
|
||||
|
||||
static status_t
|
||||
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;
|
||||
|
||||
bdev->stat.bytesRX += count;
|
||||
|
||||
if (type == BT_EVENT)
|
||||
snbuf = bdev->eventRx;
|
||||
else
|
||||
nbuf = bdev->nbufferRx[type];
|
||||
|
||||
while (count) {
|
||||
|
||||
debugf("count %d %p %p\n",count, nbuf, nb);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
} 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 */
|
||||
bdev->nbufferRx[type] = nbuf = nb->create(expectedPacketLen);
|
||||
nbuf->protocol = type;
|
||||
|
||||
|
||||
} else {
|
||||
flowf("ACL frame corrupted\n");
|
||||
return -EILSEQ;
|
||||
}
|
||||
break;
|
||||
|
||||
case BT_SCO:
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("unkown packet type in assembly");
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
if (nb == NULL) {
|
||||
port_id port;
|
||||
/* Coded for test purpose only we should panic here */
|
||||
debugf("net_buffers are not ready post manually %d/%d\n",count,expectedPacketLen);
|
||||
port = find_port(BT_USERLAND_PORT_NAME);
|
||||
if (port != B_NAME_NOT_FOUND) {
|
||||
(void)write_port(port, PACK_HEADER_PORT(bdev->num,type), data, count);
|
||||
return B_OK;
|
||||
}
|
||||
panic("Algorithm just ready to arrive here");
|
||||
return B_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
currentPacketLen = expectedPacketLen;
|
||||
|
||||
}
|
||||
else {
|
||||
/* Continuation */
|
||||
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)) {
|
||||
|
||||
flowf("Frame goes up!\n");
|
||||
post_packet_up(bdev, type, snbuf);
|
||||
snbuf = bdev->eventRx = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) {
|
||||
|
||||
flowf("Frame goes up!\n");
|
||||
post_packet_up(bdev, type, nbuf);
|
||||
bdev->nbufferRx[type] = nbuf = NULL;
|
||||
}
|
||||
|
||||
/* in case in the pipe there is info about the next buffer ... */
|
||||
count -= currentPacketLen;
|
||||
data += currentPacketLen;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- RX Complete ---
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
event_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
event_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
{
|
||||
|
||||
bt_usb_dev* bdev = cookie;
|
||||
status_t err;
|
||||
|
||||
/* TODO: or not running anymore */
|
||||
if (status == B_CANCELED)
|
||||
return;
|
||||
|
||||
if (status != B_OK || actual_len == 0)
|
||||
goto resubmit;
|
||||
|
||||
if ( assembly_rx(cookie, BT_EVENT, data, actual_len) == B_OK ) {
|
||||
bdev->stat.successfulTX++;
|
||||
} else {
|
||||
bdev->stat.errorRX++;
|
||||
}
|
||||
|
||||
resubmit:
|
||||
|
||||
err = usb->queue_interrupt(bdev->intr_in_ep->handle,
|
||||
data, bdev->max_packet_size_intr_in ,
|
||||
event_complete, bdev);
|
||||
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->eventRoom, data);
|
||||
bdev->stat.rejectedRX++;
|
||||
debugf("RX event resubmittion failed %s\n",strerror(err));
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
{
|
||||
bt_usb_dev* bdev = cookie;
|
||||
status_t err;
|
||||
|
||||
/* TODO: or not running anymore? */
|
||||
if (status == B_CANCELED)
|
||||
return;
|
||||
|
||||
if (status != B_OK || actual_len == 0)
|
||||
goto resubmit;
|
||||
|
||||
if ( assembly_rx(cookie, BT_ACL, data, actual_len) == B_OK ) {
|
||||
bdev->stat.successfulRX++;
|
||||
} else {
|
||||
bdev->stat.errorRX++;
|
||||
}
|
||||
|
||||
resubmit:
|
||||
|
||||
err = usb->queue_bulk(bdev->bulk_in_ep->handle, data,
|
||||
max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in),
|
||||
acl_rx_complete, (void*) bdev);
|
||||
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->aclRoom, data);
|
||||
bdev->stat.rejectedRX++;
|
||||
debugf("RX acl resubmittion failed %s\n", strerror(err));
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- RX ---
|
||||
#endif
|
||||
|
||||
|
||||
status_t
|
||||
submit_rx_event(bt_usb_dev* bdev)
|
||||
{
|
||||
status_t err;
|
||||
size_t size = bdev->max_packet_size_intr_in;
|
||||
void* buf = alloc_room(&bdev->eventRoom, size);
|
||||
|
||||
if (buf == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
err = usb->queue_interrupt(bdev->intr_in_ep->handle,
|
||||
buf, size ,
|
||||
event_complete, (void*) bdev);
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->eventRoom, buf);
|
||||
bdev->stat.rejectedRX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
debugf("Accepted RX Event %d\n", bdev->stat.acceptedRX);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
submit_rx_acl(bt_usb_dev* bdev)
|
||||
{
|
||||
|
||||
status_t err;
|
||||
size_t size = max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in);
|
||||
void* buf = alloc_room(&bdev->aclRoom, size);
|
||||
|
||||
if (buf == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
err = usb->queue_bulk(bdev->bulk_in_ep->handle, buf, size ,
|
||||
acl_rx_complete, bdev);
|
||||
|
||||
if (err != B_OK ) {
|
||||
reuse_room(&bdev->aclRoom, buf);
|
||||
bdev->stat.rejectedRX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedRX++;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
submit_rx_sco(bt_usb_dev* bdev)
|
||||
{
|
||||
|
||||
/* not yet implemented */
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- TX Complete ---
|
||||
#endif
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
command_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
command_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
{
|
||||
snet_buffer* snbuf = (snet_buffer*) cookie;
|
||||
bt_usb_dev* bdev = snb_cookie(snbuf);
|
||||
|
||||
debugf("%ld %02x:%02x:%02x:\n", actual_len, ((uint8*)data)[0],((uint8*)data)[1],((uint8*)data)[2]);
|
||||
|
||||
if (status != B_OK) {
|
||||
|
||||
bdev->stat.successfulTX++;
|
||||
bdev->stat.bytesTX += actual_len;
|
||||
}
|
||||
else {
|
||||
bdev->stat.errorTX++;
|
||||
/* the packet has been lost */
|
||||
/* too late to requeue it? */
|
||||
}
|
||||
|
||||
snb_park(&bdev->snetBufferRecycleTrash, snbuf);
|
||||
|
||||
#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
|
||||
// TODO: check just the empty queues?
|
||||
schedTxProcessing(bdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
|
||||
#else
|
||||
acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len)
|
||||
#endif
|
||||
|
||||
{
|
||||
|
||||
net_buffer* nbuf = (net_buffer*) cookie;
|
||||
bt_usb_dev* bdev = GET_DEVICE(nbuf);
|
||||
|
||||
if (status != B_OK) {
|
||||
|
||||
bdev->stat.successfulTX++;
|
||||
bdev->stat.bytesTX += actual_len;
|
||||
}
|
||||
else {
|
||||
bdev->stat.errorTX++;
|
||||
/* the packet has been lost */
|
||||
/* too late to requeue it? */
|
||||
}
|
||||
|
||||
nb_destroy(nbuf);
|
||||
#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS
|
||||
schedTxProcessing(bdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#pragma mark --- TX ---
|
||||
#endif
|
||||
|
||||
status_t
|
||||
submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
uint8 bRequestType = bdev->ctrl_req;
|
||||
uint8 bRequest = 0;
|
||||
uint16 wIndex = 0;
|
||||
uint16 value = 0;
|
||||
uint16 wLength = B_HOST_TO_LENDIAN_INT16(snb_size(snbuf));
|
||||
|
||||
if (!GET_BIT(bdev->state, RUNNING) ) {
|
||||
return B_DEV_NOT_READY;
|
||||
}
|
||||
|
||||
/* set cookie */
|
||||
snb_set_cookie(snbuf, bdev);
|
||||
|
||||
err = usb->queue_request(bdev->dev, bRequestType, bRequest,
|
||||
value, wIndex, wLength,
|
||||
snb_get(snbuf), wLength //???
|
||||
,command_complete, (void*) snbuf);
|
||||
|
||||
if (err != B_OK ) {
|
||||
bdev->stat.rejectedTX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedTX++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t
|
||||
submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
/* set cookie */
|
||||
SET_DEVICE(nbuf,bdev->hdev);
|
||||
|
||||
if (!GET_BIT(bdev->state, RUNNING) ) {
|
||||
return B_DEV_NOT_READY;
|
||||
}
|
||||
|
||||
|
||||
err = usb->queue_bulk(bdev->bulk_out_ep->handle,
|
||||
nb_get_whole_buffer(nbuf), nbuf->size,
|
||||
acl_tx_complete, (void*) nbuf);
|
||||
|
||||
if (err != B_OK ) {
|
||||
bdev->stat.rejectedTX++;
|
||||
}
|
||||
else {
|
||||
bdev->stat.acceptedTX++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
submit_tx_sco(bt_usb_dev* bdev)
|
||||
{
|
||||
|
||||
if (!GET_BIT(bdev->state, RUNNING) ) {
|
||||
return B_DEV_NOT_READY;
|
||||
}
|
||||
|
||||
/* not yet implemented */
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2TRANSACTION_H_
|
||||
#define _H2TRANSACTION_H_
|
||||
|
||||
#include "h2generic.h"
|
||||
|
||||
status_t submit_rx_event(bt_usb_dev* bdev);
|
||||
status_t submit_rx_acl(bt_usb_dev* bdev);
|
||||
status_t submit_rx_sco(bt_usb_dev* bdev);
|
||||
|
||||
status_t submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf);
|
||||
status_t submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf);
|
||||
status_t submit_tx_sco(bt_usb_dev* bdev);
|
||||
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2TRANSACTION_H_
|
||||
#define _H2TRANSACTION_H_
|
||||
|
||||
#include "h2generic.h"
|
||||
|
||||
status_t submit_rx_event(bt_usb_dev* bdev);
|
||||
status_t submit_rx_acl(bt_usb_dev* bdev);
|
||||
status_t submit_rx_sco(bt_usb_dev* bdev);
|
||||
|
||||
status_t submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf);
|
||||
status_t submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf);
|
||||
status_t submit_tx_sco(bt_usb_dev* bdev);
|
||||
|
||||
#endif
|
@ -1,203 +1,203 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_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 "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;
|
||||
flowf("sched\n")
|
||||
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_OK;
|
||||
port_id port;
|
||||
|
||||
if (hci == NULL) {
|
||||
|
||||
err = B_ERROR;
|
||||
|
||||
// ERROR but we will try to send if its a event!
|
||||
if (type == BT_EVENT) {
|
||||
|
||||
snet_buffer* snbuf = (snet_buffer*) buf;
|
||||
|
||||
flowf("HCI not present, Posting to userland\n");
|
||||
port = find_port(BT_USERLAND_PORT_NAME);
|
||||
if (port != B_NAME_NOT_FOUND) {
|
||||
|
||||
|
||||
err = write_port_etc(port, PACK_PORTCODE(type,bdev->hdev, -1),
|
||||
snb_get(snbuf), snb_size(snbuf), B_TIMEOUT, 1*1000*1000);
|
||||
if (err != B_OK)
|
||||
debugf("Error posting userland %s\n", strerror(err));
|
||||
|
||||
}
|
||||
else {
|
||||
flowf("ERROR:bluetooth_server not found for posting\n");
|
||||
err = B_NAME_NOT_FOUND;
|
||||
}
|
||||
/* No need to free the buffer at allocation is gonna be reused */
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: Upper layer comunication
|
||||
/* Not freeing because is being used by upper layers*/
|
||||
}
|
||||
|
||||
|
||||
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("Unkown 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;
|
||||
}
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_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 "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;
|
||||
flowf("sched\n")
|
||||
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_OK;
|
||||
port_id port;
|
||||
|
||||
if (hci == NULL) {
|
||||
|
||||
err = B_ERROR;
|
||||
|
||||
// ERROR but we will try to send if its a event!
|
||||
if (type == BT_EVENT) {
|
||||
|
||||
snet_buffer* snbuf = (snet_buffer*) buf;
|
||||
|
||||
flowf("HCI not present, Posting to userland\n");
|
||||
port = find_port(BT_USERLAND_PORT_NAME);
|
||||
if (port != B_NAME_NOT_FOUND) {
|
||||
|
||||
|
||||
err = write_port_etc(port, PACK_PORTCODE(type,bdev->hdev, -1),
|
||||
snb_get(snbuf), snb_size(snbuf), B_TIMEOUT, 1*1000*1000);
|
||||
if (err != B_OK)
|
||||
debugf("Error posting userland %s\n", strerror(err));
|
||||
|
||||
}
|
||||
else {
|
||||
flowf("ERROR:bluetooth_server not found for posting\n");
|
||||
err = B_NAME_NOT_FOUND;
|
||||
}
|
||||
/* No need to free the buffer at allocation is gonna be reused */
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: Upper layer comunication
|
||||
/* Not freeing because is being used by upper layers*/
|
||||
}
|
||||
|
||||
|
||||
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("Unkown 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;
|
||||
}
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2UPPER_H_
|
||||
#define _H2UPPER_H_
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
#include "h2generic.h"
|
||||
|
||||
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_command(hci_id hid, snet_buffer* snbuf);
|
||||
|
||||
void sched_tx_processing(bt_usb_dev* bdev);
|
||||
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2UPPER_H_
|
||||
#define _H2UPPER_H_
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
#include "h2generic.h"
|
||||
|
||||
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_command(hci_id hid, snet_buffer* snbuf);
|
||||
|
||||
void sched_tx_processing(bt_usb_dev* bdev);
|
||||
|
||||
#endif
|
@ -1,150 +1,150 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#include "h2upper.h"
|
||||
#include "h2util.h"
|
||||
#include "h2transactions.h"
|
||||
|
||||
#include <bluetooth/HCI/btHCI_acl.h>
|
||||
#include <bluetooth/HCI/btHCI_command.h>
|
||||
#include <bluetooth/HCI/btHCI_event.h>
|
||||
|
||||
#define BT_DEBUG_THIS_MODULE
|
||||
#include <btDebug.h>
|
||||
|
||||
|
||||
void*
|
||||
nb_get_whole_buffer(net_buffer* nbuf)
|
||||
{
|
||||
void* conPointer;
|
||||
status_t err;
|
||||
|
||||
/* the job could be already done */
|
||||
// !!! it could be trash from other upper protocols...
|
||||
if (nbuf->COOKIEFIELD != NULL)
|
||||
return (void*)nbuf->COOKIEFIELD;
|
||||
|
||||
if (nb == NULL)
|
||||
goto fail;
|
||||
|
||||
err = nb->direct_access(nbuf, 0, nbuf->size, &conPointer);
|
||||
|
||||
if (err != B_OK) {
|
||||
|
||||
/* pity, we are gonna need a realocation */
|
||||
nbuf->COOKIEFIELD = (uint32) malloc(nbuf->size);
|
||||
if (nbuf->COOKIEFIELD == NULL)
|
||||
goto fail;
|
||||
|
||||
err = nb->write(nbuf, 0, (void*) nbuf->COOKIEFIELD, nbuf->size);
|
||||
if (err != B_OK)
|
||||
goto free;
|
||||
|
||||
conPointer = (void*)nbuf->COOKIEFIELD;
|
||||
|
||||
}
|
||||
|
||||
return conPointer;
|
||||
|
||||
free:
|
||||
free((void*) nbuf->COOKIEFIELD);
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nb_destroy(net_buffer* nbuf)
|
||||
{
|
||||
|
||||
/* Free possible allocated */
|
||||
if (nbuf->COOKIEFIELD != NULL)
|
||||
free((void*)nbuf->COOKIEFIELD);
|
||||
|
||||
// TODO check for survivers...
|
||||
if (nb != NULL)
|
||||
nb->free(nbuf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Check from the completition if the queue is empty */
|
||||
size_t
|
||||
get_expected_size(net_buffer* nbuf)
|
||||
{
|
||||
|
||||
if (nbuf == NULL)
|
||||
panic("Analizing NULL packet");
|
||||
|
||||
switch (nbuf->protocol) {
|
||||
|
||||
case BT_ACL: {
|
||||
struct hci_acl_header* header = nb_get_whole_buffer(nbuf);
|
||||
return header->alen;
|
||||
}
|
||||
|
||||
case BT_COMMAND: {
|
||||
struct hci_command_header* header = nb_get_whole_buffer(nbuf);
|
||||
return header->clen;
|
||||
}
|
||||
|
||||
|
||||
case BT_EVENT: {
|
||||
struct hci_event_header* header = nb_get_whole_buffer(nbuf);
|
||||
return header->elen;
|
||||
}
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#pragma mark - room util -
|
||||
#endif
|
||||
|
||||
inline void
|
||||
init_room(struct list* l)
|
||||
{
|
||||
list_init(l);
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
alloc_room(struct list* l, size_t size)
|
||||
{
|
||||
|
||||
void* item = list_get_first_item(l);
|
||||
|
||||
if (item == NULL)
|
||||
item = (void*) malloc(size);
|
||||
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
reuse_room(struct list* l, void* room)
|
||||
{
|
||||
list_add_item(l, room);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
purge_room(struct list* l)
|
||||
{
|
||||
void* item;
|
||||
|
||||
while ((item = list_remove_head_item(l)) != NULL) {
|
||||
free(item);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#include "h2upper.h"
|
||||
#include "h2util.h"
|
||||
#include "h2transactions.h"
|
||||
|
||||
#include <bluetooth/HCI/btHCI_acl.h>
|
||||
#include <bluetooth/HCI/btHCI_command.h>
|
||||
#include <bluetooth/HCI/btHCI_event.h>
|
||||
|
||||
#define BT_DEBUG_THIS_MODULE
|
||||
#include <btDebug.h>
|
||||
|
||||
|
||||
void*
|
||||
nb_get_whole_buffer(net_buffer* nbuf)
|
||||
{
|
||||
void* conPointer;
|
||||
status_t err;
|
||||
|
||||
/* the job could be already done */
|
||||
// !!! it could be trash from other upper protocols...
|
||||
if (nbuf->COOKIEFIELD != NULL)
|
||||
return (void*)nbuf->COOKIEFIELD;
|
||||
|
||||
if (nb == NULL)
|
||||
goto fail;
|
||||
|
||||
err = nb->direct_access(nbuf, 0, nbuf->size, &conPointer);
|
||||
|
||||
if (err != B_OK) {
|
||||
|
||||
/* pity, we are gonna need a realocation */
|
||||
nbuf->COOKIEFIELD = (uint32) malloc(nbuf->size);
|
||||
if (nbuf->COOKIEFIELD == NULL)
|
||||
goto fail;
|
||||
|
||||
err = nb->write(nbuf, 0, (void*) nbuf->COOKIEFIELD, nbuf->size);
|
||||
if (err != B_OK)
|
||||
goto free;
|
||||
|
||||
conPointer = (void*)nbuf->COOKIEFIELD;
|
||||
|
||||
}
|
||||
|
||||
return conPointer;
|
||||
|
||||
free:
|
||||
free((void*) nbuf->COOKIEFIELD);
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nb_destroy(net_buffer* nbuf)
|
||||
{
|
||||
|
||||
/* Free possible allocated */
|
||||
if (nbuf->COOKIEFIELD != NULL)
|
||||
free((void*)nbuf->COOKIEFIELD);
|
||||
|
||||
// TODO check for survivers...
|
||||
if (nb != NULL)
|
||||
nb->free(nbuf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Check from the completition if the queue is empty */
|
||||
size_t
|
||||
get_expected_size(net_buffer* nbuf)
|
||||
{
|
||||
|
||||
if (nbuf == NULL)
|
||||
panic("Analizing NULL packet");
|
||||
|
||||
switch (nbuf->protocol) {
|
||||
|
||||
case BT_ACL: {
|
||||
struct hci_acl_header* header = nb_get_whole_buffer(nbuf);
|
||||
return header->alen;
|
||||
}
|
||||
|
||||
case BT_COMMAND: {
|
||||
struct hci_command_header* header = nb_get_whole_buffer(nbuf);
|
||||
return header->clen;
|
||||
}
|
||||
|
||||
|
||||
case BT_EVENT: {
|
||||
struct hci_event_header* header = nb_get_whole_buffer(nbuf);
|
||||
return header->elen;
|
||||
}
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#pragma mark - room util -
|
||||
#endif
|
||||
|
||||
inline void
|
||||
init_room(struct list* l)
|
||||
{
|
||||
list_init(l);
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
alloc_room(struct list* l, size_t size)
|
||||
{
|
||||
|
||||
void* item = list_get_first_item(l);
|
||||
|
||||
if (item == NULL)
|
||||
item = (void*) malloc(size);
|
||||
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
reuse_room(struct list* l, void* room)
|
||||
{
|
||||
list_add_item(l, room);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
purge_room(struct list* l)
|
||||
{
|
||||
void* item;
|
||||
|
||||
while ((item = list_remove_head_item(l)) != NULL) {
|
||||
free(item);
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,34 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2UTIL_H_
|
||||
#define _H2UTIL_H_
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
#include "h2generic.h"
|
||||
|
||||
/* net buffer utils for ACL, to be reviewed */
|
||||
#define DEVICEFIELD type
|
||||
#define SET_DEVICE(nbuf,hid) (nbuf->DEVICEFIELD=(nbuf->DEVICEFIELD&0xFFF0)|(hid&0xF))
|
||||
#define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0x0F))
|
||||
|
||||
#define COOKIEFIELD flags
|
||||
void* nb_get_whole_buffer(net_buffer* nbuf);
|
||||
void nb_destroy(net_buffer* nbuf);
|
||||
size_t get_expected_size(net_buffer* nbuf);
|
||||
|
||||
/* Room utils */
|
||||
inline void init_room(struct list* l);
|
||||
void* alloc_room(struct list* l, size_t size);
|
||||
inline void reuse_room(struct list* l, void* room);
|
||||
void purge_room(struct list* l);
|
||||
|
||||
/* list utils */
|
||||
#define list_purge(x) purge_room(x)
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _H2UTIL_H_
|
||||
#define _H2UTIL_H_
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
#include "h2generic.h"
|
||||
|
||||
/* net buffer utils for ACL, to be reviewed */
|
||||
#define DEVICEFIELD type
|
||||
#define SET_DEVICE(nbuf,hid) (nbuf->DEVICEFIELD=(nbuf->DEVICEFIELD&0xFFF0)|(hid&0xF))
|
||||
#define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0x0F))
|
||||
|
||||
#define COOKIEFIELD flags
|
||||
void* nb_get_whole_buffer(net_buffer* nbuf);
|
||||
void nb_destroy(net_buffer* nbuf);
|
||||
size_t get_expected_size(net_buffer* nbuf);
|
||||
|
||||
/* Room utils */
|
||||
inline void init_room(struct list* l);
|
||||
void* alloc_room(struct list* l, size_t size);
|
||||
inline void reuse_room(struct list* l, void* room);
|
||||
void purge_room(struct list* l);
|
||||
|
||||
/* list utils */
|
||||
#define list_purge(x) purge_room(x)
|
||||
|
||||
#endif
|
||||
|
@ -1,225 +1,225 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "snet_buffer.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
struct snet_buffer {
|
||||
struct list_link link;
|
||||
|
||||
uint8* buffer;
|
||||
|
||||
uint16 allocatedSize;
|
||||
uint16 expectedSize;
|
||||
uint16 puttingSize;
|
||||
uint16 pullingSize;
|
||||
|
||||
void* cookie;
|
||||
|
||||
};
|
||||
|
||||
|
||||
snet_buffer*
|
||||
snb_create(uint16 size)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
|
||||
#ifdef SNB_BUFFER_ATTACHED
|
||||
/* Allocating these 2 buffers together might prevent memory fragmentation? */
|
||||
snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size);
|
||||
snb->buffer = ((uint8*)snb) + sizeof(snet_buffer);
|
||||
#else
|
||||
snet_buffer* snb = malloc(sizeof (snet_buffer));
|
||||
snb->buffer = malloc(size);
|
||||
#endif
|
||||
|
||||
snb->pullingSize = snb->puttingSize = 0;
|
||||
snb->expectedSize = snb->allocatedSize = size;
|
||||
|
||||
return snb;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
snb_put(snet_buffer* snb, void* data, uint16 size)
|
||||
{
|
||||
/* TODO: check overflow */
|
||||
memcpy( &snb->buffer[snb->puttingSize], data, size);
|
||||
snb->puttingSize+=size;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
snb_pull(snet_buffer* snb, uint16 size)
|
||||
{
|
||||
/* TODO: check overflow */
|
||||
snb->pullingSize+=size;
|
||||
return &snb->buffer[snb->pullingSize-size];
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
snb_reset(snet_buffer* snb)
|
||||
{
|
||||
snb->puttingSize = snb->pullingSize = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
snb_free(snet_buffer* snb)
|
||||
{
|
||||
if (snb == NULL)
|
||||
return;
|
||||
|
||||
#ifdef SNB_BUFFER_ATTACHED
|
||||
free(snb);
|
||||
#else
|
||||
free(snb->buffer);
|
||||
free(snb);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void*
|
||||
snb_get(snet_buffer* snb)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
return snb->buffer;
|
||||
}
|
||||
|
||||
|
||||
inline uint16
|
||||
snb_size(snet_buffer* snb)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
return snb->expectedSize;
|
||||
}
|
||||
|
||||
|
||||
inline void*
|
||||
snb_cookie(snet_buffer* snb)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
return snb->cookie;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
snb_set_cookie(snet_buffer* snb, void* cookie)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
snb->cookie = cookie;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if we canot "put" more data in the buffer */
|
||||
inline bool snb_completed(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize == snb->puttingSize);
|
||||
}
|
||||
|
||||
|
||||
/* Return true if we cannot pull more more data from the buffer */
|
||||
inline bool snb_finished(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize == snb->pullingSize);
|
||||
}
|
||||
|
||||
|
||||
inline uint16 snb_remaining_to_put(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize - snb->puttingSize);
|
||||
}
|
||||
|
||||
|
||||
inline uint16 snb_remaining_to_pull(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize - snb->pullingSize);
|
||||
}
|
||||
|
||||
|
||||
/* ISSUE1: Number of packets in the worst case(we always need a bigger
|
||||
buffer than before) increases, never decreases:
|
||||
|
||||
SOL1: Delete the smallest when the queue is bigger than X elements
|
||||
SOL2: ?
|
||||
|
||||
ISSUE2: If the queue is not gonna be used for long time. Memory c
|
||||
ould be freed
|
||||
|
||||
SOL1: Provide purge func.
|
||||
SOL2: ?
|
||||
|
||||
*/
|
||||
static snet_buffer*
|
||||
snb_attempt_reuse(snet_buffer* snb, uint16 size)
|
||||
{
|
||||
if ( snb == NULL ||
|
||||
((int16)snb->allocatedSize - (int16)size) < 0 ) {
|
||||
|
||||
/* Impossible or not worth, Creating a new one */
|
||||
snb_free(snb);
|
||||
return snb_create(size);
|
||||
|
||||
}
|
||||
else {
|
||||
snb_reset(snb);
|
||||
snb->expectedSize = size;
|
||||
return snb;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
snb_park(struct list* l, snet_buffer* snb)
|
||||
{
|
||||
snet_buffer* item = NULL;
|
||||
/* insert it by order */
|
||||
while ((item = list_get_next_item(l, item)) != NULL) {
|
||||
if (item->allocatedSize > snb->allocatedSize)
|
||||
list_insert_item_before(l, item, snb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
snet_buffer*
|
||||
snb_fetch(struct list* l, uint16 size)
|
||||
{
|
||||
|
||||
snet_buffer* item = NULL;
|
||||
snet_buffer* previous = NULL;
|
||||
|
||||
if (!list_is_empty(l))
|
||||
while ((item = list_get_next_item(l, item)) != NULL) {
|
||||
if (item->allocatedSize == size) {
|
||||
/* This one is for us*/
|
||||
break;
|
||||
}
|
||||
else if (item->allocatedSize > size) {
|
||||
/* get the previous*/
|
||||
item = previous;
|
||||
break;
|
||||
}
|
||||
previous = item;
|
||||
}
|
||||
|
||||
// reusing previous pointer for another proposit
|
||||
previous = snb_attempt_reuse(item, size);
|
||||
|
||||
/* the resulting reused one is the same as we fetched? => remove it from list*/
|
||||
if (item == previous) {
|
||||
list_remove_item(l, item);
|
||||
}
|
||||
|
||||
return previous;
|
||||
}
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "snet_buffer.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
struct snet_buffer {
|
||||
struct list_link link;
|
||||
|
||||
uint8* buffer;
|
||||
|
||||
uint16 allocatedSize;
|
||||
uint16 expectedSize;
|
||||
uint16 puttingSize;
|
||||
uint16 pullingSize;
|
||||
|
||||
void* cookie;
|
||||
|
||||
};
|
||||
|
||||
|
||||
snet_buffer*
|
||||
snb_create(uint16 size)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
|
||||
#ifdef SNB_BUFFER_ATTACHED
|
||||
/* Allocating these 2 buffers together might prevent memory fragmentation? */
|
||||
snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size);
|
||||
snb->buffer = ((uint8*)snb) + sizeof(snet_buffer);
|
||||
#else
|
||||
snet_buffer* snb = malloc(sizeof (snet_buffer));
|
||||
snb->buffer = malloc(size);
|
||||
#endif
|
||||
|
||||
snb->pullingSize = snb->puttingSize = 0;
|
||||
snb->expectedSize = snb->allocatedSize = size;
|
||||
|
||||
return snb;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
snb_put(snet_buffer* snb, void* data, uint16 size)
|
||||
{
|
||||
/* TODO: check overflow */
|
||||
memcpy( &snb->buffer[snb->puttingSize], data, size);
|
||||
snb->puttingSize+=size;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
snb_pull(snet_buffer* snb, uint16 size)
|
||||
{
|
||||
/* TODO: check overflow */
|
||||
snb->pullingSize+=size;
|
||||
return &snb->buffer[snb->pullingSize-size];
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
snb_reset(snet_buffer* snb)
|
||||
{
|
||||
snb->puttingSize = snb->pullingSize = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
snb_free(snet_buffer* snb)
|
||||
{
|
||||
if (snb == NULL)
|
||||
return;
|
||||
|
||||
#ifdef SNB_BUFFER_ATTACHED
|
||||
free(snb);
|
||||
#else
|
||||
free(snb->buffer);
|
||||
free(snb);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void*
|
||||
snb_get(snet_buffer* snb)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
return snb->buffer;
|
||||
}
|
||||
|
||||
|
||||
inline uint16
|
||||
snb_size(snet_buffer* snb)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
return snb->expectedSize;
|
||||
}
|
||||
|
||||
|
||||
inline void*
|
||||
snb_cookie(snet_buffer* snb)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
return snb->cookie;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
snb_set_cookie(snet_buffer* snb, void* cookie)
|
||||
{
|
||||
/* TODO: pointer checking */
|
||||
snb->cookie = cookie;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if we canot "put" more data in the buffer */
|
||||
inline bool snb_completed(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize == snb->puttingSize);
|
||||
}
|
||||
|
||||
|
||||
/* Return true if we cannot pull more more data from the buffer */
|
||||
inline bool snb_finished(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize == snb->pullingSize);
|
||||
}
|
||||
|
||||
|
||||
inline uint16 snb_remaining_to_put(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize - snb->puttingSize);
|
||||
}
|
||||
|
||||
|
||||
inline uint16 snb_remaining_to_pull(snet_buffer* snb)
|
||||
{
|
||||
return (snb->expectedSize - snb->pullingSize);
|
||||
}
|
||||
|
||||
|
||||
/* ISSUE1: Number of packets in the worst case(we always need a bigger
|
||||
buffer than before) increases, never decreases:
|
||||
|
||||
SOL1: Delete the smallest when the queue is bigger than X elements
|
||||
SOL2: ?
|
||||
|
||||
ISSUE2: If the queue is not gonna be used for long time. Memory c
|
||||
ould be freed
|
||||
|
||||
SOL1: Provide purge func.
|
||||
SOL2: ?
|
||||
|
||||
*/
|
||||
static snet_buffer*
|
||||
snb_attempt_reuse(snet_buffer* snb, uint16 size)
|
||||
{
|
||||
if ( snb == NULL ||
|
||||
((int16)snb->allocatedSize - (int16)size) < 0 ) {
|
||||
|
||||
/* Impossible or not worth, Creating a new one */
|
||||
snb_free(snb);
|
||||
return snb_create(size);
|
||||
|
||||
}
|
||||
else {
|
||||
snb_reset(snb);
|
||||
snb->expectedSize = size;
|
||||
return snb;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
snb_park(struct list* l, snet_buffer* snb)
|
||||
{
|
||||
snet_buffer* item = NULL;
|
||||
/* insert it by order */
|
||||
while ((item = list_get_next_item(l, item)) != NULL) {
|
||||
if (item->allocatedSize > snb->allocatedSize)
|
||||
list_insert_item_before(l, item, snb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
snet_buffer*
|
||||
snb_fetch(struct list* l, uint16 size)
|
||||
{
|
||||
|
||||
snet_buffer* item = NULL;
|
||||
snet_buffer* previous = NULL;
|
||||
|
||||
if (!list_is_empty(l))
|
||||
while ((item = list_get_next_item(l, item)) != NULL) {
|
||||
if (item->allocatedSize == size) {
|
||||
/* This one is for us*/
|
||||
break;
|
||||
}
|
||||
else if (item->allocatedSize > size) {
|
||||
/* get the previous*/
|
||||
item = previous;
|
||||
break;
|
||||
}
|
||||
previous = item;
|
||||
}
|
||||
|
||||
// reusing previous pointer for another proposit
|
||||
previous = snb_attempt_reuse(item, size);
|
||||
|
||||
/* the resulting reused one is the same as we fetched? => remove it from list*/
|
||||
if (item == previous) {
|
||||
list_remove_item(l, item);
|
||||
}
|
||||
|
||||
return previous;
|
||||
}
|
||||
|
@ -1,81 +1,81 @@
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SNET_BUFFER_H_
|
||||
#define _SNET_BUFFER_H_
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
/*
|
||||
* This is a simple data structure to hold network buffers.
|
||||
* It drops many functionality that the Haiku net_buffer provides.
|
||||
*
|
||||
* - Inspired by linux sk_buff/bsd mbuf (put/pull)
|
||||
* - Contiguoussafe (no push operation)
|
||||
*
|
||||
* So snet_buffers are ONLY meant to be used when:
|
||||
* 1) You know exactily the maximun/final size of the frame
|
||||
* before allocating it, and you will never exceed it.
|
||||
* 2) You are not supposed to prepend data, only append.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Configuration parameters */
|
||||
#define SNB_BUFFER_ATTACHED
|
||||
//#define SNB_PERFORMS_OVERFLOW_CHECKS
|
||||
//#define SNB_PERFORMS_POINTER_CHECKS
|
||||
|
||||
struct snet_buffer;
|
||||
|
||||
typedef struct snet_buffer snet_buffer;
|
||||
|
||||
/* Creates a snb_buffer allocating size space for its full content */
|
||||
snet_buffer* snb_create(uint16 size);
|
||||
/* Free the snb_buffer*/
|
||||
void snb_free(snet_buffer* snb);
|
||||
/* Free the snb_buffer*/
|
||||
void* snb_get(snet_buffer* snb);
|
||||
/* Size of the snb_buffer*/
|
||||
uint16 snb_size(snet_buffer* snb);
|
||||
|
||||
/* Cookie of the snb_buffer*/
|
||||
void* snb_cookie(snet_buffer* snb);
|
||||
/* Get Cookie of the snb_buffer*/
|
||||
void snb_set_cookie(snet_buffer* snb, void* cookie);
|
||||
|
||||
/* Place the memory given by data to the "tail" of the snb */
|
||||
void snb_put(snet_buffer* snb, void* data, uint16 size);
|
||||
/* Returns a header chunk of size data */
|
||||
void* snb_pull(snet_buffer* snb, uint16 size);
|
||||
/* Discards all data put or pulled from the buffer */
|
||||
void snb_reset(snet_buffer* snb);
|
||||
|
||||
/* Return true if we canot "put" more data in the buffer */
|
||||
bool snb_completed(snet_buffer* snb);
|
||||
/* Return true if we cannot pull more more data from the buffer */
|
||||
bool snb_finished(snet_buffer* snb);
|
||||
/* Return the amount of data we can still put in the buffer */
|
||||
uint16 snb_remaining_to_put(snet_buffer* snb);
|
||||
/* Return the amount of data we can still pull in the buffer */
|
||||
uint16 snb_remaining_to_pull(snet_buffer* snb);
|
||||
|
||||
/* These to functions are provided to avoid memory fragmentation
|
||||
* allocating and freeing many snb_buffers and its possible overhead.
|
||||
* Thypical scenario would be
|
||||
* 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
|
||||
* that buffer, to snb_park the buffer, and whenever you need to allocate another
|
||||
* one snb_fetch it. That funcion will reuse most appropiated previous used one
|
||||
* snb_buff by its memory use.
|
||||
*/
|
||||
void snb_park(struct list* l, snet_buffer* snb);
|
||||
snet_buffer* snb_fetch(struct list* l, uint16 size);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SNET_BUFFER_H_
|
||||
#define _SNET_BUFFER_H_
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
/*
|
||||
* This is a simple data structure to hold network buffers.
|
||||
* It drops many functionality that the Haiku net_buffer provides.
|
||||
*
|
||||
* - Inspired by linux sk_buff/bsd mbuf (put/pull)
|
||||
* - Contiguoussafe (no push operation)
|
||||
*
|
||||
* So snet_buffers are ONLY meant to be used when:
|
||||
* 1) You know exactily the maximun/final size of the frame
|
||||
* before allocating it, and you will never exceed it.
|
||||
* 2) You are not supposed to prepend data, only append.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Configuration parameters */
|
||||
#define SNB_BUFFER_ATTACHED
|
||||
//#define SNB_PERFORMS_OVERFLOW_CHECKS
|
||||
//#define SNB_PERFORMS_POINTER_CHECKS
|
||||
|
||||
struct snet_buffer;
|
||||
|
||||
typedef struct snet_buffer snet_buffer;
|
||||
|
||||
/* Creates a snb_buffer allocating size space for its full content */
|
||||
snet_buffer* snb_create(uint16 size);
|
||||
/* Free the snb_buffer*/
|
||||
void snb_free(snet_buffer* snb);
|
||||
/* Free the snb_buffer*/
|
||||
void* snb_get(snet_buffer* snb);
|
||||
/* Size of the snb_buffer*/
|
||||
uint16 snb_size(snet_buffer* snb);
|
||||
|
||||
/* Cookie of the snb_buffer*/
|
||||
void* snb_cookie(snet_buffer* snb);
|
||||
/* Get Cookie of the snb_buffer*/
|
||||
void snb_set_cookie(snet_buffer* snb, void* cookie);
|
||||
|
||||
/* Place the memory given by data to the "tail" of the snb */
|
||||
void snb_put(snet_buffer* snb, void* data, uint16 size);
|
||||
/* Returns a header chunk of size data */
|
||||
void* snb_pull(snet_buffer* snb, uint16 size);
|
||||
/* Discards all data put or pulled from the buffer */
|
||||
void snb_reset(snet_buffer* snb);
|
||||
|
||||
/* Return true if we canot "put" more data in the buffer */
|
||||
bool snb_completed(snet_buffer* snb);
|
||||
/* Return true if we cannot pull more more data from the buffer */
|
||||
bool snb_finished(snet_buffer* snb);
|
||||
/* Return the amount of data we can still put in the buffer */
|
||||
uint16 snb_remaining_to_put(snet_buffer* snb);
|
||||
/* Return the amount of data we can still pull in the buffer */
|
||||
uint16 snb_remaining_to_pull(snet_buffer* snb);
|
||||
|
||||
/* These to functions are provided to avoid memory fragmentation
|
||||
* allocating and freeing many snb_buffers and its possible overhead.
|
||||
* Thypical scenario would be
|
||||
* 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
|
||||
* that buffer, to snb_park the buffer, and whenever you need to allocate another
|
||||
* one snb_fetch it. That funcion will reuse most appropiated previous used one
|
||||
* snb_buff by its memory use.
|
||||
*/
|
||||
void snb_park(struct list* l, snet_buffer* snb);
|
||||
snet_buffer* snb_fetch(struct list* l, uint16 size);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user