diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-22 16:46:45 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-22 16:46:45 +0900 |
commit | 8880a8b1f9a738e9b1ab17712131279a3dfb6881 (patch) | |
tree | 1de56a2bae50bd755acc34aeac705c2b3c683345 /example-cdc/usb-cdc.c | |
parent | aa3fd9876abe2131d2ebda9a418ade6a4b89f72c (diff) |
add cdc example
Diffstat (limited to 'example-cdc/usb-cdc.c')
-rw-r--r-- | example-cdc/usb-cdc.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/example-cdc/usb-cdc.c b/example-cdc/usb-cdc.c new file mode 100644 index 0000000..695c2f0 --- /dev/null +++ b/example-cdc/usb-cdc.c @@ -0,0 +1,432 @@ +#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_connection; +extern chopstx_cond_t cnd_usb_buffer_ready; + +#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_connection); + 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_buffer_ready); + chopstx_mutex_unlock (&usb_mtx); +} + +void +EP2_IN_Callback (void) +{ +} + +void +EP3_OUT_Callback (void) +{ + usb_lld_rx_enable (ENDP3); +} |