6db4831e98
Android 14
147 lines
3.6 KiB
C
147 lines
3.6 KiB
C
/*
|
|
* lib/circ_buf_packet.c
|
|
*
|
|
* Copyright (C) 2012-2017, Samsung Electronics Co., Ltd.
|
|
*
|
|
* Circular buffer packet operations.
|
|
*/
|
|
|
|
#include <linux/err.h>
|
|
#include "lib/circ_buf.h"
|
|
#include "lib/circ_buf_packet.h"
|
|
|
|
struct circ_buf_packet_header {
|
|
uint32_t packet_size;
|
|
} __packed;
|
|
|
|
size_t circ_buf_size_for_packet(size_t size)
|
|
{
|
|
return size + sizeof(struct circ_buf_packet_header);
|
|
}
|
|
|
|
ssize_t circ_buf_write_packet(struct circ_buf_desc *circ_buf_desc, const char *buf,
|
|
size_t length, enum circ_buf_user_mode mode)
|
|
{
|
|
ssize_t ret;
|
|
|
|
ret = circ_buf_write_packet_local(circ_buf_desc, buf, length, mode);
|
|
if (!IS_ERR_VALUE(ret))
|
|
circ_buf_flush_write(circ_buf_desc);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t circ_buf_write_packet_local(struct circ_buf_desc *circ_buf_desc, const char *buf,
|
|
size_t length, enum circ_buf_user_mode mode)
|
|
{
|
|
struct circ_buf_packet_header header;
|
|
ssize_t ret;
|
|
unsigned int write_count_orig = circ_buf_desc->write_count;
|
|
|
|
header.packet_size = length;
|
|
|
|
ret = circ_buf_write_local(circ_buf_desc, (void *) &header,
|
|
sizeof(struct circ_buf_packet_header), CIRC_BUF_MODE_KERNEL);
|
|
if (IS_ERR_VALUE(ret))
|
|
return ret;
|
|
|
|
ret = circ_buf_write_local(circ_buf_desc, buf, length, mode);
|
|
if (IS_ERR_VALUE(ret))
|
|
circ_buf_desc->write_count = write_count_orig;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t circ_buf_read_packet(struct circ_buf_desc *circ_buf_desc, char *buf,
|
|
size_t length, enum circ_buf_user_mode mode)
|
|
{
|
|
ssize_t ret;
|
|
|
|
ret = circ_buf_read_packet_local(circ_buf_desc, buf, length, mode);
|
|
if (!IS_ERR_VALUE(ret))
|
|
circ_buf_flush_read(circ_buf_desc);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t circ_buf_read_packet_local(struct circ_buf_desc *circ_buf_desc, char *buf,
|
|
size_t length, enum circ_buf_user_mode mode)
|
|
{
|
|
struct circ_buf_packet_header header;
|
|
ssize_t ret;
|
|
size_t packet_size;
|
|
unsigned int read_count_orig = circ_buf_desc->read_count;
|
|
|
|
ret = circ_buf_read_local(circ_buf_desc, (void *) &header,
|
|
sizeof(struct circ_buf_packet_header), CIRC_BUF_MODE_KERNEL);
|
|
if (IS_ERR_VALUE(ret))
|
|
return ret;
|
|
|
|
packet_size = header.packet_size;
|
|
if (packet_size > length) {
|
|
circ_buf_desc->read_count = read_count_orig;
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
ret = circ_buf_read_local(circ_buf_desc, buf, packet_size, mode);
|
|
if (IS_ERR_VALUE(ret))
|
|
circ_buf_desc->read_count = read_count_orig;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t circ_buf_drop_packet(struct circ_buf_desc *circ_buf_desc)
|
|
{
|
|
ssize_t ret;
|
|
|
|
ret = circ_buf_drop_packet_local(circ_buf_desc);
|
|
if (!IS_ERR_VALUE(ret))
|
|
circ_buf_flush_read(circ_buf_desc);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t circ_buf_drop_packet_local(struct circ_buf_desc *circ_buf_desc)
|
|
{
|
|
struct circ_buf_packet_header header;
|
|
ssize_t ret;
|
|
unsigned int read_count_orig = circ_buf_desc->read_count;
|
|
|
|
ret = circ_buf_read_local(circ_buf_desc, (void *) &header,
|
|
sizeof(struct circ_buf_packet_header), CIRC_BUF_MODE_KERNEL);
|
|
if (IS_ERR_VALUE(ret))
|
|
return ret;
|
|
|
|
ret = circ_buf_read_local(circ_buf_desc, NULL, header.packet_size,
|
|
CIRC_BUF_MODE_DROP);
|
|
if (IS_ERR_VALUE(ret))
|
|
circ_buf_desc->read_count = read_count_orig;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t circ_buf_peek_packet(struct circ_buf_desc *circ_buf_desc, char *buf,
|
|
size_t length, size_t offset, enum circ_buf_user_mode mode)
|
|
{
|
|
struct circ_buf_packet_header header;
|
|
ssize_t ret;
|
|
unsigned int read_count_orig = circ_buf_desc->read_count;
|
|
|
|
ret = circ_buf_read_local(circ_buf_desc, (void *) &header,
|
|
sizeof(struct circ_buf_packet_header), CIRC_BUF_MODE_KERNEL);
|
|
if (IS_ERR_VALUE(ret))
|
|
return ret;
|
|
|
|
if (offset + length > header.packet_size) {
|
|
ret = -EMSGSIZE;
|
|
goto out;
|
|
}
|
|
|
|
ret = __circ_buf_read_local(circ_buf_desc, buf, length, offset, mode);
|
|
|
|
out:
|
|
circ_buf_desc->read_count = read_count_orig;
|
|
|
|
return ret;
|
|
}
|