cr50: add support for creating multiple serial endpoints

CR50 will need three serial endpoints for the streaming AP and EC UART
and exporting its own console through USB. This change adds a macro to
create endpoints that can be recognized by the usb_serial driver.

BUG=chrome-os-partner:50702
BRANCH=none
TEST=Verify "/dev/google/Cr50*/serial/Blob" prints capital letters when
lower case letters are input.

Change-Id: Iddf2c957a00dc3cd5448a6a00de2cf61ef5dd84c
Signed-off-by: Mary Ruthven <mruthven@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/336441
Tested-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Mary Ruthven
2016-03-30 10:27:58 -07:00
committed by chrome-bot
parent 55032aa123
commit fa643a9fc7
10 changed files with 461 additions and 360 deletions

View File

@@ -29,6 +29,8 @@
#define CONFIG_USB_HID
#define CONFIG_USB_BLOB
#define CONFIG_STREAM_USB
#define CONFIG_USB_PID 0x5014
/* Enable SPI Slave (SPS) module */

View File

@@ -18,7 +18,6 @@
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(BLOB, blob_task, NULL, TASK_STACK_SIZE) \
TASK_NOTEST(TPM, tpm_task, NULL, 8192) \
TASK_NOTEST(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)

74
chip/g/blob.c Normal file
View File

@@ -0,0 +1,74 @@
/* Copyright 2015 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.
*/
/* Handle an opaque blob of data */
#include "common.h"
#include "console.h"
#include "consumer.h"
#include "queue.h"
#include "queue_policies.h"
#include "producer.h"
#include "task.h"
#include "usb-stream.h"
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
struct consumer const blob_consumer;
struct usb_stream_config const usb_blob;
static struct queue const blob_to_usb = QUEUE_DIRECT(64, uint8_t,
null_producer,
usb_blob.consumer);
static struct queue const usb_to_blob = QUEUE_DIRECT(64, uint8_t,
usb_blob.producer,
blob_consumer);
USB_STREAM_CONFIG(usb_blob,
USB_IFACE_BLOB,
USB_STR_BLOB_NAME,
USB_EP_BLOB,
USB_MAX_PACKET_SIZE,
USB_MAX_PACKET_SIZE,
usb_to_blob,
blob_to_usb)
static void blob_written(struct consumer const *consumer, size_t count)
{
int i;
uint8_t buf[USB_MAX_PACKET_SIZE];
count = QUEUE_REMOVE_UNITS(consumer->queue, buf, count);
CPRINTS("Received: count=%d buf=((%s))", count, buf);
/*
* Just to have something to test to begin with, we'll
* implement "tr a-zA-Z A-Za-z" and return the result.
*/
for (i = 0; i < count; i++) {
char tmp = buf[i];
if (tmp >= 'a' && tmp <= 'z')
buf[i] = tmp - ('a' - 'A');
else if (tmp >= 'A' && tmp <= 'Z')
buf[i] = tmp + ('a' - 'A');
}
count = QUEUE_ADD_UNITS(&blob_to_usb, buf, count);
CPRINTS("Sending: count=%d buf=((%s))", count, buf);
}
static void blob_flush(struct consumer const *consumer)
{
}
struct consumer const blob_consumer = {
.queue = &usb_to_blob,
.ops = &((struct consumer_ops const) {
.written = blob_written,
.flush = blob_flush,
}),
};

View File

@@ -47,7 +47,8 @@ chip-$(CONFIG_WATCHDOG)+=watchdog.o
chip-$(CONFIG_USB)+=usb.o usb_endpoints.o
chip-$(CONFIG_USB_CONSOLE)+=usb_console.o
chip-$(CONFIG_USB_HID)+=usb_hid.o
chip-$(CONFIG_USB_BLOB)+=usb_blob.o
chip-$(CONFIG_USB_BLOB)+=blob.o
chip-$(CONFIG_STREAM_USB)+=usb-stream.o
chip-$(CONFIG_LOW_POWER_IDLE)+=idle.o

191
chip/g/usb-stream.c Normal file
View File

@@ -0,0 +1,191 @@
/* Copyright 2015 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 "registers.h"
#include "usb-stream.h"
/* Let the USB HW IN-to-host FIFO transmit some bytes */
static void usb_enable_tx(struct usb_stream_config const *config, int len)
{
config->in_desc->flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY |
DIEPDMA_IOC | DIEPDMA_TXBYTES(len);
GR_USB_DIEPCTL(config->endpoint) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
/* Let the USB HW OUT-from-host FIFO receive some bytes */
static void usb_enable_rx(struct usb_stream_config const *config, int len)
{
config->out_desc->flags = DOEPDMA_RXBYTES(len) | DOEPDMA_LAST |
DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(config->endpoint) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
/* True if the HW Rx/OUT FIFO has bytes for us. */
static inline int rx_fifo_is_ready(struct usb_stream_config const *config)
{
return (config->out_desc->flags & DOEPDMA_BS_MASK) ==
DOEPDMA_BS_DMA_DONE;
}
/*
* This function tries to shove new bytes from the USB host into the queue for
* consumption elsewhere. It is invoked either by a HW interrupt (telling us we
* have new bytes from the USB host), or by whoever is reading bytes out of the
* other end of the queue (telling us that there's now more room in the queue
* if we still have bytes to shove in there).
*/
int rx_stream_handler(struct usb_stream_config const *config)
{
/*
* The HW FIFO buffer (rx_ram) is always filled from [0] by the
* hardware. The rx_in_fifo variable counts how many bytes of that
* buffer are actually valid, and is calculated from the HW DMA
* descriptor table. The descriptor is updated by the hardware, and it
* and rx_ram remains valid and unchanged until software tells the
* the hardware engine to accept more input.
*/
int rx_in_fifo, rx_left;
/*
* The rx_handled variable tracks how many of the bytes in the HW FIFO
* we've copied into the incoming queue. The queue may not accept all
* of them at once, so we have to keep track of where we are so that
* the next time this function is called we can try to shove the rest
* of the HW FIFO bytes into the queue.
*/
static int rx_handled;
/*
* How many of the HW FIFO bytes have we not yet handled? We need to
* know both where we are in the buffer and how many bytes we haven't
* yet enqueued. One can be calculated from the other as long as we
* know rx_in_fifo, but we need at least one static variable.
*/
rx_in_fifo = config->rx_size
- (config->out_desc->flags & DOEPDMA_RXBYTES_MASK);
rx_left = rx_in_fifo - rx_handled;
/* If we have some, try to shove them into the queue */
if (rx_left) {
size_t added = QUEUE_ADD_UNITS(
config->producer.queue, config->rx_ram + rx_handled,
rx_left);
rx_handled += added;
rx_left -= added;
}
/*
* When we've handled all the bytes in the queue ("rx_in_fifo ==
* rx_handled" and "rx_left == 0" indicate the same thing), we can
* reenable the USB HW to go fetch more.
*/
if (!rx_left) {
rx_handled = 0;
usb_enable_rx(config, config->rx_size);
}
return rx_handled;
}
/* Rx/OUT interrupt handler */
void usb_stream_rx(struct usb_stream_config const *config)
{
/* Wake up the Rx FIFO handler */
hook_call_deferred(config->deferred_rx, 0);
GR_USB_DOEPINT(config->endpoint) = 0xffffffff;
}
/* True if the Tx/IN FIFO can take some bytes from us. */
static inline int tx_fifo_is_ready(struct usb_stream_config const *config)
{
uint32_t status = config->in_desc->flags & DIEPDMA_BS_MASK;
return status == DIEPDMA_BS_DMA_DONE || status == DIEPDMA_BS_HOST_BSY;
}
/* Try to send some bytes to the host */
int tx_stream_handler(struct usb_stream_config const *config)
{
size_t count;
if (!*config->is_reset)
return 0;
count = QUEUE_REMOVE_UNITS(config->consumer.queue, config->tx_ram,
config->tx_size);
if (count)
usb_enable_tx(config, count);
return count;
}
/* Tx/IN interrupt handler */
void usb_stream_tx(struct usb_stream_config const *config)
{
/* Wake up the Tx FIFO handler */
hook_call_deferred(config->deferred_tx, 0);
/* clear the Tx/IN interrupts */
GR_USB_DIEPINT(config->endpoint) = 0xffffffff;
}
void usb_stream_reset(struct usb_stream_config const *config)
{
config->out_desc->flags = DOEPDMA_RXBYTES(config->tx_size) |
DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY |
DOEPDMA_IOC;
config->out_desc->addr = config->rx_ram;
GR_USB_DOEPDMA(config->endpoint) = (uint32_t)config->out_desc;
config->in_desc->flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY |
DIEPDMA_IOC;
config->in_desc->addr = config->tx_ram;
GR_USB_DIEPDMA(config->endpoint) = (uint32_t)config->in_desc;
GR_USB_DOEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
DXEPCTL_CNAK | DXEPCTL_EPENA;
GR_USB_DIEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
DXEPCTL_TXFNUM(config->endpoint);
GR_USB_DAINTMSK |= DAINT_INEP(config->endpoint) |
DAINT_OUTEP(config->endpoint);
*config->is_reset = 1;
/* Flush any queued data */
hook_call_deferred(config->deferred_tx, 0);
hook_call_deferred(config->deferred_rx, 0);
}
static void usb_read(struct producer const *producer, size_t count)
{
struct usb_stream_config const *config =
DOWNCAST(producer, struct usb_stream_config, producer);
hook_call_deferred(config->deferred_rx, 0);
}
static void usb_written(struct consumer const *consumer, size_t count)
{
struct usb_stream_config const *config =
DOWNCAST(consumer, struct usb_stream_config, consumer);
hook_call_deferred(config->deferred_tx, 0);
}
static void usb_flush(struct consumer const *consumer)
{
struct usb_stream_config const *config =
DOWNCAST(consumer, struct usb_stream_config, consumer);
while (tx_fifo_is_ready(config) && queue_count(consumer->queue))
;
}
struct producer_ops const usb_stream_producer_ops = {
.read = usb_read,
};
struct consumer_ops const usb_stream_consumer_ops = {
.written = usb_written,
.flush = usb_flush,
};

192
chip/g/usb-stream.h Normal file
View File

@@ -0,0 +1,192 @@
/* 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.
*/
#ifndef __CROS_EC_USB_STREAM_H
#define __CROS_EC_USB_STREAM_H
/* USB STREAM driver for Chrome EC */
#include "compile_time_macros.h"
#include "consumer.h"
#include "hooks.h"
#include "registers.h"
#include "producer.h"
#include "queue.h"
#include "usb_descriptor.h"
/*
* Compile time Per-USB stream configuration stored in flash. Instances of this
* structure are provided by the user of the USB stream. This structure binds
* together all information required to operate a USB stream.
*/
struct usb_stream_config {
/*
* Endpoint index, and pointers to the USB packet RAM buffers.
*/
int endpoint;
int *is_reset;
/*
* Deferred function to call to handle USB and Queue request.
*/
void (*deferred_tx)(void);
void (*deferred_rx)(void);
int tx_size;
int rx_size;
uint8_t *tx_ram;
uint8_t *rx_ram;
struct consumer consumer;
struct producer producer;
struct g_usb_desc *out_desc;
struct g_usb_desc *in_desc;
};
/*
* These function tables are defined by the USB Stream driver and are used to
* initialize the consumer and producer in the usb_stream_config.
*/
extern struct consumer_ops const usb_stream_consumer_ops;
extern struct producer_ops const usb_stream_producer_ops;
/*
* Convenience macro for defining USB streams and their associated state and
* buffers.
*
* NAME is used to construct the names of the packet RAM buffers, trampoline
* functions, usb_stream_state struct, and usb_stream_config struct, the
* latter is just called NAME.
*
* INTERFACE is the index of the USB interface to associate with this
* stream.
*
* INTERFACE_NAME is the index of the USB string descriptor (iInterface).
*
* ENDPOINT is the index of the USB bulk endpoint used for receiving and
* transmitting bytes.
*
* RX_SIZE and TX_SIZE are the number of bytes of USB packet RAM to allocate
* for the RX and TX packets respectively. The valid values for these
* parameters are dictated by the USB peripheral.
*
* RX_QUEUE and TX_QUEUE are the names of the RX and TX queues that this driver
* should write to and read from respectively.
*/
/*
* The following assertions can not be made because they require access to
* non-const fields, but should be kept in mind.
*
* BUILD_ASSERT(RX_QUEUE.buffer_units >= RX_SIZE);
* BUILD_ASSERT(TX_QUEUE.buffer_units >= TX_SIZE);
* BUILD_ASSERT(RX_QUEUE.unit_bytes == 1);
* BUILD_ASSERT(TX_QUEUE.unit_bytes == 1);
*/
#define USB_STREAM_CONFIG(NAME, \
INTERFACE, \
INTERFACE_NAME, \
ENDPOINT, \
RX_SIZE, \
TX_SIZE, \
RX_QUEUE, \
TX_QUEUE) \
\
static struct g_usb_desc CONCAT2(NAME, _out_desc_); \
static struct g_usb_desc CONCAT2(NAME, _in_desc_); \
static uint8_t CONCAT2(NAME, _buf_rx_)[RX_SIZE]; \
static uint8_t CONCAT2(NAME, _buf_tx_)[TX_SIZE]; \
static int CONCAT2(NAME, _is_reset_); \
static void CONCAT2(NAME, _deferred_tx_)(void); \
static void CONCAT2(NAME, _deferred_rx_)(void); \
struct usb_stream_config const NAME = { \
.endpoint = ENDPOINT, \
.is_reset = &CONCAT2(NAME, _is_reset_), \
.in_desc = &CONCAT2(NAME, _in_desc_), \
.out_desc = &CONCAT2(NAME, _out_desc_), \
.deferred_tx = CONCAT2(NAME, _deferred_tx_), \
.deferred_rx = CONCAT2(NAME, _deferred_rx_), \
.tx_size = TX_SIZE, \
.rx_size = RX_SIZE, \
.tx_ram = CONCAT2(NAME, _buf_tx_), \
.rx_ram = CONCAT2(NAME, _buf_rx_), \
.consumer = { \
.queue = &TX_QUEUE, \
.ops = &usb_stream_consumer_ops, \
}, \
.producer = { \
.queue = &RX_QUEUE, \
.ops = &usb_stream_producer_ops, \
}, \
}; \
const struct usb_interface_descriptor \
USB_IFACE_DESC(INTERFACE) = { \
.bLength = USB_DT_INTERFACE_SIZE, \
.bDescriptorType = USB_DT_INTERFACE, \
.bInterfaceNumber = INTERFACE, \
.bAlternateSetting = 0, \
.bNumEndpoints = 2, \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
.bInterfaceSubClass = USB_SUBCLASS_GOOGLE_SERIAL, \
.bInterfaceProtocol = USB_PROTOCOL_GOOGLE_SERIAL, \
.iInterface = INTERFACE_NAME, \
}; \
const struct usb_endpoint_descriptor \
USB_EP_DESC(INTERFACE, 0) = { \
.bLength = USB_DT_ENDPOINT_SIZE, \
.bDescriptorType = USB_DT_ENDPOINT, \
.bEndpointAddress = 0x80 | ENDPOINT, \
.bmAttributes = 0x02 /* Bulk IN */, \
.wMaxPacketSize = TX_SIZE, \
.bInterval = 10, \
}; \
const struct usb_endpoint_descriptor \
USB_EP_DESC(INTERFACE, 1) = { \
.bLength = USB_DT_ENDPOINT_SIZE, \
.bDescriptorType = USB_DT_ENDPOINT, \
.bEndpointAddress = ENDPOINT, \
.bmAttributes = 0x02 /* Bulk OUT */, \
.wMaxPacketSize = RX_SIZE, \
.bInterval = 0, \
}; \
static void CONCAT2(NAME, _deferred_tx_)(void) \
{ tx_stream_handler(&NAME); } \
DECLARE_DEFERRED(CONCAT2(NAME, _deferred_tx_)); \
static void CONCAT2(NAME, _deferred_rx_)(void) \
{ rx_stream_handler(&NAME); } \
DECLARE_DEFERRED(CONCAT2(NAME, _deferred_rx_)); \
static void CONCAT2(NAME, _ep_tx)(void) \
{ \
usb_stream_tx(&NAME); \
} \
static void CONCAT2(NAME, _ep_rx)(void) \
{ \
usb_stream_rx(&NAME); \
} \
static void CONCAT2(NAME, _ep_reset)(void) \
{ \
usb_stream_reset(&NAME); \
} \
USB_DECLARE_EP(ENDPOINT, \
CONCAT2(NAME, _ep_tx), \
CONCAT2(NAME, _ep_rx), \
CONCAT2(NAME, _ep_reset)); \
/*
* Handle USB and Queue request in a deferred callback.
*/
int rx_stream_handler(struct usb_stream_config const *config);
int tx_stream_handler(struct usb_stream_config const *config);
/*
* These functions are used by the trampoline functions defined above to
* connect USB endpoint events with the generic USB stream driver.
*/
void usb_stream_tx(struct usb_stream_config const *config);
void usb_stream_rx(struct usb_stream_config const *config);
void usb_stream_reset(struct usb_stream_config const *config);
#endif /* __CROS_EC_USB_STREAM_H */

View File

@@ -1,218 +0,0 @@
/* Copyright 2015 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 "blob.h"
#include "common.h"
#include "link_defs.h"
#include "printf.h"
#include "registers.h"
#include "timer.h"
#include "usb_descriptor.h"
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
static int is_reset;
/* USB-Serial descriptors */
const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_BLOB) =
{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_IFACE_BLOB,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 0, /* TODO(wfrichar): TBD */
.bInterfaceProtocol = 0, /* TODO(wfrichar): TBD */
.iInterface = USB_STR_BLOB_NAME,
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_BLOB, 0) =
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x80 | USB_EP_BLOB,
.bmAttributes = 0x02 /* Bulk IN */,
.wMaxPacketSize = USB_MAX_PACKET_SIZE,
.bInterval = 10
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_BLOB, 1) =
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_EP_BLOB,
.bmAttributes = 0x02 /* Bulk OUT */,
.wMaxPacketSize = USB_MAX_PACKET_SIZE,
.bInterval = 0
};
static uint8_t ep_buf_tx[USB_MAX_PACKET_SIZE];
static uint8_t ep_buf_rx[USB_MAX_PACKET_SIZE];
static struct g_usb_desc ep_out_desc;
static struct g_usb_desc ep_in_desc;
/* Let the USB HW IN-to-host FIFO transmit some bytes */
static void usb_enable_tx(int len)
{
ep_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC |
DIEPDMA_TXBYTES(len);
GR_USB_DIEPCTL(USB_EP_BLOB) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
/* Let the USB HW OUT-from-host FIFO receive some bytes */
static void usb_enable_rx(int len)
{
ep_out_desc.flags = DOEPDMA_RXBYTES(len) |
DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(USB_EP_BLOB) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
/* True if the HW Rx/OUT FIFO has bytes for us. */
static inline int rx_fifo_is_ready(void)
{
return (ep_out_desc.flags & DOEPDMA_BS_MASK) == DOEPDMA_BS_DMA_DONE;
}
/*
* This function tries to shove new bytes from the USB host into the queue for
* consumption elsewhere. It is invoked either by a HW interrupt (telling us we
* have new bytes from the USB host), or by whoever is reading bytes out of the
* other end of the queue (telling us that there's now more room in the queue
* if we still have bytes to shove in there).
*/
static void rx_fifo_handler(void)
{
/*
* The HW FIFO buffer (ep_buf_rx) is always filled from [0] by the
* hardware. The rx_in_fifo variable counts how many bytes of that
* buffer are actually valid, and is calculated from the HW DMA
* descriptor table. The descriptor is updated by the hardware, and it
* and ep_buf_rx remains valid and unchanged until software tells the
* the hardware engine to accept more input.
*/
int rx_in_fifo, rx_left;
/*
* The rx_handled variable tracks how many of the bytes in the HW FIFO
* we've copied into the incoming queue. The queue may not accept all
* of them at once, so we have to keep track of where we are so that
* the next time this function is called we can try to shove the rest
* of the HW FIFO bytes into the queue.
*/
static int rx_handled;
/* If the HW FIFO isn't ready, then we're waiting for more bytes */
if (!rx_fifo_is_ready())
return;
/*
* How many of the HW FIFO bytes have we not yet handled? We need to
* know both where we are in the buffer and how many bytes we haven't
* yet enqueued. One can be calculated from the other as long as we
* know rx_in_fifo, but we need at least one static variable.
*/
rx_in_fifo = USB_MAX_PACKET_SIZE
- (ep_out_desc.flags & DOEPDMA_RXBYTES_MASK);
rx_left = rx_in_fifo - rx_handled;
/* If we have some, try to shove them into the queue */
if (rx_left) {
size_t added = put_bytes_to_blob(ep_buf_rx + rx_handled,
rx_left);
rx_handled += added;
rx_left -= added;
}
/*
* When we've handled all the bytes in the queue ("rx_in_fifo ==
* rx_handled" and "rx_left == 0" indicate the same thing), we can
* reenable the USB HW to go fetch more.
*/
if (!rx_left) {
rx_handled = 0;
usb_enable_rx(USB_MAX_PACKET_SIZE);
}
}
DECLARE_DEFERRED(rx_fifo_handler);
void blob_is_ready_for_more_bytes(void)
{
hook_call_deferred(rx_fifo_handler, 0);
}
/* Rx/OUT interrupt handler */
static void con_ep_rx(void)
{
/* Wake up the Rx FIFO handler */
hook_call_deferred(rx_fifo_handler, 0);
/* clear the RX/OUT interrupts */
GR_USB_DOEPINT(USB_EP_BLOB) = 0xffffffff;
}
/* True if the Tx/IN FIFO can take some bytes from us. */
static inline int tx_fifo_is_ready(void)
{
uint32_t status = ep_in_desc.flags & DIEPDMA_BS_MASK;
return status == DIEPDMA_BS_DMA_DONE || status == DIEPDMA_BS_HOST_BSY;
}
/* Try to send some bytes to the host */
static void tx_fifo_handler(void)
{
size_t count;
if (!is_reset)
return;
/* If the HW FIFO isn't ready, then we can't do anything right now. */
if (!tx_fifo_is_ready())
return;
count = get_bytes_from_blob(ep_buf_tx, USB_MAX_PACKET_SIZE);
if (count)
usb_enable_tx(count);
}
DECLARE_DEFERRED(tx_fifo_handler);
void blob_is_ready_to_emit_bytes(void)
{
hook_call_deferred(tx_fifo_handler, 0);
}
/* Tx/IN interrupt handler */
static void con_ep_tx(void)
{
/* Wake up the Tx FIFO handler */
hook_call_deferred(tx_fifo_handler, 0);
/* clear the Tx/IN interrupts */
GR_USB_DIEPINT(USB_EP_BLOB) = 0xffffffff;
}
static void ep_reset(void)
{
ep_out_desc.flags = DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE) |
DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
ep_out_desc.addr = ep_buf_rx;
GR_USB_DOEPDMA(USB_EP_BLOB) = (uint32_t)&ep_out_desc;
ep_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY | DIEPDMA_IOC;
ep_in_desc.addr = ep_buf_tx;
GR_USB_DIEPDMA(USB_EP_BLOB) = (uint32_t)&ep_in_desc;
GR_USB_DOEPCTL(USB_EP_BLOB) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
DXEPCTL_CNAK | DXEPCTL_EPENA;
GR_USB_DIEPCTL(USB_EP_BLOB) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
DXEPCTL_TXFNUM(USB_EP_BLOB);
GR_USB_DAINTMSK |= DAINT_INEP(USB_EP_BLOB) | DAINT_OUTEP(USB_EP_BLOB);
is_reset = 1;
/* Flush any queued data */
hook_call_deferred(tx_fifo_handler, 0);
hook_call_deferred(rx_fifo_handler, 0);
}
USB_DECLARE_EP(USB_EP_BLOB, con_ep_tx, con_ep_rx, ep_reset);

View File

@@ -1,113 +0,0 @@
/* Copyright 2015 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.
*/
/* Handle an opaque blob of data */
#include "blob.h"
#include "common.h"
#include "console.h"
#include "printf.h"
#include "queue.h"
#include "task.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
#define INCOMING_QUEUE_SIZE 100
#define OUTGOING_QUEUE_SIZE 100
static void incoming_add(struct queue_policy const *queue_policy, size_t count)
{
task_wake(TASK_ID_BLOB);
}
static void incoming_remove(struct queue_policy const *queue_policy,
size_t count)
{
blob_is_ready_for_more_bytes();
}
static struct queue_policy const incoming_policy = {
.add = incoming_add,
.remove = incoming_remove,
};
static void outgoing_add(struct queue_policy const *queue_policy, size_t count)
{
blob_is_ready_to_emit_bytes();
}
static void outgoing_remove(struct queue_policy const *queue_policy,
size_t count)
{
/* we don't care */
}
static struct queue_policy const outgoing_policy = {
.add = outgoing_add,
.remove = outgoing_remove,
};
static struct queue const incoming_q = QUEUE(INCOMING_QUEUE_SIZE, uint8_t,
incoming_policy);
static struct queue const outgoing_q = QUEUE(OUTGOING_QUEUE_SIZE, uint8_t,
outgoing_policy);
/* Call this to send data to the blob-handler */
size_t put_bytes_to_blob(uint8_t *buffer, size_t count)
{
return QUEUE_ADD_UNITS(&incoming_q, buffer, count);
}
/* Call this to get data back fom the blob-handler */
size_t get_bytes_from_blob(uint8_t *buffer, size_t count)
{
return QUEUE_REMOVE_UNITS(&outgoing_q, buffer, count);
}
#define WEAK_FUNC(FOO) \
void __ ## FOO(void) {} \
void FOO(void) \
__attribute__((weak, alias(STRINGIFY(CONCAT2(__, FOO)))))
/* Default callbacks for outsiders */
WEAK_FUNC(blob_is_ready_for_more_bytes);
WEAK_FUNC(blob_is_ready_to_emit_bytes);
/* Do the magic */
void blob_task(void)
{
static uint8_t buf[INCOMING_QUEUE_SIZE];
size_t count, i;
task_id_t me = task_get_current();
while (1) {
CPRINTS("task %d waiting for events...", me);
task_wait_event(-1);
CPRINTS("task %d awakened!", me);
count = QUEUE_REMOVE_UNITS(&incoming_q, buf, sizeof(buf));
CPRINTS("task %d gets: count=%d buf=((%s))", me, count, buf);
/*
* Just to have something to test to begin with, we'll
* implement "tr a-zA-Z A-Za-z" and return the result.
*/
for (i = 0; i < count; i++) {
char tmp = buf[i];
if (tmp >= 'a' && tmp <= 'z')
buf[i] = tmp - ('a' - 'A');
else if (tmp >= 'A' && tmp <= 'Z')
buf[i] = tmp + ('a' - 'A');
}
count = QUEUE_ADD_UNITS(&outgoing_q, buf, count);
CPRINTS("task %d puts: count=%d buf=((%s))", me, buf);
}
}

View File

@@ -89,7 +89,6 @@ common-$(CONFIG_USB_PD_TCPC)+=usb_pd_tcpc.o
common-$(CONFIG_VBOOT_HASH)+=sha256.o vboot_hash.o
common-$(CONFIG_VSTORE)+=vstore.o
common-$(CONFIG_WIRELESS)+=wireless.o
common-$(HAS_TASK_BLOB)+=blob.o
common-$(HAS_TASK_CHIPSET)+=chipset.o
common-$(HAS_TASK_CONSOLE)+=console.o console_output.o uart_buffering.o
common-$(HAS_TASK_CONSOLE)+=memory_commands.o

View File

@@ -1,26 +0,0 @@
/* Copyright 2015 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.
*/
/* Generic API for handling opaque blobs of data. */
#ifndef __CROS_EC_BLOB_H
#define __CROS_EC_BLOB_H
#include <stddef.h>
#include <stdint.h>
/* Call this to send data to the blob-handler */
size_t put_bytes_to_blob(uint8_t *buffer, size_t count);
/* Call this to get data back fom the blob-handler */
size_t get_bytes_from_blob(uint8_t *buffer, size_t count);
/* Implement this to be notified when the blob-handler can take more data */
void blob_is_ready_for_more_bytes(void);
/* Implement this to be notified when the blob-handler has data to give us */
void blob_is_ready_to_emit_bytes(void);
#endif /* __CROS_EC_BLOB_H */