From 313394af2c063e20d3574cfbc1e14dd4ae0d70d0 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Tue, 5 Jan 2016 15:37:52 +0100 Subject: ucoo/hal/usb: handle CDC ACM --- ucoo/hal/usb/Config | 2 + ucoo/hal/usb/usb.stm32.cc | 54 ++++++++++++++++++++ ucoo/hal/usb/usb_desc.stm32.c | 114 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 168 insertions(+), 2 deletions(-) (limited to 'ucoo') 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 +#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 (&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 +#include #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), -- cgit v1.2.3