#include "cdc-acm.h" #include "cdc.h" #include "usb-api.h" #include "usb-core.h" #include #include #ifdef DEBUG #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) #endif static uint8_t usb_ctrl_data_buffer[32]; static struct usb_cdc_line_coding usb_line_coding = { 9600, 0x00, 0x00, 0x08 }; // 9600 baud, 8N1 static uint8_t line_state; static uint8_t events; static struct process *cdc_event_process = NULL; static void notify_user(uint8_t e) { events |= e; if(cdc_event_process) { process_poll(cdc_event_process); } } static void encapsulated_command(uint8_t *data, unsigned int length) { PRINTF("Got CDC command: length %d\n", length); usb_send_ctrl_status(); } static void set_line_encoding(uint8_t *data, unsigned int length) { if(length == 7) { #ifdef DEBUG static const char parity_char[] = { 'N', 'O', 'E', 'M', 'S' }; static const char *stop_bits_str[] = { "1", "1.5", "2" }; const struct usb_cdc_line_coding *coding = (const struct usb_cdc_line_coding *)usb_ctrl_data_buffer; char parity = ((coding->bParityType > 4) ? '?' : parity_char[coding->bParityType]); const char *stop_bits = ((coding->bCharFormat > 2) ? "?" : stop_bits_str[coding->bCharFormat]); PRINTF("Got CDC line coding: %ld/%d/%c/%s\n", coding->dwDTERate, coding->bDataBits, parity, stop_bits); #endif memcpy(&usb_line_coding, data, sizeof(usb_line_coding)); notify_user(USB_CDC_ACM_LINE_CODING); usb_send_ctrl_status(); } else { usb_error_stall(); } } static unsigned int handle_cdc_acm_requests() { PRINTF("CDC request %02x %02x\n", usb_setup_buffer.bmRequestType, usb_setup_buffer.bRequest); switch (usb_setup_buffer.bmRequestType) { case 0x21: /* CDC interface OUT requests */ /* Check if it's the right interface */ if(usb_setup_buffer.wIndex != 0) return 0; switch (usb_setup_buffer.bRequest) { case SET_CONTROL_LINE_STATE: line_state = usb_setup_buffer.wValue; notify_user(USB_CDC_ACM_LINE_STATE); usb_send_ctrl_status(); return 1; case SEND_ENCAPSULATED_COMMAND: { unsigned int len = usb_setup_buffer.wLength; if(len > sizeof(usb_ctrl_data_buffer)) len = sizeof(usb_ctrl_data_buffer); usb_get_ctrl_data(usb_ctrl_data_buffer, len, encapsulated_command); } return 1; case SET_LINE_CODING: { unsigned int len = usb_setup_buffer.wLength; if(len > sizeof(usb_ctrl_data_buffer)) len = sizeof(usb_ctrl_data_buffer); usb_get_ctrl_data(usb_ctrl_data_buffer, len, set_line_encoding); } return 1; } break; case 0xa1: /* CDC interface IN requests */ if(usb_setup_buffer.wIndex != 0) return 0; switch (usb_setup_buffer.bRequest) { case GET_ENCAPSULATED_RESPONSE: PRINTF("CDC response"); usb_send_ctrl_status(); return 1; case GET_LINE_CODING: usb_send_ctrl_response((uint8_t *) & usb_line_coding, 7); return 1; } } return 0; } static const struct USBRequestHandler cdc_acm_request_handler = { 0x21, 0x7f, 0x00, 0x00, handle_cdc_acm_requests }; static struct USBRequestHandlerHook cdc_acm_request_hook = { NULL, &cdc_acm_request_handler }; void usb_cdc_acm_setup() { usb_register_request_handler(&cdc_acm_request_hook); } uint8_t usb_cdc_acm_get_events(void) { uint8_t r = events; events = 0; return r; } uint8_t usb_cdc_acm_get_line_state(void) { return line_state; } const struct usb_cdc_line_coding * usb_cdc_acm_get_line_coding(void) { return &usb_line_coding; } void usb_cdc_acm_set_event_process(struct process *p) { cdc_event_process = p; }