From fa643a9fc754e6a5c18181ecb928fa9a5c12e7ae Mon Sep 17 00:00:00 2001 From: Mary Ruthven Date: Wed, 30 Mar 2016 10:27:58 -0700 Subject: 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 Reviewed-on: https://chromium-review.googlesource.com/336441 Tested-by: Bill Richardson Reviewed-by: Bill Richardson --- board/cr50/board.h | 2 + board/cr50/ec.tasklist | 1 - chip/g/blob.c | 74 +++++++++++++++++ chip/g/build.mk | 3 +- chip/g/usb-stream.c | 191 +++++++++++++++++++++++++++++++++++++++++++ chip/g/usb-stream.h | 192 +++++++++++++++++++++++++++++++++++++++++++ chip/g/usb_blob.c | 218 ------------------------------------------------- common/blob.c | 113 ------------------------- common/build.mk | 1 - include/blob.h | 26 ------ 10 files changed, 461 insertions(+), 360 deletions(-) create mode 100644 chip/g/blob.c create mode 100644 chip/g/usb-stream.c create mode 100644 chip/g/usb-stream.h delete mode 100644 chip/g/usb_blob.c delete mode 100644 common/blob.c delete mode 100644 include/blob.h diff --git a/board/cr50/board.h b/board/cr50/board.h index 9fde91dca2..83a370b23e 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -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 */ diff --git a/board/cr50/ec.tasklist b/board/cr50/ec.tasklist index 52f4af3000..c350701b65 100644 --- a/board/cr50/ec.tasklist +++ b/board/cr50/ec.tasklist @@ -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) diff --git a/chip/g/blob.c b/chip/g/blob.c new file mode 100644 index 0000000000..fde66aac9a --- /dev/null +++ b/chip/g/blob.c @@ -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, + }), +}; diff --git a/chip/g/build.mk b/chip/g/build.mk index a98f2e3e8f..e3f283c97f 100644 --- a/chip/g/build.mk +++ b/chip/g/build.mk @@ -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 diff --git a/chip/g/usb-stream.c b/chip/g/usb-stream.c new file mode 100644 index 0000000000..21a06c94e3 --- /dev/null +++ b/chip/g/usb-stream.c @@ -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, +}; diff --git a/chip/g/usb-stream.h b/chip/g/usb-stream.h new file mode 100644 index 0000000000..761065d8b6 --- /dev/null +++ b/chip/g/usb-stream.h @@ -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 */ diff --git a/chip/g/usb_blob.c b/chip/g/usb_blob.c deleted file mode 100644 index 8a0f350549..0000000000 --- a/chip/g/usb_blob.c +++ /dev/null @@ -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); diff --git a/common/blob.c b/common/blob.c deleted file mode 100644 index 5e563598a3..0000000000 --- a/common/blob.c +++ /dev/null @@ -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); - } -} diff --git a/common/build.mk b/common/build.mk index 4995cfe6e8..426f2d412f 100644 --- a/common/build.mk +++ b/common/build.mk @@ -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 diff --git a/include/blob.h b/include/blob.h deleted file mode 100644 index 844e8d638a..0000000000 --- a/include/blob.h +++ /dev/null @@ -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 -#include - -/* 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 */ -- cgit v1.2.1