acrn-hypervisor/hypervisor/debug/serial.c
Huihuang Shi 59771ff461 HV:treewide:fix "Reference parameter to procedure is reassigned"
Parameter's type which is pointer should not be changed in the
scope of function,assign it's value to local variable to fixed
it out.

Signed-off-by: Huihuang Shi <huihuang.shi@intel.com>
Reviewed-by: Junjie Mao <junjie.mao@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
2018-07-27 12:17:12 +08:00

369 lines
8.2 KiB
C

/*
* Copyright (C) 2018 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <hypervisor.h>
#include "serial_internal.h"
static struct uart *sio_ports[SERIAL_MAX_DEVS];
static uint8_t sio_initialized[SERIAL_MAX_DEVS];
static struct uart *get_uart_by_id(const char *uart_id, uint32_t *index)
{
/* Initialize the index to the start of array. */
*index = 0U;
while (sio_ports[*index] != NULL) {
if (strncmp(sio_ports[*index]->tgt_uart->uart_id, uart_id,
strnlen_s(sio_ports[*index]->tgt_uart->uart_id,
SERIAL_ID_MAX_LENGTH)) == 0) {
break;
}
/* No device is found if index reaches end of array. */
(*index)++;
if (*index == SERIAL_MAX_DEVS) {
return NULL;
}
}
return sio_ports[*index];
}
int serial_init(void)
{
uint32_t index = 0;
int status = 0;
while (index < SERIAL_MAX_DEVS) {
/* Allocate memory for generic control block of enabled UART */
sio_ports[index] = calloc(1, sizeof(struct uart));
if (sio_ports[index] == NULL) {
status = -ENOMEM;
break;
}
sio_ports[index]->tgt_uart = &(Tgt_Uarts[index]);
/*
* Set the open flag to false to indicate that UART port is
* not opened yet.
*/
sio_ports[index]->open_flag = false;
/* Reset the tx lock */
spinlock_init(&sio_ports[index]->tx_lock);
sio_ports[index]->rx_sio_queue = sbuf_allocate(
sio_ports[index]->tgt_uart->buffer_size,
sizeof(uint8_t));
if (sio_ports[index]->rx_sio_queue != NULL) {
sbuf_set_flags(sio_ports[index]->rx_sio_queue,
OVERWRITE_EN);
/* Call target specific initialization function */
status = sio_ports[index]->tgt_uart->
init(sio_ports[index]->tgt_uart);
if (status == 0) {
sio_initialized[index] = true;
}
} else {
status = -ENOMEM;
break;
}
index++;
}
return status;
}
uint32_t serial_open(const char *uart_id)
{
int status = SERIAL_DEV_NOT_FOUND;
struct uart *uart;
uint32_t index;
/* Get UART control block from given character ID */
uart = get_uart_by_id(uart_id, &index);
if (uart != NULL && index < SERIAL_MAX_DEVS &&
sio_initialized[index] != 0U &&
(uart->open_flag == false)) {
/* Reset the buffer lock */
spinlock_init(&uart->buffer_lock);
/* Configure the UART port to default settings. */
uart->config.data_bits = DATA_8;
uart->config.stop_bits = STOP_1;
uart->config.parity_bits = PARITY_NONE;
uart->config.baud_rate = BAUD_115200;
uart->config.flow_control = FLOW_NONE;
uart->config.read_mode = SUSPEND;
/* Open the UART hardware with default configuration. */
status = uart->tgt_uart->open(uart->tgt_uart, &(uart->config));
if (status == 0) {
uart->open_flag = true;
}
}
/* Already open serial device */
else if (uart != NULL && uart->open_flag == true) {
/* Reset the buffer lock */
spinlock_init(&uart->buffer_lock);
status = 0;
}
return (status == 0) ?
SERIAL_ENCODE_INDEX(index) :
SERIAL_INVALID_HANDLE;
}
uint32_t serial_get_rx_data(uint32_t uart_handle)
{
uint32_t index;
struct uart *uart;
int data_avail;
uint32_t rx_byte_status;
uint32_t lsr_reg, bytes_read;
uint8_t ch;
uint32_t total_bytes_read = 0U;
if (!SERIAL_VALIDATE_HANDLE(uart_handle)) {
return 0U;
}
index = SERIAL_DECODE_INDEX(uart_handle);
if (index >= SERIAL_MAX_DEVS) {
return 0U;
}
uart = sio_ports[index];
if (uart == NULL) {
return 0U;
}
/* Place all the data available in RX FIFO, in circular buffer */
data_avail = uart->tgt_uart->rx_data_is_avail(
uart->tgt_uart, &lsr_reg);
while (data_avail != 0) {
/* Read the byte */
uart->tgt_uart->read(uart->tgt_uart, (void *)&ch, &bytes_read);
/* Get RX status for this byte */
rx_byte_status = uart->tgt_uart->get_rx_err(lsr_reg);
/*
* Check if discard errors in RX character
* (parity / framing errors)
*/
if (rx_byte_status >= SD_RX_PARITY_ERROR) {
/* Increase error status if bad data */
uart->rx_error.parity_errors +=
(rx_byte_status == SD_RX_PARITY_ERROR);
uart->rx_error.frame_errors +=
(rx_byte_status == SD_RX_FRAME_ERROR);
} else {
/* Update the overrun errors */
uart->rx_error.overrun_errors +=
(rx_byte_status == SD_RX_OVERRUN_ERROR);
/* Enter Critical Section */
spinlock_obtain(&uart->buffer_lock);
/* Put the item on circular buffer */
(void)sbuf_put(uart->rx_sio_queue, &ch);
/* Exit Critical Section */
spinlock_release(&uart->buffer_lock);
}
/* Update the total bytes read */
total_bytes_read += bytes_read;
data_avail = uart->tgt_uart->rx_data_is_avail(
uart->tgt_uart, &lsr_reg);
}
return total_bytes_read;
}
int serial_getc(uint32_t uart_handle)
{
uint8_t ch;
struct uart *port;
uint32_t index;
int status = SERIAL_DEV_NOT_FOUND;
if (!SERIAL_VALIDATE_HANDLE(uart_handle)) {
goto exit;
}
index = SERIAL_DECODE_INDEX(uart_handle);
if (index >= SERIAL_MAX_DEVS) {
goto exit;
}
port = sio_ports[index];
if (port == NULL) {
goto exit;
}
/* First read a character from the circular buffer regardless of the
* read mode of UART port. If status is not CBUFFER_EMPTY, character
* read from UART port is returned to the caller. Otherwise, if read
* mode is not NO_SUSPEND, thread is blocked until a character is read
* from the port. Serial target specific HISR unblocks the thread when
* a character is received and character is then read from the circular
* buffer.
*/
/* Disable interrupts for critical section */
spinlock_obtain(&port->buffer_lock);
status = sbuf_get(port->rx_sio_queue, &ch);
/* Restore interrupts to original level. */
spinlock_release(&port->buffer_lock);
exit:
/* Return the character read, otherwise return the error status */
return ((status > 0) ? (int)(ch) : SERIAL_EOF);
}
int serial_gets(uint32_t uart_handle, char *buffer, uint32_t length_arg)
{
char *data_read = buffer;
int c;
struct uart *port;
uint32_t index;
int status = 0;
uint32_t length = length_arg;
if ((buffer == NULL) || (length == 0U)) {
return 0;
}
if (!SERIAL_VALIDATE_HANDLE(uart_handle)) {
return 0;
}
index = SERIAL_DECODE_INDEX(uart_handle);
if (index >= SERIAL_MAX_DEVS) {
return 0;
}
port = sio_ports[index];
if ((port != NULL) && (port->open_flag == true)) {
for (; length > 0U; length--) {
/* Disable interrupts for critical section */
spinlock_obtain(&port->buffer_lock);
status = sbuf_get(port->rx_sio_queue, (uint8_t *)&c);
/* Restore interrupts to original level. */
spinlock_release(&port->buffer_lock);
if (status <= 0) {
break;
}
/* Save character in buffer */
*data_read = (char) c;
data_read++;
}
}
/* Return actual number of bytes read */
return (int)(data_read - buffer);
}
static int serial_putc(uint32_t uart_handle, int c)
{
uint32_t index, bytes_written = 0U;
struct uart *uart;
int busy;
if (!SERIAL_VALIDATE_HANDLE(uart_handle)) {
return SERIAL_EOF;
}
index = SERIAL_DECODE_INDEX(uart_handle);
if (index >= SERIAL_MAX_DEVS) {
return SERIAL_EOF;
}
uart = sio_ports[index];
if (uart == NULL) {
return SERIAL_EOF;
}
/* Wait for TX hardware to be ready */
do {
busy = uart->tgt_uart->tx_is_busy(uart->tgt_uart);
} while (busy != 0);
/* Transmit character */
uart->tgt_uart->write(uart->tgt_uart, &(c), &bytes_written);
/* Return character written or EOF for error */
return ((bytes_written > 0U) ? c : (SERIAL_EOF));
}
int serial_puts(uint32_t uart_handle, const char *s_arg, uint32_t length_arg)
{
const char *s = s_arg;
const char *old_data = s;
uint32_t index;
struct uart *port;
int retval = 0;
uint32_t length = length_arg;
if ((s == NULL) || (length == 0U)) {
return 0;
}
if (!SERIAL_VALIDATE_HANDLE(uart_handle)) {
return 0;
}
index = SERIAL_DECODE_INDEX(uart_handle);
if (index >= SERIAL_MAX_DEVS) {
return 0;
}
port = sio_ports[index];
if (port == NULL) {
return 0;
}
/*
* Grab the semaphore so that strings between threads do not
* get mixed.
*/
spinlock_obtain(&port->tx_lock);
/*
* Loop through the string until desired length of bytes have
* been written or SERIAL_EOF is returned.
*/
for (; length > 0U && retval != SERIAL_EOF; s++, length--) {
retval = serial_putc(uart_handle, (int) *s);
}
/* Allow other threads to use this service. */
spinlock_release(&port->tx_lock);
/* Return actual number of bytes written */
return (int)(s - old_data);
}