From f37d83e55d76d966b2c1ba2aef8b4c6e17b0d77f Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 17 Apr 2019 16:13:58 +0900 Subject: [PATCH] New: mcu/usb-stm32l.c (not yet tested). --- ChangeLog | 1 + mcu/usb-stm32l.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 mcu/usb-stm32l.c diff --git a/ChangeLog b/ChangeLog index b7d32a7..0a6f159 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 2019-04-17 NIIBE Yutaka + * mcu/usb-stm32l.c: New. * mcu/usb-st-common.c: Factor out from usb-stm32f103.c. 2019-04-12 NIIBE Yutaka diff --git a/mcu/usb-stm32l.c b/mcu/usb-stm32l.c new file mode 100644 index 0000000..2be2984 --- /dev/null +++ b/mcu/usb-stm32l.c @@ -0,0 +1,236 @@ +/* + * usb-stm32l.c - USB driver for STM32L + * + * Copyright (C) 2019 Flying Stone Technology + * Author: NIIBE Yutaka + * + * This file is a part of Chopstx, a thread library for embedded. + * + * Chopstx is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chopstx is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * As additional permission under GNU GPL version 3 section 7, you may + * distribute non-source form of the Program without the copy of the + * GNU GPL normally required by section 4, provided you inform the + * recipients of GNU GPL by a written offer. + * + */ + +#include +#include + +#include "sys-stm32l.h" +#include "usb_lld.h" +#include "usb_lld_driver.h" + +#define REG_BASE (0x40006800UL) /* USB Peripheral Registers base address */ +#define PMA_ADDR (0x40006C00UL) /* USB Packet Memory Area base address */ + +static void +epbuf_set_tx_addr (uint8_t ep_num, uint16_t addr) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)); + + *reg_p = addr; +} + +static uint16_t +epbuf_get_tx_addr (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)); + + return *reg_p; +} + + +static void +epbuf_set_tx_count (uint8_t ep_num, uint16_t size) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)); + + *reg_p = size; +} + +static uint16_t +epbuf_get_tx_count (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)); + + return *reg_p & 0x03ff; +} + + +static void +epbuf_set_rx_addr (uint8_t ep_num, uint16_t addr) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)); + + *reg_p = addr; +} + +static uint16_t +epbuf_get_rx_addr (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)); + + return *reg_p; +} + + +static void +epbuf_set_rx_buf_size (uint8_t ep_num, uint16_t size) +{ /* Assume size is even */ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)); + uint16_t value; + + if (size <= 62) + value = (size & 0x3e) << 9; + else + value = 0x8000 | (((size >> 5) - 1) << 10); + + *reg_p = value; +} + +static uint16_t +epbuf_get_rx_count (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)); + + return *reg_p & 0x03ff; +} + +#include "usb-st-common.c" + +static int +handle_setup0 (struct usb_dev *dev) +{ + const uint16_t *pw; + uint16_t w; + uint8_t req_no; + HANDLER handler; + + pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(epbuf_get_rx_addr (ENDP0))); + w = *pw++; + + dev->dev_req.type = (w & 0xff); + dev->dev_req.request = req_no = (w >> 8); + dev->dev_req.value = *pw++; + dev->dev_req.index = *pw++; + dev->dev_req.len = *pw; + + dev->ctrl_data.addr = NULL; + dev->ctrl_data.len = 0; + dev->ctrl_data.require_zlp = 0; + + if ((dev->dev_req.type & REQUEST_TYPE) == STANDARD_REQUEST) + { + int r; + + switch (req_no) + { + case 0: handler = std_get_status; break; + case 1: handler = std_clear_feature; break; + case 3: handler = std_set_feature; break; + case 5: handler = std_set_address; break; + case 6: handler = std_get_descriptor; break; + case 8: handler = std_get_configuration; break; + case 9: handler = std_set_configuration; break; + case 10: handler = std_get_interface; break; + case 11: handler = std_set_interface; break; + default: handler = std_none; break; + } + + if ((r = (*handler) (dev)) < 0) + { + usb_lld_ctrl_error (dev); + return USB_EVENT_OK; + } + else + return r; + } + else + return USB_EVENT_CTRL_REQUEST; +} + +void +usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n) +{ + const uint8_t *s = (const uint8_t *)src; + uint16_t *p; + uint16_t w; + + if (n == 0) + return; + + if ((addr & 1)) + { + p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2); + w = *p; + w = (w & 0xff) | (*s++) << 8; + *p = w; + p += 2; + n--; + } + else + p = (uint16_t *)(PMA_ADDR + addr * 2); + + while (n >= 2) + { + w = *s++; + w |= (*s++) << 8; + *p = w; + p += 2; + n -= 2; + } + + if (n > 0) + { + w = *s; + *p = w; + } +} + +void +usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n) +{ + uint8_t *d = (uint8_t *)dst; + uint16_t *p; + uint16_t w; + + if (n == 0) + return; + + if ((addr & 1)) + { + p = (uint16_t *)(PMA_ADDR + (addr - 1)); + w = *p++; + *d++ = (w >> 8); + n--; + } + else + p = (uint16_t *)(PMA_ADDR + addr); + + while (n >= 2) + { + w = *p++; + *d++ = (w & 0xff); + *d++ = (w >> 8); + n -= 2; + } + + if (n > 0) + { + w = *p; + *d = (w & 0xff); + } +}