311 lines
7.4 KiB
C
Executable File
311 lines
7.4 KiB
C
Executable File
/**
|
|
@file circ_queue.h
|
|
@brief header file for general circular queue operations
|
|
@date 2014/02/18
|
|
@author Hankook Jang (hankook.jang@samsung.com)
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2010 Samsung Electronics.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#ifndef __MODEM_CIRCULAR_QUEUE_H__
|
|
#define __MODEM_CIRCULAR_QUEUE_H__
|
|
|
|
#include <linux/spinlock.h>
|
|
#include <linux/types.h>
|
|
|
|
#define GROUP_CIRC_QUEUE
|
|
|
|
#ifdef GROUP_CIRC_QUEUE
|
|
/**
|
|
@defgroup group_circ_queue Circular Queue
|
|
@{
|
|
*/
|
|
|
|
/**
|
|
@brief the structure for a circular queue in a memory-type interface
|
|
*/
|
|
struct circ_queue {
|
|
spinlock_t lock;
|
|
|
|
/**
|
|
* the flag and counter for checking busy status of a circualr queue
|
|
*/
|
|
atomic_t busy;
|
|
|
|
/**
|
|
* the start address of the data buffer in a circualr queue
|
|
*/
|
|
void __iomem *buff;
|
|
|
|
/**
|
|
* the size of the data buffer in a circular queue
|
|
*/
|
|
unsigned int size;
|
|
|
|
/**
|
|
* the pointer to the "HEAD (IN)" variable that contains a byte offset
|
|
* from @b @@buff
|
|
*/
|
|
void __iomem *head;
|
|
|
|
/**
|
|
* the pointer to the "TAIL (OUT)" variable that contains a byte offset
|
|
* from @b @@buff
|
|
*/
|
|
void __iomem *tail;
|
|
};
|
|
|
|
/**
|
|
@brief get the start address of the data buffer in a circular queue
|
|
|
|
@param q the pointer to a circular queue
|
|
|
|
@return the start address of the data buffer in the @e @@q
|
|
*/
|
|
static inline char *get_buff(struct circ_queue *q)
|
|
{
|
|
return q->buff;
|
|
}
|
|
|
|
/**
|
|
@brief get the size of the data buffer in a circular queue
|
|
|
|
@param q the pointer to a circular queue
|
|
|
|
@return the size of the data buffer in the @e @@q
|
|
*/
|
|
static inline unsigned int get_size(struct circ_queue *q)
|
|
{
|
|
return q->size;
|
|
}
|
|
|
|
/**
|
|
@brief get the "HEAD (IN)" pointer value of a circular queue
|
|
|
|
@param q the pointer to a circular queue
|
|
|
|
@return the "HEAD (IN)" pointer value of the @e @@q
|
|
*/
|
|
static inline unsigned int get_head(struct circ_queue *q)
|
|
{
|
|
return ioread32(q->head);
|
|
}
|
|
|
|
/**
|
|
@brief set the "HEAD (IN)" pointer value of a circular queue with @b
|
|
@@in
|
|
|
|
@param q the pointer to a circular queue
|
|
@param in the value to be stored into the "HEAD (IN)" pointer
|
|
*/
|
|
static inline void set_head(struct circ_queue *q, unsigned int in)
|
|
{
|
|
iowrite32(in, q->head);
|
|
}
|
|
|
|
/**
|
|
@brief get the "TAIL (OUT)" pointer value of a circular queue
|
|
|
|
@param q the pointer to a circular queue
|
|
|
|
@return the "TAIL (OUT)" pointer value of the @e @@q
|
|
*/
|
|
static inline unsigned int get_tail(struct circ_queue *q)
|
|
{
|
|
return ioread32(q->tail);
|
|
}
|
|
|
|
/**
|
|
@brief set the "TAIL (OUT)" pointer value of a circular queue with @e
|
|
@@out
|
|
|
|
@param q the pointer to a circular queue
|
|
@param out the value to be stored into the "TAIL (OUT)" pointer
|
|
*/
|
|
static inline void set_tail(struct circ_queue *q, unsigned int out)
|
|
{
|
|
iowrite32(out, q->tail);
|
|
}
|
|
|
|
/**
|
|
@brief check whether or not both "IN" and "OUT" pointer values are
|
|
valid
|
|
|
|
@param qsize the size of the data buffer in a circular queue
|
|
@param in the value of the "HEAD (IN)" pointer
|
|
@param out the value of the "TAIL (OUT)" pointer
|
|
|
|
@retval "true" if all pointer values are valid
|
|
@retval "false" if either IN or OUT pointer value is NOT valid
|
|
*/
|
|
static inline bool circ_valid(unsigned int qsize,
|
|
unsigned int in,
|
|
unsigned int out)
|
|
{
|
|
if (unlikely(in >= qsize))
|
|
return false;
|
|
|
|
if (unlikely(out >= qsize))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
@brief check whether or not a circular queue is empty
|
|
|
|
@param in the value of the "HEAD (IN)" pointer
|
|
@param out the value of the "TAIL (OUT)" pointer
|
|
|
|
@retval "true" if a circular queue is empty
|
|
@retval "false" if a circular queue is NOT empty
|
|
*/
|
|
static inline bool circ_empty(unsigned int in, unsigned int out)
|
|
{
|
|
return (in == out);
|
|
}
|
|
|
|
/**
|
|
@brief get the size of free space in a circular queue
|
|
|
|
@param qsize the size of the data buffer in a circular queue
|
|
@param in the value of the "HEAD (IN)" pointer
|
|
@param out the value of the "TAIL (OUT)" pointer
|
|
|
|
@return the size of free space in a circular queue
|
|
*/
|
|
static inline unsigned int circ_get_space(unsigned int qsize,
|
|
unsigned int in,
|
|
unsigned int out)
|
|
{
|
|
return (in < out) ? (out - in - 1) : (qsize + out - in - 1);
|
|
}
|
|
|
|
static inline bool circ_full(unsigned int qsize, unsigned int in,
|
|
unsigned int out)
|
|
{
|
|
return (circ_get_space(qsize, in, out) == 0);
|
|
}
|
|
|
|
/**
|
|
@brief get the size of data in a circular queue
|
|
|
|
@param qsize the size of the data buffer in a circular queue
|
|
@param in the value of the "HEAD (IN)" pointer
|
|
@param out the value of the "TAIL (OUT)" pointer
|
|
|
|
@return the size of data in a circular queue
|
|
*/
|
|
static inline unsigned int circ_get_usage(unsigned int qsize,
|
|
unsigned int in,
|
|
unsigned int out)
|
|
{
|
|
return (in >= out) ? (in - out) : (qsize - out + in);
|
|
}
|
|
|
|
/**
|
|
@brief calculate a new pointer value for a circular queue
|
|
|
|
@param qsize the size of the data buffer in a circular queue
|
|
@param p the old value of a queue pointer
|
|
@param len the length to be added to the @e @@p pointer value
|
|
|
|
@return the new value for the queue pointer
|
|
*/
|
|
static inline unsigned int circ_new_ptr(unsigned int qsize,
|
|
unsigned int p,
|
|
unsigned int len)
|
|
{
|
|
unsigned int np = (p + len);
|
|
while (np >= qsize)
|
|
np -= qsize;
|
|
return np;
|
|
}
|
|
|
|
/**
|
|
@brief copy the data in a circular queue to a local buffer
|
|
|
|
@param dst the start address of the local buffer
|
|
@param src the start address of the data buffer in a circular queue
|
|
@param qsize the size of the data buffer in a circular queue
|
|
@param out the offset in the data buffer to be read
|
|
@param len the length of data to be read
|
|
|
|
@remark This function should be invoked after checking the data length.
|
|
*/
|
|
static inline void circ_read(u8 *dst, u8 *src, unsigned int qsize,
|
|
unsigned int out, unsigned int len)
|
|
{
|
|
if ((out + len) <= qsize) {
|
|
/* ----- (out) (in) ----- */
|
|
/* ----- 7f 00 00 7e ----- */
|
|
memcpy(dst, (src + out), len);
|
|
} else {
|
|
unsigned int len1;
|
|
|
|
/* (in) ----------- (out) */
|
|
/* 00 7e ----------- 7f 00 */
|
|
|
|
/* 1) data start (out) ~ buffer end */
|
|
len1 = qsize - out;
|
|
memcpy(dst, (src + out), len1);
|
|
|
|
/* 2) buffer start ~ data end (in?) */
|
|
memcpy((dst + len1), src, (len - len1));
|
|
}
|
|
}
|
|
|
|
/**
|
|
@brief copy the data in a local buffer to a circular queue
|
|
|
|
@param dst the start address of the data buffer in a circular queue
|
|
@param src the start address of the data in a local buffer
|
|
@param qsize the size of the data buffer in a circular queue
|
|
@param in the offset in the data buffer for the data to be stored
|
|
@param len the length of data to be stored
|
|
|
|
@remark This function should be invoked after checking the free space.
|
|
*/
|
|
static inline void circ_write(u8 *dst, u8 *src, unsigned int qsize,
|
|
unsigned int in, unsigned int len)
|
|
{
|
|
if ((in + len) < qsize) {
|
|
/* (in) ----------- (out) */
|
|
/* 00 7e ----------- 7f 00 */
|
|
memcpy((dst + in), src, len);
|
|
} else {
|
|
unsigned int space;
|
|
|
|
/* ----- (out) (in) ----- */
|
|
/* ----- 7f 00 00 7e ----- */
|
|
|
|
/* 1) space start (in) ~ buffer end */
|
|
space = qsize - in;
|
|
memcpy((dst + in), src, ((len > space) ? space : len));
|
|
|
|
/* 2) buffer start ~ data end */
|
|
if (len > space)
|
|
memcpy(dst, (src + space), (len - space));
|
|
}
|
|
}
|
|
|
|
/**
|
|
// End of group_circ_queue
|
|
@}
|
|
*/
|
|
#endif
|
|
|
|
#endif
|