blob: cb57fe9e87b5d6cf320ace02bc2caa9d4c82c1ad [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
#include "bcmolt_buf.h"
#include "bcmos_system.h"
/** Initalize a bcmolt_buf stream
*
* \param buf
* \param size
* \param start
* \param endian Endianness of numbers in the resulting stream
*/
void bcmolt_buf_init(bcmolt_buf *buf, uint32_t size, uint8_t *start, bcmos_endian endian)
{
buf->len = size;
buf->curr = start;
buf->start = start;
buf->free = NULL;
buf->bh = NULL;
/* Currently, we only support reading/writing numbers in a single endianness. */
BUG_ON(endian != BCMOLT_BUF_ENDIAN_FIXED);
}
/** Allocate data buffer and initialize bcmolt_buf stream
*
* \param buf
* \param size
* \param endian Endianness of numbers in the resulting stream
* \return BCM_ERR_OK or BCM_ERR_NOMEM
*/
bcmos_errno bcmolt_buf_alloc(bcmolt_buf *buf, uint32_t size, bcmos_endian endian)
{
buf->start = bcmos_alloc(size);
if (buf->start == NULL)
{
return BCM_ERR_NOMEM;
}
bcmolt_buf_init(buf, size, buf->start, endian);
return BCM_ERR_OK;
}
/** Release data buffer pointed by bcmolt_buf stream
* \param[in,out] buf
*/
void bcmolt_buf_free(bcmolt_buf *buf)
{
if (buf->start != NULL)
{
if (buf->free)
{
buf->free(buf->bh);
buf->free = NULL;
buf->bh = NULL;
}
else
{
bcmos_free(buf->start);
}
buf->start = NULL;
}
buf->len = 0;
buf->curr = NULL;
}
/** Read from the buffer
*
* \param buf bcmolt_buf instance
* \param to Where to read to
* \param len Number of bytes to copy
*
* \return BCMOS_TRUE if successfully copied
*/
bcmos_bool bcmolt_buf_read(bcmolt_buf *buf, void *to, size_t len)
{
if ((buf->start + buf->len) >= (buf->curr + len))
{
memcpy(to, buf->curr, len);
buf->curr += len;
return BCMOS_TRUE;
}
return BCMOS_FALSE;
}
/** Transfer bytes from one buf to another
*
* \param *from Source buffer
* \param *to Destination buffer
* \param bytes Number of bytes to transfer
* \return BCMOS_TRUE if successfully transferred
*/
bcmos_bool bcmolt_buf_transfer_bytes(bcmolt_buf *from, bcmolt_buf *to, uint32_t bytes)
{
uint8_t tmp[256];
uint32_t toRead;
while (bytes != 0)
{
toRead = bytes > sizeof(tmp) ? sizeof(tmp) : bytes;
if (!bcmolt_buf_read(from, tmp, toRead) || !bcmolt_buf_write(to, tmp, toRead))
{
return BCMOS_FALSE;
}
bytes -= toRead;
}
return BCMOS_TRUE;
}
/** Write to the buffer
*
* \param buf bcmolt_buf instance
* \param from Source, to copy from
* \param len Number of bytes to copy
*
* \return BCMOS_TRUE if successfully copied
*/
bcmos_bool bcmolt_buf_write(bcmolt_buf *buf, const void *from, size_t len)
{
if ((buf->start + buf->len) >= (buf->curr + len))
{
memcpy(buf->curr, from, len);
buf->curr += len;
return BCMOS_TRUE;
}
else
{
return BCMOS_FALSE;
}
}
/** Move the current pointer to a given position in the buffer
*
* \param pos Byte position in the buffer to move the current pointer to
*
* \param *buf Input buffer
* \return BCMOS_FALSE if len takes us past the end of buffer
*/
bcmos_bool bcmolt_buf_set_pos(bcmolt_buf *buf, uint32_t pos)
{
if (pos <= buf->len)
{
buf->curr = buf->start + pos;
return BCMOS_TRUE;
}
return BCMOS_FALSE;
}
/** Move the current pointer ahead by given number of bytes
*
* \param buf bcmolt_buf instance
* \param len Number of bytes to skip
*
* \return BCMOS_FALSE if len takes us past the end of buffer
*/
bcmos_bool bcmolt_buf_skip(bcmolt_buf *buf, uint32_t len)
{
if ((buf->start + buf->len) >= (buf->curr + len))
{
buf->curr += len;
return BCMOS_TRUE;
}
return BCMOS_FALSE;
}
/** Move the current pointer back by given number of bytes
*
* \param buf bcmolt_buf instance
* \param len Number of bytes to go back
*
* \return BCMOS_FALSE if len takes us past the start of buffer
*/
bcmos_bool bcmolt_buf_rewind(bcmolt_buf *buf, uint32_t len)
{
if (buf->curr >= (buf->start + len))
{
buf->curr -= len;
return BCMOS_TRUE;
}
return BCMOS_FALSE;
}
/** Reads a boolean from a buffer
*
* \param *buf
* \param *val
*/
bcmos_bool bcmolt_buf_read_bool(bcmolt_buf *buf, bcmos_bool *val)
{
/* this function isn't inlined like the rest because it's too complex to inline cleanly */
uint8_t tmp;
if (bcmolt_buf_read_u8(buf, &tmp))
{
*val = (tmp != 0);
return BCMOS_TRUE;
}
else
{
return BCMOS_FALSE;
}
}
#ifdef __KERNEL__
EXPORT_SYMBOL(bcmolt_buf_init);
EXPORT_SYMBOL(bcmolt_buf_alloc);
EXPORT_SYMBOL(bcmolt_buf_free);
EXPORT_SYMBOL(bcmolt_buf_read);
EXPORT_SYMBOL(bcmolt_buf_transfer_bytes);
EXPORT_SYMBOL(bcmolt_buf_write);
EXPORT_SYMBOL(bcmolt_buf_set_pos);
EXPORT_SYMBOL(bcmolt_buf_skip);
EXPORT_SYMBOL(bcmolt_buf_rewind);
EXPORT_SYMBOL(bcmolt_buf_read_bool);
MODULE_LICENSE("Dual BSD/GPL");
#endif