#include <stdint.h> #include <stdlib.h> #include <chopstx.h> #include "usb_lld.h" extern chopstx_mutex_t usb_mtx; extern chopstx_cond_t cnd_usb; #define ENDP0_RXADDR (0x40) #define ENDP0_TXADDR (0x80) #define ENDP1_TXADDR (0xc0) #define ENDP2_TXADDR (0x100) #define ENDP3_RXADDR (0x140) #define USB_CDC_REQ_SET_LINE_CODING 0x20 #define USB_CDC_REQ_GET_LINE_CODING 0x21 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 #define USB_CDC_REQ_SEND_BREAK 0x23 /* USB Device Descriptor */ static const uint8_t vcom_device_desc[18] = { 18, /* bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x10, 0x01, /* bcdUSB = 1.1 */ 0x02, /* bDeviceClass (CDC). */ 0x00, /* bDeviceSubClass. */ 0x00, /* bDeviceProtocol. */ 0x40, /* bMaxPacketSize. */ 0xFF, 0xFF, /* idVendor */ 0x01, 0x00, /* idProduct */ 0x00, 0x01, /* bcdDevice */ 1, /* iManufacturer. */ 2, /* iProduct. */ 3, /* iSerialNumber. */ 1 /* bNumConfigurations. */ }; /* Configuration Descriptor tree for a CDC.*/ static const uint8_t vcom_configuration_desc[67] = { 9, USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ /* Configuration Descriptor.*/ 67, 0x00, /* wTotalLength. */ 0x02, /* bNumInterfaces. */ 0x01, /* bConfigurationValue. */ 0, /* iConfiguration. */ 0x80, /* bmAttributes (bus powered). */ 50, /* bMaxPower (100mA). */ /* Interface Descriptor.*/ 9, USB_INTERFACE_DESCRIPTOR_TYPE, 0x00, /* bInterfaceNumber. */ 0x00, /* bAlternateSetting. */ 0x01, /* bNumEndpoints. */ 0x02, /* bInterfaceClass (Communications Interface Class, CDC section 4.2). */ 0x02, /* bInterfaceSubClass (Abstract Control Model, CDC section 4.3). */ 0x01, /* bInterfaceProtocol (AT commands, CDC section 4.4). */ 0, /* iInterface. */ /* Header Functional Descriptor (CDC section 5.2.3).*/ 5, /* bLength. */ 0x24, /* bDescriptorType (CS_INTERFACE). */ 0x00, /* bDescriptorSubtype (Header Functional Descriptor). */ 0x10, 0x01, /* bcdCDC. */ /* Call Management Functional Descriptor. */ 5, /* bFunctionLength. */ 0x24, /* bDescriptorType (CS_INTERFACE). */ 0x01, /* bDescriptorSubtype (Call Management Functional Descriptor). */ 0x03, /* bmCapabilities (D0+D1). */ 0x01, /* bDataInterface. */ /* ACM Functional Descriptor.*/ 4, /* bFunctionLength. */ 0x24, /* bDescriptorType (CS_INTERFACE). */ 0x02, /* bDescriptorSubtype (Abstract Control Management Descriptor). */ 0x02, /* bmCapabilities. */ /* Union Functional Descriptor.*/ 5, /* bFunctionLength. */ 0x24, /* bDescriptorType (CS_INTERFACE). */ 0x06, /* bDescriptorSubtype (Union Functional Descriptor). */ 0x00, /* bMasterInterface (Communication Class Interface). */ 0x01, /* bSlaveInterface0 (Data Class Interface). */ /* Endpoint 2 Descriptor.*/ 7, USB_ENDPOINT_DESCRIPTOR_TYPE, ENDP2|0x80, /* bEndpointAddress. */ 0x03, /* bmAttributes (Interrupt). */ 0x08, 0x00, /* wMaxPacketSize. */ 0xFF, /* bInterval. */ /* Interface Descriptor.*/ 9, USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ 0x01, /* bInterfaceNumber. */ 0x00, /* bAlternateSetting. */ 0x02, /* bNumEndpoints. */ 0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */ 0x00, /* bInterfaceSubClass (CDC section 4.6). */ 0x00, /* bInterfaceProtocol (CDC section 4.7). */ 0x00, /* iInterface. */ /* Endpoint 3 Descriptor.*/ 7, USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ ENDP3, /* bEndpointAddress. */ 0x02, /* bmAttributes (Bulk). */ 0x40, 0x00, /* wMaxPacketSize. */ 0x00, /* bInterval. */ /* Endpoint 1 Descriptor.*/ 7, USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ ENDP1|0x80, /* bEndpointAddress. */ 0x02, /* bmAttributes (Bulk). */ 0x40, 0x00, /* wMaxPacketSize. */ 0x00 /* bInterval. */ }; /* * U.S. English language identifier. */ static const uint8_t vcom_string0[4] = { 4, /* bLength */ USB_STRING_DESCRIPTOR_TYPE, 0x09, 0x04 /* LangID = 0x0409: US-English */ }; static const uint8_t vcom_string1[] = { 23*2+2, /* bLength */ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ /* Manufacturer: "Flying Stone Technology" */ 'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0, 't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0, 'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0, }; static const uint8_t vcom_string2[] = { 14*2+2, /* bLength */ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ /* Product name: "Chopstx Sample" */ 'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0, 'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0, }; /* * Serial Number string. */ static const uint8_t vcom_string3[28] = { 28, /* bLength */ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ '0', 0, '.', 0, '0', 0, '0', 0, /* Version number */ }; #define NUM_INTERFACES 2 uint32_t bDeviceState = UNCONNECTED; /* USB device status */ void usb_cb_device_reset (void) { /* Set DEVICE as not configured */ usb_lld_set_configuration (0); /* Current Feature initialization */ usb_lld_set_feature (vcom_configuration_desc[7]); usb_lld_reset (); /* Initialize Endpoint 0 */ usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64); } void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value, uint16_t index, uint16_t len) { (void)req; (void)req_no; (void)value; (void)index; (void)len; } struct line_coding { uint32_t bitrate; uint8_t format; uint8_t paritytype; uint8_t datatype; }; static struct line_coding line_coding = { 115200, /* baud rate: 115200 */ 0x00, /* stop bits: 1 */ 0x00, /* parity: none */ 0x08 /* bits: 8 */ }; uint8_t connected; static int vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value) { if (USB_SETUP_GET (req)) { if (req_no == USB_CDC_REQ_GET_LINE_CODING) { usb_lld_set_data_to_send (&line_coding, sizeof(line_coding)); return USB_SUCCESS; } } else /* USB_SETUP_SET (req) */ { if (req_no == USB_CDC_REQ_SET_LINE_CODING) { usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding)); return USB_SUCCESS; } else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE) { uint8_t connected_saved = connected; if (value != 0) { if (connected == 0) /* It's Open call */ connected++; } else { if (connected) /* Close call */ connected = 0; } chopstx_mutex_lock (&usb_mtx); if (connected != connected_saved) chopstx_cond_signal (&cnd_usb); chopstx_mutex_unlock (&usb_mtx); return USB_SUCCESS; } } return USB_UNSUPPORT; } int usb_cb_setup (uint8_t req, uint8_t req_no, uint16_t value, uint16_t index, uint16_t len) { uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); (void)len; if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)) if (index == 0) return vcom_port_data_setup (req, req_no, value); return USB_UNSUPPORT; } int usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value) { (void)index; if (desc_type == DEVICE_DESCRIPTOR) { usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc)); return USB_SUCCESS; } else if (desc_type == CONFIG_DESCRIPTOR) { usb_lld_set_data_to_send (vcom_configuration_desc, sizeof (vcom_configuration_desc)); return USB_SUCCESS; } else if (desc_type == STRING_DESCRIPTOR) { uint8_t desc_index = value & 0xff; const uint8_t *str; int size; switch (desc_index) { case 0: str = vcom_string0; size = sizeof (vcom_string0); break; case 1: str = vcom_string1; size = sizeof (vcom_string1); break; case 2: str = vcom_string2; size = sizeof (vcom_string2); break; case 3: str = vcom_string3; size = sizeof (vcom_string3); break; default: return USB_UNSUPPORT; } usb_lld_set_data_to_send (str, size); return USB_SUCCESS; } return USB_UNSUPPORT; } static void vcom_setup_endpoints_for_interface (uint16_t interface, int stop) { if (interface == 0) { if (!stop) usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0); else usb_lld_stall_tx (ENDP2); } else if (interface == 1) { if (!stop) { usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0); usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64); } else { usb_lld_stall_tx (ENDP1); usb_lld_stall_rx (ENDP3); } } } int usb_cb_handle_event (uint8_t event_type, uint16_t value) { int i; uint8_t current_conf; switch (event_type) { case USB_EVENT_ADDRESS: bDeviceState = ADDRESSED; return USB_SUCCESS; case USB_EVENT_CONFIG: current_conf = usb_lld_current_configuration (); if (current_conf == 0) { if (value != 1) return USB_UNSUPPORT; usb_lld_set_configuration (1); for (i = 0; i < NUM_INTERFACES; i++) vcom_setup_endpoints_for_interface (i, 0); bDeviceState = CONFIGURED; } else if (current_conf != value) { if (value != 0) return USB_UNSUPPORT; usb_lld_set_configuration (0); for (i = 0; i < NUM_INTERFACES; i++) vcom_setup_endpoints_for_interface (i, 1); bDeviceState = ADDRESSED; } /* Do nothing when current_conf == value */ return USB_SUCCESS; return USB_SUCCESS; default: break; } return USB_UNSUPPORT; } int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt) { static uint8_t zero = 0; if (interface >= NUM_INTERFACES) return USB_UNSUPPORT; switch (cmd) { case USB_SET_INTERFACE: if (alt != 0) return USB_UNSUPPORT; else { vcom_setup_endpoints_for_interface (interface, 0); return USB_SUCCESS; } case USB_GET_INTERFACE: usb_lld_set_data_to_send (&zero, 1); return USB_SUCCESS; default: case USB_QUERY_INTERFACE: return USB_SUCCESS; } } void EP1_IN_Callback (void) { chopstx_mutex_lock (&usb_mtx); chopstx_cond_signal (&cnd_usb); chopstx_mutex_unlock (&usb_mtx); } void EP2_IN_Callback (void) { } void EP3_OUT_Callback (void) { usb_lld_rx_enable (ENDP3); }