static inline void cdc_acmd_read_complete(USBD* usbd, CDC_ACMD* cdc_acmd) { if (cdc_acmd->suspended) return; unsigned int to_read; if (cdc_acmd->rx_free < cdc_acmd->rx->data_size) cdc_acmd->rx_free = stream_get_free(cdc_acmd->rx_stream); to_read = cdc_acmd->rx->data_size; if (to_read > cdc_acmd->rx_free) to_read = cdc_acmd->rx_free; if (to_read < cdc_acmd->rx->data_size) cdc_acmd_notify_serial_state(usbd, cdc_acmd, CDC_SERIAL_STATE_DCD | CDC_SERIAL_STATE_DSR | CDC_SERIAL_STATE_OVERRUN); #if (USBD_CDC_ACM_DEBUG_FLOW) int i; printf("USB CDC ACM: rx "); for (i = 0; i < cdc_acmd->rx->data_size; ++i) if (((uint8_t*)io_data(cdc_acmd->rx))[i] >= ' ' && ((uint8_t*)io_data(cdc_acmd->rx))[i] <= '~') printf("%c", ((char*)io_data(cdc_acmd->rx))[i]); else printf("\\x%d", ((uint8_t*)io_data(cdc_acmd->rx))[i]); printf("\n"); #endif //USBD_CDC_ACM_DEBUG_FLOW if (to_read && stream_write(cdc_acmd->rx_stream_handle, io_data(cdc_acmd->rx), to_read)) cdc_acmd->rx_free -= to_read; usbd_usb_ep_read(usbd, cdc_acmd->data_ep, cdc_acmd->rx, cdc_acmd->data_ep_size); }
void cdc_acmd_class_resume(USBD* usbd, void* param) { CDC_ACMD* cdc_acmd = (CDC_ACMD*)param; cdc_acmd->suspended = false; #if (USBD_CDC_ACM_RX_STREAM_SIZE) stream_listen(cdc_acmd->tx_stream, USBD_IFACE(cdc_acmd->data_iface, 0), HAL_USBD_IFACE); usbd_usb_ep_read(usbd, cdc_acmd->data_ep, cdc_acmd->rx, cdc_acmd->data_ep_size); #endif //USBD_CDC_ACM_RX_STREAM_SIZE }
static void mscd_request_processed(USBD* usbd, MSCD* mscd) { //need ZLP if data transfer is not fully complete if (mscd->residue && (((mscd->cbw->dCBWDataTransferLength - mscd->residue) % mscd->ep_size) == 0)) { mscd->control->data_size = 0; if (MSC_CBW_FLAG_DATA_IN(mscd->cbw->bmCBWFlags)) usbd_usb_ep_write(usbd, mscd->ep_num, mscd->control); else { //some hardware required to be multiple of MPS usbd_usb_ep_read(usbd, mscd->ep_num, mscd->control, mscd->ep_size); } mscd->state = MSCD_STATE_ZLP; } else mscd_write_csw(usbd, mscd); }
void mscd_host_cb(void* param, unsigned int id, SCSIS_RESPONSE response, unsigned int size) { MSCD* mscd = param; switch (response) { case SCSIS_RESPONSE_READ: if (size > mscd->residue) size = mscd->residue; mscd->residue -= size; //some hardware required to be multiple of MPS usbd_usb_ep_read(mscd->usbd, mscd->ep_num, mscd->data, (size + mscd->ep_size - 1) & ~(mscd->ep_size - 1)); break; case SCSIS_RESPONSE_WRITE: if (mscd->data->data_size > mscd->residue) mscd->data->data_size = mscd->residue; mscd->residue -= mscd->data->data_size; usbd_usb_ep_write(mscd->usbd, mscd->ep_num, mscd->data); break; case SCSIS_RESPONSE_PASS: mscd->csw_status = MSC_CSW_COMMAND_PASSED; mscd_request_processed(mscd->usbd, mscd); break; case SCSIS_RESPONSE_FAIL: mscd->csw_status = MSC_CSW_COMMAND_FAILED; mscd_request_processed(mscd->usbd, mscd); break; case SCSIS_RESPONSE_NEED_IO: if (mscd->io_owner < 0) { mscd->io_owner = id; scsis_host_give_io(MSCD_SCSI(mscd)[id], mscd->data); } else mscd->io_busy_mask |= 1 << id; break; case SCSIS_RESPONSE_RELEASE_IO: mscd_release_io(mscd); break; default: break; } }
static void mscd_read_cbw(USBD* usbd, MSCD* mscd) { mscd->state = MSCD_STATE_IDLE; usbd_usb_ep_read(usbd, mscd->ep_num, mscd->control, mscd->ep_size); }
void cdc_acmd_class_configured(USBD* usbd, USB_CONFIGURATION_DESCRIPTOR* cfg) { USB_INTERFACE_DESCRIPTOR* iface; USB_INTERFACE_DESCRIPTOR* diface; CDC_UNION_DESCRIPTOR* u; USB_ENDPOINT_DESCRIPTOR* ep; uint8_t data_ep, data_iface; uint16_t data_ep_size; uint8_t control_ep, control_iface; uint16_t control_ep_size; //check control/data ep here for (iface = usb_get_first_interface(cfg); iface != NULL; iface = usb_get_next_interface(cfg, iface)) { //also skip RNDIS if ((iface->bInterfaceClass != CDC_COMM_INTERFACE_CLASS) || (iface->bInterfaceSubClass != CDC_ACM) || (iface->bInterfaceProtocol == CDC_CP_VENDOR)) continue; #if (USBD_CDC_ACM_DEBUG) printf("Found USB CDC ACM interface: %d\n", iface->bInterfaceNumber); #endif //USBD_CDC_ACM_DEBUG //find union descriptor for (u = usb_interface_get_first_descriptor(cfg, iface, CS_INTERFACE); u != NULL; u = usb_interface_get_next_descriptor(cfg, u, CS_INTERFACE)) { if ((u->bDescriptorSybType == CDC_DESCRIPTOR_UNION) && (u->bControlInterface == iface->bInterfaceNumber) && (u->bFunctionLength > sizeof(CDC_UNION_DESCRIPTOR))) break; } if (u == NULL) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Warning - no UNION descriptor, skipping interface\n"); #endif //USBD_CDC_ACM_DEBUG continue; } data_iface = ((uint8_t*)u)[sizeof(CDC_UNION_DESCRIPTOR)]; diface = usb_find_interface(cfg, data_iface); if (diface == NULL) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Warning no data interface\n"); #endif //USBD_CDC_ACM_DEBUG continue; } #if (USBD_CDC_ACM_DEBUG) printf("Found USB CDC ACM data interface: %d\n", data_iface); #endif //USBD_CDC_ACM_DEBUG ep = (USB_ENDPOINT_DESCRIPTOR*)usb_interface_get_first_descriptor(cfg, diface, USB_ENDPOINT_DESCRIPTOR_TYPE); if (ep == NULL) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Warning no data EP, skipping interface\n"); #endif //USBD_CDC_ACM_DEBUG continue; } data_ep = USB_EP_NUM(ep->bEndpointAddress); data_ep_size = ep->wMaxPacketSize; control_iface = iface->bInterfaceNumber; control_ep = control_ep_size = 0; ep = (USB_ENDPOINT_DESCRIPTOR*)usb_interface_get_first_descriptor(cfg, iface, USB_ENDPOINT_DESCRIPTOR_TYPE); if (ep != NULL) { control_ep = USB_EP_NUM(ep->bEndpointAddress); control_ep_size = ep->wMaxPacketSize; } //configuration is ok, applying CDC_ACMD* cdc_acmd = (CDC_ACMD*)malloc(sizeof(CDC_ACMD)); if (cdc_acmd == NULL) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Out of memory\n"); #endif //USBD_CDC_ACM_DEBUG return; } cdc_acmd->data_iface = data_iface; cdc_acmd->data_ep = data_ep; cdc_acmd->data_ep_size = data_ep_size; cdc_acmd->tx = cdc_acmd->rx = NULL; cdc_acmd->tx_stream = cdc_acmd->rx_stream = cdc_acmd->tx_stream_handle = cdc_acmd->rx_stream_handle = INVALID_HANDLE; cdc_acmd->suspended = false; cdc_acmd->control_iface = control_iface; cdc_acmd->control_ep = control_ep; cdc_acmd->control_ep_size = control_ep_size; cdc_acmd->notify = NULL; cdc_acmd->notify_busy = cdc_acmd->notify_pending = false; #if (USBD_CDC_ACM_FLOW_CONTROL) cdc_acmd->flow_sending = false; cdc_acmd->flow_changed = false; cdc_acmd->break_count = 0; #endif //USBD_CDC_ACM_FLOW_CONTROL #if (USBD_CDC_ACM_TX_STREAM_SIZE) cdc_acmd->tx = io_create(cdc_acmd->data_ep_size); cdc_acmd->tx_stream = stream_create(USBD_CDC_ACM_RX_STREAM_SIZE); cdc_acmd->tx_stream_handle = stream_open(cdc_acmd->tx_stream); if (cdc_acmd->tx == NULL || cdc_acmd->tx_stream_handle == INVALID_HANDLE) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Out of memory\n"); #endif //USBD_CDC_ACM_DEBUG cdc_acmd_destroy(cdc_acmd); return; } cdc_acmd->tx_size = 0; cdc_acmd->tx_idle = true; usbd_usb_ep_open(usbd, USB_EP_IN | cdc_acmd->data_ep, USB_EP_BULK, cdc_acmd->data_ep_size); stream_listen(cdc_acmd->tx_stream, USBD_IFACE(cdc_acmd->data_iface, 0), HAL_USBD_IFACE); #endif //USBD_CDC_ACM_TX_STREAM_SIZE #if (USBD_CDC_ACM_RX_STREAM_SIZE) cdc_acmd->rx = io_create(cdc_acmd->data_ep_size); cdc_acmd->rx_stream = stream_create(USBD_CDC_ACM_RX_STREAM_SIZE); cdc_acmd->rx_stream_handle = stream_open(cdc_acmd->rx_stream); if (cdc_acmd->rx == NULL || cdc_acmd->rx_stream_handle == INVALID_HANDLE) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Out of memory\n"); #endif //USBD_CDC_ACM_DEBUG cdc_acmd_destroy(cdc_acmd); return; } cdc_acmd->rx_free = 0; usbd_usb_ep_open(usbd, cdc_acmd->data_ep, USB_EP_BULK, cdc_acmd->data_ep_size); usbd_usb_ep_read(usbd, cdc_acmd->data_ep, cdc_acmd->rx, cdc_acmd->data_ep_size); #endif //USBD_CDC_ACM_RX_STREAM_SIZE usbd_register_interface(usbd, cdc_acmd->data_iface, &__CDC_ACMD_CLASS, cdc_acmd); usbd_register_endpoint(usbd, cdc_acmd->data_iface, cdc_acmd->data_ep); if (control_ep_size) { if (cdc_acmd->control_ep_size < 16) { #if (USBD_CDC_ACM_DEBUG) printf("USB CDC ACM: Warning - control endpoint is too small(%d), 16 at least required to fit notify", cdc_acmd->control_ep_size); #endif //USBD_CDC_ACM_DEBUG cdc_acmd->notify = io_create(16); } else cdc_acmd->notify = io_create(cdc_acmd->control_ep_size); if (cdc_acmd->notify == NULL) { cdc_acmd_destroy(cdc_acmd); return; } usbd_usb_ep_open(usbd, USB_EP_IN | cdc_acmd->control_ep, USB_EP_INTERRUPT, cdc_acmd->control_ep_size); usbd_register_interface(usbd, cdc_acmd->control_iface, &__CDC_ACMD_CLASS, cdc_acmd); usbd_register_endpoint(usbd, cdc_acmd->control_iface, cdc_acmd->control_ep); cdc_acmd_notify_serial_state(usbd, cdc_acmd, CDC_SERIAL_STATE_DCD | CDC_SERIAL_STATE_DSR); } cdc_acmd->DTR = cdc_acmd->RTS = false; cdc_acmd->baud.baud = 115200; cdc_acmd->baud.data_bits = 8; cdc_acmd->baud.parity = 'N'; cdc_acmd->baud.stop_bits = 1; } }