221 lines
5.5 KiB
C
221 lines
5.5 KiB
C
/* Copyright 2016 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 "queue.h"
|
|
#include "queue_policies.h"
|
|
#ifdef CONFIG_STREAM_SIGNATURE
|
|
#include "signing.h"
|
|
#endif
|
|
#ifdef CONFIG_UART_BITBANG
|
|
#include "uart_bitbang.h"
|
|
#endif
|
|
#include "uartn.h"
|
|
#include "usart.h"
|
|
#include "usb-stream.h"
|
|
|
|
#define USE_UART_INTERRUPTS (!(defined(CONFIG_CUSTOMIZED_RO) && \
|
|
defined(SECTION_IS_RO)))
|
|
#define QUEUE_SIZE 64
|
|
/*
|
|
* Want to be able to accumulate larger amounts of data while USB is
|
|
* momentarily stalled for whatever reason.
|
|
*/
|
|
#define QUEUE_SIZE_UART_RX 512
|
|
|
|
#ifdef CONFIG_STREAM_SIGNATURE
|
|
/*
|
|
* When signing over streaming data, up the relevant queue sizes.
|
|
*/
|
|
#define QUEUE_SIZE_SIG_IN 1024
|
|
#define QUEUE_SIZE_USB_IN 8192
|
|
#define QUEUE_SIZE_UART_IN 1024
|
|
#else
|
|
#define QUEUE_SIZE_SIG_IN QUEUE_SIZE
|
|
#define QUEUE_SIZE_USB_IN QUEUE_SIZE
|
|
#define QUEUE_SIZE_UART_IN QUEUE_SIZE
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_STREAM_USART1
|
|
struct usb_stream_config const ap_usb;
|
|
struct usart_config const ap_uart;
|
|
|
|
#ifdef CONFIG_STREAM_SIGNATURE
|
|
/*
|
|
* This code adds the ability to capture UART data received, and
|
|
* sign it with H1's key. This allows the log output to be verified
|
|
* as actual UART output from this board.
|
|
*
|
|
* This functionality is enabled by redirecting the UART receive queue
|
|
* to feed into the signing module rather than the usb tx. After being
|
|
* added to the running hash, the data is then pushed by the signer
|
|
* into the usb tx queue.
|
|
*/
|
|
struct signer_config const sig;
|
|
static struct queue const ap_uart_output =
|
|
QUEUE_DIRECT(QUEUE_SIZE_SIG_IN, uint8_t, ap_uart.producer,
|
|
sig.consumer);
|
|
static struct queue const sig_to_usb =
|
|
QUEUE_DIRECT(QUEUE_SIZE_USB_IN, uint8_t, sig.producer,
|
|
ap_usb.consumer);
|
|
|
|
SIGNER_CONFIG(sig, stream_uart, sig_to_usb, ap_uart_output);
|
|
|
|
#else /* Not CONFIG_STREAM_SIGNATURE */
|
|
static struct queue const ap_uart_output =
|
|
QUEUE_DIRECT(QUEUE_SIZE_UART_RX, uint8_t,
|
|
ap_uart.producer, ap_usb.consumer);
|
|
#endif
|
|
|
|
static struct queue const ap_usb_to_uart =
|
|
QUEUE_DIRECT(QUEUE_SIZE_UART_IN, uint8_t, ap_usb.producer,
|
|
ap_uart.consumer);
|
|
|
|
/*
|
|
* AP UART data is sent to the ap_uart_output queue, and received from
|
|
* the ap_usb_to_uart queue. The ap_uart_output queue is received by the
|
|
* USB bridge, or if a signer is enabled, received by the signer, which then
|
|
* passes the data to the USB bridge after processing it.
|
|
*/
|
|
USART_CONFIG(ap_uart,
|
|
UART_AP,
|
|
ap_uart_output,
|
|
ap_usb_to_uart);
|
|
|
|
/*
|
|
* The UART USB bridge receives character data from the UART's queue,
|
|
* unless signing is enabled, in which case it receives data from the
|
|
* signer's queue, after the signer has received it from the UART and
|
|
* processed it.
|
|
*/
|
|
USB_STREAM_CONFIG(ap_usb,
|
|
USB_IFACE_AP,
|
|
USB_STR_AP_NAME,
|
|
USB_EP_AP,
|
|
USB_MAX_PACKET_SIZE,
|
|
USB_MAX_PACKET_SIZE,
|
|
ap_usb_to_uart,
|
|
#ifdef CONFIG_STREAM_SIGNATURE
|
|
sig_to_usb)
|
|
#else
|
|
ap_uart_output)
|
|
#endif
|
|
#endif /* CONFIG_STREAM_USART1 */
|
|
|
|
#ifdef CONFIG_STREAM_USART2
|
|
struct usb_stream_config const ec_usb;
|
|
struct usart_config const ec_uart;
|
|
|
|
static struct queue const ec_uart_to_usb =
|
|
QUEUE_DIRECT(QUEUE_SIZE_UART_RX, uint8_t,
|
|
ec_uart.producer, ec_usb.consumer);
|
|
static struct queue const ec_usb_to_uart =
|
|
QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ec_usb.producer, ec_uart.consumer);
|
|
|
|
USART_CONFIG(ec_uart,
|
|
UART_EC,
|
|
ec_uart_to_usb,
|
|
ec_usb_to_uart);
|
|
|
|
USB_STREAM_CONFIG(ec_usb,
|
|
USB_IFACE_EC,
|
|
USB_STR_EC_NAME,
|
|
USB_EP_EC,
|
|
USB_MAX_PACKET_SIZE,
|
|
USB_MAX_PACKET_SIZE,
|
|
ec_usb_to_uart,
|
|
ec_uart_to_usb)
|
|
#endif
|
|
|
|
void get_data_from_usb(struct usart_config const *config)
|
|
{
|
|
struct queue const *uart_out = config->consumer.queue;
|
|
int c;
|
|
|
|
/* Copy output from buffer until TX fifo full or output buffer empty */
|
|
while (queue_count(uart_out) && QUEUE_REMOVE_UNITS(uart_out, &c, 1))
|
|
uartn_write_char(config->uart, c);
|
|
|
|
/* If output buffer is empty, disable transmit interrupt */
|
|
if (!queue_count(uart_out))
|
|
uartn_tx_stop(config->uart);
|
|
}
|
|
|
|
void send_data_to_usb(struct usart_config const *config)
|
|
{
|
|
struct queue const *uart_in = config->producer.queue;
|
|
int uart = config->uart;
|
|
size_t count;
|
|
size_t q_room;
|
|
size_t tail;
|
|
size_t mask;
|
|
|
|
q_room = queue_space(uart_in);
|
|
|
|
if (!q_room)
|
|
return;
|
|
|
|
mask = uart_in->buffer_units_mask;
|
|
tail = uart_in->state->tail & mask;
|
|
count = 0;
|
|
|
|
while ((count != q_room) && uartn_rx_available(uart)) {
|
|
uart_in->buffer[tail] = uartn_read_char(uart);
|
|
tail = (tail + 1) & mask;
|
|
count++;
|
|
}
|
|
if (count)
|
|
queue_advance_tail(uart_in, count);
|
|
}
|
|
|
|
static void uart_read(struct producer const *producer, size_t count)
|
|
{
|
|
}
|
|
|
|
static void uart_written(struct consumer const *consumer, size_t count)
|
|
{
|
|
struct usart_config const *config =
|
|
DOWNCAST(consumer, struct usart_config, consumer);
|
|
|
|
#ifdef CONFIG_UART_BITBANG
|
|
if (uart_bitbang_is_enabled() &&
|
|
(config->uart == bitbang_config.uart)) {
|
|
uart_bitbang_drain_tx_queue(consumer->queue);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (uartn_tx_ready(config->uart) && queue_count(consumer->queue))
|
|
uartn_tx_start(config->uart);
|
|
}
|
|
|
|
struct producer_ops const uart_producer_ops = {
|
|
.read = uart_read,
|
|
};
|
|
|
|
struct consumer_ops const uart_consumer_ops = {
|
|
.written = uart_written,
|
|
};
|
|
|
|
#if USE_UART_INTERRUPTS
|
|
#ifdef CONFIG_STREAM_USART1
|
|
/*
|
|
* Interrupt handlers for UART1
|
|
*/
|
|
CONFIGURE_INTERRUPTS(ap_uart,
|
|
GC_IRQNUM_UART1_RXINT,
|
|
GC_IRQNUM_UART1_TXINT)
|
|
#endif
|
|
|
|
#ifdef CONFIG_STREAM_USART2
|
|
/*
|
|
* Interrupt handlers for UART2
|
|
*/
|
|
CONFIGURE_INTERRUPTS(ec_uart,
|
|
GC_IRQNUM_UART2_RXINT,
|
|
GC_IRQNUM_UART2_TXINT)
|
|
#endif
|
|
#endif
|