summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2016-01-05 15:37:52 +0100
committerNicolas Schodet2019-10-07 00:44:57 +0200
commit313394af2c063e20d3574cfbc1e14dd4ae0d70d0 (patch)
treef7e4f6acbd25f9fbeeb8b100adf11968ba134ad2
parentbd32e6457b51e4f3e94d6cd5af450695e97a36ef (diff)
ucoo/hal/usb: handle CDC ACM
-rw-r--r--ucoo/hal/usb/Config2
-rw-r--r--ucoo/hal/usb/usb.stm32.cc54
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.c114
3 files changed, 168 insertions, 2 deletions
diff --git a/ucoo/hal/usb/Config b/ucoo/hal/usb/Config
index 0ec69c3..79098f2 100644
--- a/ucoo/hal/usb/Config
+++ b/ucoo/hal/usb/Config
@@ -2,6 +2,8 @@
# Theses are APBTeam IDs, given by Openmoko!
vendor_id = 0x1d50
product_id = 0x6052
+# Declare as a CDC ACM device.
+cdc_acm = false
# 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.
diff --git a/ucoo/hal/usb/usb.stm32.cc b/ucoo/hal/usb/usb.stm32.cc
index 6ec0902..1d88961 100644
--- a/ucoo/hal/usb/usb.stm32.cc
+++ b/ucoo/hal/usb/usb.stm32.cc
@@ -30,6 +30,10 @@
#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
@@ -69,6 +73,47 @@ const char *strings[] = {
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)
{
@@ -121,6 +166,15 @@ UsbStreamControl::set_config (usbd_device *usbdev, uint16_t configured)
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
}
}
diff --git a/ucoo/hal/usb/usb_desc.stm32.c b/ucoo/hal/usb/usb_desc.stm32.c
index ae14d14..c8617fd 100644
--- a/ucoo/hal/usb/usb_desc.stm32.c
+++ b/ucoo/hal/usb/usb_desc.stm32.c
@@ -22,6 +22,8 @@
*
* }}} */
#include "usb_desc.stm32.h"
+#include <libopencm3/usb/usbstd.h>
+#include <libopencm3/usb/cdc.h>
#include "config/ucoo/hal/usb.hh"
@@ -29,7 +31,7 @@ const struct usb_device_descriptor usb_desc_dev = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
- .bDeviceClass = 0xff,
+ .bDeviceClass = CONFIG_UCOO_HAL_USB_CDC_ACM ? USB_CLASS_CDC : 0xff,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
@@ -61,6 +63,8 @@ static const struct usb_endpoint_descriptor usb_desc_endp_1[] = {
},
};
+#if !CONFIG_UCOO_HAL_USB_CDC_ACM
+
static const struct usb_interface_descriptor usb_desc_iface_1[] = {
{
.bLength = USB_DT_INTERFACE_SIZE,
@@ -77,7 +81,96 @@ static const struct usb_interface_descriptor usb_desc_iface_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 = 0,
+ },
+ .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[] = {
{
@@ -159,6 +252,8 @@ static const struct usb_interface_descriptor usb_desc_iface_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,
@@ -178,11 +273,26 @@ static const struct usb_interface usb_desc_ifaces[] = {
#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_STREAM_NB,
+ .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),