mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
usb: add USB console driver
Provide access to the EC console through 2 USB bulk endpoints. (which can be used through the usbserial driver) Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=none TEST=run on Fruitpie and use the console over USB Change-Id: Ia897764f3a030972ee2ed323f293c5fca899765a Reviewed-on: https://chromium-review.googlesource.com/204167 Reviewed-by: Anton Staaf <robotboy@chromium.org> Commit-Queue: Vic Yang <victoryang@chromium.org> Tested-by: Vic Yang <victoryang@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
7746b32e17
commit
a975c98fb2
@@ -39,5 +39,6 @@ chip-$(CONFIG_FLASH)+=flash-$(FLASH_FAMILY).o
|
||||
chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o
|
||||
chip-$(CONFIG_PWM)+=pwm.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_POWER_DELIVERY)+=usb_pd_phy.o
|
||||
|
||||
245
chip/stm32/usb_console.c
Normal file
245
chip/stm32/usb_console.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/* 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 "common.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include "link_defs.h"
|
||||
#include "printf.h"
|
||||
#include "registers.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
#include "usb.h"
|
||||
|
||||
/* Console output macro */
|
||||
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
|
||||
|
||||
#define USB_CONSOLE_TIMEOUT_US (30 * MSEC)
|
||||
#define USB_CONSOLE_RX_BUF_SIZE 16
|
||||
#define RX_BUF_NEXT(i) (((i) + 1) & (USB_CONSOLE_RX_BUF_SIZE - 1))
|
||||
|
||||
static volatile char rx_buf[USB_CONSOLE_RX_BUF_SIZE];
|
||||
static volatile int rx_buf_head;
|
||||
static volatile int rx_buf_tail;
|
||||
|
||||
static int last_tx_ok = 1;
|
||||
|
||||
static int is_reset;
|
||||
|
||||
/* 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 = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0,
|
||||
};
|
||||
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_CONSOLE, 82) = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 0x80 | USB_EP_CON_TX,
|
||||
.bmAttributes = 0x02 /* Bulk IN */,
|
||||
.wMaxPacketSize = USB_MAX_PACKET_SIZE,
|
||||
.bInterval = 10
|
||||
};
|
||||
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_CONSOLE, 3) = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_EP_CON_RX,
|
||||
.bmAttributes = 0x02 /* Bulk OUT */,
|
||||
.wMaxPacketSize = USB_MAX_PACKET_SIZE,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
static usb_uint ep_buf_tx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
|
||||
static usb_uint ep_buf_rx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
|
||||
|
||||
static void con_ep_tx(void)
|
||||
{
|
||||
uint16_t ep = STM32_USB_EP(USB_EP_CON_TX);
|
||||
/* clear IT */
|
||||
STM32_USB_EP(USB_EP_CON_TX) = (ep & EP_MASK);
|
||||
return;
|
||||
}
|
||||
|
||||
static void con_ep_rx(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (btable_ep[USB_EP_CON_RX].rx_count & 0x3ff); i++) {
|
||||
int rx_buf_next = RX_BUF_NEXT(rx_buf_head);
|
||||
if (rx_buf_next != rx_buf_tail) {
|
||||
/* Not working on old STM32 ... */
|
||||
rx_buf[rx_buf_head] = ((uint8_t *)ep_buf_rx)[i];
|
||||
rx_buf_head = rx_buf_next;
|
||||
}
|
||||
}
|
||||
/* clear IT */
|
||||
STM32_TOGGLE_EP(USB_EP_CON_RX, EP_RX_MASK, EP_RX_VALID, 0);
|
||||
/* wake-up the console task */
|
||||
console_has_input();
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_getc(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (rx_buf_tail == rx_buf_head)
|
||||
return -1;
|
||||
|
||||
c = rx_buf[rx_buf_tail];
|
||||
rx_buf_tail = RX_BUF_NEXT(rx_buf_tail);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int __tx_char(void *context, int c)
|
||||
{
|
||||
uint16_t *buf = (uint16_t *)ep_buf_tx;
|
||||
int *tx_idx = context;
|
||||
|
||||
/* Do newline to CRLF translation */
|
||||
if (c == '\n' && __tx_char(context, '\r'))
|
||||
return 1;
|
||||
|
||||
if (*tx_idx > 63)
|
||||
return 1;
|
||||
if (!(*tx_idx & 1))
|
||||
buf[*tx_idx/2] = c;
|
||||
else
|
||||
buf[*tx_idx/2] |= c << 8;
|
||||
(*tx_idx)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_enable_tx(int len)
|
||||
{
|
||||
btable_ep[USB_EP_CON_TX].tx_count = len;
|
||||
STM32_TOGGLE_EP(USB_EP_CON_TX, EP_TX_MASK, EP_TX_VALID, 0);
|
||||
}
|
||||
|
||||
static inline int usb_console_tx_valid(void)
|
||||
{
|
||||
return (STM32_USB_EP(USB_EP_CON_TX) & EP_TX_MASK) == EP_TX_VALID;
|
||||
}
|
||||
|
||||
static int usb_wait_console(void)
|
||||
{
|
||||
timestamp_t deadline = get_time();
|
||||
int wait_time_us = 1;
|
||||
|
||||
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 (usb_console_tx_valid() || !is_reset) {
|
||||
if (timestamp_expired(deadline, NULL)) {
|
||||
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;
|
||||
} else {
|
||||
last_tx_ok = !usb_console_tx_valid();
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_putc(int c)
|
||||
{
|
||||
int ret;
|
||||
int tx_idx = 0;
|
||||
|
||||
ret = usb_wait_console();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __tx_char(&tx_idx, c);
|
||||
usb_enable_tx(tx_idx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usb_puts(const char *outstr)
|
||||
{
|
||||
int ret;
|
||||
int tx_idx = 0;
|
||||
|
||||
ret = usb_wait_console();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Put all characters in the output buffer */
|
||||
while (*outstr) {
|
||||
if (__tx_char(&tx_idx, *outstr++) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
usb_enable_tx(tx_idx);
|
||||
|
||||
/* Successful if we consumed all output */
|
||||
return *outstr ? EC_ERROR_OVERFLOW : EC_SUCCESS;
|
||||
}
|
||||
|
||||
int usb_vprintf(const char *format, va_list args)
|
||||
{
|
||||
int ret;
|
||||
int tx_idx = 0;
|
||||
|
||||
ret = usb_wait_console();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vfnprintf(__tx_char, &tx_idx, format, args);
|
||||
|
||||
usb_enable_tx(tx_idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ep_tx_reset(void)
|
||||
{
|
||||
/* Serial Bulk IN endpoint 2 */
|
||||
btable_ep[USB_EP_CON_TX].tx_addr = usb_sram_addr(ep_buf_tx);
|
||||
btable_ep[USB_EP_CON_TX].tx_count = 0;
|
||||
btable_ep[USB_EP_CON_TX].rx_count = 0;
|
||||
STM32_USB_EP(USB_EP_CON_TX) = (USB_EP_CON_TX << 0) /* Endpoint Addr*/ |
|
||||
(2 << 4) /* TX NAK */ |
|
||||
(0 << 9) /* Bulk EP */ |
|
||||
(0 << 12) /* RX Disabled */;
|
||||
is_reset = 1;
|
||||
}
|
||||
|
||||
static void ep_rx_reset(void)
|
||||
{
|
||||
/* Serial Bulk OUT endpoint 3 */
|
||||
btable_ep[USB_EP_CON_RX].rx_addr = usb_sram_addr(ep_buf_rx);
|
||||
btable_ep[USB_EP_CON_RX].tx_count = 0;
|
||||
btable_ep[USB_EP_CON_RX].rx_count =
|
||||
0x8000 | ((USB_MAX_PACKET_SIZE / 32 - 1) << 10);
|
||||
STM32_USB_EP(USB_EP_CON_RX) = (USB_EP_CON_RX << 0) /* Endpoint Addr */ |
|
||||
(0 << 4) /* TX Disabled */ |
|
||||
(0 << 9) /* Bulk EP */ |
|
||||
(3 << 12) /* RX VALID */;
|
||||
}
|
||||
|
||||
USB_DECLARE_EP(USB_EP_CON_TX, con_ep_tx, con_ep_tx, ep_tx_reset);
|
||||
USB_DECLARE_EP(USB_EP_CON_RX, con_ep_rx, con_ep_rx, ep_rx_reset);
|
||||
@@ -4,12 +4,14 @@
|
||||
*/
|
||||
|
||||
/* Console module for Chrome EC */
|
||||
|
||||
#include "clock.h"
|
||||
#include "console.h"
|
||||
#include "link_defs.h"
|
||||
#include "system.h"
|
||||
#include "task.h"
|
||||
#include "uart.h"
|
||||
#include "usb_console.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MAX_ARGS_PER_COMMAND 10
|
||||
@@ -205,6 +207,14 @@ static void console_init(void)
|
||||
ccputs(PROMPT);
|
||||
}
|
||||
|
||||
static int console_putc(int c)
|
||||
{
|
||||
int rv1 = uart_putc(c);
|
||||
int rv2 = usb_putc(c);
|
||||
|
||||
return rv1 == EC_SUCCESS ? rv2 : rv1;
|
||||
}
|
||||
|
||||
static void move_cursor_right(void)
|
||||
{
|
||||
if (input_pos == input_len)
|
||||
@@ -244,7 +254,7 @@ static void move_cursor_begin(void)
|
||||
static void repeat_char(char c, int cnt)
|
||||
{
|
||||
while (cnt--)
|
||||
uart_putc(c);
|
||||
console_putc(c);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_HISTORY
|
||||
@@ -289,7 +299,7 @@ static void handle_backspace(void)
|
||||
return; /* Already at beginning of line */
|
||||
|
||||
/* Move cursor back */
|
||||
uart_putc('\b');
|
||||
console_putc('\b');
|
||||
|
||||
/* Print and move anything following the cursor position */
|
||||
if (input_pos != input_len) {
|
||||
@@ -302,7 +312,7 @@ static void handle_backspace(void)
|
||||
}
|
||||
|
||||
/* Space over last character and move cursor to correct position */
|
||||
uart_putc(' ');
|
||||
console_putc(' ');
|
||||
repeat_char('\b', input_len - input_pos + 1);
|
||||
|
||||
input_len--;
|
||||
@@ -413,7 +423,7 @@ static void console_handle_char(int c)
|
||||
|
||||
case '\n':
|
||||
/* Terminate this line */
|
||||
uart_puts("\r\n");
|
||||
console_putc('\n');
|
||||
|
||||
#ifdef CONFIG_CONSOLE_HISTORY
|
||||
/* Save command in history buffer */
|
||||
@@ -512,7 +522,7 @@ static void console_handle_char(int c)
|
||||
break;
|
||||
|
||||
/* Print character */
|
||||
uart_putc(c);
|
||||
console_putc(c);
|
||||
|
||||
/* If not at end of line, print rest of line and move it down */
|
||||
if (input_pos != input_len) {
|
||||
@@ -554,12 +564,23 @@ void console_task(void)
|
||||
console_init();
|
||||
|
||||
while (1) {
|
||||
int c = uart_getc();
|
||||
int c;
|
||||
|
||||
if (c == -1)
|
||||
task_wait_event(-1); /* Wait for more input */
|
||||
else
|
||||
while (1) {
|
||||
c = uart_getc();
|
||||
if (c == -1)
|
||||
break;
|
||||
console_handle_char(c);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c = usb_getc();
|
||||
if (c == -1)
|
||||
break;
|
||||
console_handle_char(c);
|
||||
}
|
||||
|
||||
task_wait_event(-1); /* Wait for more input */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "console.h"
|
||||
#include "uart.h"
|
||||
#include "usb_console.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Default to all channels active */
|
||||
@@ -68,26 +69,36 @@ BUILD_ASSERT(ARRAY_SIZE(channel_names) == CC_CHANNEL_COUNT);
|
||||
|
||||
int cputs(enum console_channel channel, const char *outstr)
|
||||
{
|
||||
int rv1, rv2;
|
||||
|
||||
/* Filter out inactive channels */
|
||||
if (!(CC_MASK(channel) & channel_mask))
|
||||
return EC_SUCCESS;
|
||||
|
||||
return uart_puts(outstr);
|
||||
rv1 = usb_puts(outstr);
|
||||
rv2 = uart_puts(outstr);
|
||||
|
||||
return rv1 == EC_SUCCESS ? rv2 : rv1;
|
||||
}
|
||||
|
||||
int cprintf(enum console_channel channel, const char *format, ...)
|
||||
{
|
||||
int rv;
|
||||
int rv1, rv2;
|
||||
va_list args;
|
||||
|
||||
/* Filter out inactive channels */
|
||||
if (!(CC_MASK(channel) & channel_mask))
|
||||
return EC_SUCCESS;
|
||||
|
||||
usb_va_start(args, format);
|
||||
rv1 = usb_vprintf(format, args);
|
||||
usb_va_end(args);
|
||||
|
||||
va_start(args, format);
|
||||
rv = uart_vprintf(format, args);
|
||||
rv2 = uart_vprintf(format, args);
|
||||
va_end(args);
|
||||
return rv;
|
||||
|
||||
return rv1 == EC_SUCCESS ? rv2 : rv1;
|
||||
}
|
||||
|
||||
int cprints(enum console_channel channel, const char *format, ...)
|
||||
@@ -99,13 +110,21 @@ int cprints(enum console_channel channel, const char *format, ...)
|
||||
if (!(CC_MASK(channel) & channel_mask))
|
||||
return EC_SUCCESS;
|
||||
|
||||
rv = cprintf(channel, "[%T ");
|
||||
|
||||
va_start(args, format);
|
||||
rv = uart_printf("[%T ");
|
||||
r = uart_vprintf(format, args);
|
||||
if (r)
|
||||
rv = r;
|
||||
r = uart_puts("]\n");
|
||||
va_end(args);
|
||||
|
||||
usb_va_start(args, format);
|
||||
r = usb_vprintf(format, args);
|
||||
if (r)
|
||||
rv = r;
|
||||
usb_va_end(args);
|
||||
|
||||
r = cputs(channel, "]\n");
|
||||
return r ? r : rv;
|
||||
}
|
||||
|
||||
|
||||
55
include/usb_console.h
Normal file
55
include/usb_console.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* USB serial console module */
|
||||
|
||||
#ifndef __USB_CONSOLE_H
|
||||
#define __USB_CONSOLE_H
|
||||
|
||||
#ifdef CONFIG_USB_CONSOLE
|
||||
|
||||
/**
|
||||
* Put a null-terminated string to the USB console, like fputs().
|
||||
*
|
||||
* @return EC_SUCCESS, or non-zero if output was truncated.
|
||||
*/
|
||||
int usb_puts(const char *outstr);
|
||||
|
||||
/**
|
||||
* Print formatted output to the USB console, like vprintf().
|
||||
*
|
||||
* See printf.h for valid formatting codes.
|
||||
*
|
||||
* @return EC_SUCCESS, or non-zero if output was truncated.
|
||||
*/
|
||||
int usb_vprintf(const char *format, va_list args);
|
||||
|
||||
/**
|
||||
* Put a single character to the USB console, like putchar().
|
||||
*
|
||||
* @param c Character to put
|
||||
* @return EC_SUCCESS, or non-zero if output was truncated.
|
||||
*/
|
||||
int usb_putc(int c);
|
||||
|
||||
/**
|
||||
* Read a single character of input, similar to fgetc().
|
||||
*
|
||||
* @return the character, or -1 if no input waiting.
|
||||
*/
|
||||
int usb_getc(void);
|
||||
|
||||
#define usb_va_start va_start
|
||||
#define usb_va_end va_end
|
||||
#else
|
||||
#define usb_puts(x) EC_SUCCESS
|
||||
#define usb_vprintf(x, y) EC_SUCCESS
|
||||
#define usb_putc(x) EC_SUCCESS
|
||||
#define usb_getc(x) (-1)
|
||||
#define usb_va_start(x, y)
|
||||
#define usb_va_end(x)
|
||||
#endif
|
||||
|
||||
#endif /* __USB_CONSOLE_H */
|
||||
Reference in New Issue
Block a user