iBoot/include/cbuffer.h

321 lines
7.1 KiB
C

/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Computer, Inc.
*/
#ifndef _CBUFER_H_
#define _CBUFER_H_
#include <sys/types.h>
#include <sys.h>
#include <lib/libc.h>
__BEGIN_DECLS
#define CB_ALIGNMENT 64
typedef struct _CBUFFER {
uint8_t * head;
uint8_t * tail;
size_t size;
size_t readableSize;
size_t bufferSize;
uint8_t * dataStart;
uint8_t * dataEnd;
} CBUFFER;
#define cb_fix_high( ptr, pcb ) \
if( pcb->ptr >= pcb->dataEnd ) { \
pcb->ptr = pcb->dataStart; \
}
#define cb_cs_encap( theCall, retType ) \
retType ret; \
enter_critical_section(); \
ret = theCall; \
exit_critical_section(); \
return ret
static inline bool cb_initialized( CBUFFER * pcb )
{
return pcb->dataStart?true:false;
}
static inline int cb_create( CBUFFER * pcb, size_t size )
{
// round up
size = (size + CB_ALIGNMENT-1) & ~(CB_ALIGNMENT-1);
pcb->dataStart = (uint8_t *)memalign( size, CB_ALIGNMENT );
pcb->head = pcb->tail = pcb->dataStart;
pcb->dataEnd = pcb->dataStart+size;
pcb->size = 0;
pcb->readableSize = 0;
pcb->bufferSize = size;
return size;
}
static inline void cb_reset( CBUFFER * pcb )
{
enter_critical_section();
pcb->head = pcb->tail = pcb->dataStart;
pcb->size = 0;
pcb->readableSize = 0;
pcb->bufferSize = pcb->dataEnd - pcb->dataStart;
exit_critical_section();
}
static inline uint32_t cb_size( CBUFFER * pcb)
{
return pcb->size;
}
static inline uint32_t cb_readable_size( CBUFFER * pcb )
{
return pcb->readableSize;
}
static inline uint8_t * cb_get_head( CBUFFER * pcb )
{
return pcb->head;
}
static inline uint32_t cb_free_space( CBUFFER * pcb )
{
return pcb->bufferSize - cb_size(pcb);
}
static inline uint32_t cb_block_free_space_unsafe( CBUFFER * pcb )
{
uint32_t freeTotal = cb_free_space(pcb);
uint32_t freeTillEnd = pcb->dataEnd-pcb->head;
return __min( freeTotal, freeTillEnd );
}
static inline uint32_t cb_block_free_space( CBUFFER * pcb )
{
cb_cs_encap( cb_block_free_space_unsafe( pcb ), uint32_t );
}
static inline uint8_t * cb_block_read_ptr_unsafe( CBUFFER * pcb, uint32_t * pamount )
{
uint8_t * ret = pcb->tail;
/*printf( "data 0x%08X, head 0x%08X, tail 0x%08X, data end %08X, size %d\n",
(uint)pcb->dataStart, (uint)pcb->head, (uint)pcb->tail, (uint)pcb->dataEnd, (uint)cb_size( pcb ) ); */
if( pcb->head <= pcb->tail ){
// header is past tail, so there is a wrap around
*pamount = pcb->dataEnd-pcb->tail;
pcb->size -= *pamount;
pcb->readableSize -= *pamount;
pcb->tail = pcb->dataStart;
} else {
// we can consume all of it
pcb->tail = pcb->head;
*pamount = pcb->size;
pcb->size = 0;
pcb->readableSize = 0;
}
/*printf( "- data 0x%08X, head 0x%08X, tail 0x%08X, data end %08X, size %d\n",
(uint)pcb->dataStart, (uint)pcb->head, (uint)pcb->tail, (uint)pcb->dataEnd, (uint)cb_size( pcb ) ); */
return ret;
}
static inline uint8_t * cb_block_read_ptr( CBUFFER * pcb, uint32_t * pamount )
{
cb_cs_encap( cb_block_read_ptr_unsafe( pcb, pamount ), uint8_t * );
}
static inline void cb_pre_skip( CBUFFER * pcb, uint32_t amount )
{
uint32_t bfs;
enter_critical_section();
pcb->size += amount;
bfs = pcb->dataEnd-pcb->head;
if( bfs > amount ){
//printf( "a bfs %d, amount %d\n", bfs, amount );
pcb->head += amount;
} else {
//printf( "b bfs %d, amount %d\n", bfs, amount );
pcb->head = pcb->dataStart + amount-bfs;
}
exit_critical_section();
}
static inline void cb_post_skip( CBUFFER * pcb, uint32_t amount )
{
enter_critical_section();
/*printf( "$ data 0x%08X, head 0x%08X, tail 0x%08X, data end %08X, size %d\n",
(uint)pcb->dataStart, (uint)pcb->head, (uint)pcb->tail, (uint)pcb->dataEnd, (uint)cb_size( pcb ) ); */
// update internal count to reflect the new data now available to read
pcb->readableSize += amount;
/*printf( "* data 0x%08X, head 0x%08X, tail 0x%08X, data end %08X, size %d\n",
(uint)pcb->dataStart, (uint)pcb->head, (uint)pcb->tail, (uint)pcb->dataEnd, (uint)cb_size( pcb ) ); */
exit_critical_section();
}
static inline int cb_putc_unsafe( CBUFFER * pcb, uint8_t c )
{
if( cb_free_space( pcb ) ){
*pcb->head++ = c;
cb_fix_high( head, pcb );
pcb->size++;
pcb->readableSize++;
return c;
} else {
return -1;
}
}
static inline int cb_putc( CBUFFER * pcb, uint8_t c )
{
cb_cs_encap( cb_putc_unsafe( pcb, c ), int );
}
static inline int cb_peekc_unsafe( CBUFFER * pcb )
{
if( cb_size( pcb ) ){
return *pcb->tail;
} else {
return -1;
}
}
static inline int cb_peekc( CBUFFER * pcb )
{
cb_cs_encap( cb_peekc_unsafe( pcb ), int );
}
static inline int cb_getc_unsafe( CBUFFER * pcb )
{
if( cb_size( pcb ) ){
uint8_t ret = *pcb->tail++;
cb_fix_high( tail, pcb );
pcb->size--;
pcb->readableSize--;
return ret;
} else {
return -1;
}
}
static inline int cb_getc( CBUFFER * pcb )
{
cb_cs_encap( cb_getc_unsafe( pcb ), int );
}
static inline uint32_t cb_read_unsafe( CBUFFER * pcb, uint8_t * buffer, size_t size )
{
uint32_t readable = cb_readable_size( pcb );
if( readable ){
size = __min( size, readable );
size_t blockSize = pcb->dataEnd-pcb->tail;
if( blockSize < size ){
// we must copy some part of the data from tail-->dataEnd
// and then copy the rest from dataStart
memcpy( buffer, pcb->tail, blockSize );
buffer += blockSize;
blockSize = size - blockSize;
pcb->tail = pcb->dataStart + blockSize;
memcpy( buffer, pcb->dataStart, blockSize );
} else {
// we can copy the entire block from tail
memcpy( buffer, pcb->tail, size );
pcb->tail += size;
}
pcb->size -= size;
pcb->readableSize -= size;
return size;
} else {
return 0;
}
}
static inline uint32_t cb_read( CBUFFER * pcb, uint8_t * buffer, size_t size )
{
cb_cs_encap( cb_read_unsafe( pcb, buffer, size ), uint32_t );
}
static inline int cb_write_unsafe( CBUFFER * pcb, const uint8_t * buffer, size_t size )
{
if( cb_free_space( pcb ) ){
size = __min( size, pcb->bufferSize-pcb->size );
size_t blockSize = pcb->dataEnd-pcb->head;
if( blockSize < size ){
// must write in blocks from head-->dataEnd
// and then from dataStart
memcpy( pcb->head, buffer, blockSize );
buffer += blockSize;
blockSize = size - blockSize;
pcb->head = pcb->dataStart + blockSize;
memcpy( pcb->dataStart, buffer, blockSize );
} else {
memcpy( pcb->head, buffer, size );
pcb->head += size;
}
pcb->size += size;
pcb->readableSize += size;
return size;
} else {
return 0;
}
}
static inline int cb_write( CBUFFER * pcb, const uint8_t * buffer, size_t size )
{
cb_cs_encap( cb_write_unsafe( pcb, buffer, size ), int );
}
static inline void cb_free( CBUFFER * pcb )
{
free( pcb->dataStart );
pcb->dataEnd = pcb->dataStart = NULL;
}
__END_DECLS
#endif