Files
android/drivers/input/misc/aw8697_haptic/ringbuffer.c
T
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
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)
2026-09-12 13:36:46 +00:00

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;
}