2025-04-08 18:46:12 +08:00

200 lines
4.6 KiB
C

#ifndef _FIFO_H_
#define _FIFO_H_
#include "include.h"
#include "generic.h"
#include "mem_pub.h"
#include "mem_pub.h"
typedef struct kfifo
{
unsigned int in;
unsigned int out;
unsigned int mask;
unsigned int size;
unsigned char *buffer;
}KFIFO_T, *KFIFO_PTR;
/**
* kfifo_init - allocates a new FIFO using a preallocated buffer
* @buffer: the preallocated buffer to be used.
* @size: the size of the internal buffer, this have to be a power of 2.
* @gfp_mask: get_free_pages mask, passed to ke_malloc()
* @lock: the lock to be used to protect the fifo buffer
*
* Do NOT pass the kfifo to kfifo_free() after use ! Simply free the
* struct kfifo with ke_free().
*/
__INLINE struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size)
{
struct kfifo *fifo;
/* size must be a power of 2 */
BUG_ON(size & (size - 1));
fifo = os_malloc(sizeof(struct kfifo));
if (!fifo)
return NULLPTR;
fifo->buffer = buffer;
fifo->size = size;
fifo->in = 0;
fifo->out = 0;
fifo->mask = fifo->size - 1;
return fifo;
}
/**
* kfifo_alloc - allocates a new FIFO and its internal buffer
* @size: the size of the internal buffer to be allocated.
* @gfp_mask: get_free_pages mask, passed to ke_malloc()
* @lock: the lock to be used to protect the fifo buffer
*
* The size will be rounded-up to a power of 2.
*/
__INLINE struct kfifo *kfifo_alloc(unsigned int size)
{
unsigned char *buffer;
struct kfifo *ret;
buffer = os_malloc(size);
if (!buffer)
return 0;
ret = kfifo_init(buffer, size);
if (!(ret))
os_free(buffer);
return ret;
}
/**
* kfifo_free - frees the FIFO
* @fifo: the fifo to be freed.
*/
__INLINE void kfifo_free(struct kfifo *fifo)
{
os_free(fifo->buffer);
fifo->buffer = 0;
os_free(fifo);
}
/**
* __kfifo_put - puts some data into the FIFO, no locking version
* @fifo: the fifo to be used.
* @buffer: the data to be added.
* @len: the length of the data to be added.
*
* This function copies at most 'len' bytes from the 'buffer' into
* the FIFO depending on the free space, and returns the number of
* bytes copied.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/
__INLINE unsigned int kfifo_put(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int l;
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
len = _min(len, fifo->size - fifo->in + fifo->out);
/* first put the data starting from fifo->in to buffer end */
l = _min(len, fifo->size - (fifo->in & (fifo->size - 1)));
os_memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
/* then put the rest (if any) at the beginning of the buffer */
os_memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
GLOBAL_INT_RESTORE();
return len;
}
/**
* __kfifo_get - gets some data from the FIFO, no locking version
* @fifo: the fifo to be used.
* @buffer: where the data must be copied.
* @len: the size of the destination buffer.
*
* This function copies at most 'len' bytes from the FIFO into the
* 'buffer' and returns the number of copied bytes.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/
__INLINE unsigned int kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int l;
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
len = _min(len, fifo->in - fifo->out);
/* first get the data from fifo->out until the end of the buffer */
l = _min(len, fifo->size - (fifo->out & (fifo->size - 1)));
os_memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
/* then get the rest (if any) from the beginning of the buffer */
os_memcpy(buffer + l, fifo->buffer, len - l);
fifo->out += len;
GLOBAL_INT_RESTORE();
return len;
}
__INLINE unsigned int kfifo_data_size(struct kfifo *fifo)
{
return (fifo->in - fifo->out);
}
__INLINE unsigned int kfifo_unused(struct kfifo *fifo)
{
return (fifo->mask + 1) - (fifo->in - fifo->out);
}
__INLINE void kfifo_copy_out(struct kfifo *fifo, void *dst,
unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int l;
off &= fifo->mask;
l = _min(len, size - off);
os_memcpy(dst, (void *)(fifo->buffer + off), l);
os_memcpy((void *)((unsigned int)dst + l), (void *)fifo->buffer, len - l);
/*
* make sure that the data is copied before
* incrementing the fifo->out index counter
*/
}
__INLINE unsigned int kfifo_out_peek(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int l;
l = fifo->in - fifo->out;
if (len > l)
len = l;
kfifo_copy_out(fifo, buffer, len, fifo->out);
return len;
}
#endif // _FIFO_H_
// eof