138 lines
3.2 KiB
C
138 lines
3.2 KiB
C
/* Copyright 2018 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "cec.h"
|
|
#include "console.h"
|
|
#include "task.h"
|
|
|
|
#define CPRINTF(format, args...) cprintf(CC_CEC, format, ## args)
|
|
#define CPRINTS(format, args...) cprints(CC_CEC, format, ## args)
|
|
|
|
/*
|
|
* Mutex for the read-offset of the rx queue. Needed since the
|
|
* queue is read and flushed from different contexts
|
|
*/
|
|
static struct mutex rx_queue_readoffset_mutex;
|
|
|
|
int cec_transfer_get_bit(const struct cec_msg_transfer *transfer)
|
|
{
|
|
if (transfer->byte >= MAX_CEC_MSG_LEN)
|
|
return 0;
|
|
|
|
return transfer->buf[transfer->byte] & (0x80 >> transfer->bit);
|
|
}
|
|
|
|
void cec_transfer_set_bit(struct cec_msg_transfer *transfer, int val)
|
|
{
|
|
uint8_t bit_flag;
|
|
|
|
if (transfer->byte >= MAX_CEC_MSG_LEN)
|
|
return;
|
|
bit_flag = 0x80 >> transfer->bit;
|
|
transfer->buf[transfer->byte] &= ~bit_flag;
|
|
if (val)
|
|
transfer->buf[transfer->byte] |= bit_flag;
|
|
}
|
|
|
|
void cec_transfer_inc_bit(struct cec_msg_transfer *transfer)
|
|
{
|
|
if (++(transfer->bit) == 8) {
|
|
if (transfer->byte >= MAX_CEC_MSG_LEN)
|
|
return;
|
|
transfer->bit = 0;
|
|
transfer->byte++;
|
|
}
|
|
}
|
|
|
|
int cec_transfer_is_eom(const struct cec_msg_transfer *transfer, int len)
|
|
{
|
|
if (transfer->bit)
|
|
return 0;
|
|
return (transfer->byte == len);
|
|
}
|
|
|
|
void cec_rx_queue_flush(struct cec_rx_queue *queue)
|
|
{
|
|
mutex_lock(&rx_queue_readoffset_mutex);
|
|
queue->read_offset = 0;
|
|
mutex_unlock(&rx_queue_readoffset_mutex);
|
|
queue->write_offset = 0;
|
|
}
|
|
|
|
int cec_rx_queue_push(struct cec_rx_queue *queue, const uint8_t *msg,
|
|
uint8_t msg_len)
|
|
{
|
|
int i;
|
|
uint32_t offset;
|
|
|
|
if (msg_len > MAX_CEC_MSG_LEN || msg_len == 0)
|
|
return EC_ERROR_INVAL;
|
|
|
|
offset = queue->write_offset;
|
|
/* Fill in message length last, if successful. Set to zero for now */
|
|
queue->buf[offset] = 0;
|
|
offset = (offset + 1) % CEC_RX_BUFFER_SIZE;
|
|
|
|
for (i = 0 ; i < msg_len; i++) {
|
|
if (offset == queue->read_offset) {
|
|
/* Buffer full */
|
|
return EC_ERROR_OVERFLOW;
|
|
}
|
|
|
|
queue->buf[offset] = msg[i];
|
|
offset = (offset + 1) % CEC_RX_BUFFER_SIZE;
|
|
}
|
|
|
|
/*
|
|
* Don't commit if we caught up with read-offset
|
|
* since that would indicate an empty buffer
|
|
*/
|
|
if (offset == queue->read_offset) {
|
|
/* Buffer full */
|
|
return EC_ERROR_OVERFLOW;
|
|
}
|
|
|
|
/* Commit the push */
|
|
queue->buf[queue->write_offset] = msg_len;
|
|
queue->write_offset = offset;
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
int cec_rx_queue_pop(struct cec_rx_queue *queue, uint8_t *msg,
|
|
uint8_t *msg_len)
|
|
{
|
|
int i;
|
|
|
|
mutex_lock(&rx_queue_readoffset_mutex);
|
|
if (queue->read_offset == queue->write_offset) {
|
|
/* Queue empty */
|
|
mutex_unlock(&rx_queue_readoffset_mutex);
|
|
*msg_len = 0;
|
|
return -1;
|
|
}
|
|
|
|
/* The first byte in the buffer is the message length */
|
|
*msg_len = queue->buf[queue->read_offset];
|
|
if (*msg_len == 0 || *msg_len > MAX_CEC_MSG_LEN) {
|
|
mutex_unlock(&rx_queue_readoffset_mutex);
|
|
*msg_len = 0;
|
|
CPRINTF("Invalid CEC msg size: %u\n", *msg_len);
|
|
return -1;
|
|
}
|
|
|
|
queue->read_offset = (queue->read_offset + 1) % CEC_RX_BUFFER_SIZE;
|
|
for (i = 0; i < *msg_len; i++) {
|
|
msg[i] = queue->buf[queue->read_offset];
|
|
queue->read_offset = (queue->read_offset + 1) %
|
|
CEC_RX_BUFFER_SIZE;
|
|
|
|
}
|
|
|
|
mutex_unlock(&rx_queue_readoffset_mutex);
|
|
|
|
return 0;
|
|
}
|