diff options
Diffstat (limited to 'chip/stm32/usb_dwc_console.c')
-rw-r--r-- | chip/stm32/usb_dwc_console.c | 360 |
1 files changed, 0 insertions, 360 deletions
diff --git a/chip/stm32/usb_dwc_console.c b/chip/stm32/usb_dwc_console.c deleted file mode 100644 index 0d1340fb83..0000000000 --- a/chip/stm32/usb_dwc_console.c +++ /dev/null @@ -1,360 +0,0 @@ -/* 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 "common.h" -#include "config.h" -#include "console.h" -#include "link_defs.h" -#include "printf.h" -#include "queue.h" -#include "registers.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "usb_descriptor.h" -#include "usb_hw.h" - -/* Console output macro */ -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) -#define USB_CONSOLE_TIMEOUT_US (30 * MSEC) - -static int last_tx_ok = 1; - -static int is_reset; -static int is_enabled = 1; -static int is_readonly; - -/* USB-Serial descriptors */ -const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_CONSOLE) = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_IFACE_CONSOLE, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = USB_SUBCLASS_GOOGLE_SERIAL, - .bInterfaceProtocol = USB_PROTOCOL_GOOGLE_SERIAL, - .iInterface = USB_STR_CONSOLE_NAME, -}; -const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_CONSOLE, 0) = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x80 | USB_EP_CONSOLE, - .bmAttributes = 0x02 /* Bulk IN */, - .wMaxPacketSize = USB_MAX_PACKET_SIZE, - .bInterval = 10, -}; -const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_CONSOLE, 1) = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_EP_CONSOLE, - .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 queue const tx_q = QUEUE_NULL(256, uint8_t); -static struct queue const rx_q = QUEUE_NULL(USB_MAX_PACKET_SIZE, uint8_t); - - -struct dwc_usb_ep ep_console_ctl = { - .max_packet = USB_MAX_PACKET_SIZE, - .tx_fifo = USB_EP_CONSOLE, - .out_pending = 0, - .out_data = 0, - .out_databuffer = ep_buf_tx, - .out_databuffer_max = sizeof(ep_buf_tx), - .in_packets = 0, - .in_pending = 0, - .in_data = 0, - .in_databuffer = ep_buf_rx, - .in_databuffer_max = sizeof(ep_buf_rx), -}; - - - -/* Let the USB HW IN-to-host FIFO transmit some bytes */ -static void usb_enable_tx(int len) -{ - struct dwc_usb_ep *ep = &ep_console_ctl; - - ep->in_data = ep->in_databuffer; - ep->in_packets = 1; - ep->in_pending = len; - - GR_USB_DIEPTSIZ(USB_EP_CONSOLE) = 0; - - GR_USB_DIEPTSIZ(USB_EP_CONSOLE) |= DXEPTSIZ_PKTCNT(1); - GR_USB_DIEPTSIZ(USB_EP_CONSOLE) |= DXEPTSIZ_XFERSIZE(len); - GR_USB_DIEPDMA(USB_EP_CONSOLE) = (uint32_t)ep->in_data; - - GR_USB_DIEPCTL(USB_EP_CONSOLE) |= DXEPCTL_CNAK | DXEPCTL_EPENA; -} - -/* Let the USB HW OUT-from-host FIFO receive some bytes */ -static void usb_enable_rx(int len) -{ - struct dwc_usb_ep *ep = &ep_console_ctl; - - ep->out_data = ep->out_databuffer; - ep->out_pending = 0; - - GR_USB_DOEPTSIZ(USB_EP_CONSOLE) = 0; - GR_USB_DOEPTSIZ(USB_EP_CONSOLE) |= DXEPTSIZ_PKTCNT(1); - GR_USB_DOEPTSIZ(USB_EP_CONSOLE) |= DXEPTSIZ_XFERSIZE(len); - GR_USB_DOEPDMA(USB_EP_CONSOLE) = (uint32_t)ep->out_data; - - GR_USB_DOEPCTL(USB_EP_CONSOLE) |= DXEPCTL_CNAK | DXEPCTL_EPENA; -} - -/* True if the HW Rx/OUT FIFO has bytes for us. */ -static inline int rx_fifo_is_ready(void) -{ - struct dwc_usb_ep *ep = &ep_console_ctl; - - return ep->out_pending; -} - -/* - * 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). - */ -char buffer[65]; -static void rx_fifo_handler(void) -{ - struct dwc_usb_ep *ep = &ep_console_ctl; - - int rx_in_fifo; - size_t added; - - if (!rx_fifo_is_ready()) - return; - - rx_in_fifo = ep->out_pending; - added = QUEUE_ADD_UNITS(&rx_q, ep->out_databuffer, rx_in_fifo); - - if (added != rx_in_fifo) - CPRINTF("DROP CONSOLE: %d/%d process\n", added, rx_in_fifo); - - /* wake-up the console task */ - console_has_input(); - - usb_enable_rx(USB_MAX_PACKET_SIZE); -} -DECLARE_DEFERRED(rx_fifo_handler); - -/* Rx/OUT interrupt handler */ -static void con_ep_rx(void) -{ - struct dwc_usb_ep *ep = &ep_console_ctl; - - if (GR_USB_DOEPCTL(USB_EP_CONSOLE) & DXEPCTL_EPENA) - return; - - /* Bytes received decrement DOEPTSIZ XFERSIZE */ - if (GR_USB_DOEPINT(USB_EP_CONSOLE) & DOEPINT_XFERCOMPL) { - ep->out_pending = - ep->max_packet - - (GR_USB_DOEPTSIZ(USB_EP_CONSOLE) & - GC_USB_DOEPTSIZ1_XFERSIZE_MASK); - } - - /* Wake up the Rx FIFO handler */ - hook_call_deferred(&rx_fifo_handler_data, 0); - - /* clear the RX/OUT interrupts */ - GR_USB_DOEPINT(USB_EP_CONSOLE) = 0xffffffff; -} - -/* True if the Tx/IN FIFO can take some bytes from us. */ -static inline int tx_fifo_is_ready(void) -{ - return !(GR_USB_DIEPCTL(USB_EP_CONSOLE) & DXEPCTL_EPENA); -} - -/* Try to send some bytes to the host */ -static void tx_fifo_handler(void) -{ - struct dwc_usb_ep *ep = &ep_console_ctl; - 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 = QUEUE_REMOVE_UNITS(&tx_q, - ep->in_databuffer, USB_MAX_PACKET_SIZE); - if (count) - usb_enable_tx(count); -} -DECLARE_DEFERRED(tx_fifo_handler); - -static void handle_output(void) -{ - /* Wake up the Tx FIFO handler */ - hook_call_deferred(&tx_fifo_handler_data, 0); -} - -/* Tx/IN interrupt handler */ -static void con_ep_tx(void) -{ - /* Wake up the Tx FIFO handler */ - hook_call_deferred(&tx_fifo_handler_data, 0); - - /* clear the Tx/IN interrupts */ - GR_USB_DIEPINT(USB_EP_CONSOLE) = 0xffffffff; -} - -static void ep_event(enum usb_ep_event evt) -{ - if (evt != USB_EVENT_RESET) - return; - - epN_reset(USB_EP_CONSOLE); - - is_reset = 1; - - /* Flush any queued data */ - hook_call_deferred(&tx_fifo_handler_data, 0); - hook_call_deferred(&rx_fifo_handler_data, 0); - - usb_enable_rx(USB_MAX_PACKET_SIZE); -} - - -USB_DECLARE_EP(USB_EP_CONSOLE, con_ep_tx, con_ep_rx, ep_event); - -static int usb_wait_console(void) -{ - timestamp_t deadline = get_time(); - int wait_time_us = 1; - - if (!is_enabled || !tx_fifo_is_ready()) - return EC_SUCCESS; - - deadline.val += USB_CONSOLE_TIMEOUT_US; - - /* - * If the USB console is not used, Tx buffer would never free up. - * In this case, let's drop characters immediately instead of sitting - * for some time just to time out. On the other hand, if the last - * Tx is good, it's likely the host is there to receive data, and - * we should wait so that we don't clobber the buffer. - */ - if (last_tx_ok) { - while (queue_space(&tx_q) < USB_MAX_PACKET_SIZE || !is_reset) { - if (timestamp_expired(deadline, NULL) || - in_interrupt_context()) { - last_tx_ok = 0; - return EC_ERROR_TIMEOUT; - } - if (wait_time_us < MSEC) - udelay(wait_time_us); - else - usleep(wait_time_us); - wait_time_us *= 2; - } - - return EC_SUCCESS; - } - - last_tx_ok = queue_space(&tx_q); - return EC_SUCCESS; -} -static int __tx_char(void *context, int c) -{ - struct queue *state = - (struct queue *) context; - - if (c == '\n' && __tx_char(state, '\r')) - return 1; - - QUEUE_ADD_UNITS(state, &c, 1); - return 0; -} - -/* - * Public USB console implementation below. - */ -int usb_getc(void) -{ - int c; - - if (!is_enabled) - return -1; - - if (QUEUE_REMOVE_UNITS(&rx_q, &c, 1)) - return c; - - return -1; -} - -int usb_puts(const char *outstr) -{ - int ret; - struct queue state; - - if (is_readonly) - return EC_SUCCESS; - - ret = usb_wait_console(); - if (ret) - return ret; - - state = tx_q; - while (*outstr) - if (__tx_char(&state, *outstr++)) - break; - - if (queue_count(&state)) - handle_output(); - - return *outstr ? EC_ERROR_OVERFLOW : EC_SUCCESS; -} - -int usb_putc(int c) -{ - char string[2]; - - string[0] = c; - string[1] = '\0'; - return usb_puts(string); -} - -int usb_vprintf(const char *format, va_list args) -{ - int ret; - struct queue state; - - if (is_readonly) - return EC_SUCCESS; - - ret = usb_wait_console(); - if (ret) - return ret; - - state = tx_q; - ret = vfnprintf(__tx_char, &state, format, args); - - if (queue_count(&state)) - handle_output(); - - return ret; -} - -void usb_console_enable(int enabled, int readonly) -{ - is_enabled = enabled; - is_readonly = readonly; -} |