Auxiliary structure to handle with BT commands and events. To consider later moving to a module. This is part of the USB-BT driver
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22939 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
4ff174438e
commit
8354ae8795
215
src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c
Normal file
215
src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
|
||||||
|
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 != NULL && (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 != NULL && (snb->expectedSize == snb->pullingSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool snb_remaining_to_put(snet_buffer* snb)
|
||||||
|
{
|
||||||
|
return (snb != NULL && (snb->expectedSize - snb->puttingSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool snb_remaining_to_pull(snet_buffer* snb)
|
||||||
|
{
|
||||||
|
return (snb != NULL && (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return snb_attempt_reuse(item, size);
|
||||||
|
}
|
@ -0,0 +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 */
|
||||||
|
bool snb_remaining_to_put(snet_buffer* snb);
|
||||||
|
/* Return the amount of data we can still pull in the buffer */
|
||||||
|
bool 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