/* 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. */ #include "atomic.h" #include "common.h" #include "config.h" #include "link_defs.h" #include "printf.h" #include "registers.h" #include "task.h" #include "timer.h" #include "util.h" #include "usart.h" #include "usb_hw.h" #include "usb-stream.h" static size_t rx_read(struct usb_stream_config const *config) { uintptr_t address = btable_ep[config->endpoint].rx_addr; size_t count = btable_ep[config->endpoint].rx_count & 0x3ff; /* * Only read the received USB packet if there is enough space in the * receive queue. */ if (count > queue_space(config->producer.queue)) return 0; return queue_add_memcpy(config->producer.queue, (void *) address, count, memcpy_from_usbram); } static size_t tx_write(struct usb_stream_config const *config) { uintptr_t address = btable_ep[config->endpoint].tx_addr; size_t count = queue_remove_memcpy(config->consumer.queue, (void *) address, config->tx_size, memcpy_to_usbram); btable_ep[config->endpoint].tx_count = count; return count; } static int tx_valid(struct usb_stream_config const *config) { return (STM32_USB_EP(config->endpoint) & EP_TX_MASK) == EP_TX_VALID; } static int rx_valid(struct usb_stream_config const *config) { return (STM32_USB_EP(config->endpoint) & EP_RX_MASK) == EP_RX_VALID; } static int rx_disabled(struct usb_stream_config const *config) { return config->state->rx_disabled; } 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, 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, 0); } struct producer_ops const usb_stream_producer_ops = { .read = usb_read, }; struct consumer_ops const usb_stream_consumer_ops = { .written = usb_written, }; void usb_stream_deferred(struct usb_stream_config const *config) { if (!tx_valid(config) && tx_write(config)) STM32_TOGGLE_EP(config->endpoint, EP_TX_MASK, EP_TX_VALID, 0); if (!rx_valid(config) && !rx_disabled(config) && rx_read(config)) STM32_TOGGLE_EP(config->endpoint, EP_RX_MASK, EP_RX_VALID, 0); } void usb_stream_tx(struct usb_stream_config const *config) { STM32_TOGGLE_EP(config->endpoint, 0, 0, 0); hook_call_deferred(config->deferred, 0); } void usb_stream_rx(struct usb_stream_config const *config) { STM32_TOGGLE_EP(config->endpoint, 0, 0, 0); hook_call_deferred(config->deferred, 0); } static usb_uint usb_ep_rx_size(size_t bytes) { if (bytes < 64) return bytes << 9; else return 0x8000 | ((bytes - 32) << 5); } void usb_stream_event(struct usb_stream_config const *config, enum usb_ep_event evt) { int i; if (evt != USB_EVENT_RESET) return; i = config->endpoint; btable_ep[i].tx_addr = usb_sram_addr(config->tx_ram); btable_ep[i].tx_count = 0; btable_ep[i].rx_addr = usb_sram_addr(config->rx_ram); btable_ep[i].rx_count = usb_ep_rx_size(config->rx_size); config->state->rx_waiting = 0; STM32_USB_EP(i) = ((i << 0) | /* Endpoint Addr*/ (2 << 4) | /* TX NAK */ (0 << 9) | /* Bulk EP */ (rx_disabled(config) ? EP_RX_NAK : EP_RX_VALID)); } 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) { struct usb_setup_packet req; usb_read_setup_packet(rx_buf, &req); if (req.bmRequestType != (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE)) return -1; if (req.wIndex != interface || req.wLength != 0) return -1; switch (req.bRequest) { /* Set parity. */ case USB_USART_SET_PARITY: usart_set_parity(usart, req.wValue); break; /* TODO(nsanders): support reading parity. */ /* TODO(nsanders): support baud. */ default: return -1; } btable_ep[0].tx_count = 0; STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT); return 0; }