summaryrefslogtreecommitdiff
path: root/ucoo/hal/usb
diff options
context:
space:
mode:
Diffstat (limited to 'ucoo/hal/usb')
-rw-r--r--ucoo/hal/usb/Config13
-rw-r--r--ucoo/hal/usb/Module6
-rw-r--r--ucoo/hal/usb/test/Config2
-rw-r--r--ucoo/hal/usb/test/Makefile2
-rw-r--r--ucoo/hal/usb/test/test_usb.cc59
-rw-r--r--ucoo/hal/usb/usb.hh4
-rw-r--r--ucoo/hal/usb/usb.stm32.cc311
-rw-r--r--ucoo/hal/usb/usb.stm32.hh106
-rw-r--r--ucoo/hal/usb/usb_application.cc222
-rw-r--r--ucoo/hal/usb/usb_application.hh158
-rw-r--r--ucoo/hal/usb/usb_cdc.cc235
-rw-r--r--ucoo/hal/usb/usb_cdc.hh81
-rw-r--r--ucoo/hal/usb/usb_cdc_def.hh75
-rw-r--r--ucoo/hal/usb/usb_cdc_desc.hh174
-rw-r--r--ucoo/hal/usb/usb_def.hh71
-rw-r--r--ucoo/hal/usb/usb_desc.hh406
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.c303
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.h33
-rw-r--r--ucoo/hal/usb/usb_driver.cc130
-rw-r--r--ucoo/hal/usb/usb_driver.hh120
-rw-r--r--ucoo/hal/usb/usb_dwc_otg.stm32.cc412
-rw-r--r--ucoo/hal/usb/usb_dwc_otg.stm32.hh94
22 files changed, 2213 insertions, 804 deletions
diff --git a/ucoo/hal/usb/Config b/ucoo/hal/usb/Config
index 249a0ac..e0cd973 100644
--- a/ucoo/hal/usb/Config
+++ b/ucoo/hal/usb/Config
@@ -2,15 +2,12 @@
# Theses are APBTeam IDs, given by Openmoko!
vendor_id = 0x1d50
product_id = 0x6052
-# Declare as a CDC ACM device.
-cdc_acm = true
-# Number of streams, interfaces, or pair of endpoints.
-stream_nb = 1
-# Set to 0 if powered from USB cable, 1 if device has its own power supply.
-self_powered = 0
+# Set to false if powered from USB cable, true if device has its own power
+# supply.
+self_powered = false
# Maximum power consumed from USB cable (mA).
max_power = 100
# End point size, you should use 64.
ep_size = 64
-# Use HS driver instead of FS
-driver_hs = false
+# Enable trace buffer.
+trace = false
diff --git a/ucoo/hal/usb/Module b/ucoo/hal/usb/Module
index e47e0e8..b879961 100644
--- a/ucoo/hal/usb/Module
+++ b/ucoo/hal/usb/Module
@@ -1 +1,5 @@
-ucoo_hal_usb_SOURCES = usb.stm32.cc usb_desc.stm32.c
+ucoo_hal_usb_SOURCES = \
+ usb_driver.cc \
+ usb_application.cc \
+ usb_cdc.cc \
+ usb_dwc_otg.stm32.cc
diff --git a/ucoo/hal/usb/test/Config b/ucoo/hal/usb/test/Config
index a29fd20..908a0df 100644
--- a/ucoo/hal/usb/test/Config
+++ b/ucoo/hal/usb/test/Config
@@ -1,2 +1,2 @@
[ucoo/hal/usb]
-stream_nb = 1
+trace = true
diff --git a/ucoo/hal/usb/test/Makefile b/ucoo/hal/usb/test/Makefile
index 95e4648..d4849df 100644
--- a/ucoo/hal/usb/test/Makefile
+++ b/ucoo/hal/usb/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = stm32f4
PROGS = test_usb
test_usb_SOURCES = test_usb.cc
-MODULES = ucoo/hal/usb
+MODULES = ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/hal/usb/test/test_usb.cc b/ucoo/hal/usb/test/test_usb.cc
index eb2eb12..ff730a4 100644
--- a/ucoo/hal/usb/test/test_usb.cc
+++ b/ucoo/hal/usb/test/test_usb.cc
@@ -22,53 +22,34 @@
//
// }}}
#include "ucoo/hal/usb/usb.hh"
+#include "ucoo/hal/usb/usb_cdc.hh"
+#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/arch/arch.hh"
+static const auto string_descs_pack = ucoo::usb_descs_pack (
+ ucoo::usb_string_desc (ucoo::USB_LANGUAGE_EN_US),
+ ucoo::usb_string_desc (u"APBTeam"),
+ ucoo::usb_string_desc (u"test"));
+
+static const auto string_descs = ucoo::usb_descs (string_descs_pack);
+
int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- ucoo::UsbStreamControl usc ("APBTeam", "USB test");
- usc.enable ();
- ucoo::UsbStream us[] = {
- ucoo::UsbStream (usc, 0),
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 2
- ucoo::UsbStream (usc, 1),
-#endif
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 3
- ucoo::UsbStream (usc, 2),
-#endif
- };
- if (CONFIG_UCOO_HAL_USB_STREAM_NB > 1)
- {
- for (int i = 0; i < CONFIG_UCOO_HAL_USB_STREAM_NB; i++)
- us[i].block (false);
- }
- char buf[6];
+ ucoo::UsbDriverDwcOtg driver (ucoo::UsbDriverDwcOtg::Instance::OTG_FS,
+ ucoo::usb_cdc_default_device_desc (),
+ ucoo::usb_cdc_default_configuration_desc (),
+ string_descs);
+ ucoo::UsbApplicationCdcAcm cdc (driver);
+ driver.enable ();
+ cdc.write ("hello", 5);
while (1)
{
- for (int i = 0; i < CONFIG_UCOO_HAL_USB_STREAM_NB; i++)
- {
- int len = us[i].read (buf + 2, sizeof (buf) - 2);
- if (len)
- {
- buf[0] = i + '0';
- buf[1] = '>';
- len += 2;
- if (CONFIG_UCOO_HAL_USB_STREAM_NB == 1)
- us[i].write (buf, len);
- else
- {
- const char *p = buf;
- while (len)
- {
- int r = us[i].write (p, len);
- p += r;
- len -= r;
- }
- }
- }
- }
+ char buf[64];
+ int r = cdc.read (buf, sizeof (buf));
+ if (r)
+ cdc.write (buf, r);
}
}
diff --git a/ucoo/hal/usb/usb.hh b/ucoo/hal/usb/usb.hh
index 5324058..8115bc7 100644
--- a/ucoo/hal/usb/usb.hh
+++ b/ucoo/hal/usb/usb.hh
@@ -24,8 +24,10 @@
//
// }}}
+#include "usb_driver.hh"
+#include "usb_application.hh"
#ifdef TARGET_stm32
-# include "usb.stm32.hh"
+# include "usb_dwc_otg.stm32.hh"
#else
# error "not implemented for this target"
#endif
diff --git a/ucoo/hal/usb/usb.stm32.cc b/ucoo/hal/usb/usb.stm32.cc
deleted file mode 100644
index 5ed6b27..0000000
--- a/ucoo/hal/usb/usb.stm32.cc
+++ /dev/null
@@ -1,311 +0,0 @@
-// ucoolib - Microcontroller object oriented library. {{{
-//
-// Copyright (C) 2012 Nicolas Schodet
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-//
-// }}}
-#include "usb.stm32.hh"
-#include <algorithm>
-
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
-#include <libopencm3/cm3/nvic.h>
-#include <libopencm3/stm32/otg_fs.h>
-#include <libopencm3/stm32/otg_hs.h>
-
-#include "usb_desc.stm32.h"
-
-#if CONFIG_UCOO_HAL_USB_CDC_ACM
-# include <libopencm3/usb/cdc.h>
-#endif
-
-#if defined (TARGET_stm32f4)
-# if CONFIG_UCOO_HAL_USB_DRIVER_HS
-# define usb_isr otg_hs_isr
-# define usb_driver otghs_usb_driver
-# else
-# define usb_isr otg_fs_isr
-# define usb_driver otgfs_usb_driver
-# endif
-#elif defined (TARGET_stm32f1)
-# define usb_isr otg_fs_isr
-# define usb_driver otgfs_usb_driver
-#else
-# error "not implemented for this target"
-#endif
-
-static usbd_device *usbdev;
-
-// Buffer for control requests.
-static uint8_t usb_control_buffer[128];
-
-extern "C" {
-
-void
-usb_isr ()
-{
- usbd_poll (usbdev);
-}
-
-}
-
-namespace ucoo {
-
-UsbStreamControl *UsbStreamControl::instance_;
-
-const char *strings[] = {
- NULL,
- NULL
-};
-
-#if CONFIG_UCOO_HAL_USB_CDC_ACM
-
-static void
-usb_cdc_acm_send_serial_state (usbd_device *usbdev, bool active)
-{
- struct serial_state_notification
- {
- struct usb_cdc_notification notification;
- uint16_t state;
- } n;
- n.notification.bmRequestType = 0xa1;
- n.notification.bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
- n.notification.wValue = 0;
- n.notification.wIndex = 0;
- n.notification.wLength = 2;
- n.state = active ? 3 : 0;
- usbd_ep_write_packet (usbdev, 0x82, reinterpret_cast<void *> (&n),
- sizeof (n));
-}
-
-static int
-usb_cdc_acm_control_request (
- usbd_device *usbdev,
- struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete) (usbd_device *usbdev, struct usb_setup_data *req))
-{
- switch (req->bRequest)
- {
- case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- usb_cdc_acm_send_serial_state (usbdev, true);
- return USBD_REQ_HANDLED;
- case USB_CDC_REQ_SET_LINE_CODING:
- if (*len < sizeof (struct usb_cdc_line_coding))
- return USBD_REQ_NOTSUPP;
- return USBD_REQ_HANDLED;
- }
- return 0;
-}
-
-#endif /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-UsbStreamControl::RxBuffer::RxBuffer (void)
- : size (0), offset (0)
-{
-}
-
-UsbStreamControl::UsbStreamControl (const char *vendor, const char *product)
- : enabled_ (false), configured_ (false)
-{
- assert (!instance_);
- instance_ = this;
- strings[0] = vendor;
- strings[1] = product;
-}
-
-UsbStreamControl::~UsbStreamControl ()
-{
- disable ();
-}
-
-void
-UsbStreamControl::enable ()
-{
- if (!enabled_)
- {
-#if defined (TARGET_stm32f4)
-# if CONFIG_UCOO_HAL_USB_DRIVER_HS
- rcc_periph_clock_enable (RCC_OTGHS);
- rcc_periph_clock_enable (RCC_GPIOB);
- gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO14 | GPIO15);
- gpio_set_af (GPIOB, GPIO_AF12, GPIO14 | GPIO15);
-# else
- rcc_periph_clock_enable (RCC_OTGFS);
- rcc_periph_clock_enable (RCC_GPIOA);
- gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
- gpio_set_af (GPIOA, GPIO_AF10, GPIO11 | GPIO12);
-# endif
-#elif defined (TARGET_stm32f1)
- rcc_periph_clock_enable (RCC_OTGFS);
- rcc_periph_clock_enable (RCC_GPIOA);
-#endif
- usbdev = usbd_init (&usb_driver, &usb_desc_dev, &usb_desc_config,
- strings, lengthof (strings),
- usb_control_buffer, sizeof (usb_control_buffer));
-#if CONFIG_UCOO_HAL_USB_DRIVER_HS
- if (OTG_HS_CID == 0x2000)
- {
- // Different registers in F479.
- OTG_HS_GCCFG = (1 << 21) | (1 << 16);
- OTG_HS_DCTL = 0;
- }
-#else
- if (OTG_FS_CID == 0x2000)
- {
- // Different registers in F479.
- OTG_FS_GCCFG = (1 << 21) | (1 << 16);
- OTG_FS_DCTL = 0;
- }
-#endif
- usbd_register_set_config_callback (usbdev, set_config);
-#if CONFIG_UCOO_HAL_USB_DRIVER_HS
- nvic_enable_irq (NVIC_OTG_HS_IRQ);
-#else
- nvic_enable_irq (NVIC_OTG_FS_IRQ);
-#endif
- enabled_ = true;
- }
-}
-
-void
-UsbStreamControl::disable ()
-{
- if (enabled_)
- {
- enabled_ = false;
- configured_ = false;
-#if CONFIG_UCOO_HAL_USB_DRIVER_HS
- nvic_disable_irq (NVIC_OTG_HS_IRQ);
-#else
- nvic_disable_irq (NVIC_OTG_FS_IRQ);
-#endif
- usbd_disconnect (usbdev, true);
-#if defined (TARGET_stm32f4)
-# if CONFIG_UCOO_HAL_USB_DRIVER_HS
- rcc_periph_clock_disable (RCC_OTGHS);
- gpio_mode_setup (GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO14 | GPIO15);
-# else
- rcc_periph_clock_disable (RCC_OTGFS);
- gpio_mode_setup (GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO11 | GPIO12);
-# endif
-#elif defined (TARGET_stm32f1)
- rcc_periph_clock_disable (RCC_OTGFS);
-#endif
- }
-}
-
-void
-UsbStreamControl::set_config (usbd_device *usbdev, uint16_t configured)
-{
- instance_->configured_ = configured;
- if (configured)
- {
- for (int i = 0; i < stream_nb_; i++)
- {
- usbd_ep_setup (usbdev, 0x01 + i, USB_ENDPOINT_ATTR_BULK, ep_size_,
- rx_callback);
- usbd_ep_setup (usbdev, 0x81 + i, USB_ENDPOINT_ATTR_BULK, ep_size_,
- NULL);
- }
-#if CONFIG_UCOO_HAL_USB_CDC_ACM
- usbd_ep_setup (usbdev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
- usbd_register_control_callback (
- usbdev,
- USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
- USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
- usb_cdc_acm_control_request);
- usb_cdc_acm_send_serial_state (usbdev, true);
-#endif
- }
-}
-
-void
-UsbStreamControl::rx_callback (usbd_device *usbdev, uint8_t ep)
-{
- assert (ep > 0 && ep <= stream_nb_);
- int num = ep - 1;
- RxBuffer &rb = instance_->rx_buffer_[num];
- assert (rb.size == 0 && rb.offset == 0);
- usbd_ep_nak_set (usbdev, ep, 1);
- rb.size = usbd_ep_read_packet (usbdev, ep, rb.buf, ep_size_);
-}
-
-UsbStream::UsbStream (UsbStreamControl &control, int num)
- : control_ (control), num_ (num)
-{
- assert (num < UsbStreamControl::stream_nb_);
-}
-
-int
-UsbStream::read (char *buf, int count)
-{
- UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_];
- /* Wait for reception. */
- if (!rb.size && !block_)
- return 0;
- while (!rb.size)
- barrier ();
- /* Copy to provided buffer. */
- int len = std::min (count, rb.size - rb.offset);
- buf = std::copy (rb.buf + rb.offset, rb.buf + rb.offset + len, buf);
- rb.offset += len;
- /* Reload buffer? */
- if (rb.offset == rb.size)
- {
- rb.offset = rb.size = 0;
- barrier ();
- usbd_ep_nak_set (usbdev, num_ + 1, 0);
- }
- /* Done. */
- return len;
-}
-
-int
-UsbStream::write (const char *buf, int count)
-{
- int left = count;
- while (left)
- {
- if (control_.configured_)
- {
- // Do the FIFO write with IRQ locked, as the USB IP does not
- // tolerate any interruption while the FIFO is being filled.
- int len = std::min (left, UsbStreamControl::ep_size_);
- irq_flags_t f = irq_lock ();
- len = usbd_ep_write_packet (usbdev, num_ + 0x81, buf, len);
- irq_restore (f);
- buf += len;
- left -= len;
- }
- if (!block_)
- break;
- barrier ();
- }
- return count - left;
-}
-
-int
-UsbStream::poll ()
-{
- UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_];
- return rb.size - rb.offset;
-}
-
-} // namespace ucoo
diff --git a/ucoo/hal/usb/usb.stm32.hh b/ucoo/hal/usb/usb.stm32.hh
deleted file mode 100644
index 5c44e2f..0000000
--- a/ucoo/hal/usb/usb.stm32.hh
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef ucoo_hal_usb_usb_stm32_hh
-#define ucoo_hal_usb_usb_stm32_hh
-// ucoolib - Microcontroller object oriented library. {{{
-//
-// Copyright (C) 2012 Nicolas Schodet
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-//
-// }}}
-#include "ucoo/intf/stream.hh"
-#include "ucoo/common.hh"
-
-#include "config/ucoo/hal/usb.hh"
-
-#include <libopencm3/usb/usbd.h>
-
-namespace ucoo {
-
-class UsbStream;
-
-/// Top control class for an USB device. This is a limited implementation
-/// which fulfill most of our needs: one or more interfaces, each of them is
-/// handled as a character stream. This should be instantiated only once.
-class UsbStreamControl
-{
- public:
- /// Construct a new USB control object, with given VENDOR and PRODUCT
- /// strings.
- UsbStreamControl (const char *vendor, const char *product);
- /// Destruct and disable.
- ~UsbStreamControl ();
- /// Enable device.
- void enable ();
- /// Disable device.
- void disable ();
- /// Return true if the device is configured. This means that the
- /// connection is done with the host and data can be exchanged.
- bool is_configured () const { return configured_; }
- private:
- /// Called by USB stack when device is configured. This is expected to
- /// setup endpoints.
- static void set_config (usbd_device *usbdev, uint16_t wValue);
- /// Called by USB stack when a frame is received on a OUT endpoint.
- static void rx_callback (usbd_device *usbdev, uint8_t ep);
- private:
- /// Size of endpoints.
- static const int ep_size_ = CONFIG_UCOO_HAL_USB_EP_SIZE;
- /// Number of streams (also interfaces or pair of endpoints).
- static const int stream_nb_ = CONFIG_UCOO_HAL_USB_STREAM_NB;
- /// Pointer to the one and only instance.
- static UsbStreamControl *instance_;
- /// Is currently enabled?
- bool enabled_;
- /// Whether device is currently configured.
- bool configured_;
- /// Internal RX buffer type.
- struct RxBuffer
- {
- char buf[ep_size_];
- int size, offset;
- RxBuffer (void);
- };
- /// Internal RX buffer, one per stream.
- RxBuffer rx_buffer_[stream_nb_];
- friend class UsbStream;
-};
-
-/// One USB stream, instantiated for each stream, interface, or pair of
-/// endpoints.
-class UsbStream : public Stream
-{
- public:
- /// Construct from control object and stream index.
- UsbStream (UsbStreamControl &control, int num);
- /// See Stream::read.
- int read (char *buf, int count);
- /// See Stream::write.
- int write (const char *buf, int count);
- /// See Stream::poll.
- int poll ();
- private:
- /// Reference to control object.
- UsbStreamControl &control_;
- /// Stream index.
- int num_;
-};
-
-} // namespace ucoo
-
-#endif // ucoo_hal_usb_usb_stm32_hh
diff --git a/ucoo/hal/usb/usb_application.cc b/ucoo/hal/usb/usb_application.cc
new file mode 100644
index 0000000..3ae6bd5
--- /dev/null
+++ b/ucoo/hal/usb/usb_application.cc
@@ -0,0 +1,222 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_application.hh"
+#include "ucoo/hal/usb/usb_driver.hh"
+#include "ucoo/hal/usb/usb_def.hh"
+
+namespace ucoo {
+
+UsbApplication::UsbApplication (UsbDriver &driver)
+ : driver_ (driver)
+{
+ driver.register_application (*this);
+}
+
+void
+UsbApplicationWithSetup::ep_handle_out (uint8_t ep_address, int bcnt)
+{
+ assert (ep_address == 0);
+ if (setup_stage_ == SetupStage::HostToDeviceOUT)
+ {
+ if (bcnt <= data_size_)
+ {
+ if (bcnt)
+ {
+ driver_.ep_read (0, data_, bcnt);
+ data_ += bcnt;
+ data_size_ -= bcnt;
+ }
+ if (bcnt < USB_CONTROL_END_POINT_SIZE)
+ recv_done ();
+ }
+ else
+ {
+ driver_.ep_stall (0);
+ setup_stage_ = SetupStage::Idle;
+ }
+ }
+ else if (setup_stage_ == SetupStage::DeviceToHostStatusOUT && bcnt == 0)
+ {
+ // Status received, done.
+ setup_stage_ = SetupStage::Idle;
+ }
+ else
+ {
+ driver_.ep_stall (0);
+ setup_stage_ = SetupStage::Idle;
+ }
+}
+
+void
+UsbApplicationWithSetup::ep_handle_in (uint8_t ep_address)
+{
+ assert (ep_address == 0);
+ if (setup_stage_ == SetupStage::DeviceToHostIN)
+ {
+ if (data_)
+ {
+ int r = driver_.ep_write (0, data_, data_size_);
+ if (data_size_ < USB_CONTROL_END_POINT_SIZE)
+ data_ = nullptr;
+ else
+ {
+ data_ += r;
+ data_size_ -= r;
+ }
+ }
+ else
+ {
+ driver_.ep_read_ready (0, USB_CONTROL_END_POINT_SIZE);
+ setup_stage_ = SetupStage::DeviceToHostStatusOUT;
+ }
+ }
+ else if (setup_stage_ == SetupStage::HostToDeviceStatusIN)
+ {
+ // Status sent, done.
+ setup_stage_ = SetupStage::Idle;
+ }
+ else
+ {
+ driver_.ep_stall (0);
+ setup_stage_ = SetupStage::Idle;
+ }
+}
+
+void
+UsbApplicationWithSetup::send_status ()
+{
+ driver_.ep_write (0, nullptr, 0);
+ setup_stage_ = SetupStage::HostToDeviceStatusIN;
+}
+
+void
+UsbApplicationWithSetup::send (const char *data, int data_size)
+{
+ int r = driver_.ep_write (0, data, data_size);
+ if (data_size < USB_CONTROL_END_POINT_SIZE)
+ data_ = nullptr;
+ else
+ {
+ data_ = const_cast<char *> (data) + r;
+ data_size_ = data_size - r;
+ }
+ setup_stage_ = SetupStage::DeviceToHostIN;
+}
+
+void
+UsbApplicationWithSetup::recv (char *data, int data_size)
+{
+ data_ = data;
+ data_size_ = data_size;
+ driver_.ep_read_ready (0, USB_CONTROL_END_POINT_SIZE);
+ setup_stage_ = SetupStage::HostToDeviceOUT;
+}
+
+void
+UsbApplicationWithSetup::recv_done ()
+{
+ // Must be overrided if used.
+ assert_unreachable ();
+}
+
+UsbApplicationBasic::SetupResult
+UsbApplicationBasic::handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length)
+{
+ SetupResult res = SetupResult::NotHandled;
+ switch (request_n_type)
+ {
+ case USB_REQ_SET_ADDRESS:
+ if (index == 0 && length == 0)
+ {
+ usb_trace ("setup set address %d", value);
+ driver_.set_address (value);
+ send_status ();
+ res = SetupResult::Handled;
+ }
+ break;
+ case USB_REQ_GET_DESCRIPTOR:
+ usb_trace ("setup get descriptor 0x%04x", value);
+ res = send_descriptor (value >> 8, value & 0xff, index, length);
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ if (index == 0 && length == 0)
+ {
+ usb_trace ("setup set configuration %d", value);
+ driver_.set_configuration (value);
+ send_status ();
+ res = SetupResult::Handled;
+ }
+ break;
+ case USB_REQ_SET_INTERFACE:
+ if (length == 0)
+ {
+ usb_trace ("setup set interface %d", value);
+ // TODO
+ send_status ();
+ res = SetupResult::Handled;
+ }
+ break;
+ }
+ return res;
+}
+
+void
+UsbApplicationBasic::handle_configuration_set (uint8_t configuration)
+{
+}
+
+UsbApplicationBasic::SetupResult
+UsbApplicationBasic::send_descriptor (uint8_t desc_type, uint8_t desc_index,
+ uint16_t language, uint16_t length)
+{
+ const details::UsbDesc *desc = nullptr;
+ switch (desc_type)
+ {
+ case 1: // Device.
+ if (desc_index == 0 || language == 0)
+ desc = &device_desc_;
+ break;
+ case 2: // Configuration.
+ if (desc_index == 0 || language == 0)
+ desc = &configuration_desc_;
+ break;
+ case 3: // String.
+ if ((desc_index == 0 && language == 0)
+ || (desc_index != 0 && desc_index < string_descs_nb_
+ && language == ucoo::USB_LANGUAGE_EN_US))
+ desc = &string_descs_[desc_index];
+ }
+ if (desc)
+ {
+ send (desc->desc,
+ desc->desc_size < length ? desc->desc_size : length);
+ return SetupResult::Handled;
+ }
+ else
+ return SetupResult::NotHandled;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_application.hh b/ucoo/hal/usb/usb_application.hh
new file mode 100644
index 0000000..ac1ea2d
--- /dev/null
+++ b/ucoo/hal/usb/usb_application.hh
@@ -0,0 +1,158 @@
+#ifndef ucoo_hal_usb_usb_application_hh
+#define ucoo_hal_usb_usb_application_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_desc.hh"
+
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+class UsbDriver;
+
+/// Class which handles application specific controls and data exchanges.
+class UsbApplication
+{
+ public:
+ /// Response from a setup handler.
+ enum class SetupResult
+ {
+ /// Setup not handled, should continue with next registered
+ /// application.
+ NotHandled,
+ /// Setup handled, this application is now responsible for any
+ /// following IN or OUT.
+ Handled,
+ /// Setup error, STALL the control end point.
+ Error
+ };
+ public:
+ /// Handle setup message received on control end point. If message is
+ /// handled, this application is automatically made responsible for IN and
+ /// OUT on this end point. It can use ep_write right now (if it does not,
+ /// it will not receive any ep_handle_in event).
+ /// On error the control end point is STALLed.
+ virtual SetupResult handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length) = 0;
+ /// Handle configuration set, should setup any used end points.
+ virtual void handle_configuration_set (uint8_t configuration) = 0;
+ /// Handle data received on an OUT end point. The application must use
+ /// ep_read once to receive data.
+ virtual void ep_handle_out (uint8_t ep_address, int bcnt) = 0;
+ /// Handle data needed to be transmitted on an IN end point. The
+ /// application can use ep_write once to transmit data. Else the end
+ /// point is left in a NAK state.
+ virtual void ep_handle_in (uint8_t ep_address) = 0;
+ protected:
+ /// Register application.
+ UsbApplication (UsbDriver &driver);
+ protected:
+ UsbDriver &driver_;
+};
+
+/// Helper for SETUP handling.
+class UsbApplicationWithSetup : public UsbApplication
+{
+ public:
+ /// SETUP stage, to be used as a SETUP FSM.
+ enum class SetupStage
+ {
+ /// Idle, waiting for a SETUP frame.
+ Idle,
+ /// Host to device, waiting for an OUT frame.
+ HostToDeviceOUT,
+ /// Host to device, status IN frame ready to send.
+ HostToDeviceStatusIN,
+ /// Device to host, IN frame ready to send.
+ DeviceToHostIN,
+ /// Device to host, waiting for status OUT frame.
+ DeviceToHostStatusOUT,
+
+ };
+ public:
+ UsbApplicationWithSetup (UsbDriver &driver)
+ : UsbApplication (driver) { }
+ void ep_handle_out (uint8_t ep_address, int bcnt) override;
+ void ep_handle_in (uint8_t ep_address) override;
+ protected:
+ /// Send status IN.
+ void send_status ();
+ /// Enqueue data to send in response to SETUP.
+ void send (const char *data, int data_size);
+ /// Prepare to receive data after SETUP.
+ void recv (char *data, int data_size);
+ /// Data reception done after SETUP.
+ virtual void recv_done ();
+ private:
+ SetupStage setup_stage_ = SetupStage::Idle;
+ char *data_ = nullptr;
+ int data_size_ = 0;
+};
+
+/// Handle basic USB protocol.
+class UsbApplicationBasic : public UsbApplicationWithSetup
+{
+ public:
+ template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+ UsbApplicationBasic (UsbDriver &driver,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs);
+ SetupResult handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length) override;
+ void handle_configuration_set (uint8_t configuration) override;
+ private:
+ /// Send a descriptor.
+ SetupResult send_descriptor (uint8_t desc_type, uint8_t desc_index,
+ uint16_t language, uint16_t length);
+ private:
+ const details::UsbDesc device_desc_;
+ const details::UsbDesc configuration_desc_;
+ const details::UsbDesc *string_descs_;
+ const int string_descs_nb_;
+ SetupStage setup_stage_ = SetupStage::Idle;
+ const char *to_send_ = nullptr;
+ int to_send_size_ = 0;
+};
+
+template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+UsbApplicationBasic::UsbApplicationBasic (
+ UsbDriver &driver,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs)
+ : UsbApplicationWithSetup (driver),
+ device_desc_ (device_desc), configuration_desc_ (configuration_desc),
+ string_descs_ (reinterpret_cast<const details::UsbDesc *> (&string_descs)),
+ string_descs_nb_ (sizeof (string_descs) / sizeof (details::UsbDesc))
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_application_hh
diff --git a/ucoo/hal/usb/usb_cdc.cc b/ucoo/hal/usb/usb_cdc.cc
new file mode 100644
index 0000000..36d0889
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc.cc
@@ -0,0 +1,235 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_cdc.hh"
+#include "ucoo/hal/usb/usb_cdc_desc.hh"
+#include "ucoo/hal/usb/usb_driver.hh"
+
+#include "ucoo/utils/irq_locked.hh"
+
+namespace ucoo {
+
+enum
+{
+ END_POINT_RX = 0x01,
+ END_POINT_TX = 0x81,
+ END_POINT_NOTIF = 0x82,
+};
+
+static const auto device_desc = usb_device_desc (
+ 0x0200, USB_CLASS_CDC, 0, 0, USB_CONTROL_END_POINT_SIZE,
+ CONFIG_UCOO_HAL_USB_VENDOR_ID,
+ CONFIG_UCOO_HAL_USB_PRODUCT_ID,
+ 0x0100, 1, 2, 0, 1);
+
+static const auto configuration_desc = usb_configuration_desc (
+ 2, 1, 0,
+ 0x80 | (CONFIG_UCOO_HAL_USB_SELF_POWERED ? 0x40 : 0),
+ CONFIG_UCOO_HAL_USB_MAX_POWER / 2,
+ usb_interface_desc (
+ 0, 0, 1,
+ USB_CLASS_CDC, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTOCOL_AT, 0,
+ usb_endpoint_desc (END_POINT_NOTIF, 0x03, 16, 128),
+ usb_cdc_header_desc (0x0110),
+ usb_cdc_call_management_desc (0, 1),
+ usb_cdc_abstract_control_management_desc (2),
+ usb_cdc_union_desc (0, 1)),
+ usb_interface_desc (
+ 1, 0, 2,
+ USB_CLASS_DATA, 0, 0, 0,
+ usb_endpoint_desc_bulk (END_POINT_RX, CONFIG_UCOO_HAL_USB_EP_SIZE),
+ usb_endpoint_desc_bulk (END_POINT_TX, CONFIG_UCOO_HAL_USB_EP_SIZE)));
+
+details::UsbDesc
+usb_cdc_default_device_desc ()
+{
+ return device_desc;
+}
+
+details::UsbDesc
+usb_cdc_default_configuration_desc ()
+{
+ return configuration_desc;
+}
+
+UsbApplicationCdcAcm::SetupResult
+UsbApplicationCdcAcm::handle_setup (uint16_t request_n_type, uint16_t value,
+ uint16_t index, uint16_t length)
+{
+ SetupResult res = SetupResult::NotHandled;
+ switch (request_n_type)
+ {
+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+ usb_trace ("setup set control line state");
+ send_status ();
+ send_serial_state_ = true;
+ driver_.ep_write_ready (END_POINT_NOTIF);
+ res = SetupResult::Handled;
+ break;
+ case USB_CDC_REQ_SET_LINE_CODING:
+ usb_trace ("setup set line coding");
+ recv (reinterpret_cast<char *> (&line_coding_),
+ sizeof (line_coding_));
+ res = SetupResult::Handled;
+ break;
+ }
+ return res;
+}
+
+void
+UsbApplicationCdcAcm::handle_configuration_set (uint8_t configuration)
+{
+ driver_.ep_setup (END_POINT_RX, UsbDriver::EpType::Bulk,
+ CONFIG_UCOO_HAL_USB_EP_SIZE, *this);
+ driver_.ep_setup (END_POINT_TX, UsbDriver::EpType::Bulk,
+ CONFIG_UCOO_HAL_USB_EP_SIZE, *this);
+ driver_.ep_setup (END_POINT_NOTIF, UsbDriver::EpType::Interrupt,
+ 16, *this);
+ if (!rx_buffer_.full ())
+ driver_.ep_read_ready (END_POINT_RX, rx_buffer_.room ());
+ if (!tx_buffer_.empty ())
+ driver_.ep_write_ready (END_POINT_TX);
+ send_serial_state_ = true;
+ driver_.ep_write_ready (END_POINT_NOTIF);
+ configured_ = true;
+}
+
+void
+UsbApplicationCdcAcm::ep_handle_out (uint8_t ep_address, int bcnt)
+{
+ if (ep_address == 0)
+ UsbApplicationWithSetup::ep_handle_out (0, bcnt);
+ else if (ep_address == END_POINT_RX)
+ {
+ int r = driver_.ep_read (END_POINT_RX, rx_buffer_.write (),
+ rx_buffer_.room ());
+ rx_buffer_.written (r);
+ driver_.ep_read_ready (END_POINT_RX, rx_buffer_.room ());
+ }
+ else
+ assert_unreachable ();
+}
+
+void
+UsbApplicationCdcAcm::ep_handle_in (uint8_t ep_address)
+{
+ if (ep_address == 0)
+ UsbApplicationWithSetup::ep_handle_in (0);
+ else if (ep_address == END_POINT_TX)
+ {
+ if (!tx_buffer_.empty ())
+ {
+ int r = driver_.ep_write (END_POINT_TX, tx_buffer_.read (),
+ tx_buffer_.size ());
+ tx_buffer_.drop (r);
+ tx_buffer_.rewind ();
+ }
+ }
+ else if (ep_address == END_POINT_NOTIF)
+ {
+ if (send_serial_state_)
+ {
+ struct
+ {
+ UsbCdcNotification notification;
+ uint16_t state;
+ } n;
+ n.notification.bmRequestType = USB_REQ (INTERFACE, CLASS, IN, 0);
+ n.notification.bNotification = USB_CDC_NOTIFICATION_SERIAL_STATE;
+ n.notification.wValue = 0;
+ n.notification.wIndex = 0;
+ n.notification.wLength = 2;
+ n.state = active_ ? 3 : 0;
+ driver_.ep_write (END_POINT_NOTIF,
+ reinterpret_cast<const char *> (&n), sizeof (n));
+ send_serial_state_ = false;
+ }
+ }
+ else
+ assert_unreachable ();
+}
+
+int
+UsbApplicationCdcAcm::read (char *buf, int count)
+{
+ while (1)
+ {
+ {
+ IrqLocked flags;
+ if (!rx_buffer_.empty ())
+ {
+ int r = std::min (rx_buffer_.size (), count);
+ const char *f = rx_buffer_.read ();
+ std::copy (f, f + r, buf);
+ rx_buffer_.drop (r);
+ rx_buffer_.rewind ();
+ if (configured_)
+ driver_.ep_read_ready (END_POINT_RX, rx_buffer_.room ());
+ return r;
+ }
+ else if (!block_)
+ return 0;
+ }
+ yield ();
+ }
+}
+
+int
+UsbApplicationCdcAcm::write (const char *buf, int count)
+{
+ int left = count;
+ while (left)
+ {
+ {
+ IrqLocked flags;
+ if (!tx_buffer_.full ())
+ {
+ int r = std::min (tx_buffer_.room (), left);
+ std::copy (buf, buf + r, tx_buffer_.write (r));
+ if (configured_)
+ driver_.ep_write_ready (END_POINT_TX);
+ buf += r;
+ left -= r;
+ }
+ }
+ if (!block_)
+ break;
+ yield ();
+ }
+ return count - left;
+}
+
+int
+UsbApplicationCdcAcm::poll ()
+{
+ return rx_buffer_.size ();
+}
+
+void
+UsbApplicationCdcAcm::recv_done ()
+{
+ // Do not actually use the line coding information.
+ send_status ();
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_cdc.hh b/ucoo/hal/usb/usb_cdc.hh
new file mode 100644
index 0000000..7dd5aad
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc.hh
@@ -0,0 +1,81 @@
+#ifndef ucoo_hal_usb_usb_cdc_hh
+#define ucoo_hal_usb_usb_cdc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_application.hh"
+#include "ucoo/hal/usb/usb_desc.hh"
+#include "ucoo/hal/usb/usb_cdc_def.hh"
+#include "ucoo/intf/stream.hh"
+#include "ucoo/utils/buffer.hh"
+
+#include "config/ucoo/hal/usb.hh"
+
+namespace ucoo {
+
+/// Return a default device descriptor for single CDC ACM device.
+details::UsbDesc
+usb_cdc_default_device_desc ();
+
+/// Return a default configuration descriptor for single CDC ACM device.
+details::UsbDesc
+usb_cdc_default_configuration_desc ();
+
+/// Handle a CDC ACM device, in our case a simple serial port.
+class UsbApplicationCdcAcm : public UsbApplicationWithSetup, public Stream
+{
+ public:
+ UsbApplicationCdcAcm (UsbDriver &driver)
+ : UsbApplicationWithSetup (driver) { }
+ SetupResult handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length) override;
+ void handle_configuration_set (uint8_t configuration) override;
+ void ep_handle_out (uint8_t ep_address, int bcnt) override;
+ void ep_handle_in (uint8_t ep_address) override;
+ int read (char *buf, int count) override;
+ int write (const char *buf, int count) override;
+ int poll () override;
+ protected:
+ void recv_done () override;
+ private:
+ /// Send serial state over notification end point.
+ void send_serial_state (bool active);
+ private:
+ /// Line coding being received.
+ UsbCdcLineCoding line_coding_;
+ /// Whether serial port is active (always the case now).
+ static const bool active_ = true;
+ /// RX buffer.
+ Buffer<char, CONFIG_UCOO_HAL_USB_EP_SIZE * 2> rx_buffer_;
+ /// TX buffer.
+ Buffer<char, CONFIG_UCOO_HAL_USB_EP_SIZE * 2> tx_buffer_;
+ /// Is ready to exchange data?
+ bool configured_ = false;
+ /// Was serial state requested?
+ bool send_serial_state_ = false;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_cdc_hh
diff --git a/ucoo/hal/usb/usb_cdc_def.hh b/ucoo/hal/usb/usb_cdc_def.hh
new file mode 100644
index 0000000..6ad93fa
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc_def.hh
@@ -0,0 +1,75 @@
+#ifndef ucoo_hal_usb_usb_cdc_def_hh
+#define ucoo_hal_usb_usb_cdc_def_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_def.hh"
+
+namespace ucoo {
+
+enum
+{
+ USB_CDC_NOTIFICATION_SERIAL_STATE = 0x20,
+};
+
+/// Agglomeration of bmRequestType and bRequest.
+enum
+{
+ USB_CDC_REQ_SET_CONTROL_LINE_STATE = USB_REQ (INTERFACE, CLASS, OUT, 0x22),
+ USB_CDC_REQ_SET_LINE_CODING = USB_REQ (INTERFACE, CLASS, OUT, 0x20),
+};
+
+/// Line coding structure.
+struct __attribute__ ((packed, aligned (1))) UsbCdcLineCoding
+{
+ /// Data terminal rate in bits per second.
+ uint32_t dwDTERate;
+ /// Stop bits:
+ /// - 0: 1 stop bit
+ /// - 1: 1.5 stop bits
+ /// - 2: 2 stop bits
+ uint8_t bCharFormat;
+ /// Parity:
+ /// - 0: None
+ /// - 1: Odd
+ /// - 2: Even
+ /// - 3: Mark
+ /// - 4: Space
+ uint8_t bParityType;
+ /// Data bits, 5, 6, 7, 8 or 16.
+ uint8_t bDataBits;
+};
+
+/// Notification structure.
+struct __attribute__ ((packed, aligned (1))) UsbCdcNotification
+{
+ uint8_t bmRequestType;
+ uint8_t bNotification;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_cdc_def_hh
diff --git a/ucoo/hal/usb/usb_cdc_desc.hh b/ucoo/hal/usb/usb_cdc_desc.hh
new file mode 100644
index 0000000..5c1fac2
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc_desc.hh
@@ -0,0 +1,174 @@
+#ifndef ucoo_hal_usb_usb_desc_cdc_hh
+#define ucoo_hal_usb_usb_desc_cdc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_desc.hh"
+
+namespace ucoo {
+
+enum
+{
+ USB_CLASS_CDC = 0x02,
+ USB_CLASS_DATA = 0x0a,
+ USB_CDC_SUBCLASS_ACM = 0x02,
+ USB_CDC_PROTOCOL_AT = 0x01,
+};
+
+/// CDC header descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbCdcHeaderDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 0).
+ uint8_t bDescriptorSubtype;
+ /// USB CDC release number (0x0110 for USB CDC 1.1).
+ uint16_t bcdCDC;
+};
+
+/// Make a header descriptor.
+constexpr UsbCdcHeaderDesc
+usb_cdc_header_desc (uint16_t bcdCDC)
+{
+ return { sizeof (UsbCdcHeaderDesc), 0x24, 0, bcdCDC };
+}
+
+/// CDC call management descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbCdcCallManagementDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 1).
+ uint8_t bDescriptorSubtype;
+ /// Capabilities:
+ /// - bit 0: device handles call management itself
+ /// - bit 1: device can send/receive call management information over
+ /// data class interface
+ uint8_t bmCapabilities;
+ /// Interface number of data class interface used for call management.
+ uint8_t bDataInterface;
+};
+
+/// Make a call management descriptor.
+constexpr UsbCdcCallManagementDesc
+usb_cdc_call_management_desc (
+ uint8_t bmCapabilities,
+ uint8_t bDataInterface)
+{
+ return { sizeof (UsbCdcCallManagementDesc), 0x24, 1, bmCapabilities,
+ bDataInterface };
+}
+
+/// CDC abstract control management descriptor.
+struct __attribute__ ((packed, aligned (1)))
+ UsbCdcAbstractControlManagementDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 2).
+ uint8_t bDescriptorSubtype;
+ /// Capabilities:
+ /// - bit 0: support Set_Comm_Feature, Clear_Comm_Feature and
+ /// Get_Comm_Feature
+ /// - bit 1: support Set_Line_Coding, Set_Control_Line_State,
+ /// Get_Line_Coding and Serial_State notification
+ /// - bit 2: support Send_Break
+ /// - bit 3: support Network_Connection notification
+ uint8_t bmCapabilities;
+};
+
+/// Make an abstract control management descriptor.
+constexpr UsbCdcAbstractControlManagementDesc
+usb_cdc_abstract_control_management_desc (
+ uint8_t bmCapabilities)
+{
+ return { sizeof (UsbCdcAbstractControlManagementDesc), 0x24, 2,
+ bmCapabilities };
+}
+
+/// CDC union descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbCdcUnionDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 6).
+ uint8_t bDescriptorSubtype;
+ /// Interface number of the communication or data class interface
+ /// designated as the controlling interface for the union.
+ uint8_t bControlInterface;
+ /// Interface number of the first subordinated interface in the union.
+ uint8_t bSubordinateInterface0;
+ /// Other subordinated interface number follows...
+};
+
+namespace details { // {{{
+
+template<typename Desc>
+constexpr Desc
+usb_cdc_union_desc (Desc desc)
+{
+ return desc;
+}
+
+template<typename Desc, typename... Rest>
+constexpr auto
+usb_cdc_union_desc (Desc desc, uint8_t bSubordinateInterfaceN,
+ Rest... rest)
+ -> decltype (usb_cdc_union_desc (
+ Pack<Desc, uint8_t> (desc, 0), rest...))
+{
+ return usb_cdc_union_desc (
+ Pack<Desc, uint8_t> (desc, bSubordinateInterfaceN),
+ rest...);
+}
+
+} // namespace details }}}
+
+/// Make an union descriptor.
+template<typename... SubInterfaces>
+constexpr auto
+usb_cdc_union_desc (
+ uint8_t bControlInterface,
+ uint8_t bSubordinateInterface0,
+ SubInterfaces... sub_interfaces)
+ -> decltype (details::usb_cdc_union_desc (
+ (UsbCdcUnionDesc) { 0, 0, 0, 0, 0 }, sub_interfaces...))
+{
+ using Ret = decltype (details::usb_cdc_union_desc (
+ (UsbCdcUnionDesc) { 0, 0, 0, 0, 0 }, sub_interfaces...));
+ return details::usb_cdc_union_desc (
+ (UsbCdcUnionDesc) { sizeof (Ret), 0x24, 6, bControlInterface,
+ bSubordinateInterface0 }, sub_interfaces...);
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_desc_cdc_hh
diff --git a/ucoo/hal/usb/usb_def.hh b/ucoo/hal/usb/usb_def.hh
new file mode 100644
index 0000000..f02ba74
--- /dev/null
+++ b/ucoo/hal/usb/usb_def.hh
@@ -0,0 +1,71 @@
+#ifndef ucoo_hal_usb_usb_def_hh
+#define ucoo_hal_usb_usb_def_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+enum
+{
+ /// Only support one control end point size.
+ USB_CONTROL_END_POINT_SIZE = 64,
+};
+
+/// Agglomeration of bmRequestType and bRequest.
+enum
+{
+ USB_REQ_TYPE_DEVICE = 0x0000,
+ USB_REQ_TYPE_INTERFACE = 0x0001,
+ USB_REQ_TYPE_END_POINT = 0x0002,
+ USB_REQ_TYPE_OTHER = 0x0003,
+ USB_REQ_TYPE_STANDARD = 0x0000,
+ USB_REQ_TYPE_CLASS = 0x0020,
+ USB_REQ_TYPE_VENDOR = 0x0040,
+ USB_REQ_TYPE_OUT = 0x0000,
+ USB_REQ_TYPE_IN = 0x0080,
+#define USB_REQ(rec, type, dir, code) \
+ (USB_REQ_TYPE_ ## rec | USB_REQ_TYPE_ ## type | USB_REQ_TYPE_ ## dir \
+ | ((code) << 8))
+ USB_REQ_CLEAR_FEATURE_DEVICE = USB_REQ (DEVICE, STANDARD, OUT, 0x01),
+ USB_REQ_CLEAR_FEATURE_INTERFACE = USB_REQ (INTERFACE, STANDARD, OUT, 0x01),
+ USB_REQ_CLEAR_FEATURE_END_POINT = USB_REQ (END_POINT, STANDARD, OUT, 0x01),
+ USB_REQ_GET_CONFIGURATION = USB_REQ (DEVICE, STANDARD, IN, 0x08),
+ USB_REQ_GET_DESCRIPTOR = USB_REQ (DEVICE, STANDARD, IN, 0x06),
+ USB_REQ_GET_INTERFACE = USB_REQ (INTERFACE, STANDARD, IN, 0x0a),
+ USB_REQ_GET_STATUS_DEVICE = USB_REQ (DEVICE, STANDARD, IN, 0x00),
+ USB_REQ_GET_STATUS_INTERFACE = USB_REQ (INTERFACE, STANDARD, IN, 0x00),
+ USB_REQ_GET_STATUS_END_POINT = USB_REQ (END_POINT, STANDARD, IN, 0x00),
+ USB_REQ_SET_ADDRESS = USB_REQ (DEVICE, STANDARD, OUT, 0x05),
+ USB_REQ_SET_CONFIGURATION = USB_REQ (DEVICE, STANDARD, OUT, 0x09),
+ USB_REQ_SET_DESCRIPTOR = USB_REQ (DEVICE, STANDARD, OUT, 0x07),
+ USB_REQ_SET_FEATURE_DEVICE = USB_REQ (DEVICE, STANDARD, OUT, 0x03),
+ USB_REQ_SET_FEATURE_INTERFACE = USB_REQ (INTERFACE, STANDARD, OUT, 0x03),
+ USB_REQ_SET_FEATURE_END_POINT = USB_REQ (END_POINT, STANDARD, OUT, 0x03),
+ USB_REQ_SET_INTERFACE = USB_REQ (INTERFACE, STANDARD, OUT, 0x0b),
+ USB_REQ_SYNCH_FRAME = USB_REQ (END_POINT, STANDARD, IN, 0x0c),
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_def_hh
diff --git a/ucoo/hal/usb/usb_desc.hh b/ucoo/hal/usb/usb_desc.hh
new file mode 100644
index 0000000..e23af04
--- /dev/null
+++ b/ucoo/hal/usb/usb_desc.hh
@@ -0,0 +1,406 @@
+#ifndef ucoo_hal_usb_usb_desc_hh
+#define ucoo_hal_usb_usb_desc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+namespace details { // {{{
+
+/// Pack several elements in a new types (std::tuple constructor is not
+/// constexpr in C++11).
+template<typename... Elements>
+struct Pack;
+
+template<typename Head, typename... Tail>
+struct __attribute__ ((packed, aligned (1))) Pack<Head, Tail...>
+{
+ Head head;
+ Pack<Tail...> tail;
+ constexpr Pack (Head head_, Tail... tail_)
+ : head (head_), tail (tail_...) { }
+};
+
+template<typename Head>
+struct __attribute__ ((packed, aligned (1))) Pack<Head>
+{
+ Head head;
+ constexpr Pack (Head head_) : head (head_) { }
+};
+
+/// Take a pack, unpack the Nth value.
+template<int N, typename Pack>
+struct Unpack;
+
+template<typename Head, typename... Tail>
+struct Unpack<0, Pack<Head, Tail...>>
+{
+ static constexpr const Head &unpack (const Pack<Head, Tail...> &pack)
+ {
+ return pack.head;
+ }
+};
+
+template<int N, typename Head, typename... Tail>
+struct Unpack<N, Pack<Head, Tail...>>
+{
+ static constexpr auto unpack (const Pack<Head, Tail...> &pack)
+ -> decltype (Unpack<N - 1, Pack<Tail...>>::unpack (pack.tail))
+ {
+ return Unpack<N - 1, Pack<Tail...>>::unpack (pack.tail);
+ }
+};
+
+/// Type whose only purpose is to have a sequence of integer as template
+/// parameter.
+template<int ...>
+struct Range
+{
+};
+
+template<int N, int... Next>
+struct RangeGen
+{
+ using Type = typename RangeGen<N - 1, N - 1, Next...>::Type;
+};
+
+template<int... Next>
+struct RangeGen<0, Next...>
+{
+ using Type = Range<Next...>;
+};
+
+} // namespace details }}}
+
+/// Device descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbDeviceDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Device descriptor type (1).
+ uint8_t bDescriptorType;
+ /// USB spec release number (0x0200 for USB 2.0).
+ uint16_t bcdUSB;
+ /// Class code assigned by USB-IF (0x00: each interface defines its own
+ /// class, 0xff: vendor defined).
+ uint8_t bDeviceClass;
+ /// SubClass code assigned by USB-IF.
+ uint8_t bDeviceSubClass;
+ /// Protocol code assigned by USB-IF.
+ uint8_t bDeviceProtocol;
+ /// Max packet size for endpoint 0 (8, 16, 32 or 64).
+ uint8_t bMaxPacketSize0;
+ /// Vendor ID.
+ uint16_t idVendor;
+ /// Product ID.
+ uint16_t idProduct;
+ /// Device release number.
+ uint16_t bcdDevice;
+ /// Index of string descriptor describing manufacturer (0 if no string).
+ uint8_t iManufacturer;
+ /// Index of string descriptor describing product (0 if no string).
+ uint8_t iProduct;
+ /// Index of string descriptor describing device serial number (0 if no
+ /// string).
+ uint8_t iSerialNumber;
+ /// Number of possible configurations.
+ uint8_t bNumConfigurations;
+};
+
+/// Make a device descriptor.
+constexpr UsbDeviceDesc
+usb_device_desc (
+ uint16_t bcdUSB,
+ uint8_t bDeviceClass,
+ uint8_t bDeviceSubClass,
+ uint8_t bDeviceProtocol,
+ uint8_t bMaxPacketSize0,
+ uint16_t idVendor,
+ uint16_t idProduct,
+ uint16_t bcdDevice,
+ uint8_t iManufacturer,
+ uint8_t iProduct,
+ uint8_t iSerialNumber,
+ uint8_t bNumConfigurations)
+{
+ return { sizeof (UsbDeviceDesc), 1, bcdUSB, bDeviceClass, bDeviceSubClass,
+ bDeviceProtocol, bMaxPacketSize0, idVendor, idProduct, bcdDevice,
+ iManufacturer, iProduct, iSerialNumber, bNumConfigurations };
+}
+
+/// Configuration descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbConfigurationDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Configuration descriptor type (2).
+ uint8_t bDescriptorType;
+ /// Total number of bytes in this descriptor and all the following
+ /// descriptors.
+ uint16_t wTotalLength;
+ /// Number of interfaces supported by this configuration.
+ uint8_t bNumInterfaces;
+ /// Value used by Set Configuration to select this configuration.
+ uint8_t bConfigurationValue;
+ /// Index of string descriptor describing configuration (0 if no string).
+ uint8_t iConfiguration;
+ /// Attributes:
+ /// - bit 7: must be set
+ /// - bit 6: self-powered
+ /// - bit 5: remote wakeup
+ /// - others: must be 0
+ uint8_t bmAttributes;
+ /// Maximum current drawn by device in this configuration in units of
+ /// 2 mA.
+ uint8_t bMaxPower;
+};
+
+/// Make a configuration descriptor.
+template<typename... SubDesc>
+constexpr details::Pack<UsbConfigurationDesc, SubDesc...>
+usb_configuration_desc (
+ uint8_t bNumInterfaces,
+ uint8_t bConfigurationValue,
+ uint8_t iConfiguration,
+ uint8_t bmAttributes,
+ uint8_t bMaxPower,
+ SubDesc... sub_descs)
+{
+ return details::Pack<UsbConfigurationDesc, SubDesc...> (
+ { sizeof (UsbConfigurationDesc), 2,
+ sizeof (details::Pack<UsbConfigurationDesc, SubDesc...>),
+ bNumInterfaces, bConfigurationValue, iConfiguration, bmAttributes,
+ bMaxPower }, sub_descs...);
+}
+
+/// Interface descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbInterfaceDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Interface descriptor type (4).
+ uint8_t bDescriptorType;
+ /// Number identifying this interface (start at 0).
+ uint8_t bInterfaceNumber;
+ /// Value used to select this alternate setting for this interface (0 for
+ /// first and default setting).
+ uint8_t bAlternateSetting;
+ /// Number of endpoints used by this interface.
+ uint8_t bNumEndpoints;
+ /// Class code assigned by USB-IF.
+ uint8_t bInterfaceClass;
+ /// SubClass Code assigned by USB-IF.
+ uint8_t bInterfaceSubClass;
+ /// Protocol Code assigned by USB-IF.
+ uint8_t bInterfaceProtocol;
+ /// Index of string descriptor describing interface (0 if no string).
+ uint8_t iInterface;
+};
+
+/// Make an interface descriptor.
+template<typename... SubDesc>
+constexpr details::Pack<UsbInterfaceDesc, SubDesc...>
+usb_interface_desc (
+ uint8_t bInterfaceNumber,
+ uint8_t bAlternateSetting,
+ uint8_t bNumEndpoints,
+ uint8_t bInterfaceClass,
+ uint8_t bInterfaceSubClass,
+ uint8_t bInterfaceProtocol,
+ uint8_t iInterface,
+ SubDesc... sub_descs)
+{
+ return details::Pack<UsbInterfaceDesc, SubDesc...> (
+ { sizeof (UsbInterfaceDesc), 4, bInterfaceNumber, bAlternateSetting,
+ bNumEndpoints, bInterfaceClass, bInterfaceSubClass,
+ bInterfaceProtocol, iInterface }, sub_descs...);
+}
+
+/// Endpoint descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbEndpointDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Endpoint descriptor type (5).
+ uint8_t bDescriptorType;
+ /// The address of this endpoint within the device.
+ /// - bit 7: direction: 0: OUT, 1: IN
+ /// - bit 3-0: endpoint number
+ uint8_t bEndpointAddress;
+ /// Attributes:
+ /// - bit 7-6: must be 0
+ /// - bit 5-4: usage type:
+ /// - 00: data endpoint
+ /// - 01: feedback endpoint
+ /// - 10: implicit feedback data endpoint
+ /// - bit 3-2: synchronisation type
+ /// - 00: none
+ /// - 01: asynchronous
+ /// - 10: adaptive
+ /// - 11: synchronous
+ /// - bit 1-0: transfer type
+ /// - 00: control
+ /// - 01: isochronous
+ /// - 10: bulk
+ /// - 11: interrupt
+ uint8_t bmAttributes;
+ /// Maximum packet size this endpoint can send or receive when this
+ /// configuration is selected.
+ uint16_t wMaxPacketSize;
+ /// Interval for polling endpoint for data transfers. Expressed in frames
+ /// (ms) for low/full speed.
+ uint8_t bInterval;
+};
+
+/// Make an endpoint descriptor.
+template<typename... SubDesc>
+constexpr details::Pack<UsbEndpointDesc, SubDesc...>
+usb_endpoint_desc (
+ uint8_t bEndpointAddress,
+ uint8_t bmAttributes,
+ uint16_t wMaxPacketSize,
+ uint8_t bInterval,
+ SubDesc... sub_descs)
+{
+ return details::Pack<UsbEndpointDesc, SubDesc...> (
+ { sizeof (UsbEndpointDesc), 5, bEndpointAddress, bmAttributes,
+ wMaxPacketSize, bInterval }, sub_descs...);
+}
+
+/// Make a bulk endpoint descriptor, shortcut.
+template<typename... SubDesc>
+constexpr details::Pack<UsbEndpointDesc, SubDesc...>
+usb_endpoint_desc_bulk (
+ uint8_t bEndpointAddress,
+ uint16_t wMaxPacketSize,
+ SubDesc... sub_descs)
+{
+ return usb_endpoint_desc (bEndpointAddress, 0x02, wMaxPacketSize, 0,
+ sub_descs...);
+}
+
+enum
+{
+ USB_LANGUAGE_EN_US = 0x0409,
+};
+
+/// String descriptor.
+template<int Length>
+struct __attribute__ ((packed, aligned (1))) UsbStringDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// String descriptor type (3).
+ uint8_t bDescriptorType;
+ /// Unicode encoded string.
+ char16_t bString[Length];
+};
+
+namespace details { // {{{
+
+template<int LengthWithNull, int... Rng>
+constexpr UsbStringDesc<LengthWithNull - 1>
+usb_string_desc (const char16_t (&string)[LengthWithNull],
+ const Range<Rng...> &)
+{
+ return { sizeof (UsbStringDesc<LengthWithNull - 1>), 3,
+ { string[Rng]... } };
+}
+
+} // namespace details }}}
+
+/// Make a string descriptor.
+template<int LengthWithNull>
+constexpr UsbStringDesc<LengthWithNull - 1>
+usb_string_desc (const char16_t (&string)[LengthWithNull])
+{
+ return details::usb_string_desc (
+ string, typename details::RangeGen<LengthWithNull - 1>::Type ());
+}
+
+/// Make the first string descriptor (language descriptor).
+template<typename... Languages>
+constexpr UsbStringDesc<sizeof... (Languages)>
+usb_string_desc (Languages... languages)
+{
+ return { sizeof (UsbStringDesc<sizeof... (Languages)>), 3,
+ { static_cast<char16_t> (languages)... } };
+}
+
+/// Make a descriptors pack.
+template<typename... Descs>
+constexpr details::Pack<Descs...>
+usb_descs_pack (Descs... descs)
+{
+ return details::Pack<Descs...> (descs...);
+}
+
+namespace details {
+
+/// Descriptor with its size.
+struct UsbDesc
+{
+ const char *desc;
+ int desc_size;
+ template<typename Desc>
+ constexpr UsbDesc (const Desc &desc_)
+ : desc (reinterpret_cast<const char *> (&desc_)),
+ desc_size (sizeof (desc_)) { }
+};
+
+/// Descriptors with their size.
+template<typename... Elements>
+struct UsbDescs;
+
+template<typename Head>
+struct UsbDescs<Head>
+{
+ UsbDesc head;
+ constexpr UsbDescs (const Pack<Head> &pack)
+ : head (pack.head) { }
+};
+
+template<typename Head, typename... Tail>
+struct UsbDescs<Head, Tail...>
+{
+ UsbDesc head;
+ UsbDescs<Tail...> tail;
+ constexpr UsbDescs (const Pack<Head, Tail...> &pack)
+ : head (pack.head), tail (pack.tail) { }
+};
+
+} // namespace details }}}
+
+/// Make an object with descriptors and their sizes.
+template<typename... Descs>
+constexpr details::UsbDescs<Descs...>
+usb_descs (const details::Pack<Descs...> &descs_pack)
+{
+ return descs_pack;
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_desc_hh
diff --git a/ucoo/hal/usb/usb_desc.stm32.c b/ucoo/hal/usb/usb_desc.stm32.c
deleted file mode 100644
index aecc4da..0000000
--- a/ucoo/hal/usb/usb_desc.stm32.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* ucoolib - Microcontroller object oriented library. {{{
- *
- * Copyright (C) 2012 Nicolas Schodet
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * }}} */
-#include "usb_desc.stm32.h"
-#include <libopencm3/usb/usbstd.h>
-#include <libopencm3/usb/cdc.h>
-
-#include "config/ucoo/hal/usb.hh"
-
-const struct usb_device_descriptor usb_desc_dev = {
- .bLength = USB_DT_DEVICE_SIZE,
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = 0x0200,
- .bDeviceClass = CONFIG_UCOO_HAL_USB_CDC_ACM ? USB_CLASS_CDC : 0xff,
- .bDeviceSubClass = 0,
- .bDeviceProtocol = 0,
- .bMaxPacketSize0 = 64,
- .idVendor = CONFIG_UCOO_HAL_USB_VENDOR_ID,
- .idProduct = CONFIG_UCOO_HAL_USB_PRODUCT_ID,
- .bcdDevice = 0x0000,
- .iManufacturer = 1,
- .iProduct = 2,
- .iSerialNumber = 0,
- .bNumConfigurations = 1,
-};
-
-static const struct usb_endpoint_descriptor usb_desc_endp_1[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x01,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x81,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
-};
-
-#if !CONFIG_UCOO_HAL_USB_CDC_ACM
-
-static const struct usb_interface_descriptor usb_desc_iface_1[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_1,
- },
-};
-
-#else /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-static const struct usb_interface_descriptor usb_desc_iface_1[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_DATA,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_1,
- },
-};
-
-static const struct {
- struct usb_cdc_header_descriptor header;
- struct usb_cdc_call_management_descriptor call_mgmt;
- struct usb_cdc_acm_descriptor acm;
- struct usb_cdc_union_descriptor cdc_union;
-} __attribute__ ((packed)) usb_desc_func_desc_1 = {
- .header = {
- .bFunctionLength = sizeof (struct usb_cdc_header_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
- .bcdCDC = 0x0110,
- },
- .call_mgmt = {
- .bFunctionLength = sizeof (struct usb_cdc_call_management_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
- .bmCapabilities = 0,
- .bDataInterface = 1,
- },
- .acm = {
- .bFunctionLength = sizeof (struct usb_cdc_acm_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_ACM,
- .bmCapabilities = 2, /* SET_LINE_CODING, SET_CONTROL_LINE_STATE,
- GET_LINE_CODING, and SERIAL_STATE
- notification. */
- },
- .cdc_union = {
- .bFunctionLength = sizeof (struct usb_cdc_union_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_UNION,
- .bControlInterface = 0,
- .bSubordinateInterface0 = 1,
- },
-};
-
-static const struct usb_endpoint_descriptor usb_desc_endp_1_notif[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x82,
- .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
- .wMaxPacketSize = 16,
- .bInterval = 128,
- },
-};
-
-static const struct usb_interface_descriptor usb_desc_iface_1_notif[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_CDC,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_1_notif,
-
- .extra = &usb_desc_func_desc_1,
- .extralen = sizeof (usb_desc_func_desc_1),
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 2
-# if CONFIG_UCOO_HAL_USB_CDC_ACM
-# error "no enough endpoints to implement CDC ACM"
-# endif
-
-static const struct usb_endpoint_descriptor usb_desc_endp_2[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x02,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x82,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
-};
-
-static const struct usb_interface_descriptor usb_desc_iface_2[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_2,
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_STREAM_NB >= 2 */
-
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 3
-
-static const struct usb_endpoint_descriptor usb_desc_endp_3[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x03,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x83,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
-};
-
-static const struct usb_interface_descriptor usb_desc_iface_3[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 2,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_3,
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_STREAM_NB >= 3 */
-
-#if CONFIG_UCOO_HAL_USB_STREAM_NB > 3
-# error "too many streams requested"
-#endif
-
-#if !CONFIG_UCOO_HAL_USB_CDC_ACM
-
-static const struct usb_interface usb_desc_ifaces[] = {
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_1,
- },
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 2
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_2,
- },
-#endif
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 3
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_3,
- },
-#endif
-};
-
-#else /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-static const struct usb_interface usb_desc_ifaces[] = {
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_1_notif,
- },
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_1,
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-const struct usb_config_descriptor usb_desc_config = {
- .bLength = USB_DT_CONFIGURATION_SIZE,
- .bDescriptorType = USB_DT_CONFIGURATION,
- .wTotalLength = 0,
- .bNumInterfaces = CONFIG_UCOO_HAL_USB_CDC_ACM ? 2 : CONFIG_UCOO_HAL_USB_STREAM_NB,
- .bConfigurationValue = 1,
- .iConfiguration = 0,
- .bmAttributes = 0x80 | (CONFIG_UCOO_HAL_USB_SELF_POWERED ? 0x40 : 0),
- .bMaxPower = CONFIG_UCOO_HAL_USB_MAX_POWER / 2,
-
- .interface = usb_desc_ifaces,
-};
-
diff --git a/ucoo/hal/usb/usb_desc.stm32.h b/ucoo/hal/usb/usb_desc.stm32.h
deleted file mode 100644
index dca84b7..0000000
--- a/ucoo/hal/usb/usb_desc.stm32.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ucoo_hal_usb_usb_desc_stm32_h
-#define ucoo_hal_usb_usb_desc_stm32_h
-/* ucoolib - Microcontroller object oriented library. {{{
- *
- * Copyright (C) 2012 Nicolas Schodet
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * }}} */
-#include <libopencm3/usb/usbstd.h>
-
-/** USB device descriptor. */
-extern const struct usb_device_descriptor usb_desc_dev;
-/** USB configuration descriptor. */
-extern const struct usb_config_descriptor usb_desc_config;
-
-#endif /* ucoo_hal_usb_usb_desc_stm32_h */
diff --git a/ucoo/hal/usb/usb_driver.cc b/ucoo/hal/usb/usb_driver.cc
new file mode 100644
index 0000000..efd8e6c
--- /dev/null
+++ b/ucoo/hal/usb/usb_driver.cc
@@ -0,0 +1,130 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_driver.hh"
+#include "ucoo/hal/usb/usb_def.hh"
+
+namespace ucoo {
+
+Trace<CONFIG_UCOO_HAL_USB_TRACE> usb_trace;
+
+void
+UsbDriver::register_application (UsbApplication &app)
+{
+ for (auto &ap : applications_)
+ {
+ if (!ap)
+ {
+ ap = &app;
+ return;
+ }
+ }
+ assert_unreachable ();
+}
+
+void
+UsbDriver::set_configuration (int configuration)
+{
+ if (configuration == current_configuration_)
+ return;
+ assert (current_configuration_ == -1); // TODO: handle change.
+ for (auto app : applications_)
+ {
+ if (!app)
+ break;
+ app->handle_configuration_set (configuration);
+ }
+ current_configuration_ = configuration;
+}
+
+void
+UsbDriver::ep_setup (uint8_t address, EpType type, int size,
+ UsbApplication &app)
+{
+ bool in = address & 0x80;
+ int ep = address & 0x7f;
+ assert (ep < END_POINT_MAX);
+ if (in)
+ in_handlers_[ep] = &app;
+ else
+ out_handlers_[ep] = &app;
+ ep_setup (address, type, size);
+}
+
+void
+UsbDriver::handle_reset ()
+{
+ ep_setup (0, EpType::Control, USB_CONTROL_END_POINT_SIZE);
+}
+
+void
+UsbDriver::handle_setup (uint32_t *msg)
+{
+ uint16_t bmRequestType_n_bRequest = (msg[0] >> 0) & 0xffff;
+ uint16_t wValue = (msg[0] >> 16) & 0xffff;
+ uint16_t wIndex = (msg[1] >> 0) & 0xffff;
+ uint16_t wLength = (msg[1] >> 16) & 0xffff;
+ bool ok = false;
+ out_handlers_[0] = nullptr;
+ in_handlers_[0] = nullptr;
+ for (auto app : applications_)
+ {
+ if (!app)
+ break;
+ UsbApplication::SetupResult r = app->handle_setup (
+ bmRequestType_n_bRequest, wValue, wIndex, wLength);
+ if (r == UsbApplication::SetupResult::Handled)
+ {
+ out_handlers_[0] = app;
+ in_handlers_[0] = app;
+ ok = true;
+ break;
+ }
+ else if (r == UsbApplication::SetupResult::Error)
+ break;
+ }
+ if (!ok)
+ ep_stall (0);
+}
+
+void
+UsbDriver::ep_handle_out (uint8_t address, int bcnt)
+{
+ int ep_num = address;
+ if (out_handlers_[ep_num])
+ out_handlers_[ep_num]->ep_handle_out (address, bcnt);
+ else
+ ep_stall (address);
+}
+
+void
+UsbDriver::ep_handle_in (uint8_t address)
+{
+ int ep_num = address & 0x7f;
+ if (in_handlers_[ep_num])
+ in_handlers_[ep_num]->ep_handle_in (address);
+ else
+ ep_stall (address);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_driver.hh b/ucoo/hal/usb/usb_driver.hh
new file mode 100644
index 0000000..3f36b1d
--- /dev/null
+++ b/ucoo/hal/usb/usb_driver.hh
@@ -0,0 +1,120 @@
+#ifndef ucoo_hal_usb_usb_driver_hh
+#define ucoo_hal_usb_usb_driver_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_application.hh"
+
+#include "ucoo/utils/trace.hh"
+#include "config/ucoo/hal/usb.hh"
+
+namespace ucoo {
+
+extern Trace<CONFIG_UCOO_HAL_USB_TRACE> usb_trace;
+
+/// Low level USB driver.
+class UsbDriver
+{
+ public:
+ enum class EpType
+ {
+ Control,
+ Isochronous,
+ Bulk,
+ Interrupt,
+ };
+ public:
+ /// Constructor.
+ template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+ UsbDriver (const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs);
+ /// No copy constructor.
+ UsbDriver (const UsbDriver &) = delete;
+ /// Register an application, typically done in application constructor.
+ void register_application (UsbApplication &app);
+ /// Enable hardware.
+ virtual void enable () = 0;
+ /// Disable hardware.
+ virtual void disable () = 0;
+ /// Write data to an end point. Return the number of written bytes,
+ /// following bytes will have to be written once there is room in TX FIFO.
+ virtual int ep_write (uint8_t address, const char *data, int size) = 0;
+ /// Signal application have some data to send.
+ virtual void ep_write_ready (uint8_t address) = 0;
+ /// Read data from an end point. Should only be done when data is
+ /// signaled to be available. Return the number of read bytes.
+ virtual int ep_read (uint8_t address, char *data, int size) = 0;
+ /// Signal application can read data (with maximum buffer size).
+ virtual void ep_read_ready (uint8_t address, int size) = 0;
+ /// Stall an end point.
+ virtual void ep_stall (uint8_t address, bool stall = true) = 0;
+ /// Set device address.
+ virtual void set_address (uint8_t address) = 0;
+ /// Set configuration.
+ void set_configuration (int configuration);
+ /// Setup an end point, make an application responsible for it.
+ void ep_setup (uint8_t address, EpType type, int size, UsbApplication &app);
+ protected:
+ /// Setup an end point.
+ virtual void ep_setup (uint8_t address, EpType type, int size) = 0;
+ /// Handle reset, called by driver.
+ void handle_reset ();
+ /// Handle SETUP, called by driver when received.
+ void handle_setup (uint32_t *msg);
+ /// Handle OUT, called by driver when received.
+ void ep_handle_out (uint8_t address, int bcnt);
+ /// Handle IN, called by driver when transmission can be done.
+ void ep_handle_in (uint8_t address);
+ private:
+ enum {
+ APPLICATION_MAX = 3,
+ END_POINT_MAX = 4,
+ };
+ /// Registered applications.
+ UsbApplication *applications_[APPLICATION_MAX];
+ /// Handlers of OUT events.
+ UsbApplication *out_handlers_[END_POINT_MAX];
+ /// Handlers of IN events.
+ UsbApplication *in_handlers_[END_POINT_MAX];
+ /// Basic USB protocol application.
+ UsbApplicationBasic app_basic_;
+ /// Current configuration or -1 if not configured.
+ int current_configuration_ = -1;
+};
+
+template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+UsbDriver::UsbDriver (const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs)
+ : applications_ { nullptr }, out_handlers_ { nullptr },
+ in_handlers_ { nullptr },
+ app_basic_ (*this, device_desc, configuration_desc, string_descs)
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_driver_hh
diff --git a/ucoo/hal/usb/usb_dwc_otg.stm32.cc b/ucoo/hal/usb/usb_dwc_otg.stm32.cc
new file mode 100644
index 0000000..a19fca7
--- /dev/null
+++ b/ucoo/hal/usb/usb_dwc_otg.stm32.cc
@@ -0,0 +1,412 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_dwc_otg.stm32.hh"
+#include "ucoo/hal/usb/usb_def.hh"
+
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/interrupt.arm.hh"
+#include "ucoo/arch/rcc.stm32.hh"
+
+namespace ucoo {
+
+/// Information on USB hardware.
+struct UsbHardware
+{
+ /// Base address.
+ USB_OTG_TypeDef *base;
+ /// RCC identifier.
+ Rcc rcc;
+ /// Corresponding IRQ.
+ Irq irq;
+ /// Used GPIO port
+ GpioPort &gpio_port;
+#ifdef TARGET_stm32f4
+ /// D+ and D- pins.
+ int gpio_dp, gpio_dm;
+ /// GPIO alternate function.
+ int gpio_af;
+#endif
+};
+
+static const UsbHardware usb_hardware[] =
+{
+ { reg::USB_OTG_FS, Rcc::OTGFS, Irq::OTG_FS, GPIOA,
+#ifdef TARGET_stm32f4
+ 12, 11, 10
+#endif
+ },
+#ifdef USB_OTG_HS_BASE
+ { reg::USB_OTG_HS, Rcc::OTGHS, Irq::OTG_HS, GPIOB, 15, 14, 12 },
+#endif
+};
+
+static UsbDriverDwcOtg *usb_instance;
+
+template<>
+void interrupt<Irq::OTG_FS> ()
+{
+ ucoo::assert (usb_instance);
+ usb_instance->isr ();
+}
+
+#ifdef USB_OTG_HS_BASE
+template<>
+void interrupt<Irq::OTG_HS> ()
+{
+ ucoo::assert (usb_instance);
+ usb_instance->isr ();
+}
+#endif
+
+void
+UsbDriverDwcOtg::enable ()
+{
+ assert (!usb_instance);
+ usb_trace ("enable");
+ enabled_ = true;
+ usb_instance = this;
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ /// Setup GPIO (this is an exception of the global scheme where the user
+ /// do this).
+ hard.gpio_port.enable ();
+#ifdef TARGET_stm32f4
+ hard.gpio_port[hard.gpio_dp].af (hard.gpio_af);
+ hard.gpio_port[hard.gpio_dm].af (hard.gpio_af);
+#endif
+ /// Enable clock.
+ rcc_peripheral_clock_enable (hard.rcc);
+ asm volatile ("nop"); // TODO: Do not know why this is needed.
+ asm volatile ("nop");
+ asm volatile ("nop");
+ // Reset.
+ while (!(hard.base->global.GRSTCTL & USB_OTG_GRSTCTL_AHBIDL))
+ ;
+ hard.base->global.GRSTCTL = USB_OTG_GRSTCTL_CSRST;
+ while (hard.base->global.GRSTCTL & USB_OTG_GRSTCTL_CSRST)
+ ;
+ while (!(hard.base->global.GRSTCTL & USB_OTG_GRSTCTL_AHBIDL))
+ ;
+ // Setup USB core.
+ assert (rcc_ahb_freq_hz > 32000000); // Or else, should change TRDT.
+ hard.base->global.GUSBCFG = USB_OTG_GUSBCFG_FDMOD
+ | (6 * USB_OTG_GUSBCFG_TRDT_0) | USB_OTG_GUSBCFG_PHYSEL;
+ hard.base->global.GAHBCFG |= USB_OTG_GAHBCFG_GINT;
+ hard.base->global.GINTMSK |= USB_OTG_GINTMSK_RXFLVLM
+ | USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_USBRST
+ | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_IEPINT
+ | USB_OTG_GINTMSK_SRQIM /* ? */
+ | USB_OTG_GINTMSK_WUIM;
+ // TODO: USB_OTG_GCCFG_VBDEN for F479.
+ hard.base->global.GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN;
+ hard.base->device.DCFG |= USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD;
+ hard.base->device.DCTL = 0;
+ hard.base->device.DIEPMSK = USB_OTG_DIEPMSK_XFRCM;
+ hard.base->device.DAINTMSK = USB_OTG_DAINTMSK_IEPM;
+ // Enable interrupts.
+ interrupt_enable (hard.irq);
+}
+
+void
+UsbDriverDwcOtg::disable ()
+{
+ if (enabled_)
+ {
+ usb_trace ("disable");
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ hard.base->device.DCTL = USB_OTG_DCTL_SDIS;
+ interrupt_disable (hard.irq);
+ rcc_peripheral_clock_disable (hard.rcc);
+#ifdef TARGET_stm32f4
+ hard.gpio_port[hard.gpio_dp].input ();
+ hard.gpio_port[hard.gpio_dm].input ();
+#endif
+ usb_instance = nullptr;
+ }
+}
+
+int
+UsbDriverDwcOtg::ep_write (uint8_t address, const char *data, int size)
+{
+ int ep = address & 0x7f;
+ if (size > ep_in_size_[ep])
+ size = ep_in_size_[ep];
+ usb_trace ("write %d %d", ep, size);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ assert (!(hard.base->ep_in[ep].DIEPCTL & USB_OTG_DIEPCTL_EPENA));
+ hard.base->ep_in[ep].DIEPTSIZ = (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | size;
+ hard.base->ep_in[ep].DIEPCTL |=
+ USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
+ const uint32_t *data32 = reinterpret_cast<const uint32_t *> (data);
+ for (int i = 0; i < size; i += 4)
+ hard.base->fifo[ep].FIFO = *data32++;
+ return size;
+}
+
+void
+UsbDriverDwcOtg::ep_write_ready (uint8_t address)
+{
+ int ep = address & 0x7f;
+ usb_trace ("write ready %d", ep);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ irq_flags_t flags = irq_lock ();
+ // Before the interrupt is locked, an interrupt could have been triggered.
+ // This code might call ep_handle_in in this case, but only if no data was
+ // written by the application.
+ if (hard.base->ep_in[ep].DIEPCTL & USB_OTG_DIEPCTL_EPENA)
+ // End point is enabled, will trigger an interrupt when done.
+ ;
+ else if (hard.base->ep_in[ep].DIEPINT & USB_OTG_DIEPINT_XFRC)
+ // Interrupt triggered, waiting to deliver the interrupt.
+ ;
+ else
+ // Restart data flow.
+ ep_handle_in (address);
+ irq_restore (flags);
+}
+
+int
+UsbDriverDwcOtg::ep_read (uint8_t address, char *data, int size)
+{
+ int ep = address;
+ assert (ep == rx_ep_);
+ if (size > rx_length_)
+ size = rx_length_;
+ usb_trace ("read %d %d", ep, size);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ uint32_t *data32 = reinterpret_cast<uint32_t *> (data);
+ for (int i = 0; i < size / 4; i++)
+ *data32++ = hard.base->fifo[0].FIFO;
+ if (size % 4)
+ {
+ uint32_t w = hard.base->fifo[0].FIFO;
+ uint8_t *data8 = reinterpret_cast<uint8_t *> (data32);
+ for (int i = 0; i < size % 4; i++)
+ {
+ *data8++ = w & 0xff;
+ w >>= 8;
+ }
+ }
+ rx_length_ -= size;
+ if (rx_length_ == 0)
+ rx_ep_ = -1;
+ return size;
+}
+
+void
+UsbDriverDwcOtg::ep_read_ready (uint8_t address, int size)
+{
+ int ep = address;
+ usb_trace ("read ready %d %d", ep, size);
+ if (size >= ep_out_size_[ep])
+ {
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ irq_flags_t flags = irq_lock ();
+ if (!(hard.base->ep_out[ep].DOEPCTL & USB_OTG_DOEPCTL_EPENA))
+ {
+ hard.base->ep_out[ep].DOEPTSIZ = ep_out_doeptsiz_[ep];
+ hard.base->ep_out[ep].DOEPCTL |= USB_OTG_DOEPCTL_EPENA
+ | USB_OTG_DOEPCTL_CNAK;
+ usb_trace ("read ready done");
+ }
+ irq_restore (flags);
+ }
+}
+
+void
+UsbDriverDwcOtg::ep_stall (uint8_t address, bool stall)
+{
+ assert (address == 0 && stall == true);
+ usb_trace ("ep stall %d %d", address, stall);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ hard.base->ep_in[0].DIEPCTL |= USB_OTG_DIEPCTL_STALL;
+}
+
+void
+UsbDriverDwcOtg::set_address (uint8_t address)
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ hard.base->device.DCFG |= USB_OTG_DCFG_DAD_0 * address;
+}
+
+void
+UsbDriverDwcOtg::ep_setup (uint8_t address, EpType type, int size)
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ if (address == 0)
+ {
+ usb_trace ("ep setup 0");
+ assert (type == EpType::Control
+ && size == USB_CONTROL_END_POINT_SIZE);
+ hard.base->global.GRXFSIZ = rx_fifo_size_ / 4;
+ fifo_used_ = rx_fifo_size_;
+ hard.base->global.DIEPTXF0_HNPTXFSIZ =
+ (USB_CONTROL_END_POINT_SIZE / 4) << 16 | fifo_used_ / 4;
+ fifo_used_ += USB_CONTROL_END_POINT_SIZE;
+ ep_in_size_[0] = USB_CONTROL_END_POINT_SIZE;
+ ep_out_size_[0] = USB_CONTROL_END_POINT_SIZE;
+ ep_out_doeptsiz_[0] = USB_OTG_DOEPTSIZ_STUPCNT
+ | (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | USB_CONTROL_END_POINT_SIZE;
+ hard.base->ep_out[0].DOEPTSIZ = ep_out_doeptsiz_[0];
+ hard.base->ep_out[0].DOEPCTL = USB_OTG_DOEPCTL_SNAK
+ | USB_OTG_DOEPCTL_USBAEP;
+ hard.base->ep_in[0].DIEPCTL = USB_OTG_DIEPCTL_SNAK
+ | USB_OTG_DIEPCTL_USBAEP;
+ }
+ else
+ {
+ int ep = address & 0x7f;
+ uint32_t epctl =
+ USB_OTG_DOEPCTL_SD0PID_SEVNFRM
+ | USB_OTG_DOEPCTL_SNAK
+ | (type == EpType::Control ? 0 :
+ type == EpType::Isochronous ? USB_OTG_DOEPCTL_EPTYP_0 :
+ type == EpType::Bulk ? USB_OTG_DOEPCTL_EPTYP_1 :
+ USB_OTG_DOEPCTL_EPTYP_1 | USB_OTG_DOEPCTL_EPTYP_0)
+ | USB_OTG_DOEPCTL_USBAEP
+ | size;
+ if (address & 0x80)
+ {
+ usb_trace ("ep setup in %d %d %d", ep, static_cast<int> (type),
+ size);
+ hard.base->global.DIEPTXF[ep - 1] = (size / 4) << 16
+ | fifo_used_ / 4;
+ fifo_used_ += size;
+ ep_in_size_[ep] = size;
+ hard.base->ep_in[ep].DIEPCTL = epctl
+ | (ep * USB_OTG_DIEPCTL_TXFNUM_0);
+ }
+ else
+ {
+ usb_trace ("ep setup out %d %d %d", ep, static_cast<int> (type),
+ size);
+ ep_out_size_[ep] = size;
+ ep_out_doeptsiz_[ep] = (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | size;
+ hard.base->ep_out[ep].DOEPCTL = epctl;
+ }
+ }
+}
+
+void
+UsbDriverDwcOtg::isr ()
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ uint32_t gintsts = hard.base->global.GINTSTS;
+ if (gintsts & USB_OTG_GINTSTS_USBRST)
+ {
+ /* Reset. */
+ usb_trace ("isr reset");
+ hard.base->device.DCFG &= ~USB_OTG_DCFG_DAD;
+ for (int i = 0; i < END_POINT_NB; i++)
+ hard.base->ep_out[i].DOEPCTL = USB_OTG_DOEPCTL_SNAK;
+ handle_reset ();
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_USBRST;
+ }
+ if (gintsts & USB_OTG_GINTSTS_ENUMDNE)
+ {
+ /* Enumeration done. */
+ usb_trace ("isr enumeration done");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
+ }
+ if (gintsts & USB_OTG_GINTSTS_RXFLVL)
+ {
+ /* RX FIFO not empty. */
+ isr_rx_fifo ();
+ }
+ if (gintsts & USB_OTG_GINTSTS_USBSUSP)
+ {
+ /* USB suspend. */
+ usb_trace ("isr suspend");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_USBSUSP;
+ }
+ if (gintsts & USB_OTG_GINTSTS_IEPINT)
+ {
+ /* IN end point interrupt. */
+ uint32_t daint = hard.base->device.DAINT;
+ for (int i = 0; i < END_POINT_NB; i++)
+ {
+ if (daint & (1 << i))
+ {
+ usb_trace ("isr in xfrc %d", i);
+ ep_handle_in (i ? 0x80 | i : 0);
+ hard.base->ep_in[i].DIEPINT = USB_OTG_DIEPINT_XFRC;
+ }
+ }
+ }
+ if (gintsts & USB_OTG_GINTSTS_DISCINT)
+ {
+ /* Disconnect. */
+ usb_trace ("isr disconnect");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_DISCINT;
+ }
+ if (gintsts & USB_OTG_GINTSTS_SRQINT)
+ {
+ /* New session. */
+ usb_trace ("isr new session");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_SRQINT;
+ }
+ if (gintsts & USB_OTG_GINTSTS_WKUINT)
+ {
+ /* Wake up. */
+ usb_trace ("isr wake up");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_WKUINT;
+ }
+}
+
+void
+UsbDriverDwcOtg::isr_rx_fifo ()
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ uint32_t rx = hard.base->global.GRXSTSP;
+ uint32_t pkt_status = rx & USB_OTG_GRXSTSP_PKTSTS;
+ int ep = rx & USB_OTG_GRXSTSP_EPNUM;
+ int bcnt = (rx & USB_OTG_GRXSTSP_BCNT) >> USB_OTG_GRXSTSP_BCNT_Pos;
+ if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_Setup)
+ {
+ usb_trace ("isr rx setup");
+ assert (ep == 0 && bcnt == 8);
+ setup_buf_[0] = hard.base->fifo[0].FIFO;
+ setup_buf_[1] = hard.base->fifo[0].FIFO;
+ }
+ else if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_SetupCompleted)
+ {
+ usb_trace ("isr rx setup completed");
+ handle_setup (&setup_buf_[0]);
+ }
+ else if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_Out)
+ {
+ usb_trace ("isr rx out %d %d", ep, bcnt);
+ rx_ep_ = ep;
+ rx_length_ = bcnt;
+ ep_handle_out (ep, bcnt);
+ assert (rx_length_ == 0);
+ }
+ else if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_OutCompleted)
+ usb_trace ("isr rx out completed");
+ else
+ usb_trace ("isr rx other %d",
+ pkt_status >> USB_OTG_GRXSTSP_PKTSTS_Pos);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_dwc_otg.stm32.hh b/ucoo/hal/usb/usb_dwc_otg.stm32.hh
new file mode 100644
index 0000000..dec71ec
--- /dev/null
+++ b/ucoo/hal/usb/usb_dwc_otg.stm32.hh
@@ -0,0 +1,94 @@
+#ifndef ucoo_hal_usb_usb_dwc_otg_stm32_hh
+#define ucoo_hal_usb_usb_dwc_otg_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_driver.hh"
+
+namespace ucoo {
+
+/// Low level USB driver.
+class UsbDriverDwcOtg : public UsbDriver
+{
+ public:
+ enum
+ {
+ END_POINT_NB = 4,
+ };
+ enum class Instance
+ {
+ OTG_FS,
+ OTG_HS,
+ };
+ public:
+ /// Constructor for a USB OTG instance.
+ template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+ UsbDriverDwcOtg (Instance inst,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs);
+ /// Destructor, disable.
+ ~UsbDriverDwcOtg () { disable (); }
+ void enable () override;
+ void disable () override;
+ int ep_write (uint8_t address, const char *data, int size) override;
+ void ep_write_ready (uint8_t address) override;
+ int ep_read (uint8_t address, char *data, int size) override;
+ void ep_read_ready (uint8_t address, int size) override;
+ void ep_stall (uint8_t address, bool stall = true) override;
+ void set_address (uint8_t address) override;
+ protected:
+ void ep_setup (uint8_t address, EpType type, int size) override;
+ public:
+ void isr ();
+ private:
+ void isr_rx_fifo ();
+ private:
+ Instance inst_;
+ bool enabled_ = false;
+ const int rx_fifo_size_ = 512;
+ int rx_ep_ = -1;
+ int rx_length_ = -1;
+ int ep_out_size_[END_POINT_NB];
+ int ep_in_size_[END_POINT_NB];
+ uint32_t ep_out_doeptsiz_[END_POINT_NB];
+ int fifo_used_ = 0;
+ uint32_t setup_buf_[2];
+};
+
+template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+UsbDriverDwcOtg::UsbDriverDwcOtg (
+ Instance inst,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs)
+ : UsbDriver (device_desc, configuration_desc, string_descs),
+ inst_ (inst)
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_dwc_otg_stm32_hh