summaryrefslogtreecommitdiffstats
path: root/app/cdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/cdc.c')
-rw-r--r--app/cdc.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/app/cdc.c b/app/cdc.c
new file mode 100644
index 0000000..4088b6c
--- /dev/null
+++ b/app/cdc.c
@@ -0,0 +1,154 @@
+#include "project.h"
+
+static const struct usb_endpoint_descriptor comm_endp[] = {
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x83,
+ .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
+ .wMaxPacketSize = 16,
+ .bInterval = 255,
+ }
+};
+
+static const struct usb_endpoint_descriptor data_endp[] = {
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x01,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = 64,
+ .bInterval = 1,
+ },
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x82,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = 64,
+ .bInterval = 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)) cdcacm_functional_descriptors = {
+ .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 = 0,
+ },
+ .cdc_union = {
+ .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_UNION,
+ .bControlInterface = 0,
+ .bSubordinateInterface0 = 1,
+ }
+};
+
+const struct usb_interface_descriptor comm_iface[] = {
+ {
+ .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 = comm_endp,
+ .extra = &cdcacm_functional_descriptors,
+ .extralen = sizeof(cdcacm_functional_descriptors)
+ }
+};
+
+const struct usb_interface_descriptor data_iface[] = {
+ {
+ .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 = data_endp,
+ }
+};
+
+
+int cdcacm_control_request(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf,
+ uint16_t *len,
+ int (**complete)(usbd_device *usbd_dev,
+ struct usb_setup_data *req))
+{
+ (void)complete;
+ (void)buf;
+ (void)usbd_dev;
+
+ switch(req->bRequest) {
+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
+ /*
+ * This Linux cdc_acm driver requires this to be implemented
+ * even though it's optional in the CDC spec, and we don't
+ * advertise it in the ACM functional descriptor.
+ */
+ char local_buf[10];
+ struct usb_cdc_notification *notif = (void *)local_buf;
+
+ /* We echo signals back to host as notification. */
+ notif->bmRequestType = 0xA1;
+ notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
+ notif->wValue = 0;
+ notif->wIndex = 0;
+ notif->wLength = 2;
+ local_buf[8] = req->wValue & 3;
+ local_buf[9] = 0;
+ // usbd_ep_write_packet(0x83, buf, 10);
+ return 1;
+ }
+ case USB_CDC_REQ_SET_LINE_CODING:
+ if(*len < sizeof(struct usb_cdc_line_coding)) {
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
+{
+ (void)ep;
+ char buf[64];
+ int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64);
+
+
+ if (len) {
+ buf[0]^=32;
+ usbd_ep_write_packet(usbd_dev, 0x82, buf, len);
+ buf[len] = 0;
+ }
+}