diff options
Diffstat (limited to 'chip/stm32/usb.c')
-rw-r--r-- | chip/stm32/usb.c | 957 |
1 files changed, 0 insertions, 957 deletions
diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c deleted file mode 100644 index 0077815a27..0000000000 --- a/chip/stm32/usb.c +++ /dev/null @@ -1,957 +0,0 @@ -/* Copyright 2013 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 "clock.h" -#include "common.h" -#include "config.h" -#include "console.h" -#include "flash.h" -#include "gpio.h" -#include "hooks.h" -#include "link_defs.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "usb_api.h" -#include "usb_descriptor.h" -#include "usb_hw.h" - -/* Console output macro */ -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) - -#ifdef CONFIG_USB_BOS -/* v2.10 (vs 2.00) BOS Descriptor provided */ -#define USB_DEV_BCDUSB 0x0210 -#else -#define USB_DEV_BCDUSB 0x0200 -#endif - -#ifndef USB_DEV_CLASS -#define USB_DEV_CLASS USB_CLASS_PER_INTERFACE -#endif - -#ifndef CONFIG_USB_BCD_DEV -#define CONFIG_USB_BCD_DEV 0x0100 /* 1.00 */ -#endif - -#ifndef CONFIG_USB_SERIALNO -#define USB_STR_SERIALNO 0 -#else -static int usb_load_serial(void); -#endif - -#define USB_RESUME_TIMEOUT_MS 3000 - -/* USB Standard Device Descriptor */ -static const struct usb_device_descriptor dev_desc = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = USB_DEV_BCDUSB, - .bDeviceClass = USB_DEV_CLASS, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = USB_MAX_PACKET_SIZE, - .idVendor = CONFIG_USB_VID, - .idProduct = CONFIG_USB_PID, - .bcdDevice = CONFIG_USB_BCD_DEV, - .iManufacturer = USB_STR_VENDOR, - .iProduct = USB_STR_PRODUCT, - .iSerialNumber = USB_STR_SERIALNO, - .bNumConfigurations = 1 -}; - -/* USB Configuration Descriptor */ -const struct usb_config_descriptor USB_CONF_DESC(conf) = { - .bLength = USB_DT_CONFIG_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0x0BAD, /* no of returned bytes, set at runtime */ - .bNumInterfaces = USB_IFACE_COUNT, - .bConfigurationValue = 1, - .iConfiguration = USB_STR_VERSION, - .bmAttributes = 0x80 /* Reserved bit */ -#ifdef CONFIG_USB_SELF_POWERED /* bus or self powered */ - | 0x40 -#endif -#ifdef CONFIG_USB_REMOTE_WAKEUP - | 0x20 -#endif - , - .bMaxPower = (CONFIG_USB_MAXPOWER_MA / 2), -}; - -const uint8_t usb_string_desc[] = { - 4, /* Descriptor size */ - USB_DT_STRING, - 0x09, 0x04 /* LangID = 0x0409: U.S. English */ -}; - -/* Endpoint table in USB controller RAM */ -struct stm32_endpoint btable_ep[USB_EP_COUNT] __aligned(8) __usb_btable; -/* Control endpoint (EP0) buffers */ -static usb_uint ep0_buf_tx[USB_MAX_PACKET_SIZE / 2] __usb_ram; -static usb_uint ep0_buf_rx[USB_MAX_PACKET_SIZE / 2] __usb_ram; - -#define EP0_BUF_TX_SRAM_ADDR ((void *) usb_sram_addr(ep0_buf_tx)) - -static int set_addr; -/* remaining size of descriptor data to transfer */ -static int desc_left; -/* pointer to descriptor data if any */ -static const uint8_t *desc_ptr; -/* interface that should handle the next tx transaction */ -static uint8_t iface_next = USB_IFACE_COUNT; -#ifdef CONFIG_USB_REMOTE_WAKEUP -/* remote wake up feature enabled */ -static int remote_wakeup_enabled; -#endif - -void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet) -{ - packet->bmRequestType = buffer[0] & 0xff; - packet->bRequest = buffer[0] >> 8; - packet->wValue = buffer[1]; - packet->wIndex = buffer[2]; - packet->wLength = buffer[3]; -} - -struct usb_descriptor_patch { - const void *address; - uint16_t data; -}; - -static struct usb_descriptor_patch desc_patches[USB_DESC_PATCH_COUNT]; - -void set_descriptor_patch(enum usb_desc_patch_type type, - const void *address, uint16_t data) -{ - desc_patches[type].address = address; - desc_patches[type].data = data; -} - -void *memcpy_to_usbram_ep0_patch(const void *src, size_t n) -{ - int i; - void *ret; - - ret = memcpy_to_usbram((void *)usb_sram_addr(ep0_buf_tx), src, n); - - for (i = 0; i < USB_DESC_PATCH_COUNT; i++) { - unsigned int offset = desc_patches[i].address - src; - - if (offset >= n) - continue; - - memcpy_to_usbram((void *)(usb_sram_addr(ep0_buf_tx) + offset), - &desc_patches[i].data, sizeof(desc_patches[i].data)); - } - - return ret; -} - -static void ep0_send_descriptor(const uint8_t *desc, int len, - uint16_t fixup_size) -{ - /* do not send more than what the host asked for */ - len = MIN(ep0_buf_rx[3], len); - /* - * if we cannot transmit everything at once, - * keep the remainder for the next IN packet - */ - if (len >= USB_MAX_PACKET_SIZE) { - desc_left = len - USB_MAX_PACKET_SIZE; - desc_ptr = desc + USB_MAX_PACKET_SIZE; - len = USB_MAX_PACKET_SIZE; - } - memcpy_to_usbram_ep0_patch(desc, len); - if (fixup_size) /* set the real descriptor size */ - ep0_buf_tx[1] = fixup_size; - btable_ep[0].tx_count = len; - /* send the null OUT transaction if the transfer is complete */ - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, - desc_left ? 0 : EP_STATUS_OUT); -} - -/* Requests on the control endpoint (aka EP0) */ -static void ep0_rx(void) -{ - uint16_t req = ep0_buf_rx[0]; /* bRequestType | bRequest */ - - /* reset any incomplete descriptor transfer */ - desc_ptr = NULL; - iface_next = USB_IFACE_COUNT; - - /* interface specific requests */ - if ((req & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - uint8_t iface = ep0_buf_rx[2] & 0xff; - if (iface < USB_IFACE_COUNT) { - int ret; - - ret = usb_iface_request[iface](ep0_buf_rx, ep0_buf_tx); - if (ret < 0) - goto unknown_req; - if (ret == 1) - iface_next = iface; - return; - } - } - /* vendor specific request */ - if ((req & USB_TYPE_MASK) == USB_TYPE_VENDOR) { -#ifdef CONFIG_WEBUSB_URL - uint8_t b_req = req >> 8; /* bRequest in the transfer */ - uint16_t idx = ep0_buf_rx[2]; /* wIndex in the transfer */ - - if (b_req == 0x01 && idx == WEBUSB_REQ_GET_URL) { - int len = *(uint8_t *)webusb_url; - - ep0_send_descriptor(webusb_url, len, 0); - return; - } -#endif - goto unknown_req; - } - - /* TODO check setup bit ? */ - if (req == (USB_DIR_IN | (USB_REQ_GET_DESCRIPTOR << 8))) { - uint8_t type = ep0_buf_rx[1] >> 8; - uint8_t idx = ep0_buf_rx[1] & 0xff; - const uint8_t *desc; - int len; - - switch (type) { - case USB_DT_DEVICE: /* Setup : Get device descriptor */ - desc = (void *)&dev_desc; - len = sizeof(dev_desc); - break; - case USB_DT_CONFIGURATION: /* Setup : Get configuration desc */ - desc = __usb_desc; - len = USB_DESC_SIZE; - break; -#ifdef CONFIG_USB_BOS - case USB_DT_BOS: /* Setup : Get BOS descriptor */ - desc = bos_ctx.descp; - len = bos_ctx.size; - break; -#endif - case USB_DT_STRING: /* Setup : Get string descriptor */ - if (idx >= USB_STR_COUNT) - /* The string does not exist : STALL */ - goto unknown_req; -#ifdef CONFIG_USB_SERIALNO - if (idx == USB_STR_SERIALNO) - desc = (uint8_t *)usb_serialno_desc; - else -#endif - desc = usb_strings[idx]; - len = desc[0]; - break; - case USB_DT_DEVICE_QUALIFIER: /* Get device qualifier desc */ - /* Not high speed : STALL next IN used as handshake */ - goto unknown_req; - default: /* unhandled descriptor */ - goto unknown_req; - } - ep0_send_descriptor(desc, len, type == USB_DT_CONFIGURATION ? - USB_DESC_SIZE : 0); - } else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) { - uint16_t data = 0; - /* Get status */ -#ifdef CONFIG_USB_SELF_POWERED - data |= USB_REQ_GET_STATUS_SELF_POWERED; -#endif -#ifdef CONFIG_USB_REMOTE_WAKEUP - if (remote_wakeup_enabled) - data |= USB_REQ_GET_STATUS_REMOTE_WAKEUP; -#endif - memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, (void *)&data, 2); - btable_ep[0].tx_count = 2; - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, - EP_STATUS_OUT /*null OUT transaction */); - } else if ((req & 0xff) == USB_DIR_OUT) { - switch (req >> 8) { - case USB_REQ_SET_FEATURE: - case USB_REQ_CLEAR_FEATURE: -#ifdef CONFIG_USB_REMOTE_WAKEUP - if (ep0_buf_rx[1] == - USB_REQ_FEATURE_DEVICE_REMOTE_WAKEUP) { - remote_wakeup_enabled = - ((req >> 8) == USB_REQ_SET_FEATURE); - btable_ep[0].tx_count = 0; - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, - EP_TX_RX_VALID, 0); - break; - } -#endif - goto unknown_req; - case USB_REQ_SET_ADDRESS: - /* set the address after we got IN packet handshake */ - set_addr = ep0_buf_rx[1] & 0xff; - /* need null IN transaction -> TX Valid */ - btable_ep[0].tx_count = 0; - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0); - break; - case USB_REQ_SET_CONFIGURATION: - /* uint8_t cfg = ep0_buf_rx[1] & 0xff; */ - /* null IN for handshake */ - btable_ep[0].tx_count = 0; - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0); - break; - default: /* unhandled request */ - goto unknown_req; - } - - } else { - goto unknown_req; - } - - return; -unknown_req: - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0); -} - -static void ep0_tx(void) -{ - if (set_addr) { - STM32_USB_DADDR = set_addr | 0x80; - set_addr = 0; - CPRINTF("SETAD %02x\n", STM32_USB_DADDR); - } - if (desc_ptr) { - /* we have an on-going descriptor transfer */ - int len = MIN(desc_left, USB_MAX_PACKET_SIZE); - memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc_ptr, len); - btable_ep[0].tx_count = len; - desc_left -= len; - desc_ptr += len; - STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID, - desc_left ? 0 : EP_STATUS_OUT); - /* send the null OUT transaction if the transfer is complete */ - return; - } - if (iface_next < USB_IFACE_COUNT) { - int ret; - - ret = usb_iface_request[iface_next](NULL, ep0_buf_tx); - if (ret < 0) - goto error; - if (ret == 0) - iface_next = USB_IFACE_COUNT; - return; - } - -error: - STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID, 0); -} - -static void ep0_event(enum usb_ep_event evt) -{ - if (evt != USB_EVENT_RESET) - return; - - STM32_USB_EP(0) = BIT(9) /* control EP */ | - (2 << 4) /* TX NAK */ | - (3 << 12) /* RX VALID */; - - btable_ep[0].tx_addr = usb_sram_addr(ep0_buf_tx); - btable_ep[0].rx_addr = usb_sram_addr(ep0_buf_rx); - btable_ep[0].rx_count = 0x8000 | ((USB_MAX_PACKET_SIZE/32-1) << 10); - btable_ep[0].tx_count = 0; -} -USB_DECLARE_EP(0, ep0_tx, ep0_rx, ep0_event); - -static void usb_reset(void) -{ - int ep; - - for (ep = 0; ep < USB_EP_COUNT; ep++) - usb_ep_event[ep](USB_EVENT_RESET); - - /* - * set the default address : 0 - * as we are not configured yet - */ - STM32_USB_DADDR = 0 | 0x80; - CPRINTF("RST EP0 %04x\n", STM32_USB_EP(0)); -} - -#ifdef CONFIG_USB_SUSPEND -static void usb_pm_change_notify_hooks(void) -{ - hook_notify(HOOK_USB_PM_CHANGE); -} -DECLARE_DEFERRED(usb_pm_change_notify_hooks); - -/* See RM0091 Reference Manual 30.5.5 Suspend/Resume events */ -static void usb_suspend(void) -{ - CPRINTF("SUS%d\n", remote_wakeup_enabled); - - /* - * usb_suspend can be called from hook task, make sure no interrupt is - * modifying CNTR at the same time. - */ - interrupt_disable(); - /* Set FSUSP bit to activate suspend mode */ - STM32_USB_CNTR |= STM32_USB_CNTR_FSUSP; - - /* Set USB low power mode */ - STM32_USB_CNTR |= STM32_USB_CNTR_LP_MODE; - interrupt_enable(); - - clock_enable_module(MODULE_USB, 0); - - /* USB is not in use anymore, we can (hopefully) sleep now. */ - enable_sleep(SLEEP_MASK_USB_DEVICE); - - hook_call_deferred(&usb_pm_change_notify_hooks_data, 0); -} - -/* - * SOF was received (set in interrupt), reset in usb_resume in the - * unexpected state case. - */ -static volatile int sof_received; - -static void usb_resume_deferred(void) -{ - uint32_t state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK) - >> STM32_USB_FNR_RXDP_RXDM_SHIFT; - - CPRINTF("RSMd %d %04x %d\n", state, STM32_USB_CNTR, sof_received); - if (sof_received == 0 && (state == 2 || state == 3)) - usb_suspend(); - else - hook_call_deferred(&usb_pm_change_notify_hooks_data, 0); -} -DECLARE_DEFERRED(usb_resume_deferred); - -static void usb_resume(void) -{ - uint32_t state; - - clock_enable_module(MODULE_USB, 1); - - /* Clear FSUSP bit to exit suspend mode */ - STM32_USB_CNTR &= ~STM32_USB_CNTR_FSUSP; - - /* USB is in use again */ - disable_sleep(SLEEP_MASK_USB_DEVICE); - - state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK) - >> STM32_USB_FNR_RXDP_RXDM_SHIFT; - - CPRINTF("RSM %d %04x\n", state, STM32_USB_CNTR); - - /* - * Reference manual tells we should go back to sleep if state is 10 or - * 11. However, setting FSUSP and LP_MODE in this interrupt routine - * seems to lock the USB controller (see b/35775088 and b/71688150). - * Instead, we do it in a deferred routine. The host must assert the - * reset condition for 20ms, so reading D+/D- after ~3ms should be safe - * (there is no chance we end up sampling during a bus transaction). - */ - if (state == 2 || state == 3) { - /* - * This function is already called from interrupt context so - * there is no risk of race here. - */ - sof_received = 0; - STM32_USB_CNTR |= STM32_USB_CNTR_SOFM; - hook_call_deferred(&usb_resume_deferred_data, 3 * MSEC); - } else { - hook_call_deferred(&usb_pm_change_notify_hooks_data, 0); - } -} - -#ifdef CONFIG_USB_REMOTE_WAKEUP -/* - * Makes sure usb_wake is only run once. When 0, wake is in progress. - */ -static volatile int usb_wake_done = 1; - -/* - * ESOF counter (incremented in interrupt), RESUME bit is cleared when - * this reaches 0. Also used to detect resume timeout. - */ -static volatile int esof_count; - -__attribute__((weak)) -void board_usb_wake(void) -{ - /* Side-band USB wake, do nothing by default. */ -} - -/* Called 10ms after usb_wake started. */ -static void usb_wake_deferred(void) -{ - if (esof_count == 3) { - /* - * If we reach here, it means that we are not counting ESOF/SOF - * properly (either of these interrupts should occur every 1ms). - * This should never happen if we implemented the resume logic - * correctly. - * - * We reset the controller in that case, which recovers the - * interface. - */ - CPRINTF("USB stuck\n"); -#if defined(STM32_RCC_APB1RSTR2_USBFSRST) - STM32_RCC_APB1RSTR2 |= STM32_RCC_APB1RSTR2_USBFSRST; - STM32_RCC_APB1RSTR2 &= STM32_RCC_APB1RSTR2_USBFSRST; -#else - STM32_RCC_APB1RSTR |= STM32_RCC_PB1_USB; - STM32_RCC_APB1RSTR &= ~STM32_RCC_PB1_USB; -#endif - usb_init(); - } -} -DECLARE_DEFERRED(usb_wake_deferred); - -void usb_wake(void) -{ - if (!remote_wakeup_enabled || - !(STM32_USB_CNTR & STM32_USB_CNTR_FSUSP)) { - /* - * USB wake not enabled, or already woken up, or already waking - * up, nothing to do. - */ - return; - } - - /* Only allow one caller at a time. */ - if (!atomic_clear((int *)&usb_wake_done)) - return; - - CPRINTF("WAKE\n"); - - /* - * Sometimes the USB controller gets stuck, and does not count SOF/ESOF - * frames anymore, detect that. - */ - hook_call_deferred(&usb_wake_deferred_data, 10 * MSEC); - - /* - * Set RESUME bit for 1 to 15 ms, then clear it. We ask the interrupt - * routine to count 3 ESOF interrupts, which should take between - * 2 and 3 ms. - */ - esof_count = 3; - - /* STM32_USB_CNTR can also be updated from interrupt context. */ - interrupt_disable(); - STM32_USB_CNTR |= STM32_USB_CNTR_RESUME | - STM32_USB_CNTR_ESOFM | STM32_USB_CNTR_SOFM; - interrupt_enable(); - - /* Try side-band wake as well. */ - board_usb_wake(); -} -#endif - -int usb_is_suspended(void) -{ - /* Either hardware block is suspended... */ - if (STM32_USB_CNTR & STM32_USB_CNTR_FSUSP) - return 1; - -#ifdef CONFIG_USB_REMOTE_WAKEUP - /* ... or we are currently waking up. */ - if (!usb_wake_done) - return 1; -#endif - - return 0; -} - -int usb_is_remote_wakeup_enabled(void) -{ -#ifdef CONFIG_USB_REMOTE_WAKEUP - return remote_wakeup_enabled; -#else - return 0; -#endif -} -#endif /* CONFIG_USB_SUSPEND */ - -#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_USB_REMOTE_WAKEUP) -/* - * Called by usb_interrupt when usb_wake is asking us to count esof_count ESOF - * interrupts (one per millisecond), then disable RESUME, then wait for resume - * to complete. - */ -static void usb_interrupt_handle_wake(uint16_t status) -{ - int state; - int good; - - esof_count--; - - /* Keep counting. */ - if (esof_count > 0) - return; - - /* Clear RESUME bit. */ - if (esof_count == 0) - STM32_USB_CNTR &= ~STM32_USB_CNTR_RESUME; - - /* Then count down until state is resumed. */ - state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK) - >> STM32_USB_FNR_RXDP_RXDM_SHIFT; - - /* - * state 2, or receiving an SOF, means resume - * completed successfully. - */ - good = (status & STM32_USB_ISTR_SOF) || (state == 2); - - /* Either: state is ready, or we timed out. */ - if (good || state == 3 || esof_count <= -USB_RESUME_TIMEOUT_MS) { - int ep; - - STM32_USB_CNTR &= ~STM32_USB_CNTR_ESOFM; - usb_wake_done = 1; - if (!good) { - CPRINTF("wake error: cnt=%d state=%d\n", - esof_count, state); - usb_suspend(); - return; - } - - CPRINTF("RSMOK%d %d\n", -esof_count, state); - - for (ep = 1; ep < USB_EP_COUNT; ep++) - usb_ep_event[ep](USB_EVENT_DEVICE_RESUME); - } -} -#endif /* CONFIG_USB_SUSPEND && CONFIG_USB_REMOTE_WAKEUP */ - -void usb_interrupt(void) -{ - uint16_t status = STM32_USB_ISTR; - - if (status & STM32_USB_ISTR_RESET) - usb_reset(); - -#ifdef CONFIG_USB_SUSPEND - if (status & STM32_USB_ISTR_SOF) { - sof_received = 1; - /* - * The wake handler also only cares about the _first_ SOF that - * is received, so we can disable that interrupt. - */ - STM32_USB_CNTR &= ~STM32_USB_CNTR_SOFM; - } - -#ifdef CONFIG_USB_REMOTE_WAKEUP - if (status & (STM32_USB_ISTR_ESOF | STM32_USB_ISTR_SOF) && - !usb_wake_done) - usb_interrupt_handle_wake(status); -#endif - - if (status & STM32_USB_ISTR_SUSP) - usb_suspend(); - - if (status & STM32_USB_ISTR_WKUP) - usb_resume(); -#endif - - if (status & STM32_USB_ISTR_CTR) { - int ep = status & STM32_USB_ISTR_EP_ID_MASK; - if (ep < USB_EP_COUNT) { - if (status & STM32_USB_ISTR_DIR) - usb_ep_rx[ep](); - else - usb_ep_tx[ep](); - } - /* TODO: do it in a USB task */ - /* task_set_event(, 1 << ep_task); */ - } - - /* ack only interrupts that we handled */ - STM32_USB_ISTR = ~status; -} -DECLARE_IRQ(STM32_IRQ_USB_LP, usb_interrupt, 1); - -void usb_init(void) -{ - /* Enable USB device clock, possibly increasing system clock to 48MHz */ - clock_enable_module(MODULE_USB, 1); - - /* configure the pinmux */ - gpio_config_module(MODULE_USB, 1); - - /* power on sequence */ - - /* keep FRES (USB reset) and remove PDWN (power down) */ - STM32_USB_CNTR = STM32_USB_CNTR_FRES; - udelay(1); /* startup time */ - /* reset FRES and keep interrupts masked */ - STM32_USB_CNTR = 0x00; - /* clear pending interrupts */ - STM32_USB_ISTR = 0; - - /* set descriptors table offset in dedicated SRAM */ - STM32_USB_BTABLE = 0; - - /* EXTI18 is USB wake up interrupt */ - /* STM32_EXTI_RTSR |= BIT(18); */ - /* STM32_EXTI_IMR |= BIT(18); */ - - /* Enable interrupt handlers */ - task_enable_irq(STM32_IRQ_USB_LP); - /* set interrupts mask : reset/correct transfer/errors */ - STM32_USB_CNTR = STM32_USB_CNTR_CTRM | - STM32_USB_CNTR_PMAOVRM | - STM32_USB_CNTR_ERRM | -#ifdef CONFIG_USB_SUSPEND - STM32_USB_CNTR_WKUPM | - STM32_USB_CNTR_SUSPM | -#endif - STM32_USB_CNTR_RESETM; - -#ifdef CONFIG_USB_SERIALNO - usb_load_serial(); -#endif -#ifndef CONFIG_USB_INHIBIT_CONNECT - usb_connect(); -#endif - - CPRINTF("USB init done\n"); -} - -#ifndef CONFIG_USB_INHIBIT_INIT -DECLARE_HOOK(HOOK_INIT, usb_init, HOOK_PRIO_DEFAULT); -#endif - -void usb_release(void) -{ - /* signal disconnect to host */ - usb_disconnect(); - - /* power down USB */ - STM32_USB_CNTR = 0; - - /* disable interrupt handlers */ - task_disable_irq(STM32_IRQ_USB_LP); - - /* unset pinmux */ - gpio_config_module(MODULE_USB, 0); - - /* disable USB device clock, possibly slowing down system clock */ - clock_enable_module(MODULE_USB, 0); -} -/* ensure the host disconnects and reconnects over a sysjump */ -DECLARE_HOOK(HOOK_SYSJUMP, usb_release, HOOK_PRIO_DEFAULT); - -int usb_is_enabled(void) -{ - return clock_is_module_enabled(MODULE_USB); -} - -void *memcpy_to_usbram(void *dest, const void *src, size_t n) -{ - int unaligned = (((uintptr_t) dest) & 1); - usb_uint *d = &__usb_ram_start[((uintptr_t) dest) / 2]; - uint8_t *s = (uint8_t *) src; - int i; - - /* - * Handle unaligned leading byte via read/modify/write. - */ - if (unaligned && n) { - *d = (*d & ~0xff00) | (*s << 8); - n--; - s++; - d++; - } - - for (i = 0; i < n / 2; i++, s += 2) - *d++ = (s[1] << 8) | s[0]; - - /* - * There is a trailing byte to write into a final USB packet memory - * location, use a read/modify/write to be safe. - */ - if (n & 1) - *d = (*d & ~0x00ff) | *s; - - return dest; -} - -void *memcpy_from_usbram(void *dest, const void *src, size_t n) -{ - int unaligned = (((uintptr_t) src) & 1); - usb_uint const *s = &__usb_ram_start[((uintptr_t) src) / 2]; - uint8_t *d = (uint8_t *) dest; - int i; - - if (unaligned && n) { - *d = *s >> 8; - n--; - s++; - d++; - } - - for (i = 0; i < n / 2; i++) { - usb_uint value = *s++; - - *d++ = (value >> 0) & 0xff; - *d++ = (value >> 8) & 0xff; - } - - if (n & 1) - *d = *s; - - return dest; -} - -#ifdef CONFIG_USB_SERIALNO -/* This will be subbed into USB_STR_SERIALNO. */ -struct usb_string_desc *usb_serialno_desc = - USB_WR_STRING_DESC(DEFAULT_SERIALNO); - -/* Update serial number */ -static int usb_set_serial(const char *serialno) -{ - struct usb_string_desc *sd = usb_serialno_desc; - int i; - - if (!serialno) - return EC_ERROR_INVAL; - - /* Convert into unicode usb string desc. */ - for (i = 0; i < CONFIG_SERIALNO_LEN; i++) { - sd->_data[i] = serialno[i]; - if (serialno[i] == 0) - break; - } - /* Count wchars (w/o null terminator) plus size & type bytes. */ - sd->_len = (i * 2) + 2; - sd->_type = USB_DT_STRING; - - return EC_SUCCESS; -} - -/* Retrieve serial number from pstate flash. */ -static int usb_load_serial(void) -{ - const char *serialno; - int rv; - - serialno = board_read_serial(); - if (!serialno) - return EC_ERROR_ACCESS_DENIED; - - rv = usb_set_serial(serialno); - return rv; -} - -/* Save serial number into pstate region. */ -static int usb_save_serial(const char *serialno) -{ - int rv; - - if (!serialno) - return EC_ERROR_INVAL; - - /* Save this new serial number to flash. */ - rv = board_write_serial(serialno); - if (rv) - return rv; - - /* Load this new serial number to memory. */ - rv = usb_load_serial(); - return rv; -} - -static int command_serialno(int argc, char **argv) -{ - struct usb_string_desc *sd = usb_serialno_desc; - char buf[CONFIG_SERIALNO_LEN]; - int rv = EC_SUCCESS; - int i; - - if (argc != 1) { - if ((strcasecmp(argv[1], "set") == 0) && - (argc == 3)) { - ccprintf("Saving serial number\n"); - rv = usb_save_serial(argv[2]); - } else if ((strcasecmp(argv[1], "load") == 0) && - (argc == 2)) { - ccprintf("Loading serial number\n"); - rv = usb_load_serial(); - } else - return EC_ERROR_INVAL; - } - - for (i = 0; i < CONFIG_SERIALNO_LEN; i++) - buf[i] = sd->_data[i]; - ccprintf("Serial number: %s\n", buf); - return rv; -} - -DECLARE_CONSOLE_COMMAND(serialno, command_serialno, - "load/set [value]", - "Read and write USB serial number"); - -#endif /* CONFIG_USB_SERIALNO */ - -#ifdef CONFIG_MAC_ADDR - -/* Save MAC address into pstate region. */ -static int usb_save_mac_addr(const char *mac_addr) -{ - int rv; - - if (!mac_addr) { - return EC_ERROR_INVAL; - } - - /* Save this new MAC address to flash. */ - rv = board_write_mac_addr(mac_addr); - if (rv) { - return rv; - } - - /* Load this new MAC address to memory. */ - if (board_read_mac_addr() != NULL) { - return EC_SUCCESS; - } else { - return EC_ERROR_UNKNOWN; - } -} - -static int command_macaddr(int argc, char **argv) -{ - const char* buf; - int rv = EC_SUCCESS; - - if (argc != 1) { - if ((strcasecmp(argv[1], "set") == 0) && - (argc == 3)) { - ccprintf("Saving MAC address\n"); - rv = usb_save_mac_addr(argv[2]); - } else if ((strcasecmp(argv[1], "load") == 0) && - (argc == 2)) { - ccprintf("Loading MAC address\n"); - } else { - return EC_ERROR_INVAL; - } - } - - buf = board_read_mac_addr(); - if (buf == NULL) { - buf = DEFAULT_MAC_ADDR; - } - ccprintf("MAC address: %s\n", buf); - return rv; -} - -DECLARE_CONSOLE_COMMAND(macaddr, command_macaddr, - "load/set [value]", - "Read and write MAC address"); - -#endif /* CONFIG_MAC_ADDR */ |