git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26229 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Ruiz Dorantes
2008-07-02 20:59:57 +00:00
parent c8bc2d8897
commit 848c65ab3e
10 changed files with 2063 additions and 2063 deletions
@@ -1,43 +1,43 @@
/* /*
* 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_
#define BT_DRIVER_SUPPORTS_CMD 1 #define BT_DRIVER_SUPPORTS_CMD 1
#define BT_DRIVER_SUPPORTS_EVT 1 #define BT_DRIVER_SUPPORTS_EVT 1
#define BT_DRIVER_SUPPORTS_ESCO 0 #define BT_DRIVER_SUPPORTS_ESCO 0
#define BT_DRIVER_SUPPORTS_SCO 0 #define BT_DRIVER_SUPPORTS_SCO 0
#define BT_DRIVER_SUPPORTS_ACL 0 #define BT_DRIVER_SUPPORTS_ACL 0
/* TODO: move exclusive header for drivers*/ /* 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_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) #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 #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
#ifndef BLUETOOTH_DEVICE_NAME #ifndef BLUETOOTH_DEVICE_NAME
#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 BLUETOOTH_DEVICE_NAME
#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_DEVFS_NAME #define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_DEVFS_NAME
#endif #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 * 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.
* *
*/ */
#include "h2generic.h" #include "h2generic.h"
#include "h2transactions.h" #include "h2transactions.h"
#include "h2upper.h" #include "h2upper.h"
#include "h2util.h" #include "h2util.h"
#include <bluetooth/HCI/btHCI.h> #include <bluetooth/HCI/btHCI.h>
#include <bluetooth/HCI/btHCI_event.h> #include <bluetooth/HCI/btHCI_event.h>
#include <bluetooth/HCI/btHCI_acl.h> #include <bluetooth/HCI/btHCI_acl.h>
#include <ByteOrder.h> #include <ByteOrder.h>
#include <string.h> #include <string.h>
#define BT_DEBUG_THIS_MODULE #define BT_DEBUG_THIS_MODULE
#include <btDebug.h> #include <btDebug.h>
/* Forward declaration */ /* Forward declaration */
#ifndef HAIKU_TARGET_PLATFORM_HAIKU #ifndef HAIKU_TARGET_PLATFORM_HAIKU
void acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len); 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 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 command_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
void event_complete(void* cookie, uint32 status, void* data, uint32 actual_len); void event_complete(void* cookie, uint32 status, void* data, uint32 actual_len);
#else #else
void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len); 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 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 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); void event_complete(void* cookie, status_t status, void* data, size_t actual_len);
#endif #endif
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; net_buffer* nbuf = NULL;
snet_buffer* snbuf = NULL; snet_buffer* snbuf = NULL;
size_t currentPacketLen = 0; size_t currentPacketLen = 0;
size_t expectedPacketLen = 0; size_t expectedPacketLen = 0;
bdev->stat.bytesRX += count; bdev->stat.bytesRX += count;
if (type == BT_EVENT) if (type == BT_EVENT)
snbuf = bdev->eventRx; snbuf = bdev->eventRx;
else else
nbuf = bdev->nbufferRx[type]; nbuf = bdev->nbufferRx[type];
while (count) { while (count) {
debugf("count %d %p %p\n",count, nbuf, nb); debugf("count %d %p %p\n",count, nbuf, nb);
if ( (type != BT_EVENT && nbuf == NULL) || if ( (type != BT_EVENT && nbuf == NULL) ||
(type == BT_EVENT && (snbuf == NULL || snb_completed(snbuf))) ) { (type == BT_EVENT && (snbuf == NULL || snb_completed(snbuf))) ) {
/* new buffer incoming */ /* new buffer incoming */
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 = data; struct hci_event_header* headerPkt = data;
expectedPacketLen = HCI_EVENT_HDR_SIZE + headerPkt->elen; expectedPacketLen = HCI_EVENT_HDR_SIZE + headerPkt->elen;
snbuf = bdev->eventRx = snb_fetch(&bdev->snetBufferRecycleTrash, expectedPacketLen); snbuf = bdev->eventRx = snb_fetch(&bdev->snetBufferRecycleTrash, expectedPacketLen);
} else { } else {
flowf("EVENT frame corrupted\n"); flowf("EVENT frame corrupted\n");
return -EILSEQ; return -EILSEQ;
} }
break; break;
case BT_ACL: case BT_ACL:
if (count >= HCI_ACL_HDR_SIZE) { if (count >= HCI_ACL_HDR_SIZE) {
struct hci_acl_header* headerPkt = data; struct hci_acl_header* headerPkt = data;
expectedPacketLen = HCI_ACL_HDR_SIZE + B_LENDIAN_TO_HOST_INT16(headerPkt->alen); expectedPacketLen = HCI_ACL_HDR_SIZE + B_LENDIAN_TO_HOST_INT16(headerPkt->alen);
/* Create the buffer */ /* Create the buffer */
bdev->nbufferRx[type] = nbuf = nb->create(expectedPacketLen); bdev->nbufferRx[type] = nbuf = nb->create(expectedPacketLen);
nbuf->protocol = type; nbuf->protocol = type;
} else { } else {
flowf("ACL frame corrupted\n"); flowf("ACL frame corrupted\n");
return -EILSEQ; return -EILSEQ;
} }
break; break;
case BT_SCO: case BT_SCO:
break; break;
default: default:
panic("unkown packet type in assembly"); panic("unkown packet type in assembly");
break; break;
} }
#if 0 #if 0
if (nb == NULL) { if (nb == NULL) {
port_id port; port_id port;
/* Coded for test purpose only we should panic here */ /* Coded for test purpose only we should panic here */
debugf("net_buffers are not ready post manually %d/%d\n",count,expectedPacketLen); debugf("net_buffers are not ready post manually %d/%d\n",count,expectedPacketLen);
port = find_port(BT_USERLAND_PORT_NAME); port = find_port(BT_USERLAND_PORT_NAME);
if (port != B_NAME_NOT_FOUND) { if (port != B_NAME_NOT_FOUND) {
(void)write_port(port, PACK_HEADER_PORT(bdev->num,type), data, count); (void)write_port(port, PACK_HEADER_PORT(bdev->num,type), data, count);
return B_OK; return B_OK;
} }
panic("Algorithm just ready to arrive here"); panic("Algorithm just ready to arrive here");
return B_ERROR; return B_ERROR;
} }
#endif #endif
currentPacketLen = expectedPacketLen; currentPacketLen = expectedPacketLen;
} }
else { else {
/* Continuation */ /* Continuation */
if (type != BT_EVENT) if (type != BT_EVENT)
currentPacketLen = get_expected_size(nbuf) - nbuf->size; currentPacketLen = get_expected_size(nbuf) - nbuf->size;
else else
currentPacketLen = snb_remaining_to_put(snbuf); currentPacketLen = snb_remaining_to_put(snbuf);
} }
currentPacketLen = min(currentPacketLen, count); currentPacketLen = min(currentPacketLen, count);
if (type == BT_EVENT) if (type == BT_EVENT)
snb_put(snbuf, data, currentPacketLen); snb_put(snbuf, data, currentPacketLen);
else else
nb->append(nbuf, data, currentPacketLen); nb->append(nbuf, data, currentPacketLen);
/* Complete frame? */ /* Complete frame? */
if (type == BT_EVENT && snb_completed(snbuf)) { if (type == BT_EVENT && snb_completed(snbuf)) {
flowf("Frame goes up!\n"); flowf("Frame goes up!\n");
post_packet_up(bdev, type, snbuf); post_packet_up(bdev, type, snbuf);
snbuf = bdev->eventRx = NULL; snbuf = bdev->eventRx = NULL;
} }
if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) { if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) {
flowf("Frame goes up!\n"); flowf("Frame goes up!\n");
post_packet_up(bdev, type, nbuf); post_packet_up(bdev, type, nbuf);
bdev->nbufferRx[type] = nbuf = NULL; bdev->nbufferRx[type] = nbuf = NULL;
} }
/* in case in the pipe there is info about the next buffer ... */ /* in case in the pipe there is info about the next buffer ... */
count -= currentPacketLen; count -= currentPacketLen;
data += currentPacketLen; data += currentPacketLen;
} }
return B_OK; return B_OK;
} }
#if 0 #if 0
#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)
#else #else
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 = cookie;
status_t err; status_t err;
/* TODO: or not running anymore */ /* TODO: or not running anymore */
if (status == B_CANCELED) if (status == B_CANCELED)
return; return;
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(cookie, BT_EVENT, data, actual_len) == B_OK ) {
bdev->stat.successfulTX++; bdev->stat.successfulTX++;
} else { } else {
bdev->stat.errorRX++; bdev->stat.errorRX++;
} }
resubmit: resubmit:
err = usb->queue_interrupt(bdev->intr_in_ep->handle, err = usb->queue_interrupt(bdev->intr_in_ep->handle,
data, bdev->max_packet_size_intr_in , data, bdev->max_packet_size_intr_in ,
event_complete, bdev); event_complete, bdev);
if (err != B_OK ) { if (err != B_OK ) {
reuse_room(&bdev->eventRoom, data); reuse_room(&bdev->eventRoom, data);
bdev->stat.rejectedRX++; bdev->stat.rejectedRX++;
debugf("RX event resubmittion failed %s\n",strerror(err)); debugf("RX event resubmittion failed %s\n",strerror(err));
} }
else { else {
bdev->stat.acceptedRX++; bdev->stat.acceptedRX++;
} }
} }
void void
#ifndef HAIKU_TARGET_PLATFORM_HAIKU #ifndef HAIKU_TARGET_PLATFORM_HAIKU
acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
#else #else
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 = cookie;
status_t err; status_t err;
/* TODO: or not running anymore? */ /* TODO: or not running anymore? */
if (status == B_CANCELED) if (status == B_CANCELED)
return; return;
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(cookie, BT_ACL, data, actual_len) == B_OK ) {
bdev->stat.successfulRX++; bdev->stat.successfulRX++;
} else { } else {
bdev->stat.errorRX++; bdev->stat.errorRX++;
} }
resubmit: resubmit:
err = usb->queue_bulk(bdev->bulk_in_ep->handle, data, err = usb->queue_bulk(bdev->bulk_in_ep->handle, data,
max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in), max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in),
acl_rx_complete, (void*) bdev); acl_rx_complete, (void*) bdev);
if (err != B_OK ) { if (err != 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(err)); debugf("RX acl resubmittion failed %s\n", strerror(err));
} }
else { else {
bdev->stat.acceptedRX++; bdev->stat.acceptedRX++;
} }
} }
#if 0 #if 0
#pragma mark --- RX --- #pragma mark --- RX ---
#endif #endif
status_t status_t
submit_rx_event(bt_usb_dev* bdev) submit_rx_event(bt_usb_dev* bdev)
{ {
status_t err; status_t err;
size_t size = bdev->max_packet_size_intr_in; size_t size = bdev->max_packet_size_intr_in;
void* buf = alloc_room(&bdev->eventRoom, size); void* buf = alloc_room(&bdev->eventRoom, size);
if (buf == NULL) if (buf == NULL)
return ENOMEM; return ENOMEM;
err = usb->queue_interrupt(bdev->intr_in_ep->handle, err = usb->queue_interrupt(bdev->intr_in_ep->handle,
buf, size , buf, size ,
event_complete, (void*) bdev); event_complete, (void*) bdev);
if (err != B_OK ) { if (err != B_OK ) {
reuse_room(&bdev->eventRoom, buf); reuse_room(&bdev->eventRoom, buf);
bdev->stat.rejectedRX++; bdev->stat.rejectedRX++;
} }
else { else {
bdev->stat.acceptedRX++; bdev->stat.acceptedRX++;
debugf("Accepted RX Event %d\n", bdev->stat.acceptedRX); debugf("Accepted RX Event %d\n", bdev->stat.acceptedRX);
} }
return err; return err;
} }
status_t status_t
submit_rx_acl(bt_usb_dev* bdev) submit_rx_acl(bt_usb_dev* bdev)
{ {
status_t err; status_t err;
size_t size = max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in); size_t size = max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in);
void* buf = alloc_room(&bdev->aclRoom, size); void* buf = alloc_room(&bdev->aclRoom, size);
if (buf == NULL) if (buf == NULL)
return ENOMEM; return ENOMEM;
err = usb->queue_bulk(bdev->bulk_in_ep->handle, buf, size , err = usb->queue_bulk(bdev->bulk_in_ep->handle, buf, size ,
acl_rx_complete, bdev); acl_rx_complete, bdev);
if (err != B_OK ) { if (err != B_OK ) {
reuse_room(&bdev->aclRoom, buf); reuse_room(&bdev->aclRoom, buf);
bdev->stat.rejectedRX++; bdev->stat.rejectedRX++;
} }
else { else {
bdev->stat.acceptedRX++; bdev->stat.acceptedRX++;
} }
return B_ERROR; return B_ERROR;
} }
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
void void
#ifndef HAIKU_TARGET_PLATFORM_HAIKU #ifndef HAIKU_TARGET_PLATFORM_HAIKU
command_complete(void* cookie, uint32 status, void* data, uint32 actual_len) command_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
#else #else
command_complete(void* cookie, status_t status, void* data, size_t actual_len) 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 = snb_cookie(snbuf);
debugf("%ld %02x:%02x:%02x:\n", actual_len, ((uint8*)data)[0],((uint8*)data)[1],((uint8*)data)[2]); debugf("%ld %02x:%02x:%02x:\n", actual_len, ((uint8*)data)[0],((uint8*)data)[1],((uint8*)data)[2]);
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 */ /* the packet has been lost */
/* too late to requeue it? */ /* 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
} }
void void
#ifndef HAIKU_TARGET_PLATFORM_HAIKU #ifndef HAIKU_TARGET_PLATFORM_HAIKU
acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len)
#else #else
acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len) acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len)
#endif #endif
{ {
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);
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 */ /* the packet has been lost */
/* too late to requeue it? */ /* 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
status_t status_t
submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf) submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf)
{ {
status_t err; status_t err;
uint8 bRequestType = bdev->ctrl_req; uint8 bRequestType = bdev->ctrl_req;
uint8 bRequest = 0; uint8 bRequest = 0;
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));
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);
err = usb->queue_request(bdev->dev, bRequestType, bRequest, err = usb->queue_request(bdev->dev, bRequestType, bRequest,
value, wIndex, wLength, value, wIndex, wLength,
snb_get(snbuf), wLength //??? snb_get(snbuf), wLength //???
,command_complete, (void*) snbuf); ,command_complete, (void*) snbuf);
if (err != B_OK ) { if (err != B_OK ) {
bdev->stat.rejectedTX++; bdev->stat.rejectedTX++;
} }
else { else {
bdev->stat.acceptedTX++; bdev->stat.acceptedTX++;
} }
return err; return err;
} }
status_t status_t
submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf) submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf)
{ {
status_t err; status_t err;
/* 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;
} }
err = usb->queue_bulk(bdev->bulk_out_ep->handle, err = usb->queue_bulk(bdev->bulk_out_ep->handle,
nb_get_whole_buffer(nbuf), nbuf->size, nb_get_whole_buffer(nbuf), nbuf->size,
acl_tx_complete, (void*) nbuf); acl_tx_complete, (void*) nbuf);
if (err != B_OK ) { if (err != B_OK ) {
bdev->stat.rejectedTX++; bdev->stat.rejectedTX++;
} }
else { else {
bdev->stat.acceptedTX++; bdev->stat.acceptedTX++;
} }
return err; return err;
} }
status_t status_t
submit_tx_sco(bt_usb_dev* bdev) submit_tx_sco(bt_usb_dev* bdev)
{ {
if (!GET_BIT(bdev->state, RUNNING) ) { if (!GET_BIT(bdev->state, RUNNING) ) {
return B_DEV_NOT_READY; return B_DEV_NOT_READY;
} }
/* not yet implemented */ /* not yet implemented */
return B_ERROR; return B_ERROR;
} }
@@ -1,21 +1,21 @@
/* /*
* 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_
#define _H2TRANSACTION_H_ #define _H2TRANSACTION_H_
#include "h2generic.h" #include "h2generic.h"
status_t submit_rx_event(bt_usb_dev* bdev); status_t submit_rx_event(bt_usb_dev* bdev);
status_t submit_rx_acl(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_rx_sco(bt_usb_dev* bdev);
status_t submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf); 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_acl(bt_usb_dev* bdev, net_buffer* nbuf);
status_t submit_tx_sco(bt_usb_dev* bdev); status_t submit_tx_sco(bt_usb_dev* bdev);
#endif #endif
@@ -1,203 +1,203 @@
/* /*
* 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.
* *
*/ */
#include <string.h> #include <string.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
#include <bluetooth/HCI/btHCI_transport.h> #include <bluetooth/HCI/btHCI_transport.h>
#include "h2upper.h" #include "h2upper.h"
#include "h2transactions.h" #include "h2transactions.h"
#include "snet_buffer.h" #include "snet_buffer.h"
#define BT_DEBUG_THIS_MODULE #define BT_DEBUG_THIS_MODULE
#include <btDebug.h> #include <btDebug.h>
/* TODO: split for commands and comunication(ACL&SCO) */ /* TODO: split for commands and comunication(ACL&SCO) */
void void
sched_tx_processing(bt_usb_dev* bdev) sched_tx_processing(bt_usb_dev* bdev)
{ {
net_buffer* nbuf; net_buffer* nbuf;
snet_buffer* snbuf; snet_buffer* snbuf;
status_t err; status_t err;
flowf("sched\n") flowf("sched\n")
if (!TEST_AND_SET(&bdev->state, PROCESSING)) { if (!TEST_AND_SET(&bdev->state, PROCESSING)) {
/* We are not processing in another thread so... START!! */ /* We are not processing in another thread so... START!! */
do { do {
/* Do while this bit is on... so someone should set it before we stop the iterations*/ /* Do while this bit is on... so someone should set it before we stop the iterations*/
CLEAR_BIT(bdev->state, SENDING); CLEAR_BIT(bdev->state, SENDING);
/* check Commands*/ /* check Commands*/
#ifdef EMPTY_COMMAND_QUEUE #ifdef EMPTY_COMMAND_QUEUE
while (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND]) ) { while (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND]) ) {
#else #else
if (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND]) ) { if (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND]) ) {
#endif #endif
snbuf = list_remove_head_item(&bdev->nbuffersTx[BT_COMMAND]); snbuf = list_remove_head_item(&bdev->nbuffersTx[BT_COMMAND]);
err = submit_tx_command(bdev, snbuf); err = submit_tx_command(bdev, snbuf);
if (err != B_OK) { if (err != B_OK) {
/* re-head it*/ /* re-head it*/
list_insert_item_before(&bdev->nbuffersTx[BT_COMMAND], list_insert_item_before(&bdev->nbuffersTx[BT_COMMAND],
list_get_first_item(&bdev->nbuffersTx[BT_COMMAND]), snbuf); list_get_first_item(&bdev->nbuffersTx[BT_COMMAND]), snbuf);
} }
} }
/* check Acl */ /* check Acl */
#define EMPTY_ACL_QUEUE #define EMPTY_ACL_QUEUE
#ifdef EMPTY_ACL_QUEUE #ifdef EMPTY_ACL_QUEUE
while (!list_is_empty(&bdev->nbuffersTx[BT_ACL]) ) { while (!list_is_empty(&bdev->nbuffersTx[BT_ACL]) ) {
#else #else
if (!list_is_empty(&bdev->nbuffersTx[BT_ACL]) ) { if (!list_is_empty(&bdev->nbuffersTx[BT_ACL]) ) {
#endif #endif
nbuf = list_remove_head_item(&bdev->nbuffersTx[BT_ACL]); nbuf = list_remove_head_item(&bdev->nbuffersTx[BT_ACL]);
err = submit_tx_acl(bdev, nbuf); err = submit_tx_acl(bdev, nbuf);
if (err != B_OK) { if (err != B_OK) {
/* re-head it*/ /* re-head it*/
list_insert_item_before(&bdev->nbuffersTx[BT_ACL], list_insert_item_before(&bdev->nbuffersTx[BT_ACL],
list_get_first_item(&bdev->nbuffersTx[BT_ACL]), nbuf); list_get_first_item(&bdev->nbuffersTx[BT_ACL]), nbuf);
} }
} }
if (!list_is_empty(&bdev->nbuffersTx[BT_SCO]) ) { if (!list_is_empty(&bdev->nbuffersTx[BT_SCO]) ) {
/* TODO to be implemented */ /* TODO to be implemented */
} }
} while (GET_BIT(bdev->state, SENDING)); } while (GET_BIT(bdev->state, SENDING));
CLEAR_BIT(bdev->state, PROCESSING); CLEAR_BIT(bdev->state, PROCESSING);
} else { } else {
/* We are processing so MARK that we need to still go on with that ... */ /* We are processing so MARK that we need to still go on with that ... */
SET_BIT(bdev->state, SENDING); SET_BIT(bdev->state, SENDING);
} }
} }
status_t status_t
post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf) post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf)
{ {
status_t err = B_OK; status_t err = B_OK;
port_id port; port_id port;
if (hci == NULL) { if (hci == NULL) {
err = B_ERROR; err = B_ERROR;
// ERROR but we will try to send if its a event! // ERROR but we will try to send if its a event!
if (type == BT_EVENT) { if (type == BT_EVENT) {
snet_buffer* snbuf = (snet_buffer*) buf; snet_buffer* snbuf = (snet_buffer*) buf;
flowf("HCI not present, Posting to userland\n"); flowf("HCI not present, Posting to userland\n");
port = find_port(BT_USERLAND_PORT_NAME); 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(type,bdev->hdev, -1), err = write_port_etc(port, PACK_PORTCODE(type,bdev->hdev, -1),
snb_get(snbuf), snb_size(snbuf), B_TIMEOUT, 1*1000*1000); snb_get(snbuf), snb_size(snbuf), 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;
} }
/* No need to free the buffer at allocation is gonna be reused */ /* No need to free the buffer at allocation is gonna be reused */
} }
} }
else { else {
// TODO: Upper layer comunication // TODO: Upper layer comunication
/* Not freeing because is being used by upper layers*/ /* Not freeing because is being used by upper layers*/
} }
return err; return err;
} }
status_t status_t
send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf) send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf)
{ {
bt_usb_dev* bdev = fetch_device(NULL, hid); bt_usb_dev* bdev = fetch_device(NULL, hid);
status_t err = B_OK; status_t err = B_OK;
if (bdev == NULL) if (bdev == NULL)
return B_ERROR; return B_ERROR;
// TODO: check if device is actually ready for this // TODO: check if device is actually ready for this
// TODO: Lock Device // TODO: Lock Device
if (nbuf != NULL) { if (nbuf != NULL) {
if (type != nbuf->protocol) // a bit strict maybe? if (type != nbuf->protocol) // a bit strict maybe?
panic("Upper layer has not filled correctly a packet"); panic("Upper layer has not filled correctly a packet");
switch (type) { switch (type) {
case BT_COMMAND: case BT_COMMAND:
case BT_ACL: case BT_ACL:
case BT_SCO: case BT_SCO:
list_add_item(&bdev->nbuffersTx[type],nbuf); list_add_item(&bdev->nbuffersTx[type],nbuf);
bdev->nbuffersPendingTx[type]++; bdev->nbuffersPendingTx[type]++;
break; break;
default: default:
debugf("Unkown packet type for sending %d\n",type); debugf("Unkown packet type for sending %d\n",type);
// TODO: free the net_buffer -> no, allow upper layer // TODO: free the net_buffer -> no, allow upper layer
// handle it with the given error // handle it with the given error
err = B_BAD_VALUE; err = B_BAD_VALUE;
break; break;
} }
} else { } else {
flowf("tx sched provoked"); flowf("tx sched provoked");
} }
// TODO: check if device is actually ready for this // TODO: check if device is actually ready for this
// TODO: unLock device // TODO: unLock device
/* sched in All cases even if nbuf is null (hidden way to provoke re-scheduling)*/ /* sched in All cases even if nbuf is null (hidden way to provoke re-scheduling)*/
sched_tx_processing(bdev); sched_tx_processing(bdev);
return err; return err;
} }
status_t status_t
send_command(hci_id hid, snet_buffer* snbuf) send_command(hci_id hid, snet_buffer* snbuf)
{ {
bt_usb_dev* bdev = fetch_device(NULL, hid); bt_usb_dev* bdev = fetch_device(NULL, hid);
status_t err = B_OK; status_t err = B_OK;
if (bdev == NULL) if (bdev == NULL)
return B_ERROR; return B_ERROR;
// TODO: check if device is actually ready for this // TODO: check if device is actually ready for this
// TODO: mutex? // TODO: mutex?
if (snbuf != NULL) { if (snbuf != NULL) {
list_add_item(&bdev->nbuffersTx[BT_COMMAND],snbuf); list_add_item(&bdev->nbuffersTx[BT_COMMAND],snbuf);
bdev->nbuffersPendingTx[BT_COMMAND]++; bdev->nbuffersPendingTx[BT_COMMAND]++;
} else { } else {
err = B_BAD_VALUE; err = B_BAD_VALUE;
flowf("tx sched provoked"); flowf("tx sched provoked");
} }
// TODO: check if device is actually ready for this // TODO: check if device is actually ready for this
// TODO: mutex? // TODO: mutex?
/* sched in All cases even if nbuf is null (hidden way to provoke re-scheduling)*/ /* sched in All cases even if nbuf is null (hidden way to provoke re-scheduling)*/
sched_tx_processing(bdev); sched_tx_processing(bdev);
return err; return err;
} }
@@ -1,21 +1,21 @@
/* /*
* 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_
#include <util/list.h> #include <util/list.h>
#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
@@ -1,150 +1,150 @@
/* /*
* 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.
* *
*/ */
#include <malloc.h> #include <malloc.h>
#include "h2upper.h" #include "h2upper.h"
#include "h2util.h" #include "h2util.h"
#include "h2transactions.h" #include "h2transactions.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>
#define BT_DEBUG_THIS_MODULE #define BT_DEBUG_THIS_MODULE
#include <btDebug.h> #include <btDebug.h>
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;
/* 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;
if (nb == NULL) if (nb == NULL)
goto fail; goto fail;
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) {
/* pity, we are gonna need a realocation */ /* pity, 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;
err = nb->write(nbuf, 0, (void*) nbuf->COOKIEFIELD, nbuf->size); err = nb->write(nbuf, 0, (void*) nbuf->COOKIEFIELD, nbuf->size);
if (err != B_OK) if (err != B_OK)
goto free; goto free;
conPointer = (void*)nbuf->COOKIEFIELD; conPointer = (void*)nbuf->COOKIEFIELD;
} }
return conPointer; return conPointer;
free: free:
free((void*) nbuf->COOKIEFIELD); free((void*) nbuf->COOKIEFIELD);
fail: fail:
return NULL; return NULL;
} }
void void
nb_destroy(net_buffer* nbuf) nb_destroy(net_buffer* nbuf)
{ {
/* Free possible allocated */ /* Free possible allocated */
if (nbuf->COOKIEFIELD != NULL) if (nbuf->COOKIEFIELD != NULL)
free((void*)nbuf->COOKIEFIELD); free((void*)nbuf->COOKIEFIELD);
// TODO check for survivers... // TODO check for survivers...
if (nb != NULL) if (nb != NULL)
nb->free(nbuf); nb->free(nbuf);
} }
/* Check from the completition if the queue is empty */ /* Check from the completition if the queue is empty */
size_t size_t
get_expected_size(net_buffer* nbuf) get_expected_size(net_buffer* nbuf)
{ {
if (nbuf == NULL) if (nbuf == NULL)
panic("Analizing NULL packet"); panic("Analizing NULL packet");
switch (nbuf->protocol) { switch (nbuf->protocol) {
case BT_ACL: { case BT_ACL: {
struct hci_acl_header* header = nb_get_whole_buffer(nbuf); struct hci_acl_header* header = nb_get_whole_buffer(nbuf);
return header->alen; return header->alen;
} }
case BT_COMMAND: { case BT_COMMAND: {
struct hci_command_header* header = nb_get_whole_buffer(nbuf); struct hci_command_header* header = nb_get_whole_buffer(nbuf);
return header->clen; return header->clen;
} }
case BT_EVENT: { case BT_EVENT: {
struct hci_event_header* header = nb_get_whole_buffer(nbuf); struct hci_event_header* header = nb_get_whole_buffer(nbuf);
return header->elen; return header->elen;
} }
default: default:
break; break;
} }
return B_ERROR; return B_ERROR;
} }
#if 0 #if 0
#pragma mark - room util - #pragma mark - room util -
#endif #endif
inline void inline void
init_room(struct list* l) init_room(struct list* l)
{ {
list_init(l); list_init(l);
} }
void* void*
alloc_room(struct list* l, size_t size) alloc_room(struct list* l, size_t size)
{ {
void* item = list_get_first_item(l); void* item = list_get_first_item(l);
if (item == NULL) if (item == NULL)
item = (void*) malloc(size); item = (void*) malloc(size);
return item; return item;
} }
inline void inline 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);
} }
void void
purge_room(struct list* l) purge_room(struct list* l)
{ {
void* item; void* item;
while ((item = list_remove_head_item(l)) != NULL) { while ((item = list_remove_head_item(l)) != NULL) {
free(item); free(item);
} }
} }
@@ -1,34 +1,34 @@
/* /*
* 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_
#include <util/list.h> #include <util/list.h>
#include "h2generic.h" #include "h2generic.h"
/* 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&0xFFF0)|(hid&0xF)) #define SET_DEVICE(nbuf,hid) (nbuf->DEVICEFIELD=(nbuf->DEVICEFIELD&0xFFF0)|(hid&0xF))
#define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0x0F)) #define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0x0F))
#define COOKIEFIELD flags #define COOKIEFIELD flags
void* nb_get_whole_buffer(net_buffer* nbuf); void* nb_get_whole_buffer(net_buffer* nbuf);
void nb_destroy(net_buffer* nbuf); 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); inline 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); inline 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)
#endif #endif
@@ -1,225 +1,225 @@
/* /*
* 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.
* *
*/ */
#include "snet_buffer.h" #include "snet_buffer.h"
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.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;
}; };
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
snet_buffer* snb = malloc(sizeof (snet_buffer)); snet_buffer* snb = malloc(sizeof (snet_buffer));
snb->buffer = malloc(size); snb->buffer = malloc(size);
#endif #endif
snb->pullingSize = snb->puttingSize = 0; snb->pullingSize = snb->puttingSize = 0;
snb->expectedSize = snb->allocatedSize = size; snb->expectedSize = snb->allocatedSize = size;
return snb; return snb;
} }
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;
} }
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 inline void
snb_reset(snet_buffer* snb) snb_reset(snet_buffer* snb)
{ {
snb->puttingSize = snb->pullingSize = 0; snb->puttingSize = snb->pullingSize = 0;
} }
void void
snb_free(snet_buffer* snb) snb_free(snet_buffer* snb)
{ {
if (snb == NULL) if (snb == NULL)
return; return;
#ifdef SNB_BUFFER_ATTACHED #ifdef SNB_BUFFER_ATTACHED
free(snb); free(snb);
#else #else
free(snb->buffer); free(snb->buffer);
free(snb); free(snb);
#endif #endif
} }
inline void* inline 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 inline 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* inline 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 inline 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) inline 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) inline 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) inline 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) inline 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 /* ISSUE1: Number of packets in the worst case(we always need a bigger
buffer than before) increases, never decreases: buffer than before) increases, never decreases:
SOL1: Delete the smallest when the queue is bigger than X elements SOL1: Delete the smallest when the queue is bigger than X elements
SOL2: ? SOL2: ?
ISSUE2: If the queue is not gonna be used for long time. Memory c ISSUE2: If the queue is not gonna be used for long time. Memory c
ould be freed ould be freed
SOL1: Provide purge func. SOL1: Provide purge func.
SOL2: ? 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 || if ( snb == NULL ||
((int16)snb->allocatedSize - (int16)size) < 0 ) { ((int16)snb->allocatedSize - (int16)size) < 0 ) {
/* 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);
} }
else { else {
snb_reset(snb); snb_reset(snb);
snb->expectedSize = size; snb->expectedSize = size;
return snb; return snb;
} }
} }
void void
snb_park(struct list* l, snet_buffer* snb) 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 = list_get_next_item(l, item)) != NULL) {
if (item->allocatedSize > snb->allocatedSize) if (item->allocatedSize > snb->allocatedSize)
list_insert_item_before(l, item, snb); list_insert_item_before(l, item, snb);
} }
} }
snet_buffer* snet_buffer*
snb_fetch(struct list* l, uint16 size) snb_fetch(struct list* l, uint16 size)
{ {
snet_buffer* item = NULL; snet_buffer* item = NULL;
snet_buffer* previous = NULL; snet_buffer* previous = NULL;
if (!list_is_empty(l)) if (!list_is_empty(l))
while ((item = list_get_next_item(l, item)) != NULL) { while ((item = 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;
} }
else if (item->allocatedSize > size) { else if (item->allocatedSize > size) {
/* get the previous*/ /* get the previous*/
item = previous; item = previous;
break; break;
} }
previous = item; previous = item;
} }
// reusing previous pointer for another proposit // reusing previous pointer for another proposit
previous = snb_attempt_reuse(item, size); previous = 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 == previous) { if (item == previous) {
list_remove_item(l, item); list_remove_item(l, item);
} }
return previous; return previous;
} }
@@ -1,81 +1,81 @@
/* /*
* 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 _SNET_BUFFER_H_ #ifndef _SNET_BUFFER_H_
#define _SNET_BUFFER_H_ #define _SNET_BUFFER_H_
#include <util/list.h> #include <util/list.h>
/* /*
* This is a simple data structure to hold network buffers. * This is a simple data structure to hold network buffers.
* It drops many functionality that the Haiku net_buffer provides. * It drops many functionality that the Haiku net_buffer provides.
* *
* - Inspired by linux sk_buff/bsd mbuf (put/pull) * - Inspired by linux sk_buff/bsd mbuf (put/pull)
* - Contiguoussafe (no push operation) * - Contiguoussafe (no push operation)
* *
* 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.
* *
*/ */
/* Configuration parameters */ /* Configuration parameters */
#define SNB_BUFFER_ATTACHED #define SNB_BUFFER_ATTACHED
//#define SNB_PERFORMS_OVERFLOW_CHECKS //#define SNB_PERFORMS_OVERFLOW_CHECKS
//#define SNB_PERFORMS_POINTER_CHECKS //#define SNB_PERFORMS_POINTER_CHECKS
struct snet_buffer; 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 another
* one snb_fetch it. That funcion will reuse most appropiated previous used one * one snb_fetch it. That funcion will reuse most appropiated previous used one
* snb_buff by its memory use. * 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);
#endif #endif