Squashed backup commit (no shallow-clone history issues) of xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream commit 9eece662e) plus all fixes applied to get everpal_defconfig building clean against a modern (GCC 15.2.0) toolchain -- see the previous commit message on the lineage-23.2 branch (also in this repo history is not available here since this is a squashed snapshot; full incremental history lives in the local DL380 checkout and the upstream GitHub remote). Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
214 lines
5.2 KiB
C
214 lines
5.2 KiB
C
/*
|
|
* reader shoule NEVER block !!!, if no data is avaliable, just return zero
|
|
* writer will block if there is no space, and wakend up by reader or force exit
|
|
* there is 1 writer and 1 reader for each buffer, so no lock is used
|
|
* writer shoule read rd_index to check if free size is enought, and then fill this buffer update wr_index
|
|
* reader shoule read wr_index to check if avaliable size is enought, and then read the buffer and update rd_index
|
|
* empty: wr_index==rd_index
|
|
* full: (wr_index +1) % BUFFER_SIZE == rd_index
|
|
* total avaliable size is BUFFER_SIZE -1
|
|
*/
|
|
#define DEBUG
|
|
#include <linux/errno.h>
|
|
#include "ringbuffer.h"
|
|
|
|
#define BUFFER_SIZE (1024 * 8 + 1)
|
|
|
|
struct rb {
|
|
char *gbuffer;
|
|
atomic_t wr_index;
|
|
atomic_t rd_index;
|
|
atomic_t eof;
|
|
volatile int32_t aval_size; // avalibale to write size.
|
|
atomic_t buf_condition, exit;
|
|
wait_queue_head_t wait_q;
|
|
};
|
|
|
|
struct rb *grb;
|
|
|
|
int32_t get_free_size(int32_t tail, int32_t head)
|
|
{
|
|
if (head == tail)
|
|
return BUFFER_SIZE - 1;
|
|
else if (head < tail)
|
|
return (head + BUFFER_SIZE - 1 - tail);
|
|
else
|
|
return(head - tail - 1);
|
|
}
|
|
|
|
int write_rb(const char *data, int32_t size)
|
|
{
|
|
int32_t tail = atomic_read(&grb->wr_index);
|
|
int32_t head = atomic_read(&grb->rd_index);
|
|
int32_t part;
|
|
int32_t ret;
|
|
grb->aval_size = get_free_size(tail, head);
|
|
|
|
pr_debug("write write index %d, read index %d, free size %d", tail, head, grb->aval_size);
|
|
|
|
while ((grb->aval_size < size) && (!atomic_read(&grb->exit))) {
|
|
pr_debug("no space avaliable");
|
|
pr_info("%s goint to waiting irq exit\n", __func__);
|
|
ret = wait_event_interruptible(grb->wait_q, atomic_read(&grb->buf_condition) == 1);
|
|
if (ret == -ERESTARTSYS) {
|
|
pr_err("%s wake up by signal return erro\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
atomic_set(&grb->buf_condition, 0);
|
|
tail = atomic_read(&grb->wr_index);
|
|
head = atomic_read(&grb->rd_index);
|
|
grb->aval_size = get_free_size(tail, head);
|
|
}
|
|
if (atomic_read(&grb->exit) == 1) {
|
|
pr_debug("exit write_rb");
|
|
return -EPERM;
|
|
}
|
|
|
|
part = BUFFER_SIZE - tail;
|
|
if (part < size) {
|
|
memcpy(grb->gbuffer + tail, data, part);
|
|
memcpy(grb->gbuffer, data + part, size - part);
|
|
tail = size - part;
|
|
} else {
|
|
memcpy(grb->gbuffer + tail, data, size);
|
|
tail += size;
|
|
if (tail >= BUFFER_SIZE)
|
|
tail = tail % BUFFER_SIZE;
|
|
}
|
|
atomic_set(&grb->wr_index, tail);
|
|
grb->aval_size = get_free_size(tail, head);
|
|
pr_debug("after write %d, write index %d, read index %d, aval_size %d", size, tail, head, grb->aval_size);
|
|
return size;
|
|
}
|
|
|
|
int read_rb(char *data, int32_t size)
|
|
{
|
|
int32_t tail;
|
|
int32_t head;
|
|
int32_t filled_size;
|
|
void *buf;
|
|
int32_t read_bytes, part;
|
|
buf = data;
|
|
|
|
pr_debug("read_rb data:%p, size %d", data, (int)size);
|
|
|
|
tail = atomic_read(&grb->wr_index);
|
|
head = atomic_read(&grb->rd_index);
|
|
grb->aval_size = get_free_size(tail, head);
|
|
filled_size = BUFFER_SIZE - 1 - grb->aval_size; // aready write size.
|
|
|
|
pr_debug("write index %d, read index %d, filled size %d", tail, head, filled_size);
|
|
read_bytes = MIN (size, filled_size);
|
|
if (size > filled_size)
|
|
pr_debug("buffer underrun , req size %d, filled size %d", size, filled_size);
|
|
part = BUFFER_SIZE - head;
|
|
if (part < read_bytes) {
|
|
memcpy(buf, grb->gbuffer + head, part);
|
|
memcpy((char *)buf + part, grb->gbuffer, read_bytes - part);
|
|
head = read_bytes - part;
|
|
} else {
|
|
memcpy(buf, grb->gbuffer + head, read_bytes);
|
|
head += read_bytes;
|
|
if (head >= BUFFER_SIZE)
|
|
head = head % BUFFER_SIZE;
|
|
}
|
|
atomic_set(&grb->rd_index, head);
|
|
grb->aval_size = get_free_size(tail, head);
|
|
|
|
//add wakeup here
|
|
atomic_set(&grb->buf_condition, 1);
|
|
wake_up_interruptible(&grb->wait_q);
|
|
pr_debug("read_rb: after read %d write index %d, read index %d, aval_size %d", read_bytes, tail, head, grb->aval_size);
|
|
|
|
return atomic_read(&grb->eof) ? read_bytes : size;
|
|
}
|
|
|
|
int get_rb_free_size(void)
|
|
{
|
|
int32_t tail = atomic_read(&grb->wr_index);
|
|
int32_t head = atomic_read(&grb->rd_index);
|
|
grb->aval_size = get_free_size(tail, head);
|
|
return grb->aval_size;
|
|
}
|
|
|
|
int get_rb_avalible_size(void)
|
|
{
|
|
return BUFFER_SIZE - 1 - get_rb_free_size();
|
|
}
|
|
|
|
int get_rb_max_size(void)
|
|
{
|
|
return BUFFER_SIZE - 1;
|
|
}
|
|
|
|
void rb_force_exit(void)
|
|
{
|
|
pr_debug("rb force exit");
|
|
atomic_set(&grb->exit, 1);
|
|
atomic_set(&grb->buf_condition, 1);
|
|
wake_up_interruptible(&grb->wait_q);
|
|
}
|
|
|
|
void rb_end(void)
|
|
{
|
|
atomic_set(&grb->eof, 1);
|
|
}
|
|
|
|
int rb_shoule_exit(void)
|
|
{
|
|
return atomic_read(&grb->eof) || atomic_read(&grb->exit);
|
|
}
|
|
|
|
int create_rb(void)
|
|
{
|
|
int32_t tail;
|
|
int32_t head;
|
|
grb = kzalloc(sizeof(struct rb), GFP_KERNEL);
|
|
if (grb == NULL) {
|
|
goto err;;
|
|
}
|
|
grb->gbuffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
|
|
if (grb->gbuffer == NULL) {
|
|
goto err;
|
|
}
|
|
|
|
rb_init();
|
|
|
|
init_waitqueue_head(&grb->wait_q);
|
|
tail = atomic_read(&grb->wr_index);
|
|
head = atomic_read(&grb->rd_index);
|
|
grb->aval_size = get_free_size(tail, head);
|
|
|
|
return 0;
|
|
err:
|
|
if (grb)
|
|
kfree(grb);
|
|
if (grb->gbuffer)
|
|
kfree(grb->gbuffer);
|
|
return -EPERM;
|
|
}
|
|
|
|
void rb_init(void)
|
|
{
|
|
pr_debug("rb init");
|
|
atomic_set(&grb->wr_index, 0);
|
|
atomic_set(&grb->rd_index, 0);
|
|
atomic_set(&grb->buf_condition, 0);
|
|
atomic_set(&grb->exit, 0);
|
|
atomic_set(&grb->eof, 0);
|
|
}
|
|
|
|
int release_rb(void)
|
|
{
|
|
if (grb != NULL) {
|
|
if (grb->gbuffer) {
|
|
kfree(grb->gbuffer);
|
|
grb->gbuffer = NULL;
|
|
}
|
|
kfree(grb);
|
|
grb = NULL;
|
|
}
|
|
return 0;
|
|
}
|