diff options
| author | hathach <[email protected]> | 2020-04-17 13:38:22 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2020-04-17 13:38:22 +0700 |
| commit | 05476d9ad72321aa6e57ff5acbc4b25e1366fead (patch) | |
| tree | 10a12e71a679243ad5775ed7e0088242b8e763c8 /src | |
| parent | f4df82939955d86f6c2e826e1bc9f4b5bb713df8 (diff) | |
| parent | 85f0894fff89baaaa91a6dc3554a3149fc2fc062 (diff) | |
Merge branch 'master' into remove-dcd-set-config
Diffstat (limited to 'src')
32 files changed, 695 insertions, 386 deletions
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 14b9a3153..95b14ba54 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -223,11 +223,11 @@ void cdcd_reset(uint8_t rhport) bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length) { // Only support ACM subclass - TU_ASSERT ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass); + TU_VERIFY ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass); - // Only support AT commands, no protocol and vendor specific commands. - TU_ASSERT(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) || - itf_desc->bInterfaceProtocol == 0xff); + // Note: 0xFF can be used with RNDIS + TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA)); // Find available interface cdcd_interface_t * p_cdc = NULL; @@ -262,12 +262,12 @@ bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - (*p_length) += p_desc[DESC_OFFSET_LEN]; + (*p_length) += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) && + if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) { // next to endpoint descriptor diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 595e7fd62..5e45e8f6b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -86,7 +86,7 @@ bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) { // TODO consider all AT Command as serial candidate return tuh_cdc_mounted(dev_addr) && - (CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].itf_protocol) && + (CDC_COMM_PROTOCOL_NONE <= cdch_data[dev_addr-1].itf_protocol) && (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); } diff --git a/src/class/dfu/dfu_rt_device.c b/src/class/dfu/dfu_rt_device.c index ad1871dad..0ef5fe63f 100644 --- a/src/class/dfu/dfu_rt_device.c +++ b/src/class/dfu/dfu_rt_device.c @@ -61,8 +61,8 @@ bool dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16 (void) rhport; // Ensure this is DFU Runtime - TU_ASSERT(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS); - TU_ASSERT(itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT); + TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS); + TU_VERIFY(itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT); uint8_t const * p_desc = tu_desc_next( itf_desc ); (*p_length) = sizeof(tusb_desc_interface_t); diff --git a/src/class/dfu/dfu_rt_device.h b/src/class/dfu/dfu_rt_device.h index 4348a0f3a..294d993e3 100644 --- a/src/class/dfu/dfu_rt_device.h +++ b/src/class/dfu/dfu_rt_device.h @@ -58,7 +58,7 @@ typedef enum //--------------------------------------------------------------------+ // Invoked when received new data -TU_ATTR_WEAK void tud_dfu_rt_reboot_to_dfu(void); +TU_ATTR_WEAK void tud_dfu_rt_reboot_to_dfu(void); // TODO rename to _cb convention //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 7cb35f1ce..cbdc5bece 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -160,6 +160,8 @@ void hidd_reset(uint8_t rhport) bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t *p_len) { + TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); + uint8_t const *p_desc = (uint8_t const *) desc_itf; // Find available interface diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index ae6e3afe1..6eb522380 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -253,21 +253,31 @@ void midid_reset(uint8_t rhport) } } -bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length) +bool midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t *p_length) { - // For now handle the audio control interface as well. - if ( AUDIO_SUBCLASS_CONTROL == p_interface_desc->bInterfaceSubClass) { - uint8_t const * p_desc = tu_desc_next ( (uint8_t const *) p_interface_desc ); - (*p_length) = sizeof(tusb_desc_interface_t); - // Skip over the class specific descriptor. - (*p_length) += tu_desc_len(p_desc); + // 1st Interface is Audio Control v1 + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_PROTOCOL_V1 == desc_itf->bInterfaceProtocol); + + uint16_t drv_len = tu_desc_len(desc_itf); + uint8_t const * p_desc = tu_desc_next(desc_itf); + + // Skip Class Specific descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) ) + { + drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); - return true; } - TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == p_interface_desc->bInterfaceSubClass && - AUDIO_PROTOCOL_V1 == p_interface_desc->bInterfaceProtocol ); + // 2nd Interface is MIDI Streaming + TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc)); + tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc; + + TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && + AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && + AUDIO_PROTOCOL_V1 == desc_midi->bInterfaceProtocol ); // Find available interface midid_interface_t * p_midi = NULL; @@ -280,13 +290,15 @@ bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, } } - p_midi->itf_num = p_interface_desc->bInterfaceNumber; + p_midi->itf_num = desc_midi->bInterfaceNumber; - uint8_t const * p_desc = tu_desc_next( (uint8_t const *) p_interface_desc ); - (*p_length) = sizeof(tusb_desc_interface_t); + // next descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + // Find and open endpoint descriptors uint8_t found_endpoints = 0; - while (found_endpoints < p_interface_desc->bNumEndpoints) + while (found_endpoints < desc_midi->bNumEndpoints) { if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE]) { @@ -298,14 +310,16 @@ bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, p_midi->ep_out = ep_addr; } - (*p_length) += p_desc[DESC_OFFSET_LEN]; + drv_len += p_desc[DESC_OFFSET_LEN]; p_desc = tu_desc_next(p_desc); found_endpoints += 1; } - (*p_length) += p_desc[DESC_OFFSET_LEN]; + drv_len += p_desc[DESC_OFFSET_LEN]; p_desc = tu_desc_next(p_desc); } + *p_length = drv_len; + // Prepare for incoming data TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false); diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 06cc9dbb6..68f5587fd 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -157,7 +157,8 @@ void mscd_reset(uint8_t rhport) bool mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_len) { // only support SCSI's BOT protocol - TU_ASSERT(MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && + TU_VERIFY(TUSB_CLASS_MSC == itf_desc->bInterfaceClass && + MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol); mscd_interface_t * p_msc = &_mscd_itf; diff --git a/src/class/net/net_device.c b/src/class/net/net_device.c index 68520625a..0f2ccbd44 100644 --- a/src/class/net/net_device.c +++ b/src/class/net/net_device.c @@ -27,7 +27,7 @@ #include "tusb_option.h" -#if ( TUSB_OPT_DEVICE_ENABLED && (CFG_TUD_NET != OPT_NET_NONE) ) +#if ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_NET ) #include "net_device.h" #include "device/usbd_pvt.h" @@ -40,40 +40,60 @@ void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networ //--------------------------------------------------------------------+ typedef struct { - uint8_t itf_num; + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + uint8_t ep_notif; uint8_t ep_in; uint8_t ep_out; + + bool ecm_mode; + + // Endpoint descriptor use to open/close when receving SetInterface + // TODO since configuration descriptor may not be long-lived memory, we should + // keep a copy of endpoint attribute instead + uint8_t const * ecm_desc_epdata; + } netd_interface_t; -#if CFG_TUD_NET == OPT_NET_ECM - #define CFG_TUD_NET_PACKET_PREFIX_LEN 0 - #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 - #define CFG_TUD_NET_INTERFACESUBCLASS CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL -#elif CFG_TUD_NET == OPT_NET_RNDIS - #define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) - #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 - #define CFG_TUD_NET_INTERFACESUBCLASS TUD_RNDIS_ITF_SUBCLASS -#elif CFG_TUD_NET == OPT_NET_EEM - #define CFG_TUD_NET_PACKET_PREFIX_LEN 2 - #define CFG_TUD_NET_PACKET_SUFFIX_LEN 4 - #define CFG_TUD_NET_INTERFACESUBCLASS CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL -#endif +#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) +#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; -#if CFG_TUD_NET == OPT_NET_ECM - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static tusb_control_request_t notify = - { - .bmRequestType = 0x21, - .bRequest = 0 /* NETWORK_CONNECTION */, +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +static const struct ecm_notify_struct ecm_notify_nc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, .wValue = 1 /* Connected */, .wLength = 0, - }; -#elif CFG_TUD_NET == OPT_NET_RNDIS - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t rndis_buf[120]; -#endif + }, +}; + +static const struct ecm_notify_struct ecm_notify_csc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, + .wLength = 8, + }, + .downlink = 9728000, + .uplink = 9728000, +}; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union +{ + uint8_t rndis_buf[120]; + struct ecm_notify_struct ecm_buf; +} notify; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -115,19 +135,28 @@ void netd_reset(uint8_t rhport) bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length) { - // sanity check the descriptor - TU_ASSERT (CFG_TUD_NET_INTERFACESUBCLASS == itf_desc->bInterfaceSubClass); + bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass && + TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); + + bool const is_ecm = (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL == itf_desc->bInterfaceSubClass && + 0x00 == itf_desc->bInterfaceProtocol); + + TU_VERIFY ( is_rndis || is_ecm ); // confirm interface hasn't already been allocated - TU_ASSERT(0 == _netd_itf.ep_in); + TU_ASSERT(0 == _netd_itf.ep_notif); - //------------- first Interface -------------// + // sanity check the descriptor + _netd_itf.ecm_mode = is_ecm; + + //------------- Management Interface -------------// _netd_itf.itf_num = itf_desc->bInterfaceNumber; - uint8_t const * p_desc = tu_desc_next( itf_desc ); (*p_length) = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); -#if CFG_TUD_NET != OPT_NET_EEM // Communication Functional Descriptors while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) ) { @@ -142,35 +171,49 @@ bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - (*p_length) += p_desc[DESC_OFFSET_LEN]; + (*p_length) += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } - //------------- second Interface -------------// - if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) + //------------- Data Interface -------------// + // - RNDIS Data followed immediately by a pair of endpoints + // - CDC-ECM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for active networking + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc)); + + do { - // next to endpoint descriptor + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass); + + (*p_length) += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); - (*p_length) += sizeof(tusb_desc_interface_t); - } -#endif + }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) ); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - if (TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE]) + if ( _netd_itf.ecm_mode ) + { + // ECM by default is in-active, save the endpoint attribute + // to open later when received setInterface + _netd_itf.ecm_desc_epdata = p_desc; + }else { - // Open endpoint pair + // Open endpoint pair for RNDIS TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); - (*p_length) += 2*sizeof(tusb_desc_endpoint_t); - } + tud_network_init_cb(); - tud_network_init_cb(); + // we are ready to transmit a packet + can_xmit = true; - // we are ready to transmit a packet - can_xmit = true; + // prepare for incoming packets + tud_network_recv_renew(); + } - // prepare for incoming packets - tud_network_recv_renew(); + (*p_length) += 2*sizeof(tusb_desc_endpoint_t); return true; } @@ -181,116 +224,167 @@ bool netd_control_complete(uint8_t rhport, tusb_control_request_t const * reques { (void) rhport; - // Handle class request only - TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - TU_VERIFY (_netd_itf.itf_num == request->wIndex); - -#if CFG_TUD_NET == OPT_NET_RNDIS - if (request->bmRequestType_bit.direction == TUSB_DIR_OUT) + // Handle RNDIS class control OUT only + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + request->bmRequestType_bit.direction == TUSB_DIR_OUT && + _netd_itf.itf_num == request->wIndex) { - rndis_class_set_handler(rndis_buf, request->wLength); + if ( !_netd_itf.ecm_mode ) + { + rndis_class_set_handler(notify.rndis_buf, request->wLength); + } } -#endif return true; } +static void ecm_report(bool nc) +{ + notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; + notify.ecm_buf.header.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); +} + // Handle class control request // return false to stall control endpoint (e.g unsupported request) bool netd_control_request(uint8_t rhport, tusb_control_request_t const * request) { - // Handle class request only - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); - TU_VERIFY (_netd_itf.itf_num == request->wIndex); + tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); + } + break; -#if CFG_TUD_NET == OPT_NET_ECM - /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ - if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) - { - tud_control_xfer(rhport, request, NULL, 0); - notify.wIndex = request->wIndex; - usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_notif, (uint8_t *)¬ify, sizeof(notify)); - } -#elif CFG_TUD_NET == OPT_NET_RNDIS - if (request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *)rndis_buf; - uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); - TU_ASSERT(msglen <= sizeof(rndis_buf)); - tud_control_xfer(rhport, request, rndis_buf, msglen); - } - else - { - tud_control_xfer(rhport, request, rndis_buf, sizeof(rndis_buf)); + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); + + // ACM-ECM only: qequest to enable/disable network activities + TU_VERIFY(_netd_itf.ecm_mode); + + _netd_itf.itf_data_alt = req_alt; + + if ( _netd_itf.itf_data_alt ) + { + // TODO since we don't actually close endpoint + // hack here to not re-open it + if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) + { + TU_ASSERT(_netd_itf.ecm_desc_epdata); + TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); + + // TODO should be merge with RNDIS's after endpoint opened + // Also should have opposite callback for application to disable network !! + tud_network_init_cb(); + can_xmit = true; // we are ready to transmit a packet + tud_network_recv_renew(); // prepare for incoming packets + } + }else + { + // TODO close the endpoint pair + // For now pretend that we did, this should have no harm since host won't try to + // communicate with the endpoints again + // _netd_itf.ep_in = _netd_itf.ep_out = 0 + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (_netd_itf.itf_num == request->wIndex); + + if (_netd_itf.ecm_mode) + { + /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ + if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) + { + tud_control_xfer(rhport, request, NULL, 0); + ecm_report(true); + } + } + else + { + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *)notify.rndis_buf; + uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); + TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); + tud_control_xfer(rhport, request, notify.rndis_buf, msglen); + } + else + { + tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf)); + } + } + break; + + // unsupported request + default: return false; } -#else - (void)rhport; -#endif return true; } -struct cdc_eem_packet_header -{ - uint16_t length:14; - uint16_t bmCRC:1; - uint16_t bmType:1; -}; - static void handle_incoming_packet(uint32_t len) { uint8_t *pnt = received; uint32_t size = 0; -#if CFG_TUD_NET == OPT_NET_ECM - size = len; -#elif CFG_TUD_NET == OPT_NET_RNDIS - rndis_data_packet_t *r = (rndis_data_packet_t *)pnt; - if (len >= sizeof(rndis_data_packet_t)) - if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) - if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) - { - pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; - size = r->DataLength; - } -#elif CFG_TUD_NET == OPT_NET_EEM - struct cdc_eem_packet_header *hdr = (struct cdc_eem_packet_header *)pnt; - - (void)len; - - if (hdr->bmType) + if (_netd_itf.ecm_mode) { - /* EEM Control Packet: discard it */ - tud_network_recv_renew(); + size = len; } else { - /* EEM Data Packet */ - pnt += CFG_TUD_NET_PACKET_PREFIX_LEN; - size = hdr->length - 4; /* discard the unused CRC-32 */ + rndis_data_packet_t *r = (rndis_data_packet_t *)pnt; + if (len >= sizeof(rndis_data_packet_t)) + if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) + if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) + { + pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; + size = r->DataLength; + } } -#endif + + bool accepted = false; if (size) { struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL); - bool accepted = true; if (p) { memcpy(p->payload, pnt, size); p->len = size; accepted = tud_network_recv_cb(p); - } - if (!p || !accepted) - { - /* if a buffer couldn't be allocated or accepted by the callback, we must discard this packet */ - tud_network_recv_renew(); + if (!accepted) pbuf_free(p); } } + + if (!accepted) + { + /* if a buffer was never handled by user code, we must renew on the user's behalf */ + tud_network_recv_renew(); + } } bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) @@ -320,6 +414,11 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } } + if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) + { + if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); + } + return true; } @@ -337,7 +436,7 @@ void tud_network_xmit(struct pbuf *p) if (!can_xmit) return; - len = CFG_TUD_NET_PACKET_PREFIX_LEN; + len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; data = transmitted + len; for(q = p; q != NULL; q = q->next) @@ -347,23 +446,15 @@ void tud_network_xmit(struct pbuf *p) len += q->len; } -#if CFG_TUD_NET == OPT_NET_RNDIS - rndis_data_packet_t *hdr = (rndis_data_packet_t *)transmitted; - memset(hdr, 0, sizeof(rndis_data_packet_t)); - hdr->MessageType = REMOTE_NDIS_PACKET_MSG; - hdr->MessageLength = len; - hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); - hdr->DataLength = len - sizeof(rndis_data_packet_t); -#elif CFG_TUD_NET == OPT_NET_EEM - struct cdc_eem_packet_header *hdr = (struct cdc_eem_packet_header *)transmitted; - /* append a fake CRC-32; the standard allows 0xDEADBEEF, which takes less CPU time */ - data[0] = 0xDE; data[1] = 0xAD; data[2] = 0xBE; data[3] = 0xEF; - /* adjust length to reflect added fake CRC-32 */ - len += 4; - hdr->bmType = 0; /* EEM Data Packet */ - hdr->length = len - sizeof(struct cdc_eem_packet_header); - hdr->bmCRC = 0; /* Ethernet Frame CRC-32 set to 0xDEADBEEF */ -#endif + if (!_netd_itf.ecm_mode) + { + rndis_data_packet_t *hdr = (rndis_data_packet_t *)transmitted; + memset(hdr, 0, sizeof(rndis_data_packet_t)); + hdr->MessageType = REMOTE_NDIS_PACKET_MSG; + hdr->MessageLength = len; + hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); + hdr->DataLength = len - sizeof(rndis_data_packet_t); + } do_in_xfer(transmitted, len); } diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 92d8d34ef..abe26ced3 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -263,17 +263,19 @@ void usbtmcd_init_cb(void) bool usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length) { (void)rhport; - TU_ASSERT(usbtmc_state.state == STATE_CLOSED); uint8_t const * p_desc; uint8_t found_endpoints = 0; + TU_VERIFY(itf_desc->bInterfaceClass == TUD_USBTMC_APP_CLASS); + TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS); + #ifndef NDEBUG - TU_ASSERT(itf_desc->bInterfaceClass == TUD_USBTMC_APP_CLASS); - TU_ASSERT(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS); // Only 2 or 3 endpoints are allowed for USBTMC. TU_ASSERT((itf_desc->bNumEndpoints == 2) || (itf_desc->bNumEndpoints ==3)); #endif + TU_ASSERT(usbtmc_state.state == STATE_CLOSED); + // Interface (*p_length) = 0u; p_desc = (uint8_t const *) itf_desc; diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 8db5005f4..7f2fe9793 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -168,6 +168,8 @@ void vendord_reset(uint8_t rhport) bool vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_len) { + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass); + // Find available interface vendord_interface_t* p_vendor = NULL; for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index c37c19bad..70d0db942 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -139,6 +139,7 @@ typedef enum TUSB_REQ_RCPT_OTHER } tusb_request_recipient_t; +// https://www.usb.org/defined-class-codes typedef enum { TUSB_CLASS_UNSPECIFIED = 0 , @@ -178,6 +179,12 @@ typedef enum typedef enum { + APP_SUBCLASS_USBTMC = 0x03, + APP_SUBCLASS_DFU_RUNTIME = 0x01 +} app_subclass_type_t; + +typedef enum +{ DEVICE_CAPABILITY_WIRELESS_USB = 0x01, DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, diff --git a/src/device/dcd.h b/src/device/dcd.h index f4e6edb95..99a0e01ca 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -89,7 +89,7 @@ typedef struct TU_ATTR_ALIGNED(4) void dcd_init (uint8_t rhport); // Interrupt Handler -void dcd_irq_handler(uint8_t rhport) TU_ATTR_USED; +void dcd_int_handler(uint8_t rhport); // Enable device interrupt void dcd_int_enable (uint8_t rhport); @@ -106,10 +106,10 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num); // Wake up host void dcd_remote_wakeup(uint8_t rhport); -// Connect or disconnect D+/D- line pull-up resistor. -// Defined in dcd source if MCU has internal pull-up. -// Otherwise, may be defined in BSP. +// Connect by enabling internal pull-up resistor on D+/D- void dcd_connect(uint8_t rhport) TU_ATTR_WEAK; + +// Disconnect by disabling internal pull-up resistor on D+/D- void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK; //--------------------------------------------------------------------+ @@ -123,6 +123,10 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re // Configure endpoint's registers according to descriptor bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +// Close an endpoint. +// Since it is weak, caller must TU_ASSERT this function's existence before calling it. +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; + // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); diff --git a/src/device/usbd.c b/src/device/usbd.c index 55d6aa7eb..26183c960 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -73,8 +73,17 @@ enum { DRVID_INVALID = 0xFFu }; //--------------------------------------------------------------------+ // Class Driver //--------------------------------------------------------------------+ -typedef struct { - uint8_t class_code; +#if CFG_TUSB_DEBUG >= 2 + #define DRIVER_NAME(_name) .name = _name, +#else + #define DRIVER_NAME(_name) +#endif + +typedef struct +{ + #if CFG_TUSB_DEBUG >= 2 + char const* name; + #endif void (* init ) (void); void (* reset ) (uint8_t rhport); @@ -89,7 +98,7 @@ static usbd_class_driver_t const _usbd_driver[] = { #if CFG_TUD_CDC { - .class_code = TUSB_CLASS_CDC, + DRIVER_NAME("CDC") .init = cdcd_init, .reset = cdcd_reset, .open = cdcd_open, @@ -102,7 +111,7 @@ static usbd_class_driver_t const _usbd_driver[] = #if CFG_TUD_MSC { - .class_code = TUSB_CLASS_MSC, + DRIVER_NAME("MSC") .init = mscd_init, .reset = mscd_reset, .open = mscd_open, @@ -115,7 +124,7 @@ static usbd_class_driver_t const _usbd_driver[] = #if CFG_TUD_HID { - .class_code = TUSB_CLASS_HID, + DRIVER_NAME("HID") .init = hidd_init, .reset = hidd_reset, .open = hidd_open, @@ -128,7 +137,7 @@ static usbd_class_driver_t const _usbd_driver[] = #if CFG_TUD_MIDI { - .class_code = TUSB_CLASS_AUDIO, + DRIVER_NAME("MIDI") .init = midid_init, .open = midid_open, .reset = midid_reset, @@ -141,7 +150,7 @@ static usbd_class_driver_t const _usbd_driver[] = #if CFG_TUD_VENDOR { - .class_code = TUSB_CLASS_VENDOR_SPECIFIC, + DRIVER_NAME("VENDOR") .init = vendord_init, .reset = vendord_reset, .open = vendord_open, @@ -153,12 +162,8 @@ static usbd_class_driver_t const _usbd_driver[] = #endif #if CFG_TUD_USBTMC - // Presently USBTMC is the only defined class with the APP_SPECIFIC class code. - // We maybe need to add subclass codes here, or a callback to ask if a driver can - // handle a particular interface. { - .class_code = TUD_USBTMC_APP_CLASS, - //.subclass_code = TUD_USBTMC_APP_SUBCLASS + DRIVER_NAME("TMC") .init = usbtmcd_init_cb, .reset = usbtmcd_reset_cb, .open = usbtmcd_open_cb, @@ -171,8 +176,7 @@ static usbd_class_driver_t const _usbd_driver[] = #if CFG_TUD_DFU_RT { - .class_code = TUD_DFU_APP_CLASS, - //.subclass_code = TUD_DFU_APP_SUBCLASS + DRIVER_NAME("DFU-RT") .init = dfu_rtd_init, .reset = dfu_rtd_reset, .open = dfu_rtd_open, @@ -185,19 +189,14 @@ static usbd_class_driver_t const _usbd_driver[] = #if CFG_TUD_NET { - .class_code = -#if CFG_TUD_NET == OPT_NET_RNDIS - TUD_RNDIS_ITF_CLASS, -#else - TUSB_CLASS_CDC, -#endif + DRIVER_NAME("NET") .init = netd_init, .reset = netd_reset, .open = netd_open, .control_request = netd_control_request, .control_complete = netd_control_complete, .xfer_cb = netd_xfer_cb, - .sof = NULL + .sof = NULL, }, #endif }; @@ -244,32 +243,6 @@ static char const* const _usbd_event_str[DCD_EVENT_COUNT] = "FUNC_CALL" }; -// must be same driver order as usbd_class_drivers[] -static char const* const _usbd_driver_str[USBD_CLASS_DRIVER_COUNT] = -{ - #if CFG_TUD_CDC - "CDC", - #endif - #if CFG_TUD_MSC - "MSC", - #endif - #if CFG_TUD_HID - "HID", - #endif - #if CFG_TUD_MIDI - "MIDI", - #endif - #if CFG_TUD_VENDOR - "Vendor", - #endif - #if CFG_TUD_USBTMC - "USBTMC" - #endif - #if CFG_TUD_NET - "NET" - #endif -}; - static char const* const _tusb_std_request_str[] = { "Get Status" , @@ -326,7 +299,7 @@ bool tud_init (void) // Init class drivers for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) { - TU_LOG2("%s init\r\n", _usbd_driver_str[i]); + TU_LOG2("%s init\r\n", _usbd_driver[i].name); _usbd_driver[i].init(); } @@ -435,7 +408,7 @@ void tud_task (void) uint8_t const drv_id = _usbd_dev.ep2drv[epnum][ep_dir]; TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,); - TU_LOG2(" %s xfer callback\r\n", _usbd_driver_str[drv_id]); + TU_LOG2(" %s xfer callback\r\n", _usbd_driver[drv_id].name); _usbd_driver[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); } } @@ -480,7 +453,7 @@ static bool invoke_class_control(uint8_t rhport, uint8_t drvid, tusb_control_req TU_ASSERT(_usbd_driver[drvid].control_request); usbd_control_set_complete_callback(_usbd_driver[drvid].control_complete); - TU_LOG2(" %s control request\r\n", _usbd_driver_str[drvid]); + TU_LOG2(" %s control request\r\n", _usbd_driver[drvid].name); return _usbd_driver[drvid].control_request(rhport, request); } @@ -596,38 +569,17 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const uint8_t const drvid = _usbd_dev.itf2drv[itf]; TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT); - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) + // all requests to Interface (STD or Class) is forwarded to class driver. + // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE + if ( !invoke_class_control(rhport, drvid, p_request) ) { - switch ( p_request->bRequest ) - { - case TUSB_REQ_GET_INTERFACE: - { - // TODO not support alternate interface yet - uint8_t alternate = 0; - tud_control_xfer(rhport, p_request, &alternate, 1); - } - break; + // For GET_INTERFACE, it is mandatory to respond even if the class + // driver doesn't use alternate settings. + TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && + TUSB_REQ_GET_INTERFACE == p_request->bRequest); - case TUSB_REQ_SET_INTERFACE: - { - uint8_t const alternate = (uint8_t) p_request->wValue; - - // TODO not support alternate interface yet - TU_ASSERT(alternate == 0); - tud_control_status(rhport, p_request); - } - break; - - default: - // forward to class driver: "STD request to Interface" - // GET HID REPORT DESCRIPTOR falls into this case - TU_VERIFY(invoke_class_control(rhport, drvid, p_request)); - break; - } - }else - { - // forward to class driver: "non-STD request to Interface" - TU_VERIFY(invoke_class_control(rhport, drvid, p_request)); + uint8_t alternate = 0; + tud_control_xfer(rhport, p_request, &alternate, 1); } } break; @@ -727,37 +679,59 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) while( p_desc < desc_end ) { - // Each interface always starts with Interface or Association descriptor + tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL; + + // Class will always starts with Interface Association (if any) and then Interface descriptor if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) { - p_desc = tu_desc_next(p_desc); // ignore Interface Association - }else - { - TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); + desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc; + p_desc = tu_desc_next(p_desc); // next to Interface + } + + TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); - tusb_desc_interface_t* desc_itf = (tusb_desc_interface_t*) p_desc; + tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc; + uint8_t drv_id; + uint16_t drv_len; + + for (drv_id = 0; drv_id < USBD_CLASS_DRIVER_COUNT; drv_id++) + { + usbd_class_driver_t const *driver = &_usbd_driver[drv_id]; - // Check if class is supported - uint8_t drv_id; - for (drv_id = 0; drv_id < USBD_CLASS_DRIVER_COUNT; drv_id++) + drv_len = 0; + if ( driver->open(rhport, desc_itf, &drv_len) ) { - if ( _usbd_driver[drv_id].class_code == desc_itf->bInterfaceClass ) break; - } - TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT ); + // Interface number must not be used already + TU_ASSERT( DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] ); - // Interface number must not be used already TODO alternate interface - TU_ASSERT( DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] ); - _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id; + TU_LOG2(" %s open\r\n", _usbd_driver[drv_id].name); + _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id; - uint16_t itf_len=0; - TU_LOG2(" %s open\r\n", _usbd_driver_str[drv_id]); - TU_ASSERT( _usbd_driver[drv_id].open(rhport, desc_itf, &itf_len) ); - TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); + // If IAD exist, assign all interfaces to the same driver + if (desc_itf_assoc) + { + // IAD's first interface number and class/subclass/protocol should match with opened interface + TU_ASSERT(desc_itf_assoc->bFirstInterface == desc_itf->bInterfaceNumber && + desc_itf_assoc->bFunctionClass == desc_itf->bInterfaceClass && + desc_itf_assoc->bFunctionSubClass == desc_itf->bInterfaceSubClass && + desc_itf_assoc->bFunctionProtocol == desc_itf->bInterfaceProtocol); - mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, itf_len, drv_id); + for(uint8_t i=1; i<desc_itf_assoc->bInterfaceCount; i++) + { + _usbd_dev.itf2drv[desc_itf->bInterfaceNumber+i] = drv_id; + } + } - p_desc += itf_len; // next interface + break; + } } + + // Assert if cannot find supported driver + TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT && drv_len >= sizeof(tusb_desc_interface_t) ); + + mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, drv_len, drv_id); // TODO refactor + + p_desc += drv_len; // next interface } // invoke callback @@ -1035,4 +1009,20 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) return _usbd_dev.ep_status[epnum][dir].stalled; } +/** + * usbd_edpt_close will disable an endpoint. + * + * In progress transfers on this EP may be delivered after this call. + * + */ +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + TU_ASSERT(dcd_edpt_close, /**/); + TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); + + dcd_edpt_close(rhport, ep_addr); + + return; +} + #endif diff --git a/src/device/usbd.h b/src/device/usbd.h index 6b31d8113..fcb4e5c5f 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -48,7 +48,7 @@ bool tud_init (void); void tud_task (void); // Interrupt handler, name alias to DCD -#define tud_irq_handler dcd_irq_handler +#define tud_int_handler dcd_int_handler // Check if device is connected and configured bool tud_mounted(void); @@ -183,9 +183,9 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re // Interface number, string index, EP notification address and size, EP data address (out, in) and size. #define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \ /* Interface Associate */\ - 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, 0,\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, 0,\ /* CDC Control Interface */\ - 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, _stridx,\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, _stridx,\ /* CDC Header */\ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ /* CDC Call */\ @@ -291,23 +291,23 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re // Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID, // bulk-in endpoint ID #define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \ -/* Interface */ \ + /* Interface */ \ 0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx #define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u #define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \ -/* Endpoint Out */ \ -7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \ -/* Endpoint In */ \ -7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u + /* Endpoint Out */ \ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \ + /* Endpoint In */ \ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u #define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u) /* optional interrupt endpoint */ \ // _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number? #define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \ -7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16 + 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16 #define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u) @@ -342,12 +342,14 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re //------------- CDC-ECM -------------// -// Length of template descriptor: 62 bytes -#define TUD_CDC_ECM_DESC_LEN (9+5+5+13+7+9+7+7) +// Length of template descriptor: 71 bytes +#define TUD_CDC_ECM_DESC_LEN (8+9+5+5+13+7+9+9+7+7) // CDC-ECM Descriptor Template // Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. #define TUD_CDC_ECM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, 0,\ /* CDC Control Interface */\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, _desc_stridx,\ /* CDC-ECM Header */\ @@ -358,8 +360,10 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\ /* Endpoint Notification */\ 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\ - /* CDC Data Interface */\ - 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* CDC Data Interface (default inactive) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* CDC Data Interface (alternative active) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ /* Endpoint In */\ 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ /* Endpoint Out */\ @@ -372,10 +376,10 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re /* Windows XP */ #define TUD_RNDIS_ITF_CLASS TUSB_CLASS_CDC #define TUD_RNDIS_ITF_SUBCLASS CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL - #define TUD_RNDIS_ITF_PROTOCOL CDC_COMM_PROTOCOL_MICROSOFT_RNDIS + #define TUD_RNDIS_ITF_PROTOCOL 0xFF /* CDC_COMM_PROTOCOL_MICROSOFT_RNDIS */ #else /* Windows 7+ */ - #define TUD_RNDIS_ITF_CLASS 0xE0 + #define TUD_RNDIS_ITF_CLASS TUSB_CLASS_WIRELESS_CONTROLLER #define TUD_RNDIS_ITF_SUBCLASS 0x01 #define TUD_RNDIS_ITF_PROTOCOL 0x03 #endif @@ -408,22 +412,6 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 -//------------- CDC-EEM -------------// - -// Length of template descriptor: 23 bytes -#define TUD_CDC_EEM_DESC_LEN (9+7+7) - -// CDC-EEM Descriptor Template -// Interface number, description string index, EP data address (out, in) and size. -#define TUD_CDC_EEM_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ - /* EEM Interface */\ - 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL, CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL, _stridx,\ - /* Endpoint In */\ - 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ - /* Endpoint Out */\ - 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 - - #ifdef __cplusplus } #endif diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index b9947044b..26b9700e8 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -38,6 +38,7 @@ //--------------------------------------------------------------------+ //bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); // Submit a usb transfer bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c index 126f3ea20..986df3b3b 100644 --- a/src/portable/espressif/esp32s2/dcd_esp32s2.c +++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -190,9 +190,6 @@ void dcd_init(uint8_t rhport) USB_ENUMDONEMSK_M | USB_RESETDETMSK_M | USB_DISCONNINTMSK_M; - - ESP_LOGV(TAG, "DCD init - Soft CONNECT"); - USB0.dctl &= ~USB_SFTDISCON_M; // Connect } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) @@ -216,18 +213,20 @@ void dcd_remote_wakeup(uint8_t rhport) (void)rhport; } -// disconnect by disabling internal pull-up resistor on D+/D- -void dcd_disconnect(uint8_t rhport) -{ - USB0.dctl |= USB_SFTDISCON_M; -} - // connect by enabling internal pull-up resistor on D+/D- void dcd_connect(uint8_t rhport) { + (void) rhport; USB0.dctl &= ~USB_SFTDISCON_M; } +// disconnect by disabling internal pull-up resistor on D+/D- +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + USB0.dctl |= USB_SFTDISCON_M; +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ @@ -639,7 +638,7 @@ static void handle_epin_ints(void) } -static void dcd_int_handler(void* arg) +static void _dcd_int_handler(void* arg) { (void) arg; @@ -727,7 +726,7 @@ static void dcd_int_handler(void* arg) void dcd_int_enable (uint8_t rhport) { (void) rhport; - esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, (intr_handler_t) dcd_int_handler, NULL, &usb_ih); + esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, (intr_handler_t) _dcd_int_handler, NULL, &usb_ih); } void dcd_int_disable (uint8_t rhport) diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index 2c01f8017..bd61df86a 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -331,7 +331,7 @@ void maybe_transfer_complete(void) { } -void dcd_irq_handler (uint8_t rhport) +void dcd_int_handler (uint8_t rhport) { (void) rhport; diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 93d9029d6..7703ee0dc 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -138,9 +138,6 @@ void dcd_init (uint8_t rhport) (void) rhport; tu_memclr(_dcd_xfer, sizeof(_dcd_xfer)); - - // Enable pull-up, disable transceiver - UDP->UDP_TXVC = UDP_TXVC_PUON | UDP_TXVC_TXVDIS_Msk; } // Enable device interrupt @@ -186,6 +183,23 @@ void dcd_remote_wakeup (uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + + // Enable pull-up, disable transceiver + UDP->UDP_TXVC = UDP_TXVC_PUON | UDP_TXVC_TXVDIS_Msk; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + + // disable both pullup and transceiver + UDP->UDP_TXVC = UDP_TXVC_TXVDIS_Msk; +} + + //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ @@ -333,7 +347,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) //--------------------------------------------------------------------+ // ISR //--------------------------------------------------------------------+ -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { uint32_t const intr_mask = UDP->UDP_IMR; uint32_t const intr_status = UDP->UDP_ISR & intr_mask; diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 389266217..95240f9f0 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -373,7 +373,7 @@ void bus_reset(void) _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE; } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void) rhport; diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 050aea255..9195b8dbe 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -306,7 +306,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) ep->CFG |= USBD_CFG_CSTALL_Msk; } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void) rhport; diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index df72cbb2d..edd1e14a7 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -312,7 +312,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) ep->CFG |= USBD_CFG_CSTALL_Msk; } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void) rhport; diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 3baed87c5..aceb6df09 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -112,8 +112,6 @@ static struct uint16_t total_bytes; } ctrl_in_xfer; -static volatile bool configuration_changed; - static volatile struct xfer_ctl_t *current_dma_xfer; @@ -219,7 +217,6 @@ static void bus_reset(void) /* Reset USB device address */ USBD->FADDR = 0; - configuration_changed = false; current_dma_xfer = NULL; } @@ -305,7 +302,6 @@ void dcd_set_config(uint8_t rhport, uint8_t config_num) { (void) rhport; (void) config_num; - configuration_changed = true; } void dcd_remote_wakeup(uint8_t rhport) @@ -435,7 +431,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) } } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void) rhport; @@ -579,15 +575,14 @@ void dcd_irq_handler(uint8_t rhport) else if (cep_state & USBD_CEPINTSTS_STSDONEIF_Msk) { /* given ACK from host has happened, we can now set the address (if not already done) */ - if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0)) USBD->FADDR = assigned_address; - - if (configuration_changed) + if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0)) { + USBD->FADDR = assigned_address; + for (enum ep_enum ep_index = PERIPH_EPA; ep_index < PERIPH_MAX_EP; ep_index++) { if (USBD->EP[ep_index].EPCFG & USBD_EPCFG_EPEN_Msk) USBD->EP[ep_index].EPRSPCTL = USBD_EPRSPCTL_TOGGLE_Msk; } - configuration_changed = false; } USBD->CEPINTEN = USBD_CEPINTEN_SETUPPKIEN_Msk; diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 1d755ce63..21a678c66 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -181,9 +181,7 @@ void dcd_init(uint8_t rhport) LPC_USB->UDCAH = (uint32_t) _dcd.udca; LPC_USB->DMAIntEn = (DMA_INT_END_OF_XFER_MASK /*| DMA_INT_NEW_DD_REQUEST_MASK*/ | DMA_INT_ERROR_MASK); - sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1); // connect - - // USB IRQ priority should be set by application previously + // Clear pending IRQ NVIC_ClearPendingIRQ(USB_IRQn); } @@ -221,6 +219,18 @@ void dcd_remote_wakeup(uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, SIE_DEV_STATUS_CONNECT_STATUS_MASK); +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 0); +} + //--------------------------------------------------------------------+ // CONTROL HELPER //--------------------------------------------------------------------+ @@ -498,7 +508,7 @@ static void dd_complete_isr(uint8_t rhport, uint8_t ep_id) } // main USB IRQ handler -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { uint32_t const dev_int_status = LPC_USB->DevIntSt & LPC_USB->DevIntEn; LPC_USB->DevIntClr = dev_int_status;// Acknowledge handled interrupt diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 9af8e6019..c1f80185b 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -95,7 +95,7 @@ enum { CMDSTAT_DEVICE_ADDR_MASK = TU_BIT(7 )-1, CMDSTAT_DEVICE_ENABLE_MASK = TU_BIT(7 ), CMDSTAT_SETUP_RECEIVED_MASK = TU_BIT(8 ), - CMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), ///< reflect the softconnect only, does not reflect the actual attached state + CMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), ///< reflect the soft-connect only, does not reflect the actual attached state CMDSTAT_DEVICE_SUSPEND_MASK = TU_BIT(17), CMDSTAT_CONNECT_CHANGE_MASK = TU_BIT(24), CMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25), @@ -209,6 +209,18 @@ void dcd_remote_wakeup(uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + DCD_REGS->DEVCMDSTAT |= CMDSTAT_DEVICE_CONNECT_MASK; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + DCD_REGS->DEVCMDSTAT &= ~CMDSTAT_DEVICE_CONNECT_MASK; +} + //--------------------------------------------------------------------+ // DCD Endpoint Port //--------------------------------------------------------------------+ @@ -333,7 +345,7 @@ static void process_xfer_isr(uint32_t int_status) } } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void) rhport; // TODO support multiple USB on supported mcu such as LPC55s69 diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 2872f1435..539629c3d 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -322,7 +322,7 @@ void dcd_init(uint8_t rhport) { tu_memclr(&_dcd_data, sizeof(dcd_data_t)); - dcd_registers_t* const dcd_reg = _dcd_controller[rhport].regs; + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; // Reset controller dcd_reg->USBCMD |= USBCMD_RESET; @@ -342,7 +342,6 @@ void dcd_init(uint8_t rhport) dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_RESET | INTR_SUSPEND /*| INTR_SOF*/; dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0 - dcd_reg->USBCMD |= TU_BIT(0); // connect } void dcd_int_enable(uint8_t rhport) @@ -376,6 +375,18 @@ void dcd_remote_wakeup(uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + dcd_reg->USBCMD |= USBCMD_RUN_STOP; +} + +void dcd_disconnect(uint8_t rhport) +{ + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + dcd_reg->USBCMD &= ~USBCMD_RUN_STOP; +} + //--------------------------------------------------------------------+ // HELPER //--------------------------------------------------------------------+ @@ -492,7 +503,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t //--------------------------------------------------------------------+ // ISR //--------------------------------------------------------------------+ -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { dcd_registers_t* const dcd_reg = _dcd_controller[rhport].regs; diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index 320b7237e..7fd630384 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -201,6 +201,18 @@ void dcd_remote_wakeup(uint8_t rhport) DEV_WAKEUP(usbdev); } +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + DEV_CONNECT(usbdev); +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + DEV_DISCONNECT(usbdev); +} + //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 2939e5ae2..dbc1e6952 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -63,19 +63,16 @@ * Current driver limitations (i.e., a list of features for you to add): * - STALL handled, but not tested. * - Does it work? No clue. - * - All EP BTABLE buffers are created as max 64 bytes. - * - Smaller can be requested, but it has to be an even number. + * - All EP BTABLE buffers are created based on max packet size of first EP opened with that address. * - No isochronous endpoints * - Endpoint index is the ID of the endpoint * - This means that priority is given to endpoints with lower ID numbers * - Code is mixing up EP IX with EP ID. Everywhere. - * - No way to close endpoints; Can a device be reconfigured without a reset? * - Packet buffer memory is copied in the interrupt. * - This is better for performance, but means interrupts are disabled for longer * - DMA may be the best choice, but it could also be pushed to the USBD task. * - No double-buffering * - No DMA - * - No provision to control the D+ pull-up using GPIO on devices without an internal pull-up. * - Minimal error handling * - Perhaps error interrupts should be reported to the stack, or cause a device reset? * - Assumes a single USB peripheral; I think that no hardware has multiple so this is fine. @@ -131,15 +128,16 @@ * Configuration *****************************************************/ -// HW supports max of 8 endpoints, but this can be reduced to save RAM +// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM +// (8u here would mean 8 IN and 8 OUT) #ifndef MAX_EP_COUNT -# define MAX_EP_COUNT 8u +# define MAX_EP_COUNT 8U #endif // If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it // Both of these MUST be a multiple of 2, and are in byte units. #ifndef DCD_STM32_BTABLE_BASE -# define DCD_STM32_BTABLE_BASE 0u +# define DCD_STM32_BTABLE_BASE 0U #endif #ifndef DCD_STM32_BTABLE_LENGTH @@ -163,7 +161,9 @@ typedef struct uint8_t * buffer; uint16_t total_len; uint16_t queued_len; - uint16_t max_packet_size; + uint16_t pma_ptr; + uint8_t max_packet_size; + uint8_t pma_alloc_size; } xfer_ctl_t; static xfer_ctl_t xfer_status[MAX_EP_COUNT][2]; @@ -177,15 +177,19 @@ static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; static uint8_t remoteWakeCountdown; // When wake is requested -// EP Buffers assigned from end of memory location, to minimize their chance of crashing // into the stack. -static uint16_t ep_buf_ptr; static void dcd_handle_bus_reset(void); -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); static void dcd_ep_ctr_handler(void); +// PMA allocation/access +static uint8_t open_ep_count; +static uint16_t ep_buf_ptr; ///< Points to first free memory location +static void dcd_pma_alloc_reset(void); +static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); +static void dcd_pma_free(uint8_t ep_addr); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); // Using a function due to better type checks // This seems better than having to do type casts everywhere else @@ -219,7 +223,7 @@ void dcd_init (uint8_t rhport) asm("NOP"); } USB->CNTR = 0; // Enable USB - + USB->BTABLE = DCD_STM32_BTABLE_BASE; reg16_clear_bits(&USB->ISTR, USB_ISTR_ALL_EVENTS); // Clear pending interrupts @@ -231,12 +235,6 @@ void dcd_init (uint8_t rhport) pcd_set_endpoint(USB,i,0u); } - // Initialize the BTABLE for EP0 at this point (though setting up the EP0R is unneeded) - // This is actually not necessary, but helps debugging to start with a blank RAM area - for(uint32_t i=0;i<(DCD_STM32_BTABLE_LENGTH>>1); i++) - { - pma[PMA_STRIDE*(DCD_STM32_BTABLE_BASE + i)] = 0u; - } USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_SOFM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; dcd_handle_bus_reset(); @@ -368,7 +366,7 @@ static void dcd_handle_bus_reset(void) pcd_set_endpoint(USB,i,0u); } - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) + dcd_pma_alloc_reset(); dcd_edpt_open (0, &ep0OUT_desc); dcd_edpt_open (0, &ep0IN_desc); @@ -501,7 +499,7 @@ static void dcd_ep_ctr_handler(void) } } -void dcd_irq_handler(uint8_t rhport) { +void dcd_int_handler(uint8_t rhport) { (void) rhport; @@ -592,6 +590,85 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re } } +static void dcd_pma_alloc_reset(void) +{ + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) + //TU_LOG2("dcd_pma_alloc_reset()\r\n"); + for(uint32_t i=0; i<MAX_EP_COUNT; i++) + { + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + } +} + +/*** + * Allocate a section of PMA + * + * If the EP number has already been allocated, and the new allocation + * is larger than the old allocation, then this will fail with a TU_ASSERT. + * (This is done to simplify the code. More complicated algorithms could be used) + * + * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. + */ +static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir); + + if(epXferCtl->pma_alloc_size != 0U) + { + //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr); + // Previously allocated + TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc + return epXferCtl->pma_ptr; + } + + uint16_t addr = ep_buf_ptr; + ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + + // Verify no overflow + TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); + + epXferCtl->pma_ptr = addr; + epXferCtl->pma_alloc_size = length; + //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); + + return addr; +} + +/*** + * Free a block of PMA space + */ +static void dcd_pma_free(uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Presently, this should never be called for EP0 IN/OUT + TU_ASSERT(open_ep_count > 2, /**/); + TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/); + open_ep_count--; + + // If count is 2, only EP0 should be open, so allocations can be mostly reset. + + if(open_ep_count == 2) + { + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0 + + // Skip EP0 + for(uint32_t i=1; i<MAX_EP_COUNT; i++) + { + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + } + } +} + // The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, // so I'm using the #define from HAL here, instead. @@ -601,28 +678,30 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); const uint16_t epMaxPktSize = p_endpoint_desc->wMaxPacketSize.size; + uint16_t pma_addr; + uint32_t wType; + // Isochronous not supported (yet), and some other driver assumptions. - TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); TU_ASSERT(epnum < MAX_EP_COUNT); // Set type switch(p_endpoint_desc->bmAttributes.xfer) { case TUSB_XFER_CONTROL: - pcd_set_eptype(USB, epnum, USB_EP_CONTROL); + wType = USB_EP_CONTROL; break; #if (0) case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported - pcd_set_eptype(USB, epnum, USB_EP_ISOCHRONOUS); break; + wType = USB_EP_ISOCHRONOUS; break; #endif case TUSB_XFER_BULK: - pcd_set_eptype(USB, epnum, USB_EP_BULK); + wType = USB_EP_CONTROL; break; case TUSB_XFER_INTERRUPT: - pcd_set_eptype(USB, epnum, USB_EP_INTERRUPT); + wType = USB_EP_INTERRUPT; break; default: @@ -630,32 +709,59 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc return false; } + pcd_set_eptype(USB, epnum, wType); pcd_set_ep_address(USB, epnum, epnum); // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) // or being double-buffered (bulk endpoints) pcd_clear_ep_kind(USB,0); + pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->wMaxPacketSize.size); + if(dir == TUSB_DIR_IN) { - *pcd_ep_tx_address_ptr(USB, epnum) = ep_buf_ptr; + *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr; pcd_set_ep_tx_cnt(USB, epnum, p_endpoint_desc->wMaxPacketSize.size); pcd_clear_tx_dtog(USB, epnum); pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK); } else { - *pcd_ep_rx_address_ptr(USB, epnum) = ep_buf_ptr; + *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr; pcd_set_ep_rx_cnt(USB, epnum, p_endpoint_desc->wMaxPacketSize.size); pcd_clear_rx_dtog(USB, epnum); pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK); } xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize; - ep_buf_ptr = (uint16_t)(ep_buf_ptr + p_endpoint_desc->wMaxPacketSize.size); // increment buffer pointer return true; } +/** + * Close an endpoint. + * + * This function may be called with interrupts enabled or disabled. + * + * This also clears transfers in progress, should there be any. + */ +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + uint32_t const epnum = tu_edpt_number(ep_addr); + uint32_t const dir = tu_edpt_dir(ep_addr); + + if(dir == TUSB_DIR_IN) + { + pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS); + } + else + { + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS); + } + + dcd_pma_free(ep_addr); +} + // Currently, single-buffered, and only 64 bytes at a time (max) static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index dc752b37a..0c9c2650d 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -209,10 +209,6 @@ void dcd_init (uint8_t rhport) // Enable USB transceiver. USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_PWRDWN; - - // Soft Connect -> Enable pullup on D+/D-. - // This step does not appear to be specified in the programmer's model. - dev->DCTL &= ~USB_OTG_DCTL_SDIS; } void dcd_int_enable (uint8_t rhport) @@ -250,6 +246,23 @@ void dcd_remote_wakeup(uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + USB_OTG_DeviceTypeDef * dev = DEVICE_BASE; + + dev->DCTL &= ~USB_OTG_DCTL_SDIS; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + USB_OTG_DeviceTypeDef * dev = DEVICE_BASE; + + dev->DCTL |= USB_OTG_DCTL_SDIS; +} + + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ @@ -656,7 +669,7 @@ static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointType } } -void dcd_irq_handler(uint8_t rhport) { +void dcd_int_handler(uint8_t rhport) { (void) rhport; diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index d29c98e55..ba1383f31 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -91,6 +91,18 @@ void dcd_remote_wakeup (uint8_t rhport) (void) rhport; } +// Connect by enabling internal pull-up resistor on D+/D- +void dcd_connect(uint8_t rhport) +{ + (void) rhport; +} + +// Disconnect by disabling internal pull-up resistor on D+/D- +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; +} + //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index edccec33f..da75a7f3f 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -134,9 +134,6 @@ void dcd_init (uint8_t rhport) // Enable reset and wait for it before continuing. USBIE |= RSTRIE; - // Enable pullup. - USBCNF |= PUR_EN; - USBKEYPID = 0; } @@ -207,6 +204,28 @@ void dcd_remote_wakeup(uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + dcd_int_disable(rhport); + + USBKEYPID = USBKEY; + USBCNF |= PUR_EN; // Enable pullup. + USBKEYPID = 0; + + dcd_int_enable(rhport); +} + +void dcd_disconnect(uint8_t rhport) +{ + dcd_int_disable(rhport); + + USBKEYPID = USBKEY; + USBCNF &= ~PUR_EN; // Disable pullup. + USBKEYPID = 0; + + dcd_int_enable(rhport); +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ @@ -539,7 +558,7 @@ static void handle_setup_packet(void) dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true); } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void) rhport; diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index 1054e71d6..8dde874fc 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -397,6 +397,19 @@ void dcd_remote_wakeup(uint8_t rhport) (void) rhport; } +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + usb_pullup_out_write(1); +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + usb_pullup_out_write(0); +} + + //--------------------------------------------------------------------+ // DCD Endpoint Port //--------------------------------------------------------------------+ @@ -613,7 +626,7 @@ static void handle_setup(void) usb_setup_ev_pending_write(1); } -void dcd_irq_handler(uint8_t rhport) +void dcd_int_handler(uint8_t rhport) { (void)rhport; uint8_t next_ev; diff --git a/src/tusb_option.h b/src/tusb_option.h index 6e2a2f125..0826a5aab 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -124,15 +124,6 @@ #define OPT_MODE_HIGH_SPEED 0x10 ///< High speed /** @} */ -/** \defgroup group_supported_netif Supported Network Interface - * \ref CFG_TUD_NET must be defined to one of these - * @{ */ -#define OPT_NET_NONE 0 ///< No network interface -#define OPT_NET_ECM 1 ///< CDC-ECM -#define OPT_NET_RNDIS 2 ///< RNDIS -#define OPT_NET_EEM 3 ///< CDC-EEM -/** @} */ - #ifndef CFG_TUSB_RHPORT0_MODE #define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE #endif |
