| /* Copyright (c) 2014 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 |
| |
| #if defined(CHIP_FAMILY_STM32F4) |
| #include "usb_dwc_stream.h" |
| #else |
| |
| /* STM32 USB STREAM driver for Chrome EC */ |
| |
| #include "compile_time_macros.h" |
| #include "consumer.h" |
| #include "hooks.h" |
| #include "producer.h" |
| #include "queue.h" |
| #include "usart.h" |
| #include "usb_descriptor.h" |
| #include "usb_hw.h" |
| |
| #include <stdint.h> |
| |
| /* |
| * Per-USB stream state stored in RAM. Zero initialization of this structure |
| * by the BSS initialization leaves it in a valid and correctly initialized |
| * state, so there is no need currently for a usb_stream_init style function. |
| */ |
| struct usb_stream_state { |
| /* |
| * Flag indicating that there is a full RX buffer in the USB packet RAM |
| * that we were not able to move into the RX queue because there was |
| * not enough room when the packet was initially received. The |
| * producer read operation checks this flag so that once there is |
| * room in the queue it can copy the RX buffer into the queue and |
| * restart USB reception by marking the RX buffer as VALID. |
| */ |
| int rx_waiting; |
| /* |
| * Flag indicating that the incoming data on the USB link are discarded. |
| */ |
| int rx_disabled; |
| }; |
| |
| /* |
| * 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 { |
| /* |
| * Pointer to usb_stream_state structure. The state structure |
| * maintains per USB stream information. |
| */ |
| struct usb_stream_state volatile *state; |
| |
| /* |
| * Endpoint index, and pointers to the USB packet RAM buffers. |
| */ |
| int endpoint; |
| |
| /* |
| * Deferred function to call to handle USB and Queue request. |
| */ |
| const struct deferred_data *deferred; |
| |
| size_t rx_size; |
| size_t tx_size; |
| |
| usb_uint *rx_ram; |
| usb_uint *tx_ram; |
| |
| struct consumer consumer; |
| struct producer producer; |
| }; |
| |
| /* |
| * 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_CLASS, INTERFACE_SUBCLASS, INTERFACE_PROTOCOL are the |
| * .bInterfaceClass, .bInterfaceSubClass, and .bInterfaceProtocol fields |
| * respectively in the USB interface descriptor. |
| * |
| * 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_FULL(NAME, \ |
| INTERFACE, \ |
| INTERFACE_CLASS, \ |
| INTERFACE_SUBCLASS, \ |
| INTERFACE_PROTOCOL, \ |
| INTERFACE_NAME, \ |
| ENDPOINT, \ |
| RX_SIZE, \ |
| TX_SIZE, \ |
| RX_QUEUE, \ |
| TX_QUEUE) \ |
| \ |
| BUILD_ASSERT(RX_SIZE <= USB_MAX_PACKET_SIZE); \ |
| BUILD_ASSERT(TX_SIZE <= USB_MAX_PACKET_SIZE); \ |
| BUILD_ASSERT(RX_SIZE > 0); \ |
| BUILD_ASSERT(TX_SIZE > 0); \ |
| BUILD_ASSERT((RX_SIZE < 64 && (RX_SIZE & 0x01) == 0) || \ |
| (RX_SIZE < 1024 && (RX_SIZE & 0x1f) == 0)); \ |
| BUILD_ASSERT((TX_SIZE < 64 && (TX_SIZE & 0x01) == 0) || \ |
| (TX_SIZE < 1024 && (TX_SIZE & 0x1f) == 0)); \ |
| \ |
| static usb_uint CONCAT2(NAME, _ep_rx_buffer)[RX_SIZE / 2] __usb_ram; \ |
| static usb_uint CONCAT2(NAME, _ep_tx_buffer)[TX_SIZE / 2] __usb_ram; \ |
| static struct usb_stream_state CONCAT2(NAME, _state); \ |
| static void CONCAT2(NAME, _deferred_)(void); \ |
| DECLARE_DEFERRED(CONCAT2(NAME, _deferred_)); \ |
| struct usb_stream_config const NAME = { \ |
| .state = &CONCAT2(NAME, _state), \ |
| .endpoint = ENDPOINT, \ |
| .deferred = &CONCAT2(NAME, _deferred__data), \ |
| .rx_size = RX_SIZE, \ |
| .tx_size = TX_SIZE, \ |
| .rx_ram = CONCAT2(NAME, _ep_rx_buffer), \ |
| .tx_ram = CONCAT2(NAME, _ep_tx_buffer), \ |
| .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 = INTERFACE_CLASS, \ |
| .bInterfaceSubClass = INTERFACE_SUBCLASS, \ |
| .bInterfaceProtocol = INTERFACE_PROTOCOL, \ |
| .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, _ep_tx)(void) \ |
| { \ |
| usb_stream_tx(&NAME); \ |
| } \ |
| static void CONCAT2(NAME, _ep_rx)(void) \ |
| { \ |
| usb_stream_rx(&NAME); \ |
| } \ |
| static void CONCAT2(NAME, _ep_event)(enum usb_ep_event evt) \ |
| { \ |
| usb_stream_event(&NAME, evt); \ |
| } \ |
| USB_DECLARE_EP(ENDPOINT, \ |
| CONCAT2(NAME, _ep_tx), \ |
| CONCAT2(NAME, _ep_rx), \ |
| CONCAT2(NAME, _ep_event)); \ |
| static void CONCAT2(NAME, _deferred_)(void) \ |
| { usb_stream_deferred(&NAME); } |
| |
| /* This is a short version for declaring Google serial endpoints */ |
| #define USB_STREAM_CONFIG(NAME, \ |
| INTERFACE, \ |
| INTERFACE_NAME, \ |
| ENDPOINT, \ |
| RX_SIZE, \ |
| TX_SIZE, \ |
| RX_QUEUE, \ |
| TX_QUEUE) \ |
| USB_STREAM_CONFIG_FULL(NAME, \ |
| INTERFACE, \ |
| USB_CLASS_VENDOR_SPEC, \ |
| USB_SUBCLASS_GOOGLE_SERIAL, \ |
| USB_PROTOCOL_GOOGLE_SERIAL, \ |
| INTERFACE_NAME, \ |
| ENDPOINT, \ |
| RX_SIZE, \ |
| TX_SIZE, \ |
| RX_QUEUE, \ |
| TX_QUEUE) |
| |
| /* Declare a utility interface for setting parity/baud. */ |
| #define USB_USART_IFACE(NAME, INTERFACE, USART_CFG) \ |
| static int CONCAT2(NAME, _interface_)(usb_uint *rx_buf, \ |
| usb_uint *tx_buf) \ |
| { return usb_usart_interface(&NAME, &USART_CFG, INTERFACE, \ |
| rx_buf, tx_buf); } \ |
| USB_DECLARE_IFACE(INTERFACE, \ |
| CONCAT2(NAME, _interface_)) |
| |
| /* This is a medium version for declaring Google serial endpoints */ |
| #define USB_STREAM_CONFIG_USART_IFACE(NAME, \ |
| INTERFACE, \ |
| INTERFACE_NAME, \ |
| ENDPOINT, \ |
| RX_SIZE, \ |
| TX_SIZE, \ |
| RX_QUEUE, \ |
| TX_QUEUE, \ |
| USART_CFG) \ |
| USB_STREAM_CONFIG_FULL(NAME, \ |
| INTERFACE, \ |
| USB_CLASS_VENDOR_SPEC, \ |
| USB_SUBCLASS_GOOGLE_SERIAL, \ |
| USB_PROTOCOL_GOOGLE_SERIAL, \ |
| INTERFACE_NAME, \ |
| ENDPOINT, \ |
| RX_SIZE, \ |
| TX_SIZE, \ |
| RX_QUEUE, \ |
| TX_QUEUE); \ |
| USB_USART_IFACE(NAME, INTERFACE, USART_CFG) |
| |
| /* |
| * Handle USB and Queue request in a deferred callback. |
| */ |
| void usb_stream_deferred(struct usb_stream_config const *config); |
| |
| /* |
| * Handle control interface requests. |
| */ |
| enum usb_usart { |
| USB_USART_REQ_PARITY = 0, |
| USB_USART_SET_PARITY = 1, |
| USB_USART_REQ_BAUD = 2, |
| USB_USART_SET_BAUD = 3, |
| }; |
| int usb_usart_interface(struct usb_stream_config const *config, |
| struct usart_config const *usart, |
| int interface, usb_uint *rx_buf, usb_uint *tx_buf); |
| |
| /* |
| * 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_event(struct usb_stream_config const *config, |
| enum usb_ep_event evt); |
| |
| #endif /* defined(CHIP_FAMILY_STM32F4) */ |
| #endif /* __CROS_EC_USB_STREAM_H */ |